Add mise task runner and update AGENTS.md

Amolith created

Change summary

AGENTS.md | 11 ++---------
mise.toml | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 58 insertions(+), 9 deletions(-)

Detailed changes

AGENTS.md 🔗

@@ -3,13 +3,9 @@
 ## Commands
 
 ```sh
-go build ./...                  # build all
-go test ./...                   # test all
-go test ./internal/silverbullet/ # test single package
+mise run check # fmt, lint, vet, vuln, build, and test
 ```
 
-Build with version: `go build -ldflags "-X git.secluded.site/sb-mcp/internal/server.Version=$VERSION" ./cmd/sb-mcp/`
-
 Run: `sb-mcp serve` (stdio) or `sb-mcp serve --http :3001` (streamable HTTP)
 
 ## Landmines
@@ -18,7 +14,4 @@ Run: `sb-mcp serve` (stdio) or `sb-mcp serve --http :3001` (streamable HTTP)
 - **Space Lua is camelCase**, not snake_case. All built-in functions (`space.readPage`, `space.writePage`) use camelCase. Writing `space.read_page` will fail.
 - **Bearer auth and password auth coexist** — `SB_TOKEN` sets `Authorization: Bearer ...`, while `SB_USER`/`SB_PASS` logs in via `POST /.auth` and sends a session `Cookie`. They use different headers, no override. For proxy auth (e.g. Exe.dev), use SB password authentication with Exe Bearer auth or SB Bearer auth with Exe HTTP Basic credentials embedded in `SB_URL` (`https://user:pass@host`).
 - **Timeout clamping**: Lua timeouts <1 are clamped to 1, >21600 clamped to 21600. No error raised; the value silently changes.
-
-## Environment
-
-Required: `SB_URL` (must be http(s)). Optional: `SB_USER`/`SB_PASS` (basic auth), `SB_TOKEN` (bearer), `SB_TIMEOUT` (seconds, default 120).
+- **`DisableLocalhostProtection: true`** is set on the StreamableHTTP handler because nginx proxies with the external Host header. Removing it will cause 403s from the SDK's DNS rebinding protection.

mise.toml 🔗

@@ -0,0 +1,56 @@
+[env]
+CGO_ENABLED = "0"
+
+[tools]
+go = "latest"
+"go:golang.org/x/vuln/cmd/govulncheck" = "latest"
+"go:mvdan.cc/gofumpt" = "latest"
+golangci-lint = "latest"
+
+[tasks.build]
+run = "go build -ldflags \"-X git.secluded.site/sb-mcp/internal/server.Version=$(git describe --tags --always --dirty 2>/dev/null || echo dev)\" ./cmd/sb-mcp/"
+
+[tasks.install]
+run = "go install -ldflags \"-X git.secluded.site/sb-mcp/internal/server.Version=$(git describe --tags --always --dirty 2>/dev/null || echo dev)\" ./cmd/sb-mcp/"
+
+[tasks.test]
+run = "go test -v ./..."
+
+[tasks.fmt]
+run = "gofumpt -w ."
+
+[tasks."fmt:check"]
+run = """
+output=$(gofumpt -d .)
+if [ -n "$output" ]; then
+  echo "$output"
+  echo "Files unformatted; execute 'mise run fmt'"
+  exit 1
+fi
+"""
+
+[tasks.fix]
+run = "jj --config 'fix.tools.gofumpt.command=[\"gofumpt\"]' --config 'fix.tools.gofumpt.patterns=[\"glob:**/*.go\"]' fix"
+
+[tasks.lint]
+run = "golangci-lint run"
+
+[tasks.vuln]
+run = "govulncheck ./..."
+
+[tasks.vet]
+run = "go vet ./..."
+
+[tasks."test:quiet"]
+run = """
+output=$(go test ./... 2>&1)
+if [ $? -eq 0 ]; then
+  echo "✓"
+else
+  echo "$output"
+  exit 1
+fi
+"""
+
+[tasks.check]
+depends = ["fmt", "vet", "lint", "vuln", "build", "test:quiet"]