diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..95775d7 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,150 @@ +# CLAUDE.md — core/go-php + +## What This Is + +Standalone `core-php` binary for PHP/Laravel development. Merges the FrankenPHP handler (CGO) with PHP dev CLI commands (pure Go). Produces a single binary that `core` can invoke as a subprocess. + +**Module path**: `forge.lthn.ai/core/go-php` +**Binary**: `cmd/core-php/main.go` → `./bin/core-php` +**Pattern**: `cli.Main()` + `cli.WithCommands("php", php.AddPHPCommands)` + +## Build + +```bash +# Dev tooling only (no FrankenPHP, no CGO needed) +CGO_ENABLED=0 go build -o ./bin/core-php ./cmd/core-php +CGO_ENABLED=0 go test ./... + +# With FrankenPHP (needs PHP-ZTS + CGO) +go build -o ./bin/core-php ./cmd/core-php +``` + +## Current State + +- All code merged from `core/php` + `core/go-php` into single module +- Entry point exists at `cmd/core-php/main.go` +- Tests pass (`CGO_ENABLED=0 go test ./...`) +- `init()` in `cmd.go` still calls `cli.RegisterCommands()` — needs removing (standalone binary pattern) +- No Taskfile yet +- No CLAUDE.md until now +- FrankenPHP handler files: `handler.go`, `bridge.go`, `extract.go`, `env.go` +- FrankenPHP serve command: `cmd_serve_frankenphp.go` (exists, needs build tags) +- Dev CLI commands: `cmd_dev.go`, `cmd_build.go`, `cmd_deploy.go`, `cmd_ci.go`, `cmd_quality.go`, `cmd_packages.go`, `cmd_qa_runner.go` + +## Why This Matters + +Completing go-php unblocks a chain: +1. `core/go-php` done → `core/php` namespace freed +2. `core/php-framework` relocates to `core/php` (matching `core/go` pattern) +3. `core/ts` created from Deno prototype (the original seed project) + +## Plan — Tasks To Complete + +### Task 1: Clean up `init()` registration + +**File**: `cmd.go` + +Remove `init()` that calls `cli.RegisterCommands()`. The standalone binary uses `cli.Main()` directly — `init()` registration is the old pattern for when this was a library imported by the main `core` binary. + +Keep `AddPHPCommands` exported (the entry point calls it). + +**Verify**: `CGO_ENABLED=0 go build -o ./bin/core-php ./cmd/core-php && ./bin/core-php php --help` + +### Task 2: Build-tag the FrankenPHP files + +FrankenPHP requires CGO + PHP-ZTS headers. Files that import `github.com/dunglas/frankenphp` need build tags so the binary compiles without them. + +**Files needing `//go:build cgo`**: +- `handler.go` +- `bridge.go` +- `cmd_serve_frankenphp.go` +- Any file importing FrankenPHP + +**Create stubs** (`//go:build !cgo`): +- `cmd_serve_frankenphp_nocgo.go` — prints "requires CGO + PHP-ZTS" +- `handler_nocgo.go` — nil/noop exports if other files reference Handler + +**Verify**: `CGO_ENABLED=0 go build ./...` AND `CGO_ENABLED=0 go test ./...` + +### Task 3: Add Taskfile.yml + +Based on the BugSETI pattern (`/Users/snider/Code/host-uk/core/cmd/bugseti/Taskfile.yml`): + +```yaml +version: '3' + +tasks: + build: + desc: Build core-php binary + cmds: + - CGO_ENABLED=0 go build -o ./bin/core-php ./cmd/core-php + + build-frankenphp: + desc: Build with FrankenPHP support (needs PHP-ZTS) + cmds: + - go build -o ./bin/core-php ./cmd/core-php + + test: + desc: Run tests + cmds: + - CGO_ENABLED=0 go test ./... + + run: + desc: Build and run + cmds: + - task: build + - ./bin/core-php {{.CLI_ARGS}} +``` + +### Task 4: Verify all commands register + +Run `./bin/core-php php --help` and confirm all subcommands appear: +- `dev` — Laravel dev server (FrankenPHP + Vite + Horizon) +- `build` — Docker/production builds +- `deploy` — Deployment commands +- `ci` — CI pipeline +- `quality` / `qa` — Code quality (Pint, PHPStan) +- `packages` — Composer package management +- `serve` — FrankenPHP server (CGO only) + +### Task 5: Push to forge + +```bash +git add -A +git commit -m "feat: standalone core-php binary with build tags + +- Remove init() registration, use cli.Main() pattern +- Build-tag FrankenPHP files (cgo/!cgo) +- Add Taskfile.yml +- Add CLAUDE.md + +Co-Authored-By: Virgil " + +git push origin main +``` + +**Remote**: `ssh://git@forge.lthn.ai:2223/core/go-php.git` + +## Coding Standards + +- **UK English** in comments and docs +- **Strict error handling**: wrap with context, no silent swallows +- **Test naming**: `_Good`, `_Bad`, `_Ugly` suffix pattern +- **No init()**: standalone binary pattern uses `cli.Main()` + `cli.WithCommands()` +- **License**: EUPL-1.2 +- **Co-author**: `Co-Authored-By: Virgil ` + +## Key Dependencies + +| Package | Role | +|---------|------| +| `forge.lthn.ai/core/cli` | CLI framework (cobra + bubbletea TUI) | +| `forge.lthn.ai/core/go` | Core framework (services, DI) | +| `forge.lthn.ai/core/go-i18n` | Internationalisation | +| `github.com/dunglas/frankenphp` | PHP-in-Go (CGO, optional) | + +## Reference + +- CLI pattern: `/Users/snider/Code/host-uk/cli/main.go` +- BugSETI Taskfile: `/Users/snider/Code/host-uk/core/cmd/bugseti/Taskfile.yml` +- FrankenPHP native app: see `frankenphp-native.md` in memory diff --git a/Taskfile.yml b/Taskfile.yml new file mode 100644 index 0000000..4d8f35e --- /dev/null +++ b/Taskfile.yml @@ -0,0 +1,23 @@ +version: '3' + +tasks: + build: + desc: Build core-php binary + cmds: + - CGO_ENABLED=0 go build -o ./bin/core-php ./cmd/core-php + + build-frankenphp: + desc: Build with FrankenPHP support (needs PHP-ZTS) + cmds: + - go build -o ./bin/core-php ./cmd/core-php + + test: + desc: Run tests + cmds: + - CGO_ENABLED=0 go test ./... + + run: + desc: Build and run + cmds: + - task: build + - ./bin/core-php {{.CLI_ARGS}} diff --git a/cmd.go b/cmd.go index 10adf74..4cecacc 100644 --- a/cmd.go +++ b/cmd.go @@ -9,10 +9,6 @@ import ( "forge.lthn.ai/core/go/pkg/io" ) -func init() { - cli.RegisterCommands(AddPHPCommands) -} - // DefaultMedium is the default filesystem medium used by the php package. // It defaults to io.Local (unsandboxed filesystem access). // Use SetMedium to change this for testing or sandboxed operation. diff --git a/go.mod b/go.mod index 68ab7d6..b26c4ec 100644 --- a/go.mod +++ b/go.mod @@ -32,6 +32,7 @@ require ( github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect github.com/gammazero/deque v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/klauspost/compress v1.18.4 // indirect github.com/lucasb-eyer/go-colorful v1.3.0 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-localereader v0.0.1 // indirect diff --git a/go.sum b/go.sum index 5a91748..e6ba3aa 100644 --- a/go.sum +++ b/go.sum @@ -49,8 +49,7 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= -github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= +github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=