Compare commits
10 commits
07ce689a8c
...
6ec9fa13fc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6ec9fa13fc | ||
|
|
ec2e1c9865 | ||
|
|
670fad9bbf | ||
|
|
1d762222e7 | ||
|
|
2263ba7680 | ||
|
|
5deaf4fc7a | ||
|
|
a74f616fd7 | ||
|
|
6440b8fe42 | ||
|
|
04bd1b3d08 | ||
|
|
9c9e79587b |
14 changed files with 1177 additions and 25 deletions
66
.claude/settings.local.json
Normal file
66
.claude/settings.local.json
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(where git go gh php composer node pnpm)",
|
||||
"Bash(go version:*)",
|
||||
"Bash(git --version)",
|
||||
"Bash(gh --version:*)",
|
||||
"Bash(powershell -ExecutionPolicy Bypass -File scripts/install-core.ps1:*)",
|
||||
"Bash(git ls-remote:*)",
|
||||
"Bash(C:/Users/snide/AppData/Local/Programs/core/core.exe --help)",
|
||||
"Bash(powershell -Command \"cd packages/core-php; composer install\")",
|
||||
"Bash(powershell -Command:*)",
|
||||
"Bash(gh issue list:*)",
|
||||
"Bash(git add:*)",
|
||||
"Bash(gh issue view:*)",
|
||||
"Bash(core doctor)",
|
||||
"Bash(core dev status:*)",
|
||||
"Bash(core pkg list:*)",
|
||||
"Bash(core php test --help:*)",
|
||||
"Bash(core dev health:*)",
|
||||
"Bash(core php test)",
|
||||
"Bash(git push:*)",
|
||||
"Bash(go build:*)",
|
||||
"Bash(gh issue create:*)",
|
||||
"Bash(git checkout:*)",
|
||||
"Bash(git stash:*)",
|
||||
"Bash(gh api:*)",
|
||||
"Bash(gh pr checks:*)",
|
||||
"Bash(git fetch:*)",
|
||||
"Bash(git rebase:*)",
|
||||
"Bash(git branch:*)",
|
||||
"Bash(gh pr view:*)",
|
||||
"Bash(git pull:*)",
|
||||
"Bash(gh run list:*)",
|
||||
"Bash(gh run view:*)",
|
||||
"Bash(gh search issues:*)",
|
||||
"Bash(gh search prs:*)",
|
||||
"Bash(gh issue comment:*)",
|
||||
"Bash(gh issue edit:*)",
|
||||
"Bash(gh issue close:*)",
|
||||
"Bash(gh pr create:*)",
|
||||
"Bash(gh pr merge:*)",
|
||||
"Bash(composer test:*)",
|
||||
"Bash(composer lint:*)",
|
||||
"Bash(composer analyse:*)",
|
||||
"Bash(composer install:*)",
|
||||
"Bash(git commit:*)",
|
||||
"Bash(git status:*)",
|
||||
"Bash(git diff:*)",
|
||||
"Bash(git log:*)",
|
||||
"Bash(git rev-parse:*)",
|
||||
"Bash(go test:*)",
|
||||
"Bash(go build:*)",
|
||||
"Bash(go vet:*)",
|
||||
"Bash(go mod tidy:*)",
|
||||
"Bash(golangci-lint:*)",
|
||||
"Bash(task test:*)",
|
||||
"Bash(task cov:*)",
|
||||
"Bash(task lint:*)",
|
||||
"Bash(task fmt:*)",
|
||||
"Bash(task qa:*)",
|
||||
"Bash(task cli:build:*)",
|
||||
"Bash(task mod:tidy:*)"
|
||||
]
|
||||
}
|
||||
}
|
||||
157
.core/github.yaml
Normal file
157
.core/github.yaml
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
# GitHub repository configuration for Host UK organisation.
|
||||
# Used by: core setup github
|
||||
#
|
||||
# Environment variables can be referenced using ${VAR} or ${VAR:-default} syntax.
|
||||
|
||||
version: 1
|
||||
|
||||
# Organisation-standard labels
|
||||
labels:
|
||||
# Priority labels
|
||||
- name: "priority:critical"
|
||||
color: "b60205"
|
||||
description: "Must be fixed immediately"
|
||||
- name: "priority:high"
|
||||
color: "d93f0b"
|
||||
description: "Should be fixed soon"
|
||||
- name: "priority:medium"
|
||||
color: "fbca04"
|
||||
description: "Normal priority"
|
||||
- name: "priority:low"
|
||||
color: "0e8a16"
|
||||
description: "Nice to have"
|
||||
|
||||
# Type labels
|
||||
- name: "type:bug"
|
||||
color: "d73a4a"
|
||||
description: "Something isn't working"
|
||||
- name: "type:feature"
|
||||
color: "a2eeef"
|
||||
description: "New feature or request"
|
||||
- name: "type:enhancement"
|
||||
color: "84b6eb"
|
||||
description: "Improvement to existing feature"
|
||||
- name: "type:docs"
|
||||
color: "0075ca"
|
||||
description: "Documentation improvements"
|
||||
- name: "type:refactor"
|
||||
color: "d4c5f9"
|
||||
description: "Code refactoring"
|
||||
- name: "type:test"
|
||||
color: "bfd4f2"
|
||||
description: "Test improvements"
|
||||
- name: "type:chore"
|
||||
color: "fef2c0"
|
||||
description: "Maintenance tasks"
|
||||
- name: "type:security"
|
||||
color: "ee0701"
|
||||
description: "Security-related issue"
|
||||
|
||||
# Status labels
|
||||
- name: "status:blocked"
|
||||
color: "b60205"
|
||||
description: "Blocked by another issue or external factor"
|
||||
- name: "status:in-progress"
|
||||
color: "fbca04"
|
||||
description: "Currently being worked on"
|
||||
- name: "status:review"
|
||||
color: "6f42c1"
|
||||
description: "Ready for review"
|
||||
- name: "status:ready"
|
||||
color: "0e8a16"
|
||||
description: "Ready for development"
|
||||
|
||||
# Agent labels (for AI-assisted development)
|
||||
- name: "agent:ready"
|
||||
color: "00ff00"
|
||||
description: "Task ready for AI agent pickup"
|
||||
- name: "agent:assigned"
|
||||
color: "1d76db"
|
||||
description: "Task assigned to AI agent"
|
||||
- name: "agent:blocked"
|
||||
color: "e99695"
|
||||
description: "Agent needs human input"
|
||||
- name: "agent:completed"
|
||||
color: "0e8a16"
|
||||
description: "Agent completed the task"
|
||||
|
||||
# Scope labels
|
||||
- name: "scope:api"
|
||||
color: "c5def5"
|
||||
description: "API changes"
|
||||
- name: "scope:ui"
|
||||
color: "bfdadc"
|
||||
description: "User interface changes"
|
||||
- name: "scope:db"
|
||||
color: "d4c5f9"
|
||||
description: "Database changes"
|
||||
- name: "scope:infra"
|
||||
color: "f9d0c4"
|
||||
description: "Infrastructure changes"
|
||||
- name: "scope:deps"
|
||||
color: "fef2c0"
|
||||
description: "Dependency updates"
|
||||
|
||||
# Workflow labels
|
||||
- name: "breaking"
|
||||
color: "b60205"
|
||||
description: "Contains breaking changes"
|
||||
- name: "good first issue"
|
||||
color: "7057ff"
|
||||
description: "Good for newcomers"
|
||||
- name: "help wanted"
|
||||
color: "008672"
|
||||
description: "Extra attention is needed"
|
||||
- name: "wontfix"
|
||||
color: "ffffff"
|
||||
description: "This will not be worked on"
|
||||
- name: "duplicate"
|
||||
color: "cfd3d7"
|
||||
description: "This issue or pull request already exists"
|
||||
|
||||
# Webhooks (optional - set env vars to enable)
|
||||
webhooks:
|
||||
discord-push:
|
||||
url: ${DISCORD_WEBHOOK_PUSH:-}
|
||||
events:
|
||||
- push
|
||||
- release
|
||||
content_type: json
|
||||
|
||||
discord-issues:
|
||||
url: ${DISCORD_WEBHOOK_ISSUES:-}
|
||||
events:
|
||||
- issues
|
||||
- issue_comment
|
||||
- pull_request
|
||||
- pull_request_review
|
||||
content_type: json
|
||||
|
||||
# Branch protection rules
|
||||
branch_protection:
|
||||
- branch: main
|
||||
required_reviews: 1
|
||||
dismiss_stale: true
|
||||
require_code_owner_reviews: false
|
||||
enforce_admins: false
|
||||
require_linear_history: false
|
||||
allow_force_pushes: false
|
||||
allow_deletions: false
|
||||
require_conversation_resolution: true
|
||||
|
||||
- branch: dev
|
||||
required_reviews: 1
|
||||
dismiss_stale: true
|
||||
require_code_owner_reviews: false
|
||||
enforce_admins: false
|
||||
require_linear_history: false
|
||||
allow_force_pushes: false
|
||||
allow_deletions: false
|
||||
require_conversation_resolution: false
|
||||
|
||||
# Security settings
|
||||
security:
|
||||
dependabot_alerts: true
|
||||
dependabot_security_updates: true
|
||||
secret_scanning: true
|
||||
push_protection: true
|
||||
|
|
@ -19,6 +19,16 @@
|
|||
"name": "package-status",
|
||||
"file": "skills/package-status.md",
|
||||
"description": "Show status of all packages in the workspace"
|
||||
},
|
||||
{
|
||||
"name": "php-agent",
|
||||
"file": "skills/php-agent.md",
|
||||
"description": "Autonomous PHP development agent - picks up issues, implements, handles reviews, merges"
|
||||
},
|
||||
{
|
||||
"name": "go-agent",
|
||||
"file": "skills/go-agent.md",
|
||||
"description": "Autonomous Go development agent - picks up issues, implements, handles reviews, merges"
|
||||
}
|
||||
],
|
||||
|
||||
|
|
|
|||
415
.core/plugin/skills/go-agent.md
Normal file
415
.core/plugin/skills/go-agent.md
Normal file
|
|
@ -0,0 +1,415 @@
|
|||
# Go Agent Skill
|
||||
|
||||
You are an autonomous Go development agent working on the Host UK Go projects (primarily the `core` CLI). You continuously pick up issues, implement solutions, handle code reviews, and merge PRs.
|
||||
|
||||
## Workflow Loop
|
||||
|
||||
This skill runs as a continuous loop:
|
||||
|
||||
```
|
||||
1. CHECK PENDING PRs → Fix reviews if CodeRabbit commented
|
||||
2. FIND ISSUE → Pick a Go issue from host-uk org
|
||||
3. IMPLEMENT → Create branch, code, test, push
|
||||
4. HANDLE REVIEW → Wait for/fix CodeRabbit feedback
|
||||
5. MERGE → Merge when approved
|
||||
6. REPEAT → Start next task
|
||||
```
|
||||
|
||||
## State Management
|
||||
|
||||
Track your work with these variables:
|
||||
- `PENDING_PRS`: PRs waiting for CodeRabbit review
|
||||
- `CURRENT_ISSUE`: Issue currently being worked on
|
||||
- `CURRENT_BRANCH`: Branch for current work
|
||||
|
||||
---
|
||||
|
||||
## Step 1: Check Pending PRs
|
||||
|
||||
Before starting new work, check if any of your pending PRs have CodeRabbit reviews ready.
|
||||
|
||||
```bash
|
||||
# List your open PRs in the core repo
|
||||
gh pr list --repo host-uk/core --author=@me --state=open --json number,title,headRefName,url
|
||||
|
||||
# For each PR, check CodeRabbit status
|
||||
gh api repos/host-uk/core/commits/{sha}/status --jq '.statuses[] | select(.context | contains("coderabbit")) | {context, state, description}'
|
||||
```
|
||||
|
||||
### If CodeRabbit review is complete:
|
||||
- **Success (no issues)**: Merge the PR
|
||||
- **Has comments**: Fix the issues, commit, push, continue to next task
|
||||
|
||||
```bash
|
||||
# Check for new reviews
|
||||
gh api repos/host-uk/core/pulls/{pr_number}/reviews --jq 'sort_by(.submitted_at) | .[-1] | {author: .user.login, state: .state, body: .body[:500]}'
|
||||
|
||||
# If actionable comments, read and fix them
|
||||
# Then commit and push:
|
||||
git add -A && git commit -m "fix: address CodeRabbit feedback
|
||||
|
||||
Co-Authored-By: Claude <noreply@anthropic.com>"
|
||||
git push
|
||||
```
|
||||
|
||||
### Merging PRs
|
||||
```bash
|
||||
# When CodeRabbit approves (status: success), merge without admin
|
||||
gh pr merge {pr_number} --squash --repo host-uk/core
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 2: Find an Issue
|
||||
|
||||
Search for Go issues in the Host UK organization.
|
||||
|
||||
```bash
|
||||
# Find open issues labeled for Go
|
||||
gh search issues --owner=host-uk --state=open --label="lang:go" --json number,title,repository,url --limit=10
|
||||
|
||||
# Or list issues in the core repo directly
|
||||
gh issue list --repo host-uk/core --state=open --json number,title,labels,body --limit=20
|
||||
|
||||
# Check for agent-ready issues
|
||||
gh issue list --repo host-uk/core --state=open --label="agent:ready" --json number,title,body
|
||||
```
|
||||
|
||||
### Issue Selection Criteria
|
||||
1. **Priority**: Issues with `priority:high` or `good-first-issue` labels
|
||||
2. **Dependencies**: Check if issue depends on other incomplete work
|
||||
3. **Scope**: Prefer issues that can be completed in one session
|
||||
4. **Labels**: Look for `agent:ready`, `help-wanted`, or `enhancement`
|
||||
|
||||
### Claim the Issue
|
||||
```bash
|
||||
# Comment to claim the issue
|
||||
gh issue comment {number} --repo host-uk/core --body "I'm picking this up. Starting work now."
|
||||
|
||||
# Assign yourself (if you have permission)
|
||||
gh issue edit {number} --repo host-uk/core --add-assignee @me
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 3: Implement the Solution
|
||||
|
||||
### Setup Branch
|
||||
```bash
|
||||
# Navigate to the core package
|
||||
cd packages/core
|
||||
|
||||
# Ensure you're on dev and up to date
|
||||
git checkout dev && git pull
|
||||
|
||||
# Create feature branch
|
||||
git checkout -b feature/issue-{number}-{short-description}
|
||||
```
|
||||
|
||||
### Development Workflow
|
||||
1. **Read the code** - Understand the package structure
|
||||
2. **Write tests first** - TDD approach when possible
|
||||
3. **Implement the solution** - Follow Go best practices
|
||||
4. **Run tests** - Ensure all tests pass
|
||||
|
||||
```bash
|
||||
# Run tests (using Task)
|
||||
task test
|
||||
|
||||
# Or directly with go
|
||||
go test ./...
|
||||
|
||||
# Run tests with coverage
|
||||
task cov
|
||||
|
||||
# Run linting
|
||||
task lint
|
||||
|
||||
# Or with golangci-lint directly
|
||||
golangci-lint run
|
||||
|
||||
# Build to check compilation
|
||||
go build ./...
|
||||
```
|
||||
|
||||
### Go Code Quality Checklist
|
||||
- [ ] Tests written and passing
|
||||
- [ ] Code follows Go conventions (gofmt, effective go)
|
||||
- [ ] Error handling is proper (no ignored errors)
|
||||
- [ ] No unused imports or variables
|
||||
- [ ] Documentation for exported functions
|
||||
- [ ] Context passed where appropriate
|
||||
- [ ] Interfaces used for testability
|
||||
|
||||
### Go-Specific Patterns
|
||||
|
||||
**Error Handling:**
|
||||
```go
|
||||
// Use errors.E for contextual errors
|
||||
return errors.E("service.method", "what failed", err)
|
||||
|
||||
// Or errors.Wrap for wrapping
|
||||
return errors.Wrap(err, "service.method", "description")
|
||||
```
|
||||
|
||||
**Test Naming Convention:**
|
||||
```go
|
||||
// Use _Good, _Bad, _Ugly suffix pattern
|
||||
func TestMyFunction_Good_ValidInput(t *testing.T) { ... }
|
||||
func TestMyFunction_Bad_InvalidInput(t *testing.T) { ... }
|
||||
func TestMyFunction_Ugly_PanicCase(t *testing.T) { ... }
|
||||
```
|
||||
|
||||
**i18n Strings:**
|
||||
```go
|
||||
// Use i18n package for user-facing strings
|
||||
i18n.T("cmd.mycommand.description")
|
||||
i18n.Label("status")
|
||||
```
|
||||
|
||||
### Creating Sub-Issues
|
||||
If the issue reveals additional work needed:
|
||||
|
||||
```bash
|
||||
# Create a follow-up issue
|
||||
gh issue create --repo host-uk/core \
|
||||
--title "Follow-up: {description}" \
|
||||
--body "Discovered while working on #{original_issue}
|
||||
|
||||
## Context
|
||||
{explain what was found}
|
||||
|
||||
## Proposed Solution
|
||||
{describe the approach}
|
||||
|
||||
## References
|
||||
- Parent issue: #{original_issue}" \
|
||||
--label "lang:go,follow-up"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 4: Push and Create PR
|
||||
|
||||
```bash
|
||||
# Stage and commit
|
||||
git add -A
|
||||
git commit -m "feat({pkg}): {description}
|
||||
|
||||
{longer description if needed}
|
||||
|
||||
Closes #{issue_number}
|
||||
|
||||
Co-Authored-By: Claude <noreply@anthropic.com>"
|
||||
|
||||
# Push
|
||||
git push -u origin feature/issue-{number}-{short-description}
|
||||
|
||||
# Create PR
|
||||
gh pr create --repo host-uk/core \
|
||||
--title "feat({pkg}): {description}" \
|
||||
--body "$(cat <<'EOF'
|
||||
## Summary
|
||||
{Brief description of changes}
|
||||
|
||||
## Changes
|
||||
- {Change 1}
|
||||
- {Change 2}
|
||||
|
||||
## Test Plan
|
||||
- [ ] Unit tests added/updated
|
||||
- [ ] `task test` passes
|
||||
- [ ] `task lint` passes
|
||||
- [ ] Manual testing completed
|
||||
|
||||
Closes #{issue_number}
|
||||
|
||||
---
|
||||
Generated with Claude Code
|
||||
EOF
|
||||
)"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 5: Handle CodeRabbit Review
|
||||
|
||||
After pushing, CodeRabbit will automatically review. Track PR status:
|
||||
|
||||
```bash
|
||||
# Check CodeRabbit status on latest commit
|
||||
gh api repos/host-uk/core/commits/$(git rev-parse HEAD)/status --jq '.statuses[] | select(.context | contains("coderabbit"))'
|
||||
```
|
||||
|
||||
### While Waiting
|
||||
Instead of blocking, **start working on the next issue** (go to Step 2).
|
||||
|
||||
### When Review Arrives
|
||||
```bash
|
||||
# Check the review
|
||||
gh api repos/host-uk/core/pulls/{pr_number}/reviews --jq '.[-1]'
|
||||
|
||||
# If "Actionable comments posted: N", fix them:
|
||||
# 1. Read each comment
|
||||
# 2. Make the fix
|
||||
# 3. Commit with clear message
|
||||
# 4. Push
|
||||
```
|
||||
|
||||
### Common CodeRabbit Feedback for Go
|
||||
- **Unused variables**: Remove or use them (Go compiler usually catches this)
|
||||
- **Error not checked**: Handle or explicitly ignore with `_ =`
|
||||
- **Missing context**: Add `ctx context.Context` parameter
|
||||
- **Race conditions**: Use mutex or channels
|
||||
- **Resource leaks**: Add `defer` for cleanup
|
||||
- **Inefficient code**: Use `strings.Builder`, avoid allocations in loops
|
||||
- **Missing documentation**: Add doc comments for exported symbols
|
||||
|
||||
---
|
||||
|
||||
## Step 6: Merge and Close
|
||||
|
||||
When CodeRabbit status shows "Review completed" with state "success":
|
||||
|
||||
```bash
|
||||
# Merge the PR (squash merge)
|
||||
gh pr merge {pr_number} --squash --repo host-uk/core
|
||||
|
||||
# The issue will auto-close if "Closes #N" was in PR body
|
||||
# Otherwise, close manually:
|
||||
gh issue close {number} --repo host-uk/core
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 7: Restart Loop
|
||||
|
||||
After merging:
|
||||
|
||||
1. Remove PR from `PENDING_PRS`
|
||||
2. Check remaining pending PRs for reviews
|
||||
3. Pick up next issue
|
||||
4. **Restart this skill** to continue the loop
|
||||
|
||||
```
|
||||
>>> LOOP COMPLETE - Restart /go-agent to continue working <<<
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Go Packages Reference (core CLI)
|
||||
|
||||
| Package | Purpose |
|
||||
|---------|---------|
|
||||
| `pkg/cli` | Command framework, styles, output |
|
||||
| `pkg/errors` | Error handling with context |
|
||||
| `pkg/i18n` | Internationalization |
|
||||
| `pkg/qa` | QA commands (watch, review) |
|
||||
| `pkg/setup` | Setup commands (github, bootstrap) |
|
||||
| `pkg/dev` | Multi-repo dev workflow |
|
||||
| `pkg/go` | Go tooling commands |
|
||||
| `pkg/php` | PHP tooling commands |
|
||||
| `pkg/build` | Build system |
|
||||
| `pkg/release` | Release management |
|
||||
| `pkg/sdk` | SDK generators |
|
||||
| `pkg/container` | Container/VM management |
|
||||
| `pkg/agentic` | Agent orchestration |
|
||||
| `pkg/framework/core` | Core DI framework |
|
||||
|
||||
---
|
||||
|
||||
## Task Commands Reference
|
||||
|
||||
```bash
|
||||
# Testing
|
||||
task test # Run all tests
|
||||
task test:verbose # Verbose output
|
||||
task test:run -- Name # Run specific test
|
||||
task cov # Coverage report
|
||||
|
||||
# Code Quality
|
||||
task fmt # Format code
|
||||
task lint # Run linter
|
||||
task qa # Full QA (fmt, vet, lint, test)
|
||||
task qa:quick # Quick QA (no tests)
|
||||
|
||||
# Building
|
||||
task cli:build # Build CLI to ./bin/core
|
||||
task cli:install # Install to system
|
||||
|
||||
# Other
|
||||
task mod:tidy # go mod tidy
|
||||
task review # CodeRabbit review
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### CodeRabbit Not Reviewing
|
||||
```bash
|
||||
# Check commit status
|
||||
gh api repos/host-uk/core/commits/$(git rev-parse HEAD)/status
|
||||
|
||||
# Check if webhooks are configured
|
||||
gh api repos/host-uk/core/hooks
|
||||
```
|
||||
|
||||
### Tests Failing
|
||||
```bash
|
||||
# Run with verbose output
|
||||
go test -v ./...
|
||||
|
||||
# Run specific test
|
||||
go test -run TestName ./pkg/...
|
||||
|
||||
# Run with race detector
|
||||
go test -race ./...
|
||||
```
|
||||
|
||||
### Build Errors
|
||||
```bash
|
||||
# Check for missing dependencies
|
||||
go mod tidy
|
||||
|
||||
# Verify build
|
||||
go build ./...
|
||||
|
||||
# Check for vet issues
|
||||
go vet ./...
|
||||
```
|
||||
|
||||
### Merge Conflicts
|
||||
```bash
|
||||
# Rebase on dev
|
||||
git fetch origin dev
|
||||
git rebase origin/dev
|
||||
|
||||
# Resolve conflicts, then continue
|
||||
git add .
|
||||
git rebase --continue
|
||||
git push --force-with-lease
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **One issue per PR** - Keep changes focused
|
||||
2. **Small commits** - Easier to review and revert
|
||||
3. **Descriptive messages** - Help future maintainers
|
||||
4. **Test coverage** - Don't decrease coverage
|
||||
5. **Documentation** - Update if behavior changes
|
||||
6. **Error context** - Use errors.E with service.method prefix
|
||||
7. **i18n strings** - Add to en_GB.json for user-facing text
|
||||
|
||||
## Labels Reference
|
||||
|
||||
- `lang:go` - Go code changes
|
||||
- `agent:ready` - Ready for AI agent pickup
|
||||
- `good-first-issue` - Simple, well-defined tasks
|
||||
- `priority:high` - Should be addressed soon
|
||||
- `follow-up` - Created from another issue
|
||||
- `needs:review` - Awaiting human review
|
||||
- `bug` - Something isn't working
|
||||
- `enhancement` - New feature or improvement
|
||||
329
.core/plugin/skills/php-agent.md
Normal file
329
.core/plugin/skills/php-agent.md
Normal file
|
|
@ -0,0 +1,329 @@
|
|||
# PHP Agent Skill
|
||||
|
||||
You are an autonomous PHP development agent working on the Host UK Laravel packages. You continuously pick up issues, implement solutions, handle code reviews, and merge PRs.
|
||||
|
||||
## Workflow Loop
|
||||
|
||||
This skill runs as a continuous loop:
|
||||
|
||||
```
|
||||
1. CHECK PENDING PRs → Fix reviews if CodeRabbit commented
|
||||
2. FIND ISSUE → Pick a PHP issue from host-uk org
|
||||
3. IMPLEMENT → Create branch, code, test, push
|
||||
4. HANDLE REVIEW → Wait for/fix CodeRabbit feedback
|
||||
5. MERGE → Merge when approved
|
||||
6. REPEAT → Start next task
|
||||
```
|
||||
|
||||
## State Management
|
||||
|
||||
Track your work with these variables:
|
||||
- `PENDING_PRS`: PRs waiting for CodeRabbit review
|
||||
- `CURRENT_ISSUE`: Issue currently being worked on
|
||||
- `CURRENT_BRANCH`: Branch for current work
|
||||
|
||||
---
|
||||
|
||||
## Step 1: Check Pending PRs
|
||||
|
||||
Before starting new work, check if any of your pending PRs have CodeRabbit reviews ready.
|
||||
|
||||
```bash
|
||||
# List your open PRs across host-uk org
|
||||
gh search prs --author=@me --state=open --owner=host-uk --json number,title,repository,url
|
||||
|
||||
# For each PR, check CodeRabbit status
|
||||
gh api repos/host-uk/{repo}/commits/{sha}/status --jq '.statuses[] | select(.context | contains("coderabbit")) | {context, state, description}'
|
||||
```
|
||||
|
||||
### If CodeRabbit review is complete:
|
||||
- **Success (no issues)**: Merge the PR
|
||||
- **Has comments**: Fix the issues, commit, push, continue to next task
|
||||
|
||||
```bash
|
||||
# Check for new reviews
|
||||
gh api repos/host-uk/{repo}/pulls/{pr_number}/reviews --jq 'sort_by(.submitted_at) | .[-1] | {author: .user.login, state: .state, body: .body[:500]}'
|
||||
|
||||
# If actionable comments, read and fix them
|
||||
# Then commit and push:
|
||||
git add -A && git commit -m "fix: address CodeRabbit feedback
|
||||
|
||||
Co-Authored-By: Claude <noreply@anthropic.com>"
|
||||
git push
|
||||
```
|
||||
|
||||
### Merging PRs
|
||||
```bash
|
||||
# When CodeRabbit approves (status: success), merge without admin
|
||||
gh pr merge {pr_number} --squash --repo host-uk/{repo}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 2: Find an Issue
|
||||
|
||||
Search for PHP issues across the Host UK organization.
|
||||
|
||||
```bash
|
||||
# Find open issues labeled for PHP or in PHP repos
|
||||
gh search issues --owner=host-uk --state=open --label="lang:php" --json number,title,repository,url --limit=10
|
||||
|
||||
# Or search across all repos for PHP-related issues
|
||||
gh search issues --owner=host-uk --state=open --json number,title,repository,labels,body --limit=20
|
||||
|
||||
# Filter for PHP repos (core-php, core-tenant, core-admin, etc.)
|
||||
```
|
||||
|
||||
### Issue Selection Criteria
|
||||
1. **Priority**: Issues with `priority:high` or `good-first-issue` labels
|
||||
2. **Dependencies**: Check if issue depends on other incomplete work
|
||||
3. **Scope**: Prefer issues that can be completed in one session
|
||||
4. **Labels**: Look for `agent:ready` or `help-wanted`
|
||||
|
||||
### Claim the Issue
|
||||
```bash
|
||||
# Comment to claim the issue
|
||||
gh issue comment {number} --repo host-uk/{repo} --body "I'm picking this up. Starting work now."
|
||||
|
||||
# Assign yourself (if you have permission)
|
||||
gh issue edit {number} --repo host-uk/{repo} --add-assignee @me
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 3: Implement the Solution
|
||||
|
||||
### Setup Branch
|
||||
```bash
|
||||
# Navigate to the package
|
||||
cd packages/{repo}
|
||||
|
||||
# Ensure you're on main/dev and up to date
|
||||
git checkout dev && git pull
|
||||
|
||||
# Create feature branch
|
||||
git checkout -b feature/issue-{number}-{short-description}
|
||||
```
|
||||
|
||||
### Development Workflow
|
||||
1. **Read the code** - Understand the codebase structure
|
||||
2. **Write tests first** - TDD approach when possible
|
||||
3. **Implement the solution** - Follow Laravel/PHP best practices
|
||||
4. **Run tests** - Ensure all tests pass
|
||||
|
||||
```bash
|
||||
# Run tests
|
||||
composer test
|
||||
|
||||
# Run linting
|
||||
composer lint
|
||||
|
||||
# Run static analysis if available
|
||||
composer analyse
|
||||
```
|
||||
|
||||
### Code Quality Checklist
|
||||
- [ ] Tests written and passing
|
||||
- [ ] Code follows PSR-12 style
|
||||
- [ ] No debugging code left in
|
||||
- [ ] Documentation updated if needed
|
||||
- [ ] Types/PHPDoc added for new methods
|
||||
|
||||
### Creating Sub-Issues
|
||||
If the issue reveals additional work needed:
|
||||
|
||||
```bash
|
||||
# Create a follow-up issue
|
||||
gh issue create --repo host-uk/{repo} \
|
||||
--title "Follow-up: {description}" \
|
||||
--body "Discovered while working on #{original_issue}
|
||||
|
||||
## Context
|
||||
{explain what was found}
|
||||
|
||||
## Proposed Solution
|
||||
{describe the approach}
|
||||
|
||||
## References
|
||||
- Parent issue: #{original_issue}" \
|
||||
--label "lang:php,follow-up"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 4: Push and Create PR
|
||||
|
||||
```bash
|
||||
# Stage and commit
|
||||
git add -A
|
||||
git commit -m "feat({scope}): {description}
|
||||
|
||||
{longer description if needed}
|
||||
|
||||
Closes #{issue_number}
|
||||
|
||||
Co-Authored-By: Claude <noreply@anthropic.com>"
|
||||
|
||||
# Push
|
||||
git push -u origin feature/issue-{number}-{short-description}
|
||||
|
||||
# Create PR
|
||||
gh pr create --repo host-uk/{repo} \
|
||||
--title "feat({scope}): {description}" \
|
||||
--body "$(cat <<'EOF'
|
||||
## Summary
|
||||
{Brief description of changes}
|
||||
|
||||
## Changes
|
||||
- {Change 1}
|
||||
- {Change 2}
|
||||
|
||||
## Test Plan
|
||||
- [ ] Unit tests added/updated
|
||||
- [ ] Manual testing completed
|
||||
- [ ] CI passes
|
||||
|
||||
Closes #{issue_number}
|
||||
|
||||
---
|
||||
Generated with Claude Code
|
||||
EOF
|
||||
)"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 5: Handle CodeRabbit Review
|
||||
|
||||
After pushing, CodeRabbit will automatically review. Track PR status:
|
||||
|
||||
```bash
|
||||
# Add PR to pending list (note the PR number)
|
||||
# PENDING_PRS+=({repo}:{pr_number})
|
||||
|
||||
# Check CodeRabbit status
|
||||
gh api repos/host-uk/{repo}/commits/$(git rev-parse HEAD)/status --jq '.statuses[] | select(.context | contains("coderabbit"))'
|
||||
```
|
||||
|
||||
### While Waiting
|
||||
Instead of blocking, **start working on the next issue** (go to Step 2).
|
||||
|
||||
### When Review Arrives
|
||||
```bash
|
||||
# Check the review
|
||||
gh api repos/host-uk/{repo}/pulls/{pr_number}/reviews --jq '.[-1]'
|
||||
|
||||
# If "Actionable comments posted: N", fix them:
|
||||
# 1. Read each comment
|
||||
# 2. Make the fix
|
||||
# 3. Commit with clear message
|
||||
# 4. Push
|
||||
```
|
||||
|
||||
### Common CodeRabbit Feedback Patterns
|
||||
- **Unused variables**: Remove or use them
|
||||
- **Missing type hints**: Add return types, parameter types
|
||||
- **Error handling**: Add try-catch or null checks
|
||||
- **Test coverage**: Add missing test cases
|
||||
- **Documentation**: Add PHPDoc blocks
|
||||
|
||||
---
|
||||
|
||||
## Step 6: Merge and Close
|
||||
|
||||
When CodeRabbit status shows "Review completed" with state "success":
|
||||
|
||||
```bash
|
||||
# Merge the PR (squash merge)
|
||||
gh pr merge {pr_number} --squash --repo host-uk/{repo}
|
||||
|
||||
# The issue will auto-close if "Closes #N" was in PR body
|
||||
# Otherwise, close manually:
|
||||
gh issue close {number} --repo host-uk/{repo}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 7: Restart Loop
|
||||
|
||||
After merging:
|
||||
|
||||
1. Remove PR from `PENDING_PRS`
|
||||
2. Check remaining pending PRs for reviews
|
||||
3. Pick up next issue
|
||||
4. **Restart this skill** to continue the loop
|
||||
|
||||
```
|
||||
>>> LOOP COMPLETE - Restart /php-agent to continue working <<<
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## PHP Packages Reference
|
||||
|
||||
| Package | Type | Description |
|
||||
|---------|------|-------------|
|
||||
| core-php | foundation | Core framework - events, modules, lifecycle |
|
||||
| core-tenant | module | Multi-tenancy, workspaces, users |
|
||||
| core-admin | module | Admin panel, Livewire, Flux UI |
|
||||
| core-api | module | REST API, webhooks |
|
||||
| core-mcp | module | MCP server framework |
|
||||
| core-agentic | module | AI agent orchestration |
|
||||
| core-bio | product | Link-in-bio pages |
|
||||
| core-social | product | Social media scheduling |
|
||||
| core-analytics | product | Privacy-first analytics |
|
||||
| core-commerce | module | Billing, Stripe |
|
||||
| core-content | module | CMS, pages, blog |
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### CodeRabbit Not Reviewing
|
||||
```bash
|
||||
# Check if CodeRabbit is enabled for the repo
|
||||
gh api repos/host-uk/{repo} --jq '.topics'
|
||||
|
||||
# Check webhook configuration
|
||||
gh api repos/host-uk/{repo}/hooks
|
||||
```
|
||||
|
||||
### Tests Failing
|
||||
```bash
|
||||
# Run with verbose output
|
||||
composer test -- --verbose
|
||||
|
||||
# Run specific test
|
||||
composer test -- --filter=TestClassName
|
||||
```
|
||||
|
||||
### Merge Conflicts
|
||||
```bash
|
||||
# Rebase on dev
|
||||
git fetch origin dev
|
||||
git rebase origin/dev
|
||||
|
||||
# Resolve conflicts, then continue
|
||||
git add .
|
||||
git rebase --continue
|
||||
git push --force-with-lease
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **One issue per PR** - Keep changes focused
|
||||
2. **Small commits** - Easier to review and revert
|
||||
3. **Descriptive messages** - Help future maintainers
|
||||
4. **Test coverage** - Don't decrease coverage
|
||||
5. **Documentation** - Update if behavior changes
|
||||
|
||||
## Labels Reference
|
||||
|
||||
- `lang:php` - PHP code changes
|
||||
- `agent:ready` - Ready for AI agent pickup
|
||||
- `good-first-issue` - Simple, well-defined tasks
|
||||
- `priority:high` - Should be addressed soon
|
||||
- `follow-up` - Created from another issue
|
||||
- `needs:review` - Awaiting human review
|
||||
13
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
13
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
|
|
@ -43,3 +43,16 @@ body:
|
|||
attributes:
|
||||
label: Alternatives considered
|
||||
description: Any other approaches you've thought about?
|
||||
|
||||
- type: dropdown
|
||||
id: complexity
|
||||
attributes:
|
||||
label: Estimated complexity
|
||||
description: How much work do you think this requires?
|
||||
options:
|
||||
- "Small - Quick fix, single file, < 1 hour"
|
||||
- "Medium - Multiple files, few hours to a day"
|
||||
- "Large - Significant changes, multiple days"
|
||||
- "Unknown - Not sure"
|
||||
validations:
|
||||
required: false
|
||||
|
|
|
|||
110
.github/workflows/auto-label.yml
vendored
Normal file
110
.github/workflows/auto-label.yml
vendored
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
name: Auto Label Issues
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [opened, edited]
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
|
||||
jobs:
|
||||
label:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Auto-label based on content
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const issue = context.payload.issue;
|
||||
const title = issue.title.toLowerCase();
|
||||
const body = (issue.body || '').toLowerCase();
|
||||
const content = title + ' ' + body;
|
||||
|
||||
const labelsToAdd = [];
|
||||
|
||||
// Type labels based on title prefix
|
||||
if (title.includes('[bug]')) {
|
||||
labelsToAdd.push('bug');
|
||||
} else if (title.includes('[feature]') || title.includes('feat(') || title.includes('feat:')) {
|
||||
labelsToAdd.push('enhancement');
|
||||
} else if (title.includes('[docs]') || title.includes('docs(') || title.includes('docs:')) {
|
||||
labelsToAdd.push('documentation');
|
||||
}
|
||||
|
||||
// Project labels based on content
|
||||
if (content.includes('core dev') || content.includes('core work') || content.includes('core commit') || content.includes('core push')) {
|
||||
labelsToAdd.push('project:core-cli');
|
||||
}
|
||||
if (content.includes('core php') || content.includes('composer') || content.includes('pest') || content.includes('phpstan')) {
|
||||
labelsToAdd.push('project:core-php');
|
||||
}
|
||||
if (content.includes('setup') || content.includes('install') || content.includes('makefile')) {
|
||||
labelsToAdd.push('project:workstation');
|
||||
}
|
||||
|
||||
// Priority detection
|
||||
if (content.includes('critical') || content.includes('urgent') || content.includes('breaking')) {
|
||||
labelsToAdd.push('priority:high');
|
||||
}
|
||||
|
||||
// Agent labels
|
||||
if (content.includes('agent') || content.includes('ai ') || content.includes('claude') || content.includes('agentic')) {
|
||||
labelsToAdd.push('agentic');
|
||||
}
|
||||
|
||||
// Complexity - from template dropdown or heuristics
|
||||
if (body.includes('small - quick fix')) {
|
||||
labelsToAdd.push('complexity:small');
|
||||
labelsToAdd.push('good first issue');
|
||||
} else if (body.includes('medium - multiple files')) {
|
||||
labelsToAdd.push('complexity:medium');
|
||||
} else if (body.includes('large - significant')) {
|
||||
labelsToAdd.push('complexity:large');
|
||||
} else if (!body.includes('unknown - not sure')) {
|
||||
// Heuristic complexity detection
|
||||
const checklistCount = (body.match(/- \[ \]/g) || []).length;
|
||||
const codeBlocks = (body.match(/```/g) || []).length / 2;
|
||||
const sections = (body.match(/^##/gm) || []).length;
|
||||
const fileRefs = (body.match(/\.(go|php|js|ts|yml|yaml|json|md)\b/g) || []).length;
|
||||
|
||||
const complexKeywords = ['refactor', 'rewrite', 'migration', 'breaking change', 'across repos', 'architecture'];
|
||||
const simpleKeywords = ['simple', 'quick fix', 'typo', 'minor', 'trivial'];
|
||||
|
||||
const hasComplexKeyword = complexKeywords.some(k => content.includes(k));
|
||||
const hasSimpleKeyword = simpleKeywords.some(k => content.includes(k));
|
||||
|
||||
let score = checklistCount * 2 + codeBlocks + sections + fileRefs;
|
||||
score += hasComplexKeyword ? 5 : 0;
|
||||
score -= hasSimpleKeyword ? 3 : 0;
|
||||
|
||||
if (hasSimpleKeyword || score <= 2) {
|
||||
labelsToAdd.push('complexity:small');
|
||||
labelsToAdd.push('good first issue');
|
||||
} else if (score <= 6) {
|
||||
labelsToAdd.push('complexity:medium');
|
||||
} else {
|
||||
labelsToAdd.push('complexity:large');
|
||||
}
|
||||
}
|
||||
|
||||
// Apply labels if any detected
|
||||
if (labelsToAdd.length > 0) {
|
||||
// Filter to only existing labels
|
||||
const existingLabels = await github.rest.issues.listLabelsForRepo({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
per_page: 100
|
||||
});
|
||||
const validLabels = existingLabels.data.map(l => l.name);
|
||||
const filteredLabels = labelsToAdd.filter(l => validLabels.includes(l));
|
||||
|
||||
if (filteredLabels.length > 0) {
|
||||
await github.rest.issues.addLabels({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: issue.number,
|
||||
labels: filteredLabels
|
||||
});
|
||||
console.log(`Added labels: ${filteredLabels.join(', ')}`);
|
||||
}
|
||||
}
|
||||
7
.idea/dictionaries/hostuk.xml
generated
7
.idea/dictionaries/hostuk.xml
generated
|
|
@ -1,4 +1,3 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<component name="ProjectDictionaryState">
|
||||
<dictionary name="hostuk">
|
||||
<words>
|
||||
|
|
@ -9,14 +8,14 @@
|
|||
<w>hostuk</w>
|
||||
<w>laravel</w>
|
||||
<w>livewire</w>
|
||||
<w>middlewares</w>
|
||||
<w>mcp</w>
|
||||
<w>middlewares</w>
|
||||
<w>multitenancy</w>
|
||||
<w>namespacing</w>
|
||||
<w>notifyhost</w>
|
||||
<w>oauth</w>
|
||||
<w>pint</w>
|
||||
<w>phpstan</w>
|
||||
<w>pint</w>
|
||||
<w>sanctum</w>
|
||||
<w>serializable</w>
|
||||
<w>socialhost</w>
|
||||
|
|
@ -31,4 +30,4 @@
|
|||
<w>webhooks</w>
|
||||
</words>
|
||||
</dictionary>
|
||||
</component>
|
||||
</component>
|
||||
|
|
@ -32,7 +32,7 @@ You're now ready to develop. The workspace starts with `core-php` as the active
|
|||
core doctor
|
||||
|
||||
# See workspace status
|
||||
core health
|
||||
core dev health
|
||||
|
||||
# Run tests in the active package (core-php)
|
||||
core php test
|
||||
|
|
|
|||
10
TODO.md
10
TODO.md
|
|
@ -1,7 +1,15 @@
|
|||
# TODO - Session Summary 2026-01-31
|
||||
# TODO - Session Summary 2026-02-01
|
||||
|
||||
## ✅ Completed Today
|
||||
|
||||
### Issue Auto-Labeling
|
||||
- [x] Issue templates (bug_report.yml, feature_request.yml) for core + core-devops
|
||||
- [x] Auto-label workflow detects: type, project, priority, agentic keywords
|
||||
- [x] Complexity dropdown in feature request template
|
||||
- [x] Heuristic complexity detection (checklist count, code blocks, sections, file refs, keywords)
|
||||
- [x] Retroactively labeled unlabeled issues in core repo
|
||||
- [x] Test issue #70 created and auto-labeled correctly
|
||||
|
||||
### GitHub Org Setup
|
||||
- [x] Dev branches as default (all repos)
|
||||
- [x] Labels taxonomy (agent:*, priority:*, type:*, lang:*)
|
||||
|
|
|
|||
|
|
@ -123,6 +123,13 @@ repos:
|
|||
description: Starter template for new projects
|
||||
docs: false
|
||||
|
||||
# Claude Code plugin
|
||||
core-claude:
|
||||
type: meta
|
||||
depends_on: []
|
||||
description: Claude Code plugin for Host UK monorepo
|
||||
docs: false
|
||||
|
||||
# This repo (meta)
|
||||
core-devops:
|
||||
type: meta
|
||||
|
|
|
|||
|
|
@ -27,9 +27,25 @@ if ($PSVersionTable.PSVersion.Major -lt 4) {
|
|||
}
|
||||
|
||||
$Repo = "host-uk/core"
|
||||
$Version = "main" # Build from main until stable Windows releases are available
|
||||
$MinDiskSpaceMB = 100 # Minimum required disk space in MB
|
||||
|
||||
# Resolve latest release version from GitHub API
|
||||
function Get-LatestVersion {
|
||||
try {
|
||||
if (Test-Command gh) {
|
||||
$version = gh release view --repo $Repo --json tagName -q '.tagName' 2>$null
|
||||
if ($version) { return $version }
|
||||
}
|
||||
|
||||
# Fallback to GitHub API
|
||||
$response = Invoke-RestMethod -Uri "https://api.github.com/repos/$Repo/releases/latest" -UseBasicParsing
|
||||
if ($response.tag_name) { return $response.tag_name }
|
||||
} catch {
|
||||
Write-Warn "Could not determine latest version, using default branch"
|
||||
}
|
||||
return $null
|
||||
}
|
||||
|
||||
function Write-Info { Write-Host "[INFO] $args" -ForegroundColor Green }
|
||||
function Write-Warn { Write-Host "[WARN] $args" -ForegroundColor Yellow }
|
||||
function Write-Err { Write-Host "[ERROR] $args" -ForegroundColor Red; exit 1 }
|
||||
|
|
@ -213,10 +229,10 @@ function Set-SecureDirectoryAcl {
|
|||
# Download pre-built binary with integrity verification
|
||||
function Download-Binary {
|
||||
$arch = if ([Environment]::Is64BitOperatingSystem) { "amd64" } else { "386" }
|
||||
$binaryUrl = "https://github.com/$Repo/releases/download/$Version/core-windows-$arch.exe"
|
||||
$checksumUrl = "https://github.com/$Repo/releases/download/$Version/checksums.txt"
|
||||
$binaryUrl = "https://github.com/$Repo/releases/latest/download/core-windows-$arch.exe"
|
||||
$checksumUrl = "https://github.com/$Repo/releases/latest/download/checksums.txt"
|
||||
|
||||
Write-Info "Attempting to download pre-built binary (version $Version)..."
|
||||
Write-Info "Attempting to download pre-built binary..."
|
||||
Write-Info "URL: $binaryUrl"
|
||||
|
||||
# Track temp file for cleanup
|
||||
|
|
@ -340,20 +356,25 @@ function Build-FromSource {
|
|||
$null = Set-SecureDirectoryAcl -Path $tmpdir -Required
|
||||
|
||||
try {
|
||||
Write-Info "Cloning $Repo (version $Version)..."
|
||||
$cloneDir = Join-Path $tmpdir "Core"
|
||||
|
||||
# Clone specific tag for reproducibility
|
||||
git clone --depth 1 --branch $Version "https://github.com/$Repo.git" $cloneDir
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Err "Failed to clone repository at version $Version"
|
||||
# Resolve latest version for reproducible builds
|
||||
$version = Get-LatestVersion
|
||||
if ($version) {
|
||||
Write-Info "Resolved latest version: $version"
|
||||
} else {
|
||||
Write-Warn "Building from default branch (version unknown)"
|
||||
}
|
||||
|
||||
# Verify GPG signature on tag (if available, skip for branches)
|
||||
if ($Version -match "^v\d") {
|
||||
$null = Test-GitTagSignature -RepoPath $cloneDir -Tag $Version
|
||||
Write-Info "Cloning $Repo..."
|
||||
$cloneDir = Join-Path $tmpdir "Core"
|
||||
|
||||
# Clone specific version if available, otherwise default branch
|
||||
if ($version) {
|
||||
git clone --depth 1 --branch $version "https://github.com/$Repo.git" $cloneDir
|
||||
} else {
|
||||
Write-Warn "Building from branch '$Version' - GPG verification skipped (only applies to tags)"
|
||||
git clone --depth 1 "https://github.com/$Repo.git" $cloneDir
|
||||
}
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Err "Failed to clone repository"
|
||||
}
|
||||
|
||||
Write-Info "Building core CLI..."
|
||||
|
|
@ -462,7 +483,7 @@ function Verify {
|
|||
|
||||
# Main
|
||||
function Main {
|
||||
Write-Info "Installing Core CLI (version $Version)..."
|
||||
Write-Info "Installing Core CLI..."
|
||||
|
||||
# Check disk space before starting
|
||||
$null = Test-DiskSpace -Path $InstallDir
|
||||
|
|
|
|||
|
|
@ -21,10 +21,24 @@ set -e
|
|||
# - No TLS certificate pinning (relies on system CA store)
|
||||
|
||||
REPO="host-uk/core"
|
||||
VERSION="v0.1.0" # Pinned version - update when releasing new versions
|
||||
VERSION="${CORE_VERSION:-latest}" # Use latest release, or set CORE_VERSION=dev for dev builds
|
||||
INSTALL_DIR="${INSTALL_DIR:-$HOME/.local/bin}"
|
||||
BUILD_FROM_SOURCE="${BUILD_FROM_SOURCE:-auto}"
|
||||
|
||||
# Resolve "latest" to actual release tag
|
||||
resolve_version() {
|
||||
if [[ "$VERSION" == "latest" ]]; then
|
||||
if has gh; then
|
||||
VERSION=$(gh release view --repo "$REPO" --json tagName -q '.tagName' 2>/dev/null) || VERSION="dev"
|
||||
elif has curl; then
|
||||
VERSION=$(curl -fsSL "https://api.github.com/repos/$REPO/releases/latest" 2>/dev/null | grep '"tag_name"' | head -1 | cut -d'"' -f4) || VERSION="dev"
|
||||
else
|
||||
VERSION="dev"
|
||||
fi
|
||||
info "Resolved latest version: $VERSION"
|
||||
fi
|
||||
}
|
||||
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
|
|
@ -75,7 +89,8 @@ verify_hash() {
|
|||
|
||||
actual_hash=$(compute_sha256 "$file")
|
||||
|
||||
if [[ "${actual_hash,,}" != "${expected_hash,,}" ]]; then
|
||||
# Case-insensitive compare (bash 3 compatible)
|
||||
if [[ "$(echo "$actual_hash" | tr '[:upper:]' '[:lower:]')" != "$(echo "$expected_hash" | tr '[:upper:]' '[:lower:]')" ]]; then
|
||||
rm -f "$file"
|
||||
error "Hash verification failed! Expected: $expected_hash, Got: $actual_hash. The downloaded file may be corrupted or tampered with."
|
||||
fi
|
||||
|
|
@ -282,6 +297,7 @@ verify() {
|
|||
}
|
||||
|
||||
main() {
|
||||
resolve_version
|
||||
info "Installing Core CLI (version $VERSION)..."
|
||||
|
||||
# Verify install directory is safe before starting
|
||||
|
|
|
|||
|
|
@ -44,7 +44,8 @@ verify_hash() {
|
|||
|
||||
actual_hash=$(compute_sha256 "$file")
|
||||
|
||||
if [[ "${actual_hash,,}" != "${expected_hash,,}" ]]; then
|
||||
# Case-insensitive compare (bash 3 compatible)
|
||||
if [[ "$(echo "$actual_hash" | tr '[:upper:]' '[:lower:]')" != "$(echo "$expected_hash" | tr '[:upper:]' '[:lower:]')" ]]; then
|
||||
rm -f "$file"
|
||||
error "Hash verification failed! Expected: $expected_hash, Got: $actual_hash"
|
||||
fi
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue