01fb5a2703
There is no CI: the instance has no act_runner and none is planned, so releases are cut by hand. That makes `make check` the only thing standing between a mistake and the tracker, and it is one command: gofmt, vet, the suite with the cache defeated, `go mod verify`, a vendored build, and `kettle gen skills --check`. The last one is the invariant worth having — the plugin's SKILL.md command reference is generated from the binary's registry, so a flag that changed cannot ship with documentation that recommends the old one. `cli/cmd/release` publishes to Gitea using the same SDK the binary already vendors, which is a pleasing thing to be able to say: nothing third-party handles the artifacts. It is a second binary rather than a `kettle` subcommand on purpose — `kettle`'s command tree is what generates the plugin's skills, so a verb there ships to every operator, and publishing a release is build infrastructure. It is idempotent end to end: an existing release for the tag is reused, an asset of the same name is replaced rather than doubled, and a retried run converges instead of duplicating. `make release` refuses three things, each with its own message: a dirty working tree, a TAG that is not what `git describe` reports, and a tag the remote does not have. A release built from uncommitted code is unreproducible and nobody finds out until they need to reproduce it. `kettle version` reports the stamp, the toolchain and the VCS revision. The default is `dev`, and a hand build says so and means it — a binary out of somebody's working tree is not a release and must not claim to be one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
44 lines
1.9 KiB
Markdown
44 lines
1.9 KiB
Markdown
# AGENTS.md — cmd/kettle
|
|
|
|
The binary's entry point, and all of it:
|
|
|
|
```go
|
|
func main() { os.Exit(cmd.Main(os.Args[1:])) }
|
|
```
|
|
|
|
One file, `main.go`, holding a package comment and that line. The sibling
|
|
[`cmd/release`](../release/AGENTS.md) is the module's other binary — build
|
|
infrastructure, deliberately not a `kettle` verb.
|
|
|
|
## Why it is empty
|
|
|
|
Everything a `main` usually accumulates — flag parsing, dispatch, usage text,
|
|
error formatting, exit codes — is in [`internal/cmd`](../../internal/cmd/AGENTS.md),
|
|
where it is **testable**. A `main` package cannot be imported, so anything written
|
|
here can only be exercised by running the binary; the command tree is instead a
|
|
library with one caller, and its tests run it as a subprocess *and* call into it
|
|
directly where that is cheaper.
|
|
|
|
The exit status is the only thing this layer owns, and it owns it because
|
|
`os.Exit` skips deferred functions: it has to happen after everything else is
|
|
finished, at the outermost frame, and nowhere else in the tree may call it.
|
|
|
|
The version a build reports is **not** stamped here either. `-ldflags -X` names
|
|
`internal/cmd.Version`, because that is where the `version` command reads it and
|
|
where a test can build with the flag and read the answer back — a `-X` whose symbol
|
|
path is one character wrong is silently ignored, and the binary goes on saying `dev`.
|
|
|
|
## Adding a command
|
|
|
|
Nothing here changes. A new command is a `register(&Command{…})` in an `init()`
|
|
over in [`internal/cmd`](../../internal/cmd/AGENTS.md) — that is the whole point
|
|
of a registry.
|
|
|
|
## Keeping this file true
|
|
|
|
- **Scope:** `main.go`, and the reason it stays this short.
|
|
- **Update it when** this package grows a second file or a line that does anything
|
|
but delegate — which should be treated as a design change and argued for, not
|
|
documented after the fact.
|
|
- **Do not** describe commands, flags or exit codes here.
|