diff --git a/.core/plugin/skills/go.md b/.core/plugin/skills/go.md index 22a2227f..19696881 100644 --- a/.core/plugin/skills/go.md +++ b/.core/plugin/skills/go.md @@ -30,7 +30,7 @@ core/ package domain import ( - "github.com/host-uk/core/pkg/cli" + "forge.lthn.ai/core/cli/pkg/cli" "github.com/spf13/cobra" ) @@ -53,7 +53,7 @@ func NewNameCmd() *cobra.Command { ## CLI Output Helpers ```go -import "github.com/host-uk/core/pkg/cli" +import "forge.lthn.ai/core/cli/pkg/cli" cli.Success("Operation completed") // Green check cli.Warning("Something to note") // Yellow warning diff --git a/.core/task/issue/258/spec.md b/.core/task/issue/258/spec.md index 3ba5142e..4456199e 100644 --- a/.core/task/issue/258/spec.md +++ b/.core/task/issue/258/spec.md @@ -1,7 +1,7 @@ # Issue 258: Smart Test Detection ## Original Issue - + ## Summary Make `core test` smart — detect changed Go files and run only relevant tests. diff --git a/.gh-actions/ISSUE_TEMPLATE/bug_report.yml b/.gh-actions/ISSUE_TEMPLATE/bug_report.yml deleted file mode 100644 index 7ed124f0..00000000 --- a/.gh-actions/ISSUE_TEMPLATE/bug_report.yml +++ /dev/null @@ -1,58 +0,0 @@ -name: Bug Report -description: Report a problem with the core CLI -title: "[Bug]: " -labels: ["bug", "triage"] -body: - - type: markdown - attributes: - value: | - Thanks for reporting! Please fill out the details below. - - - type: dropdown - id: os - attributes: - label: Operating System - options: - - macOS - - Windows - - Linux (Ubuntu/Debian) - - Linux (Other) - validations: - required: true - - - type: input - id: command - attributes: - label: Command - description: Which command failed? - placeholder: "e.g., core dev work, core php test" - validations: - required: true - - - type: input - id: version - attributes: - label: Version - description: Output of `core version` - placeholder: "e.g., core v0.1.0" - - - type: textarea - id: description - attributes: - label: What happened? - description: Describe the issue - validations: - required: true - - - type: textarea - id: expected - attributes: - label: Expected behaviour - description: What should have happened? - - - type: textarea - id: logs - attributes: - label: Error output - description: Paste any error messages - render: shell diff --git a/.gh-actions/ISSUE_TEMPLATE/config.yml b/.gh-actions/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index bc677307..00000000 --- a/.gh-actions/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1,8 +0,0 @@ -blank_issues_enabled: true -contact_links: - - name: Host UK Documentation - url: https://github.com/host-uk/core-devops - about: Setup guides and workspace documentation - - name: Discussions - url: https://github.com/orgs/host-uk/discussions - about: Ask questions and share ideas \ No newline at end of file diff --git a/.gh-actions/ISSUE_TEMPLATE/feature_request.yml b/.gh-actions/ISSUE_TEMPLATE/feature_request.yml deleted file mode 100644 index fe73d800..00000000 --- a/.gh-actions/ISSUE_TEMPLATE/feature_request.yml +++ /dev/null @@ -1,58 +0,0 @@ -name: Feature Request -description: Suggest a new feature or enhancement -title: "[Feature]: " -labels: ["enhancement"] -body: - - type: markdown - attributes: - value: | - Thanks for the suggestion! Please describe your idea below. - - - type: dropdown - id: area - attributes: - label: Area - options: - - dev commands (work, commit, push, pull) - - php commands (test, lint, stan) - - GitHub integration (issues, reviews, ci) - - New command - - Documentation - - Other - validations: - required: true - - - type: textarea - id: problem - attributes: - label: Problem or use case - description: What problem does this solve? - validations: - required: true - - - type: textarea - id: solution - attributes: - label: Proposed solution - description: How would you like it to work? - validations: - required: true - - - type: textarea - id: alternatives - 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 diff --git a/.gh-actions/dependabot.yml b/.gh-actions/dependabot.yml deleted file mode 100644 index ad64fb72..00000000 --- a/.gh-actions/dependabot.yml +++ /dev/null @@ -1,24 +0,0 @@ -version: 2 -updates: - - package-ecosystem: "gomod" - directory: "/" - schedule: - interval: "weekly" - day: "monday" - labels: - - "type:dependencies" - - "priority:low" - commit-message: - prefix: "deps(go):" - - - package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: "weekly" - day: "monday" - labels: - - "type:dependencies" - - "priority:low" - commit-message: - prefix: "deps(actions):" - diff --git a/.gh-actions/workflows/agent-verify.yml b/.gh-actions/workflows/agent-verify.yml deleted file mode 100644 index d8bcb16e..00000000 --- a/.gh-actions/workflows/agent-verify.yml +++ /dev/null @@ -1,10 +0,0 @@ -name: Agent Verification - -on: - issues: - types: [labeled] - -jobs: - verify: - uses: host-uk/.github/.github/workflows/agent-verify.yml@main - secrets: inherit diff --git a/.gh-actions/workflows/alpha-release-manual.yml b/.gh-actions/workflows/alpha-release-manual.yml deleted file mode 100644 index e9e194ad..00000000 --- a/.gh-actions/workflows/alpha-release-manual.yml +++ /dev/null @@ -1,92 +0,0 @@ -# https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflow_dispatch -name: "Alpha Release: Manual" - -on: - workflow_dispatch: - -permissions: - contents: write - id-token: write - attestations: write - -env: - NEXT_VERSION: "0.0.4" - -jobs: - build: - strategy: - matrix: - include: - - os: ubuntu-latest - platform: linux/amd64 - - os: ubuntu-latest - platform: linux/arm64 - - os: macos-latest - platform: darwin/universal - - os: windows-latest - platform: windows/amd64 - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v6 - - - name: Build - uses: host-uk/build@v3 - with: - build-name: core - build-platform: ${{ matrix.platform }} - build: true - package: true - sign: false - - release: - needs: build - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - - - name: Download artifacts - uses: actions/download-artifact@v7 - with: - path: dist - merge-multiple: true - - - name: Prepare release files - run: | - mkdir -p release - cp dist/* release/ 2>/dev/null || true - ls -la release/ - - - name: Create alpha release - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - VERSION="v${{ env.NEXT_VERSION }}-alpha.${{ github.run_number }}" - - gh release create "$VERSION" \ - --title "Alpha: $VERSION" \ - --notes "Canary build from dev branch. - - **Version:** $VERSION - **Commit:** ${{ github.sha }} - **Built:** $(date -u +'%Y-%m-%d %H:%M:%S UTC') - **Run:** ${{ github.run_id }} - - ## Channel: Alpha (Canary) - - This is an automated pre-release for early testing. - - - Systems and early adopters can test breaking changes - - Quality scoring determines promotion to beta - - Use stable releases for production - - ## Installation - - \`\`\`bash - # macOS/Linux - curl -fsSL https://github.com/host-uk/core/releases/download/$VERSION/core-linux-amd64 -o core - chmod +x core && sudo mv core /usr/local/bin/ - \`\`\` - " \ - --prerelease \ - --target dev \ - release/* diff --git a/.gh-actions/workflows/alpha-release-push.yml b/.gh-actions/workflows/alpha-release-push.yml deleted file mode 100644 index 674e107c..00000000 --- a/.gh-actions/workflows/alpha-release-push.yml +++ /dev/null @@ -1,93 +0,0 @@ -# https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#push -name: "Alpha Release: Push" - -on: - push: - branches: [dev] - -permissions: - contents: write - id-token: write - attestations: write - -env: - NEXT_VERSION: "0.0.4" - -jobs: - build: - strategy: - matrix: - include: - - os: ubuntu-latest - platform: linux/amd64 - - os: ubuntu-latest - platform: linux/arm64 - - os: macos-latest - platform: darwin/universal - - os: windows-latest - platform: windows/amd64 - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v6 - - - name: Build - uses: host-uk/build@v3 - with: - build-name: core - build-platform: ${{ matrix.platform }} - build: true - package: true - sign: false - - release: - needs: build - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - - - name: Download artifacts - uses: actions/download-artifact@v7 - with: - path: dist - merge-multiple: true - - - name: Prepare release files - run: | - mkdir -p release - cp dist/* release/ 2>/dev/null || true - ls -la release/ - - - name: Create alpha release - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - VERSION="v${{ env.NEXT_VERSION }}-alpha.${{ github.run_number }}" - - gh release create "$VERSION" \ - --title "Alpha: $VERSION" \ - --notes "Canary build from dev branch. - - **Version:** $VERSION - **Commit:** ${{ github.sha }} - **Built:** $(date -u +'%Y-%m-%d %H:%M:%S UTC') - **Run:** ${{ github.run_id }} - - ## Channel: Alpha (Canary) - - This is an automated pre-release for early testing. - - - Systems and early adopters can test breaking changes - - Quality scoring determines promotion to beta - - Use stable releases for production - - ## Installation - - \`\`\`bash - # macOS/Linux - curl -fsSL https://github.com/host-uk/core/releases/download/$VERSION/core-linux-amd64 -o core - chmod +x core && sudo mv core /usr/local/bin/ - \`\`\` - " \ - --prerelease \ - --target dev \ - release/* diff --git a/.gh-actions/workflows/alpha-release.yml b/.gh-actions/workflows/alpha-release.yml deleted file mode 100644 index c75177c1..00000000 --- a/.gh-actions/workflows/alpha-release.yml +++ /dev/null @@ -1,500 +0,0 @@ -name: Alpha Release - -on: - push: - branches: [dev] - workflow_dispatch: - -permissions: - contents: write - id-token: write - attestations: write - -env: - # Next version - update when releasing - NEXT_VERSION: "0.0.4" - -jobs: - build: - strategy: - matrix: - include: - - os: ubuntu-latest - goos: linux - goarch: amd64 - - os: ubuntu-latest - goos: linux - goarch: arm64 - - os: macos-latest - goos: darwin - goarch: arm64 - - os: windows-latest - goos: windows - goarch: amd64 - runs-on: ${{ matrix.os }} - env: - GOOS: ${{ matrix.goos }} - GOARCH: ${{ matrix.goarch }} - steps: - - uses: actions/checkout@v6 - - # GUI build disabled until build action supports Wails v3 - # - name: Wails Build Action - # uses: host-uk/build@v4.0.0 - # with: - # build-name: core - # build-platform: ${{ matrix.goos }}/${{ matrix.goarch }} - # build: true - # package: true - # sign: false - - - name: Setup Go - uses: host-uk/build/actions/setup/go@v4.0.0 - with: - go-version: "1.25" - - - name: Build CLI - shell: bash - run: | - EXT="" - if [ "$GOOS" = "windows" ]; then EXT=".exe"; fi - BINARY="core${EXT}" - ARCHIVE_PREFIX="core-${GOOS}-${GOARCH}" - - APP_VERSION="${{ env.NEXT_VERSION }}-alpha.${{ github.run_number }}" - go build -ldflags "-s -w -X github.com/host-uk/core/pkg/cli.AppVersion=${APP_VERSION}" -o "./bin/${BINARY}" . - - # Create tar.gz for Homebrew (non-Windows) - if [ "$GOOS" != "windows" ]; then - tar czf "./bin/${ARCHIVE_PREFIX}.tar.gz" -C ./bin "${BINARY}" - fi - - # Create zip for Scoop (Windows) - if [ "$GOOS" = "windows" ]; then - cd ./bin && zip "${ARCHIVE_PREFIX}.zip" "${BINARY}" && cd .. - fi - - # Rename raw binary to platform-specific name for release - mv "./bin/${BINARY}" "./bin/${ARCHIVE_PREFIX}${EXT}" - - - name: Upload artifact - uses: actions/upload-artifact@v4 - with: - name: core-${{ matrix.goos }}-${{ matrix.goarch }} - path: ./bin/core-* - - build-ide: - strategy: - matrix: - include: - - os: macos-latest - goos: darwin - goarch: arm64 - - os: ubuntu-latest - goos: linux - goarch: amd64 - - os: windows-latest - goos: windows - goarch: amd64 - runs-on: ${{ matrix.os }} - env: - GOOS: ${{ matrix.goos }} - GOARCH: ${{ matrix.goarch }} - defaults: - run: - working-directory: internal/core-ide - steps: - - uses: actions/checkout@v6 - - - name: Setup Go - uses: host-uk/build/actions/setup/go@v4.0.0 - with: - go-version: "1.25" - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: "20" - - - name: Install Wails CLI - run: go install github.com/wailsapp/wails/v3/cmd/wails3@latest - - - name: Install frontend dependencies - working-directory: internal/core-ide/frontend - run: npm ci - - - name: Generate bindings - run: wails3 generate bindings -f '-tags production' -clean=false -ts -i - - - name: Build frontend - working-directory: internal/core-ide/frontend - run: npm run build - - - name: Install Linux dependencies - if: matrix.goos == 'linux' - run: | - sudo apt-get update - sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev - - - name: Build IDE - shell: bash - run: | - EXT="" - if [ "$GOOS" = "windows" ]; then EXT=".exe"; fi - BINARY="core-ide${EXT}" - ARCHIVE_PREFIX="core-ide-${GOOS}-${GOARCH}" - - BUILD_FLAGS="-tags production -trimpath -buildvcs=false" - - if [ "$GOOS" = "windows" ]; then - # Windows: no CGO, use windowsgui linker flag - export CGO_ENABLED=0 - LDFLAGS="-w -s -H windowsgui" - - # Generate Windows syso resource - cd build - wails3 generate syso -arch ${GOARCH} -icon windows/icon.ico -manifest windows/wails.exe.manifest -info windows/info.json -out ../wails_windows_${GOARCH}.syso - cd .. - elif [ "$GOOS" = "darwin" ]; then - export CGO_ENABLED=1 - export CGO_CFLAGS="-mmacosx-version-min=10.15" - export CGO_LDFLAGS="-mmacosx-version-min=10.15" - export MACOSX_DEPLOYMENT_TARGET="10.15" - LDFLAGS="-w -s" - else - export CGO_ENABLED=1 - LDFLAGS="-w -s" - fi - - go build ${BUILD_FLAGS} -ldflags="${LDFLAGS}" -o "./bin/${BINARY}" - - # Clean up syso files - rm -f *.syso - - # Package - if [ "$GOOS" = "darwin" ]; then - # Create .app bundle - mkdir -p "./bin/Core IDE.app/Contents/"{MacOS,Resources} - cp build/darwin/icons.icns "./bin/Core IDE.app/Contents/Resources/" - cp "./bin/${BINARY}" "./bin/Core IDE.app/Contents/MacOS/" - cp build/darwin/Info.plist "./bin/Core IDE.app/Contents/" - codesign --force --deep --sign - "./bin/Core IDE.app" - tar czf "./bin/${ARCHIVE_PREFIX}.tar.gz" -C ./bin "Core IDE.app" - elif [ "$GOOS" = "windows" ]; then - cd ./bin && zip "${ARCHIVE_PREFIX}.zip" "${BINARY}" && cd .. - else - tar czf "./bin/${ARCHIVE_PREFIX}.tar.gz" -C ./bin "${BINARY}" - fi - - # Rename raw binary - mv "./bin/${BINARY}" "./bin/${ARCHIVE_PREFIX}${EXT}" - - - name: Upload artifact - uses: actions/upload-artifact@v4 - with: - name: core-ide-${{ matrix.goos }}-${{ matrix.goarch }} - path: internal/core-ide/bin/core-ide-* - - release: - needs: [build, build-ide] - runs-on: ubuntu-latest - outputs: - version: ${{ steps.version.outputs.version }} - steps: - - uses: actions/checkout@v6 - - - name: Set version - id: version - run: echo "version=v${{ env.NEXT_VERSION }}-alpha.${{ github.run_number }}" >> "$GITHUB_OUTPUT" - - - name: Download artifacts - uses: actions/download-artifact@v7 - with: - path: dist - merge-multiple: true - - - name: Prepare release files - run: | - mkdir -p release - cp dist/* release/ 2>/dev/null || true - ls -la release/ - - - name: Create alpha release - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - VERSION: ${{ steps.version.outputs.version }} - run: | - gh release create "$VERSION" \ - --title "Alpha: $VERSION" \ - --notes "Canary build from dev branch. - - **Version:** $VERSION - **Commit:** ${{ github.sha }} - **Built:** $(date -u +'%Y-%m-%d %H:%M:%S UTC') - **Run:** ${{ github.run_id }} - - ## Channel: Alpha (Canary) - - This is an automated pre-release for early testing. - - - Systems and early adopters can test breaking changes - - Quality scoring determines promotion to beta - - Use stable releases for production - - ## Installation - - \`\`\`bash - # Homebrew (macOS/Linux) - brew install host-uk/tap/core - - # Scoop (Windows) - scoop bucket add host-uk https://github.com/host-uk/scoop-bucket - scoop install core - - # Direct download (example: Linux amd64) - curl -fsSL https://github.com/host-uk/core/releases/download/$VERSION/core-linux-amd64 -o core - chmod +x core && sudo mv core /usr/local/bin/ - \`\`\` - " \ - --prerelease \ - --target dev \ - release/* - - update-tap: - needs: release - runs-on: ubuntu-latest - steps: - - name: Download artifacts - uses: actions/download-artifact@v7 - with: - path: dist - merge-multiple: true - - - name: Generate checksums - run: | - cd dist - for f in *.tar.gz; do - sha256sum "$f" | awk '{print $1}' > "${f}.sha256" - done - echo "=== Checksums ===" - cat *.sha256 - - - name: Update Homebrew formula - env: - GH_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }} - VERSION: ${{ needs.release.outputs.version }} - run: | - # Strip leading 'v' for formula version - FORMULA_VERSION="${VERSION#v}" - - # Read checksums - DARWIN_ARM64=$(cat dist/core-darwin-arm64.tar.gz.sha256) - LINUX_AMD64=$(cat dist/core-linux-amd64.tar.gz.sha256) - LINUX_ARM64=$(cat dist/core-linux-arm64.tar.gz.sha256) - - # Clone tap repo (configure auth for push) - gh repo clone host-uk/homebrew-tap /tmp/tap -- --depth=1 - cd /tmp/tap - git remote set-url origin "https://x-access-token:${GH_TOKEN}@github.com/host-uk/homebrew-tap.git" - cd - - mkdir -p /tmp/tap/Formula - - # Write formula - cat > /tmp/tap/Formula/core.rb << FORMULA - # typed: false - # frozen_string_literal: true - - class Core < Formula - desc "Host UK development CLI" - homepage "https://github.com/host-uk/core" - version "${FORMULA_VERSION}" - license "EUPL-1.2" - - on_macos do - url "https://github.com/host-uk/core/releases/download/${VERSION}/core-darwin-arm64.tar.gz" - sha256 "${DARWIN_ARM64}" - end - - on_linux do - if Hardware::CPU.arm? - url "https://github.com/host-uk/core/releases/download/${VERSION}/core-linux-arm64.tar.gz" - sha256 "${LINUX_ARM64}" - else - url "https://github.com/host-uk/core/releases/download/${VERSION}/core-linux-amd64.tar.gz" - sha256 "${LINUX_AMD64}" - end - end - - def install - bin.install "core" - end - - test do - system "\#{bin}/core", "--version" - end - end - FORMULA - - # Remove leading whitespace from heredoc - sed -i 's/^ //' /tmp/tap/Formula/core.rb - - # Read IDE checksums (may not exist if build-ide failed) - IDE_DARWIN_ARM64=$(cat dist/core-ide-darwin-arm64.tar.gz.sha256 2>/dev/null || echo "") - IDE_LINUX_AMD64=$(cat dist/core-ide-linux-amd64.tar.gz.sha256 2>/dev/null || echo "") - - # Write core-ide Formula (Linux binary) - if [ -n "${IDE_LINUX_AMD64}" ]; then - cat > /tmp/tap/Formula/core-ide.rb << FORMULA - # typed: false - # frozen_string_literal: true - - class CoreIde < Formula - desc "Host UK desktop development environment" - homepage "https://github.com/host-uk/core" - version "${FORMULA_VERSION}" - license "EUPL-1.2" - - on_linux do - url "https://github.com/host-uk/core/releases/download/${VERSION}/core-ide-linux-amd64.tar.gz" - sha256 "${IDE_LINUX_AMD64}" - end - - def install - bin.install "core-ide" - end - end - FORMULA - sed -i 's/^ //' /tmp/tap/Formula/core-ide.rb - fi - - # Write core-ide Cask (macOS .app bundle) - if [ -n "${IDE_DARWIN_ARM64}" ]; then - mkdir -p /tmp/tap/Casks - cat > /tmp/tap/Casks/core-ide.rb << CASK - cask "core-ide" do - version "${FORMULA_VERSION}" - sha256 "${IDE_DARWIN_ARM64}" - - url "https://github.com/host-uk/core/releases/download/${VERSION}/core-ide-darwin-arm64.tar.gz" - name "Core IDE" - desc "Host UK desktop development environment" - homepage "https://github.com/host-uk/core" - - app "Core IDE.app" - end - CASK - sed -i 's/^ //' /tmp/tap/Casks/core-ide.rb - fi - - cd /tmp/tap - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - git add . - git diff --cached --quiet && echo "No changes to tap" && exit 0 - git commit -m "Update core to ${FORMULA_VERSION}" - git push - - update-scoop: - needs: release - runs-on: ubuntu-latest - steps: - - name: Download artifacts - uses: actions/download-artifact@v7 - with: - path: dist - merge-multiple: true - - - name: Generate checksums - run: | - cd dist - for f in *.zip; do - [ -f "$f" ] || continue - sha256sum "$f" | awk '{print $1}' > "${f}.sha256" - done - echo "=== Checksums ===" - cat *.sha256 2>/dev/null || echo "No zip checksums" - - - name: Update Scoop manifests - env: - GH_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }} - VERSION: ${{ needs.release.outputs.version }} - run: | - # Strip leading 'v' for manifest version - MANIFEST_VERSION="${VERSION#v}" - - # Read checksums - WIN_AMD64=$(cat dist/core-windows-amd64.zip.sha256 2>/dev/null || echo "") - IDE_WIN_AMD64=$(cat dist/core-ide-windows-amd64.zip.sha256 2>/dev/null || echo "") - - # Clone scoop bucket - gh repo clone host-uk/scoop-bucket /tmp/scoop -- --depth=1 - cd /tmp/scoop - git remote set-url origin "https://x-access-token:${GH_TOKEN}@github.com/host-uk/scoop-bucket.git" - - # Write core.json manifest - cat > core.json << 'MANIFEST' - { - "version": "VERSION_PLACEHOLDER", - "description": "Host UK development CLI", - "homepage": "https://github.com/host-uk/core", - "license": "EUPL-1.2", - "architecture": { - "64bit": { - "url": "URL_PLACEHOLDER", - "hash": "HASH_PLACEHOLDER", - "bin": "core.exe" - } - }, - "checkver": "github", - "autoupdate": { - "architecture": { - "64bit": { - "url": "https://github.com/host-uk/core/releases/download/v$version/core-windows-amd64.zip" - } - } - } - } - MANIFEST - - sed -i "s|VERSION_PLACEHOLDER|${MANIFEST_VERSION}|g" core.json - sed -i "s|URL_PLACEHOLDER|https://github.com/host-uk/core/releases/download/${VERSION}/core-windows-amd64.zip|g" core.json - sed -i "s|HASH_PLACEHOLDER|${WIN_AMD64}|g" core.json - sed -i 's/^ //' core.json - - # Write core-ide.json manifest - if [ -n "${IDE_WIN_AMD64}" ]; then - cat > core-ide.json << 'MANIFEST' - { - "version": "VERSION_PLACEHOLDER", - "description": "Host UK desktop development environment", - "homepage": "https://github.com/host-uk/core", - "license": "EUPL-1.2", - "architecture": { - "64bit": { - "url": "URL_PLACEHOLDER", - "hash": "HASH_PLACEHOLDER", - "bin": "core-ide.exe" - } - }, - "checkver": "github", - "autoupdate": { - "architecture": { - "64bit": { - "url": "https://github.com/host-uk/core/releases/download/v$version/core-ide-windows-amd64.zip" - } - } - } - } - MANIFEST - sed -i "s|VERSION_PLACEHOLDER|${MANIFEST_VERSION}|g" core-ide.json - sed -i "s|URL_PLACEHOLDER|https://github.com/host-uk/core/releases/download/${VERSION}/core-ide-windows-amd64.zip|g" core-ide.json - sed -i "s|HASH_PLACEHOLDER|${IDE_WIN_AMD64}|g" core-ide.json - sed -i 's/^ //' core-ide.json - fi - - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - git add . - git diff --cached --quiet && echo "No changes to scoop bucket" && exit 0 - git commit -m "Update core to ${MANIFEST_VERSION}" - git push diff --git a/.gh-actions/workflows/auto-label.yml b/.gh-actions/workflows/auto-label.yml deleted file mode 100644 index a32e3760..00000000 --- a/.gh-actions/workflows/auto-label.yml +++ /dev/null @@ -1,113 +0,0 @@ -# https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#issues -name: "Auto Label: Issue Created/Edited" - -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@v8 - 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'); - } - - // Language labels - if (content.includes('.go') || content.includes('golang') || content.includes('go mod')) { - labelsToAdd.push('go'); - } - - // 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(', ')}`); - } - } diff --git a/.gh-actions/workflows/auto-merge.yml b/.gh-actions/workflows/auto-merge.yml deleted file mode 100644 index 57cd8306..00000000 --- a/.gh-actions/workflows/auto-merge.yml +++ /dev/null @@ -1,54 +0,0 @@ -name: Auto Merge - -on: - pull_request: - types: [opened, reopened, ready_for_review] - -permissions: - contents: write - pull-requests: write - -env: - GH_REPO: ${{ github.repository }} - -jobs: - merge: - runs-on: ubuntu-latest - if: github.event.pull_request.draft == false - steps: - - name: Checkout - uses: actions/checkout@v6 - - name: Enable auto-merge - uses: actions/github-script@v7 - env: - PR_NUMBER: ${{ github.event.pull_request.number }} - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const author = context.payload.pull_request.user.login; - const association = context.payload.pull_request.author_association; - - // Trusted bot accounts (act as org members) - const trustedBots = ['google-labs-jules[bot]']; - const isTrustedBot = trustedBots.includes(author); - - // Check author association from webhook payload - const trusted = ['MEMBER', 'OWNER', 'COLLABORATOR']; - if (!isTrustedBot && !trusted.includes(association)) { - core.info(`${author} is ${association} — skipping auto-merge`); - return; - } - - try { - await exec.exec('gh', [ - 'pr', 'merge', process.env.PR_NUMBER, - '--auto', - '--merge', - '-R', `${context.repo.owner}/${context.repo.repo}` - ]); - core.info(`Auto-merge enabled for #${process.env.PR_NUMBER}`); - } catch (error) { - core.error(`Failed to enable auto-merge: ${error.message}`); - throw error; - } diff --git a/.gh-actions/workflows/auto-project.yml b/.gh-actions/workflows/auto-project.yml deleted file mode 100644 index 9244ba20..00000000 --- a/.gh-actions/workflows/auto-project.yml +++ /dev/null @@ -1,10 +0,0 @@ -name: Auto Project - -on: - issues: - types: [opened, labeled] - -jobs: - project: - uses: host-uk/.github/.github/workflows/auto-project.yml@main - secrets: inherit diff --git a/.gh-actions/workflows/bugseti-release.yml b/.gh-actions/workflows/bugseti-release.yml deleted file mode 100644 index ca9c36b4..00000000 --- a/.gh-actions/workflows/bugseti-release.yml +++ /dev/null @@ -1,309 +0,0 @@ -# BugSETI Release Workflow -# Builds for all platforms and creates GitHub releases -name: "BugSETI Release" - -on: - push: - tags: - - 'bugseti-v*.*.*' # Stable: bugseti-v1.0.0 - - 'bugseti-v*.*.*-beta.*' # Beta: bugseti-v1.0.0-beta.1 - - 'bugseti-nightly-*' # Nightly: bugseti-nightly-20260205 - -permissions: - contents: write - -env: - APP_NAME: bugseti - WAILS_VERSION: "3" - -jobs: - # Determine release channel from tag - prepare: - runs-on: ubuntu-latest - outputs: - version: ${{ steps.version.outputs.version }} - channel: ${{ steps.version.outputs.channel }} - prerelease: ${{ steps.version.outputs.prerelease }} - steps: - - name: Determine version and channel - id: version - env: - TAG: ${{ github.ref_name }} - run: | - if [[ "$TAG" == bugseti-nightly-* ]]; then - VERSION="${TAG#bugseti-}" - CHANNEL="nightly" - PRERELEASE="true" - elif [[ "$TAG" == *-beta.* ]]; then - VERSION="${TAG#bugseti-v}" - CHANNEL="beta" - PRERELEASE="true" - else - VERSION="${TAG#bugseti-v}" - CHANNEL="stable" - PRERELEASE="false" - fi - - echo "version=${VERSION}" >> "$GITHUB_OUTPUT" - echo "channel=${CHANNEL}" >> "$GITHUB_OUTPUT" - echo "prerelease=${PRERELEASE}" >> "$GITHUB_OUTPUT" - - echo "Tag: $TAG" - echo "Version: $VERSION" - echo "Channel: $CHANNEL" - echo "Prerelease: $PRERELEASE" - - build: - needs: prepare - strategy: - fail-fast: false - matrix: - include: - # macOS ARM64 (Apple Silicon) - - os: macos-latest - goos: darwin - goarch: arm64 - ext: "" - archive: tar.gz - # macOS AMD64 (Intel) - - os: macos-13 - goos: darwin - goarch: amd64 - ext: "" - archive: tar.gz - # Linux AMD64 - - os: ubuntu-latest - goos: linux - goarch: amd64 - ext: "" - archive: tar.gz - # Linux ARM64 - - os: ubuntu-24.04-arm - goos: linux - goarch: arm64 - ext: "" - archive: tar.gz - # Windows AMD64 - - os: windows-latest - goos: windows - goarch: amd64 - ext: ".exe" - archive: zip - - runs-on: ${{ matrix.os }} - env: - GOOS: ${{ matrix.goos }} - GOARCH: ${{ matrix.goarch }} - VERSION: ${{ needs.prepare.outputs.version }} - CHANNEL: ${{ needs.prepare.outputs.channel }} - - defaults: - run: - working-directory: cmd/bugseti - - steps: - - uses: actions/checkout@v6 - - - name: Setup Go - uses: host-uk/build/actions/setup/go@v4.0.0 - with: - go-version: "1.25" - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: "20" - - - name: Install Wails CLI - run: go install github.com/wailsapp/wails/v3/cmd/wails3@latest - - - name: Install frontend dependencies - working-directory: cmd/bugseti/frontend - run: npm ci - - - name: Generate bindings - run: wails3 generate bindings -f '-tags production' -clean=false -ts -i - - - name: Build frontend - working-directory: cmd/bugseti/frontend - run: npm run build - - - name: Install Linux dependencies - if: matrix.goos == 'linux' - run: | - sudo apt-get update - sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev libayatana-appindicator3-dev - - - name: Build BugSETI - shell: bash - env: - EXT: ${{ matrix.ext }} - ARCHIVE: ${{ matrix.archive }} - COMMIT_SHA: ${{ github.sha }} - run: | - BINARY="${APP_NAME}${EXT}" - ARCHIVE_PREFIX="${APP_NAME}-${GOOS}-${GOARCH}" - - BUILD_FLAGS="-tags production -trimpath -buildvcs=false" - - # Version injection via ldflags - LDFLAGS="-s -w" - LDFLAGS="${LDFLAGS} -X github.com/host-uk/core/internal/bugseti.Version=${VERSION}" - LDFLAGS="${LDFLAGS} -X github.com/host-uk/core/internal/bugseti.Channel=${CHANNEL}" - LDFLAGS="${LDFLAGS} -X github.com/host-uk/core/internal/bugseti.Commit=${COMMIT_SHA}" - LDFLAGS="${LDFLAGS} -X github.com/host-uk/core/internal/bugseti.BuildTime=$(date -u +%Y-%m-%dT%H:%M:%SZ)" - - if [ "$GOOS" = "windows" ]; then - export CGO_ENABLED=0 - LDFLAGS="${LDFLAGS} -H windowsgui" - - # Generate Windows syso resource - cd build - wails3 generate syso -arch ${GOARCH} -icon windows/icon.ico -manifest windows/wails.exe.manifest -info windows/info.json -out ../wails_windows_${GOARCH}.syso 2>/dev/null || true - cd .. - elif [ "$GOOS" = "darwin" ]; then - export CGO_ENABLED=1 - export CGO_CFLAGS="-mmacosx-version-min=10.15" - export CGO_LDFLAGS="-mmacosx-version-min=10.15" - export MACOSX_DEPLOYMENT_TARGET="10.15" - else - export CGO_ENABLED=1 - fi - - mkdir -p bin - go build ${BUILD_FLAGS} -ldflags="${LDFLAGS}" -o "./bin/${BINARY}" - - # Clean up syso files - rm -f *.syso - - # Package based on platform - if [ "$GOOS" = "darwin" ]; then - # Create .app bundle - mkdir -p "./bin/BugSETI.app/Contents/"{MacOS,Resources} - cp build/darwin/icons.icns "./bin/BugSETI.app/Contents/Resources/" 2>/dev/null || true - cp "./bin/${BINARY}" "./bin/BugSETI.app/Contents/MacOS/" - cp build/darwin/Info.plist "./bin/BugSETI.app/Contents/" - codesign --force --deep --sign - "./bin/BugSETI.app" 2>/dev/null || true - tar czf "./bin/${ARCHIVE_PREFIX}.tar.gz" -C ./bin "BugSETI.app" - elif [ "$GOOS" = "windows" ]; then - cd ./bin && zip "${ARCHIVE_PREFIX}.zip" "${BINARY}" && cd .. - else - tar czf "./bin/${ARCHIVE_PREFIX}.tar.gz" -C ./bin "${BINARY}" - fi - - # Rename raw binary for individual download - mv "./bin/${BINARY}" "./bin/${ARCHIVE_PREFIX}${EXT}" - - # Generate checksum - cd ./bin - sha256sum "${ARCHIVE_PREFIX}.${ARCHIVE}" > "${ARCHIVE_PREFIX}.${ARCHIVE}.sha256" - sha256sum "${ARCHIVE_PREFIX}${EXT}" > "${ARCHIVE_PREFIX}${EXT}.sha256" - - - name: Upload artifact - uses: actions/upload-artifact@v4 - with: - name: bugseti-${{ matrix.goos }}-${{ matrix.goarch }} - path: | - cmd/bugseti/bin/bugseti-* - retention-days: 7 - - release: - needs: [prepare, build] - runs-on: ubuntu-latest - env: - TAG_NAME: ${{ github.ref_name }} - VERSION: ${{ needs.prepare.outputs.version }} - CHANNEL: ${{ needs.prepare.outputs.channel }} - PRERELEASE: ${{ needs.prepare.outputs.prerelease }} - REPO: ${{ github.repository }} - steps: - - uses: actions/checkout@v6 - - - name: Download all artifacts - uses: actions/download-artifact@v7 - with: - path: dist - merge-multiple: true - - - name: List release files - run: | - echo "=== Release files ===" - ls -la dist/ - echo "=== Checksums ===" - cat dist/*.sha256 - - - name: Create release - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - # Determine release title - if [ "$CHANNEL" = "nightly" ]; then - TITLE="BugSETI Nightly (${VERSION})" - elif [ "$CHANNEL" = "beta" ]; then - TITLE="BugSETI v${VERSION} (Beta)" - else - TITLE="BugSETI v${VERSION}" - fi - - # Create release notes - cat > release-notes.md << EOF - ## BugSETI ${VERSION} - - **Channel:** ${CHANNEL} - - ### Downloads - - | Platform | Architecture | Binary | Archive | - |----------|-------------|--------|---------| - | macOS | ARM64 (Apple Silicon) | [bugseti-darwin-arm64](https://github.com/${REPO}/releases/download/${TAG_NAME}/bugseti-darwin-arm64) | [tar.gz](https://github.com/${REPO}/releases/download/${TAG_NAME}/bugseti-darwin-arm64.tar.gz) | - | macOS | AMD64 (Intel) | [bugseti-darwin-amd64](https://github.com/${REPO}/releases/download/${TAG_NAME}/bugseti-darwin-amd64) | [tar.gz](https://github.com/${REPO}/releases/download/${TAG_NAME}/bugseti-darwin-amd64.tar.gz) | - | Linux | AMD64 | [bugseti-linux-amd64](https://github.com/${REPO}/releases/download/${TAG_NAME}/bugseti-linux-amd64) | [tar.gz](https://github.com/${REPO}/releases/download/${TAG_NAME}/bugseti-linux-amd64.tar.gz) | - | Linux | ARM64 | [bugseti-linux-arm64](https://github.com/${REPO}/releases/download/${TAG_NAME}/bugseti-linux-arm64) | [tar.gz](https://github.com/${REPO}/releases/download/${TAG_NAME}/bugseti-linux-arm64.tar.gz) | - | Windows | AMD64 | [bugseti-windows-amd64.exe](https://github.com/${REPO}/releases/download/${TAG_NAME}/bugseti-windows-amd64.exe) | [zip](https://github.com/${REPO}/releases/download/${TAG_NAME}/bugseti-windows-amd64.zip) | - - ### Checksums (SHA256) - - \`\`\` - $(cat dist/*.sha256) - \`\`\` - - --- - *BugSETI - Distributed Bug Fixing, like SETI@home but for code* - EOF - - # Build release command - RELEASE_ARGS=( - --title "$TITLE" - --notes-file release-notes.md - ) - - if [ "$PRERELEASE" = "true" ]; then - RELEASE_ARGS+=(--prerelease) - fi - - # Create the release - gh release create "$TAG_NAME" \ - "${RELEASE_ARGS[@]}" \ - dist/* - - # Scheduled nightly builds - nightly: - if: github.event_name == 'schedule' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - - - name: Create nightly tag - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - DATE=$(date -u +%Y%m%d) - TAG="bugseti-nightly-${DATE}" - - # Delete existing nightly tag for today if it exists - gh release delete "$TAG" --yes 2>/dev/null || true - git push origin ":refs/tags/$TAG" 2>/dev/null || true - - # Create new tag - git tag "$TAG" - git push origin "$TAG" diff --git a/.gh-actions/workflows/ci-manual.yml b/.gh-actions/workflows/ci-manual.yml deleted file mode 100644 index fd5459cc..00000000 --- a/.gh-actions/workflows/ci-manual.yml +++ /dev/null @@ -1,41 +0,0 @@ -# https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflow_dispatch -name: "CI: Manual" - -on: - workflow_dispatch: - -env: - CORE_VERSION: dev - -jobs: - qa: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - - - name: Set up Go - uses: actions/setup-go@v6 - with: - go-version-file: 'go.mod' - - - name: Install system dependencies - run: | - sudo apt-get update - sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev - - - name: Build core CLI - run: | - go build -ldflags "-X github.com/host-uk/core/pkg/cli.AppVersion=${{ env.CORE_VERSION }}" -o /usr/local/bin/core . - core --version - - - name: Generate code - run: go generate ./internal/cmd/updater/... - - - name: Run QA - # Skip lint until golangci-lint supports Go 1.25 - run: core go qa --skip=lint - - - name: Verify build - run: | - core build --targets=linux/amd64 --ci - dist/linux_amd64/core --version diff --git a/.gh-actions/workflows/ci-pull-request.yml b/.gh-actions/workflows/ci-pull-request.yml deleted file mode 100644 index e4cfc420..00000000 --- a/.gh-actions/workflows/ci-pull-request.yml +++ /dev/null @@ -1,42 +0,0 @@ -# https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request -name: "CI: Pull Request" - -on: - pull_request: - branches: [dev, main] - -env: - CORE_VERSION: dev - -jobs: - qa: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - - - name: Set up Go - uses: actions/setup-go@v6 - with: - go-version-file: 'go.mod' - - - name: Install system dependencies - run: | - sudo apt-get update - sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev - - - name: Build core CLI - run: | - go build -ldflags "-X github.com/host-uk/core/pkg/cli.AppVersion=${{ env.CORE_VERSION }}" -o /usr/local/bin/core . - core --version - - - name: Generate code - run: go generate ./internal/cmd/updater/... - - - name: Run QA - # Skip lint until golangci-lint supports Go 1.25 - run: core go qa --skip=lint - - - name: Verify build - run: | - core build --targets=linux/amd64 --ci - dist/linux_amd64/core --version diff --git a/.gh-actions/workflows/ci-push.yml b/.gh-actions/workflows/ci-push.yml deleted file mode 100644 index 7039b678..00000000 --- a/.gh-actions/workflows/ci-push.yml +++ /dev/null @@ -1,42 +0,0 @@ -# https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#push -name: "CI: Push" - -on: - push: - branches: [dev, main] - -env: - CORE_VERSION: dev - -jobs: - qa: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - - - name: Set up Go - uses: actions/setup-go@v6 - with: - go-version-file: 'go.mod' - - - name: Install system dependencies - run: | - sudo apt-get update - sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev - - - name: Build core CLI - run: | - go build -ldflags "-X github.com/host-uk/core/pkg/cli.AppVersion=${{ env.CORE_VERSION }}" -o /usr/local/bin/core . - core --version - - - name: Generate code - run: go generate ./internal/cmd/updater/... - - - name: Run QA - # Skip lint until golangci-lint supports Go 1.25 - run: core go qa --skip=lint - - - name: Verify build - run: | - core build --targets=linux/amd64 --ci - dist/linux_amd64/core --version diff --git a/.gh-actions/workflows/ci.yml b/.gh-actions/workflows/ci.yml deleted file mode 100644 index 0de17332..00000000 --- a/.gh-actions/workflows/ci.yml +++ /dev/null @@ -1,49 +0,0 @@ -name: CI - -on: - push: - branches: [dev, main] - pull_request: - branches: [dev, main] - workflow_dispatch: - -permissions: - contents: read - -env: - CORE_VERSION: dev - -jobs: - qa: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - - - name: Set up Go - uses: actions/setup-go@v6 - with: - go-version-file: 'go.mod' - - - name: Install system dependencies - run: | - sudo apt-get update - # Try 4.1 first (Ubuntu 22.04+), fall back to 4.0 (Ubuntu 20.04) - sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev || \ - sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev - - - name: Build core CLI - run: | - go build -ldflags "-X github.com/host-uk/core/pkg/cli.AppVersion=${{ env.CORE_VERSION }}" -o /usr/local/bin/core . - core --version - - - name: Generate code - run: go generate ./internal/cmd/updater/... - - - name: Run QA - # Skip lint until golangci-lint supports Go 1.25 - run: core go qa --skip=lint - - - name: Verify build - run: | - core build --targets=linux/amd64 --ci - dist/linux_amd64/core --version diff --git a/.gh-actions/workflows/codeql-pull-request.yml b/.gh-actions/workflows/codeql-pull-request.yml deleted file mode 100644 index 4121a5b8..00000000 --- a/.gh-actions/workflows/codeql-pull-request.yml +++ /dev/null @@ -1,32 +0,0 @@ -# https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request -name: "CodeQL: Pull Request" - -on: - pull_request: - branches: [dev, main] - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - - steps: - - name: Checkout - uses: actions/checkout@v6 - - - name: Initialize CodeQL - uses: github/codeql-action/init@v4 - with: - languages: go - - - name: Autobuild - uses: github/codeql-action/autobuild@v4 - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v4 - with: - category: "/language:go" diff --git a/.gh-actions/workflows/codeql-push.yml b/.gh-actions/workflows/codeql-push.yml deleted file mode 100644 index 37bb3de8..00000000 --- a/.gh-actions/workflows/codeql-push.yml +++ /dev/null @@ -1,32 +0,0 @@ -# https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#push -name: "CodeQL: Push" - -on: - push: - branches: [dev, main] - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - - steps: - - name: Checkout - uses: actions/checkout@v6 - - - name: Initialize CodeQL - uses: github/codeql-action/init@v4 - with: - languages: go - - - name: Autobuild - uses: github/codeql-action/autobuild@v4 - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v4 - with: - category: "/language:go" diff --git a/.gh-actions/workflows/codeql-schedule.yml b/.gh-actions/workflows/codeql-schedule.yml deleted file mode 100644 index bcb565c0..00000000 --- a/.gh-actions/workflows/codeql-schedule.yml +++ /dev/null @@ -1,32 +0,0 @@ -# https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#schedule -name: "CodeQL: Schedule" - -on: - schedule: - - cron: "0 6 * * 1" - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - - steps: - - name: Checkout - uses: actions/checkout@v6 - - - name: Initialize CodeQL - uses: github/codeql-action/init@v4 - with: - languages: go - - - name: Autobuild - uses: github/codeql-action/autobuild@v4 - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v4 - with: - category: "/language:go" diff --git a/.gh-actions/workflows/codescan-pull-request.yml b/.gh-actions/workflows/codescan-pull-request.yml deleted file mode 100644 index f6c16727..00000000 --- a/.gh-actions/workflows/codescan-pull-request.yml +++ /dev/null @@ -1,30 +0,0 @@ -# https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request -name: "Code Scanning: Pull Request" - -on: - pull_request: - branches: ["dev"] - -jobs: - CodeQL: - runs-on: ubuntu-latest - - permissions: - security-events: write - actions: read - contents: read - - steps: - - name: "Checkout Repository" - uses: actions/checkout@v6 - - - name: "Initialize CodeQL" - uses: github/codeql-action/init@v4 - with: - languages: go,javascript,typescript - - - name: "Autobuild" - uses: github/codeql-action/autobuild@v4 - - - name: "Perform CodeQL Analysis" - uses: github/codeql-action/analyze@v4 diff --git a/.gh-actions/workflows/codescan-push.yml b/.gh-actions/workflows/codescan-push.yml deleted file mode 100644 index bf8694c6..00000000 --- a/.gh-actions/workflows/codescan-push.yml +++ /dev/null @@ -1,30 +0,0 @@ -# https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#push -name: "Code Scanning: Push" - -on: - push: - branches: ["dev"] - -jobs: - CodeQL: - runs-on: ubuntu-latest - - permissions: - security-events: write - actions: read - contents: read - - steps: - - name: "Checkout Repository" - uses: actions/checkout@v6 - - - name: "Initialize CodeQL" - uses: github/codeql-action/init@v4 - with: - languages: go,javascript,typescript - - - name: "Autobuild" - uses: github/codeql-action/autobuild@v4 - - - name: "Perform CodeQL Analysis" - uses: github/codeql-action/analyze@v4 diff --git a/.gh-actions/workflows/codescan-schedule.yml b/.gh-actions/workflows/codescan-schedule.yml deleted file mode 100644 index b9778c16..00000000 --- a/.gh-actions/workflows/codescan-schedule.yml +++ /dev/null @@ -1,30 +0,0 @@ -# https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#schedule -name: "Code Scanning: Schedule" - -on: - schedule: - - cron: "0 2 * * 1-5" - -jobs: - CodeQL: - runs-on: ubuntu-latest - - permissions: - security-events: write - actions: read - contents: read - - steps: - - name: "Checkout Repository" - uses: actions/checkout@v6 - - - name: "Initialize CodeQL" - uses: github/codeql-action/init@v4 - with: - languages: go,javascript,typescript - - - name: "Autobuild" - uses: github/codeql-action/autobuild@v4 - - - name: "Perform CodeQL Analysis" - uses: github/codeql-action/analyze@v4 diff --git a/.gh-actions/workflows/coverage-manual.yml b/.gh-actions/workflows/coverage-manual.yml deleted file mode 100644 index 68f0b077..00000000 --- a/.gh-actions/workflows/coverage-manual.yml +++ /dev/null @@ -1,46 +0,0 @@ -# https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflow_dispatch -name: "Coverage: Manual" - -on: - workflow_dispatch: - -env: - CORE_VERSION: dev - -jobs: - coverage: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - - - name: Set up Go - uses: actions/setup-go@v6 - with: - go-version-file: 'go.mod' - - - name: Install system dependencies - run: | - sudo apt-get update - sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev - - - name: Build core CLI - run: | - go build -ldflags "-X github.com/host-uk/core/pkg/cli.AppVersion=${{ env.CORE_VERSION }}" -o /usr/local/bin/core . - core --version - - - name: Generate code - run: go generate ./internal/cmd/updater/... - - - name: Run coverage - run: core go cov - - - name: Upload coverage reports to Codecov - uses: codecov/codecov-action@v5 - with: - token: ${{ secrets.CODECOV_TOKEN }} - - - name: Upload coverage report - uses: actions/upload-artifact@v6 - with: - name: coverage-report - path: coverage.txt diff --git a/.gh-actions/workflows/coverage-pull-request.yml b/.gh-actions/workflows/coverage-pull-request.yml deleted file mode 100644 index 60daaaf5..00000000 --- a/.gh-actions/workflows/coverage-pull-request.yml +++ /dev/null @@ -1,47 +0,0 @@ -# https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request -name: "Coverage: Pull Request" - -on: - pull_request: - branches: [dev, main] - -env: - CORE_VERSION: dev - -jobs: - coverage: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - - - name: Set up Go - uses: actions/setup-go@v6 - with: - go-version-file: 'go.mod' - - - name: Install system dependencies - run: | - sudo apt-get update - sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev - - - name: Build core CLI - run: | - go build -ldflags "-X github.com/host-uk/core/pkg/cli.AppVersion=${{ env.CORE_VERSION }}" -o /usr/local/bin/core . - core --version - - - name: Generate code - run: go generate ./internal/cmd/updater/... - - - name: Run coverage - run: core go cov - - - name: Upload coverage reports to Codecov - uses: codecov/codecov-action@v5 - with: - token: ${{ secrets.CODECOV_TOKEN }} - - - name: Upload coverage report - uses: actions/upload-artifact@v6 - with: - name: coverage-report - path: coverage.txt diff --git a/.gh-actions/workflows/coverage-push.yml b/.gh-actions/workflows/coverage-push.yml deleted file mode 100644 index 3f93d976..00000000 --- a/.gh-actions/workflows/coverage-push.yml +++ /dev/null @@ -1,47 +0,0 @@ -# https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#push -name: "Coverage: Push" - -on: - push: - branches: [dev, main] - -env: - CORE_VERSION: dev - -jobs: - coverage: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - - - name: Set up Go - uses: actions/setup-go@v6 - with: - go-version-file: 'go.mod' - - - name: Install system dependencies - run: | - sudo apt-get update - sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev - - - name: Build core CLI - run: | - go build -ldflags "-X github.com/host-uk/core/pkg/cli.AppVersion=${{ env.CORE_VERSION }}" -o /usr/local/bin/core . - core --version - - - name: Generate code - run: go generate ./internal/cmd/updater/... - - - name: Run coverage - run: core go cov - - - name: Upload coverage reports to Codecov - uses: codecov/codecov-action@v5 - with: - token: ${{ secrets.CODECOV_TOKEN }} - - - name: Upload coverage report - uses: actions/upload-artifact@v6 - with: - name: coverage-report - path: coverage.txt diff --git a/.gh-actions/workflows/coverage.yml b/.gh-actions/workflows/coverage.yml deleted file mode 100644 index e9b2d64e..00000000 --- a/.gh-actions/workflows/coverage.yml +++ /dev/null @@ -1,54 +0,0 @@ -name: Coverage - -on: - push: - branches: [dev, main] - pull_request: - branches: [dev, main] - workflow_dispatch: - -permissions: - contents: read - -env: - CORE_VERSION: dev - -jobs: - coverage: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - - - name: Set up Go - uses: actions/setup-go@v6 - with: - go-version-file: 'go.mod' - - - name: Install system dependencies - run: | - sudo apt-get update - # Try 4.1 first (Ubuntu 22.04+), fall back to 4.0 (Ubuntu 20.04) - sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev || \ - sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev - - - name: Build core CLI - run: | - go build -ldflags "-X github.com/host-uk/core/pkg/cli.AppVersion=${{ env.CORE_VERSION }}" -o /usr/local/bin/core . - core --version - - - name: Generate code - run: go generate ./internal/cmd/updater/... - - - name: Run coverage - run: core go cov --output coverage.txt --threshold 40 --branch-threshold 35 - - - name: Upload coverage reports to Codecov - uses: codecov/codecov-action@v5 - with: - token: ${{ secrets.CODECOV_TOKEN }} - - - name: Upload coverage report - uses: actions/upload-artifact@v6 - with: - name: coverage-report - path: coverage.txt diff --git a/.gh-actions/workflows/pr-build-manual.yml b/.gh-actions/workflows/pr-build-manual.yml deleted file mode 100644 index 2c02cfb4..00000000 --- a/.gh-actions/workflows/pr-build-manual.yml +++ /dev/null @@ -1,89 +0,0 @@ -# https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflow_dispatch -name: "PR Build: Manual" - -on: - workflow_dispatch: - inputs: - pr_number: - description: 'PR number to build' - required: true - type: number - -permissions: - contents: write - pull-requests: read - -env: - NEXT_VERSION: "0.0.4" - -jobs: - build: - strategy: - matrix: - include: - - os: ubuntu-latest - platform: linux/amd64 - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v6 - - - name: Build - uses: host-uk/build@v3 - with: - build-name: core - build-platform: ${{ matrix.platform }} - build: true - package: true - sign: false - - draft-release: - needs: build - runs-on: ubuntu-latest - env: - PR_NUM: ${{ inputs.pr_number }} - PR_SHA: ${{ github.sha }} - steps: - - uses: actions/checkout@v6 - - - name: Download artifacts - uses: actions/download-artifact@v7 - with: - path: dist - merge-multiple: true - - - name: Prepare release files - run: | - mkdir -p release - cp dist/* release/ 2>/dev/null || true - ls -la release/ - - - name: Create draft release - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - TAG="v${{ env.NEXT_VERSION }}.pr.${PR_NUM}.bid.${{ github.run_id }}" - - # Delete existing draft for this PR if it exists - gh release delete "$TAG" -y 2>/dev/null || true - git push origin ":refs/tags/$TAG" 2>/dev/null || true - - gh release create "$TAG" \ - --title "Draft: PR #${PR_NUM}" \ - --notes "Draft build for PR #${PR_NUM}. - - **Version:** $TAG - **PR:** #${PR_NUM} - **Commit:** ${PR_SHA} - **Built:** $(date -u +'%Y-%m-%d %H:%M:%S UTC') - **Run:** ${{ github.run_id }} - - ## Channel: Draft - - This is a draft build for testing PR changes before merge. - Not intended for production use. - - Build artifacts available for download and testing. - " \ - --draft \ - --prerelease \ - release/* diff --git a/.gh-actions/workflows/pr-build-pull-request.yml b/.gh-actions/workflows/pr-build-pull-request.yml deleted file mode 100644 index 66ec7c6f..00000000 --- a/.gh-actions/workflows/pr-build-pull-request.yml +++ /dev/null @@ -1,89 +0,0 @@ -# https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request -name: "PR Build: Pull Request" - -on: - pull_request: - types: [opened, synchronize, reopened] - -permissions: - contents: write - pull-requests: read - -env: - NEXT_VERSION: "0.0.4" - -jobs: - build: - # Only build if PR is from the same repo (not forks) - if: github.event.pull_request.head.repo.full_name == github.repository - strategy: - matrix: - include: - - os: ubuntu-latest - platform: linux/amd64 - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v6 - with: - ref: ${{ github.event.pull_request.head.sha }} - - - name: Build - uses: host-uk/build@v3 - with: - build-name: core - build-platform: ${{ matrix.platform }} - build: true - package: true - sign: false - - draft-release: - needs: build - runs-on: ubuntu-latest - env: - PR_NUM: ${{ github.event.pull_request.number }} - PR_SHA: ${{ github.event.pull_request.head.sha }} - steps: - - uses: actions/checkout@v6 - - - name: Download artifacts - uses: actions/download-artifact@v7 - with: - path: dist - merge-multiple: true - - - name: Prepare release files - run: | - mkdir -p release - cp dist/* release/ 2>/dev/null || true - ls -la release/ - - - name: Create draft release - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - TAG="v${{ env.NEXT_VERSION }}.pr.${PR_NUM}.bid.${{ github.run_id }}" - - # Delete existing draft for this PR if it exists - gh release delete "$TAG" -y 2>/dev/null || true - git push origin ":refs/tags/$TAG" 2>/dev/null || true - - gh release create "$TAG" \ - --title "Draft: PR #${PR_NUM}" \ - --notes "Draft build for PR #${PR_NUM}. - - **Version:** $TAG - **PR:** #${PR_NUM} - **Commit:** ${PR_SHA} - **Built:** $(date -u +'%Y-%m-%d %H:%M:%S UTC') - **Run:** ${{ github.run_id }} - - ## Channel: Draft - - This is a draft build for testing PR changes before merge. - Not intended for production use. - - Build artifacts available for download and testing. - " \ - --draft \ - --prerelease \ - release/* diff --git a/.gh-actions/workflows/pr-build.yml b/.gh-actions/workflows/pr-build.yml deleted file mode 100644 index c928aa58..00000000 --- a/.gh-actions/workflows/pr-build.yml +++ /dev/null @@ -1,113 +0,0 @@ -name: PR Build - -on: - pull_request: - types: [opened, synchronize, reopened] - workflow_dispatch: - inputs: - pr_number: - description: 'PR number to build' - required: true - type: number - -permissions: - contents: write - pull-requests: read - -env: - # Next version - update when releasing - NEXT_VERSION: "0.0.4" - -jobs: - build: - # Only build if PR is from the same repo (not forks) or manually triggered - if: github.event.pull_request.head.repo.full_name == github.repository || github.event_name == 'workflow_dispatch' - strategy: - matrix: - include: - - os: ubuntu-latest - goos: linux - goarch: amd64 - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - with: - ref: ${{ github.event.pull_request.head.sha || github.sha }} - - # GUI build disabled until build action supports Wails v3 - # - name: Wails Build Action - # uses: host-uk/build@v4.0.0 - # with: - # build-name: core - # build-platform: ${{ matrix.goos }}/${{ matrix.goarch }} - # build: true - # package: true - # sign: false - - - name: Setup Go - uses: host-uk/build/actions/setup/go@v4.0.0 - with: - go-version: "1.25" - - - name: Build CLI - run: go build -o ./bin/core . - - - name: Upload artifact - uses: actions/upload-artifact@v4 - with: - name: core-${{ matrix.goos }}-${{ matrix.goarch }} - path: ./bin/core - - draft-release: - needs: build - runs-on: ubuntu-latest - env: - # Safe: PR number is numeric, not user-controlled string - PR_NUM: ${{ github.event.pull_request.number || inputs.pr_number }} - PR_SHA: ${{ github.event.pull_request.head.sha || github.sha }} - steps: - - uses: actions/checkout@v6 - - - name: Download artifacts - uses: actions/download-artifact@v7 - with: - path: dist - merge-multiple: true - - - name: Prepare release files - run: | - mkdir -p release - cp dist/* release/ 2>/dev/null || true - ls -la release/ - - - name: Create draft release - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - # Use dots for build metadata (semver v1 compatible) - TAG="v${{ env.NEXT_VERSION }}.pr.${PR_NUM}.bid.${{ github.run_id }}" - - # Delete existing draft for this PR if it exists - gh release delete "$TAG" -y 2>/dev/null || true - git push origin ":refs/tags/$TAG" 2>/dev/null || true - - gh release create "$TAG" \ - --title "Draft: PR #${PR_NUM}" \ - --notes "Draft build for PR #${PR_NUM}. - - **Version:** $TAG - **PR:** #${PR_NUM} - **Commit:** ${PR_SHA} - **Built:** $(date -u +'%Y-%m-%d %H:%M:%S UTC') - **Run:** ${{ github.run_id }} - - ## Channel: Draft - - This is a draft build for testing PR changes before merge. - Not intended for production use. - - Build artifacts available for download and testing. - " \ - --draft \ - --prerelease \ - release/* diff --git a/.gh-actions/workflows/pr-gate.yml b/.gh-actions/workflows/pr-gate.yml deleted file mode 100644 index 31a8c37e..00000000 --- a/.gh-actions/workflows/pr-gate.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: PR Gate - -on: - pull_request_target: - types: [opened, synchronize, reopened, labeled] - -permissions: - contents: read - pull-requests: read - -jobs: - org-gate: - runs-on: ubuntu-latest - steps: - - name: Check org membership or approval label - uses: actions/github-script@v7 - with: - script: | - const author = context.payload.pull_request.user.login; - const association = context.payload.pull_request.author_association; - - // Trusted accounts - const trustedAuthors = ['google-labs-jules[bot]', 'Snider']; - if (trustedAuthors.includes(author)) { - core.info(`${author} is trusted — gate passed`); - return; - } - - // Check author association - const trustedAssociations = ['MEMBER', 'OWNER', 'COLLABORATOR']; - if (trustedAssociations.includes(association)) { - core.info(`${author} is ${association} — gate passed`); - return; - } - - // Check for external-approved label - const labels = context.payload.pull_request.labels.map(l => l.name); - if (labels.includes('external-approved')) { - core.info('external-approved label present — gate passed'); - return; - } - - core.setFailed( - `External PR from ${author} requires an org member to add the "external-approved" label before merge.` - ); diff --git a/.gh-actions/workflows/release.yml b/.gh-actions/workflows/release.yml deleted file mode 100644 index 97bf11e0..00000000 --- a/.gh-actions/workflows/release.yml +++ /dev/null @@ -1,454 +0,0 @@ -# https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#push -name: "Release: Tag Push" - -on: - push: - tags: - - 'v*.*.*' - -permissions: - contents: write - -jobs: - build: - strategy: - matrix: - include: - - os: ubuntu-latest - goos: linux - goarch: amd64 - - os: ubuntu-latest - goos: linux - goarch: arm64 - - os: macos-latest - goos: darwin - goarch: arm64 - - os: windows-latest - goos: windows - goarch: amd64 - runs-on: ${{ matrix.os }} - env: - GOOS: ${{ matrix.goos }} - GOARCH: ${{ matrix.goarch }} - steps: - - uses: actions/checkout@v6 - - - name: Setup Go - uses: host-uk/build/actions/setup/go@v4.0.0 - with: - go-version: "1.25" - - - name: Build CLI - shell: bash - run: | - EXT="" - if [ "$GOOS" = "windows" ]; then EXT=".exe"; fi - BINARY="core${EXT}" - ARCHIVE_PREFIX="core-${GOOS}-${GOARCH}" - - APP_VERSION="${GITHUB_REF_NAME#v}" - go build -ldflags "-s -w -X github.com/host-uk/core/pkg/cli.AppVersion=${APP_VERSION}" -o "./bin/${BINARY}" . - - # Create tar.gz for Homebrew (non-Windows) - if [ "$GOOS" != "windows" ]; then - tar czf "./bin/${ARCHIVE_PREFIX}.tar.gz" -C ./bin "${BINARY}" - fi - - # Create zip for Scoop (Windows) - if [ "$GOOS" = "windows" ]; then - cd ./bin && zip "${ARCHIVE_PREFIX}.zip" "${BINARY}" && cd .. - fi - - # Rename raw binary to platform-specific name for release - mv "./bin/${BINARY}" "./bin/${ARCHIVE_PREFIX}${EXT}" - - - name: Upload artifact - uses: actions/upload-artifact@v4 - with: - name: core-${{ matrix.goos }}-${{ matrix.goarch }} - path: ./bin/core-* - - build-ide: - strategy: - matrix: - include: - - os: macos-latest - goos: darwin - goarch: arm64 - - os: ubuntu-latest - goos: linux - goarch: amd64 - - os: windows-latest - goos: windows - goarch: amd64 - runs-on: ${{ matrix.os }} - env: - GOOS: ${{ matrix.goos }} - GOARCH: ${{ matrix.goarch }} - defaults: - run: - working-directory: internal/core-ide - steps: - - uses: actions/checkout@v6 - - - name: Setup Go - uses: host-uk/build/actions/setup/go@v4.0.0 - with: - go-version: "1.25" - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: "20" - - - name: Install Wails CLI - run: go install github.com/wailsapp/wails/v3/cmd/wails3@latest - - - name: Install frontend dependencies - working-directory: internal/core-ide/frontend - run: npm ci - - - name: Generate bindings - run: wails3 generate bindings -f '-tags production' -clean=false -ts -i - - - name: Build frontend - working-directory: internal/core-ide/frontend - run: npm run build - - - name: Install Linux dependencies - if: matrix.goos == 'linux' - run: | - sudo apt-get update - sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev - - - name: Build IDE - shell: bash - run: | - EXT="" - if [ "$GOOS" = "windows" ]; then EXT=".exe"; fi - BINARY="core-ide${EXT}" - ARCHIVE_PREFIX="core-ide-${GOOS}-${GOARCH}" - - BUILD_FLAGS="-tags production -trimpath -buildvcs=false" - - if [ "$GOOS" = "windows" ]; then - # Windows: no CGO, use windowsgui linker flag - export CGO_ENABLED=0 - LDFLAGS="-w -s -H windowsgui" - - # Generate Windows syso resource - cd build - wails3 generate syso -arch ${GOARCH} -icon windows/icon.ico -manifest windows/wails.exe.manifest -info windows/info.json -out ../wails_windows_${GOARCH}.syso - cd .. - elif [ "$GOOS" = "darwin" ]; then - export CGO_ENABLED=1 - export CGO_CFLAGS="-mmacosx-version-min=10.15" - export CGO_LDFLAGS="-mmacosx-version-min=10.15" - export MACOSX_DEPLOYMENT_TARGET="10.15" - LDFLAGS="-w -s" - else - export CGO_ENABLED=1 - LDFLAGS="-w -s" - fi - - go build ${BUILD_FLAGS} -ldflags="${LDFLAGS}" -o "./bin/${BINARY}" - - # Clean up syso files - rm -f *.syso - - # Package - if [ "$GOOS" = "darwin" ]; then - # Create .app bundle - mkdir -p "./bin/Core IDE.app/Contents/"{MacOS,Resources} - cp build/darwin/icons.icns "./bin/Core IDE.app/Contents/Resources/" - cp "./bin/${BINARY}" "./bin/Core IDE.app/Contents/MacOS/" - cp build/darwin/Info.plist "./bin/Core IDE.app/Contents/" - codesign --force --deep --sign - "./bin/Core IDE.app" - tar czf "./bin/${ARCHIVE_PREFIX}.tar.gz" -C ./bin "Core IDE.app" - elif [ "$GOOS" = "windows" ]; then - cd ./bin && zip "${ARCHIVE_PREFIX}.zip" "${BINARY}" && cd .. - else - tar czf "./bin/${ARCHIVE_PREFIX}.tar.gz" -C ./bin "${BINARY}" - fi - - # Rename raw binary - mv "./bin/${BINARY}" "./bin/${ARCHIVE_PREFIX}${EXT}" - - - name: Upload artifact - uses: actions/upload-artifact@v4 - with: - name: core-ide-${{ matrix.goos }}-${{ matrix.goarch }} - path: internal/core-ide/bin/core-ide-* - - release: - needs: [build, build-ide] - runs-on: ubuntu-latest - outputs: - version: ${{ steps.version.outputs.version }} - steps: - - uses: actions/checkout@v6 - - - name: Set version - id: version - run: echo "version=${{ github.ref_name }}" >> "$GITHUB_OUTPUT" - - - name: Download artifacts - uses: actions/download-artifact@v7 - with: - path: dist - merge-multiple: true - - - name: Prepare release files - run: | - mkdir -p release - cp dist/* release/ 2>/dev/null || true - ls -la release/ - - - name: Create release - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - TAG_NAME: ${{ github.ref_name }} - run: | - gh release create "$TAG_NAME" \ - --title "Release $TAG_NAME" \ - --generate-notes \ - release/* - - update-tap: - needs: release - runs-on: ubuntu-latest - steps: - - name: Download artifacts - uses: actions/download-artifact@v7 - with: - path: dist - merge-multiple: true - - - name: Generate checksums - run: | - cd dist - for f in *.tar.gz; do - sha256sum "$f" | awk '{print $1}' > "${f}.sha256" - done - echo "=== Checksums ===" - cat *.sha256 - - - name: Update Homebrew formula - env: - GH_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }} - VERSION: ${{ needs.release.outputs.version }} - run: | - # Strip leading 'v' for formula version - FORMULA_VERSION="${VERSION#v}" - - # Read checksums - DARWIN_ARM64=$(cat dist/core-darwin-arm64.tar.gz.sha256) - LINUX_AMD64=$(cat dist/core-linux-amd64.tar.gz.sha256) - LINUX_ARM64=$(cat dist/core-linux-arm64.tar.gz.sha256) - - # Clone tap repo (configure auth for push) - gh repo clone host-uk/homebrew-tap /tmp/tap -- --depth=1 - cd /tmp/tap - git remote set-url origin "https://x-access-token:${GH_TOKEN}@github.com/host-uk/homebrew-tap.git" - cd - - mkdir -p /tmp/tap/Formula - - # Write formula - cat > /tmp/tap/Formula/core.rb << FORMULA - # typed: false - # frozen_string_literal: true - - class Core < Formula - desc "Host UK development CLI" - homepage "https://github.com/host-uk/core" - version "${FORMULA_VERSION}" - license "EUPL-1.2" - - on_macos do - url "https://github.com/host-uk/core/releases/download/${VERSION}/core-darwin-arm64.tar.gz" - sha256 "${DARWIN_ARM64}" - end - - on_linux do - if Hardware::CPU.arm? - url "https://github.com/host-uk/core/releases/download/${VERSION}/core-linux-arm64.tar.gz" - sha256 "${LINUX_ARM64}" - else - url "https://github.com/host-uk/core/releases/download/${VERSION}/core-linux-amd64.tar.gz" - sha256 "${LINUX_AMD64}" - end - end - - def install - bin.install "core" - end - - test do - system "\#{bin}/core", "--version" - end - end - FORMULA - - # Remove leading whitespace from heredoc - sed -i 's/^ //' /tmp/tap/Formula/core.rb - - # Read IDE checksums (may not exist if build-ide failed) - IDE_DARWIN_ARM64=$(cat dist/core-ide-darwin-arm64.tar.gz.sha256 2>/dev/null || echo "") - IDE_LINUX_AMD64=$(cat dist/core-ide-linux-amd64.tar.gz.sha256 2>/dev/null || echo "") - - # Write core-ide Formula (Linux binary) - if [ -n "${IDE_LINUX_AMD64}" ]; then - cat > /tmp/tap/Formula/core-ide.rb << FORMULA - # typed: false - # frozen_string_literal: true - - class CoreIde < Formula - desc "Host UK desktop development environment" - homepage "https://github.com/host-uk/core" - version "${FORMULA_VERSION}" - license "EUPL-1.2" - - on_linux do - url "https://github.com/host-uk/core/releases/download/${VERSION}/core-ide-linux-amd64.tar.gz" - sha256 "${IDE_LINUX_AMD64}" - end - - def install - bin.install "core-ide" - end - end - FORMULA - sed -i 's/^ //' /tmp/tap/Formula/core-ide.rb - fi - - # Write core-ide Cask (macOS .app bundle) - if [ -n "${IDE_DARWIN_ARM64}" ]; then - mkdir -p /tmp/tap/Casks - cat > /tmp/tap/Casks/core-ide.rb << CASK - cask "core-ide" do - version "${FORMULA_VERSION}" - sha256 "${IDE_DARWIN_ARM64}" - - url "https://github.com/host-uk/core/releases/download/${VERSION}/core-ide-darwin-arm64.tar.gz" - name "Core IDE" - desc "Host UK desktop development environment" - homepage "https://github.com/host-uk/core" - - app "Core IDE.app" - end - CASK - sed -i 's/^ //' /tmp/tap/Casks/core-ide.rb - fi - - cd /tmp/tap - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - git add . - git diff --cached --quiet && echo "No changes to tap" && exit 0 - git commit -m "Update core to ${FORMULA_VERSION}" - git push - - update-scoop: - needs: release - runs-on: ubuntu-latest - steps: - - name: Download artifacts - uses: actions/download-artifact@v7 - with: - path: dist - merge-multiple: true - - - name: Generate checksums - run: | - cd dist - for f in *.zip; do - [ -f "$f" ] || continue - sha256sum "$f" | awk '{print $1}' > "${f}.sha256" - done - echo "=== Checksums ===" - cat *.sha256 2>/dev/null || echo "No zip checksums" - - - name: Update Scoop manifests - env: - GH_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }} - VERSION: ${{ needs.release.outputs.version }} - run: | - # Strip leading 'v' for manifest version - MANIFEST_VERSION="${VERSION#v}" - - # Read checksums - WIN_AMD64=$(cat dist/core-windows-amd64.zip.sha256 2>/dev/null || echo "") - IDE_WIN_AMD64=$(cat dist/core-ide-windows-amd64.zip.sha256 2>/dev/null || echo "") - - # Clone scoop bucket - gh repo clone host-uk/scoop-bucket /tmp/scoop -- --depth=1 - cd /tmp/scoop - git remote set-url origin "https://x-access-token:${GH_TOKEN}@github.com/host-uk/scoop-bucket.git" - - # Write core.json manifest - cat > core.json << 'MANIFEST' - { - "version": "VERSION_PLACEHOLDER", - "description": "Host UK development CLI", - "homepage": "https://github.com/host-uk/core", - "license": "EUPL-1.2", - "architecture": { - "64bit": { - "url": "URL_PLACEHOLDER", - "hash": "HASH_PLACEHOLDER", - "bin": "core.exe" - } - }, - "checkver": "github", - "autoupdate": { - "architecture": { - "64bit": { - "url": "https://github.com/host-uk/core/releases/download/v$version/core-windows-amd64.zip" - } - } - } - } - MANIFEST - - sed -i "s|VERSION_PLACEHOLDER|${MANIFEST_VERSION}|g" core.json - sed -i "s|URL_PLACEHOLDER|https://github.com/host-uk/core/releases/download/${VERSION}/core-windows-amd64.zip|g" core.json - sed -i "s|HASH_PLACEHOLDER|${WIN_AMD64}|g" core.json - sed -i 's/^ //' core.json - - # Write core-ide.json manifest - if [ -n "${IDE_WIN_AMD64}" ]; then - cat > core-ide.json << 'MANIFEST' - { - "version": "VERSION_PLACEHOLDER", - "description": "Host UK desktop development environment", - "homepage": "https://github.com/host-uk/core", - "license": "EUPL-1.2", - "architecture": { - "64bit": { - "url": "URL_PLACEHOLDER", - "hash": "HASH_PLACEHOLDER", - "bin": "core-ide.exe" - } - }, - "checkver": "github", - "autoupdate": { - "architecture": { - "64bit": { - "url": "https://github.com/host-uk/core/releases/download/v$version/core-ide-windows-amd64.zip" - } - } - } - } - MANIFEST - sed -i "s|VERSION_PLACEHOLDER|${MANIFEST_VERSION}|g" core-ide.json - sed -i "s|URL_PLACEHOLDER|https://github.com/host-uk/core/releases/download/${VERSION}/core-ide-windows-amd64.zip|g" core-ide.json - sed -i "s|HASH_PLACEHOLDER|${IDE_WIN_AMD64}|g" core-ide.json - sed -i 's/^ //' core-ide.json - fi - - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - git add . - git diff --cached --quiet && echo "No changes to scoop bucket" && exit 0 - git commit -m "Update core to ${MANIFEST_VERSION}" - git push diff --git a/.woodpecker/core.yml b/.woodpecker/core.yml index 7e1e7b29..dcab5683 100644 --- a/.woodpecker/core.yml +++ b/.woodpecker/core.yml @@ -9,9 +9,9 @@ steps: - go mod download - >- go build - -ldflags "-X github.com/host-uk/core/pkg/cli.AppVersion=ci - -X github.com/host-uk/core/pkg/cli.BuildCommit=${CI_COMMIT_SHA:0:7} - -X github.com/host-uk/core/pkg/cli.BuildDate=$(date -u +%Y%m%d)" + -ldflags "-X forge.lthn.ai/core/cli/pkg/cli.AppVersion=ci + -X forge.lthn.ai/core/cli/pkg/cli.BuildCommit=${CI_COMMIT_SHA:0:7} + -X forge.lthn.ai/core/cli/pkg/cli.BuildDate=$(date -u +%Y%m%d)" -o ./bin/core . - ./bin/core --version diff --git a/README.md b/README.md index 07e28c37..4d213f6c 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,14 @@ # Core [![codecov](https://codecov.io/gh/host-uk/core/branch/dev/graph/badge.svg)](https://codecov.io/gh/host-uk/core) -[![Go Test Coverage](https://github.com/host-uk/core/actions/workflows/coverage.yml/badge.svg)](https://github.com/host-uk/core/actions/workflows/coverage.yml) -[![Code Scanning](https://github.com/host-uk/core/actions/workflows/codescan.yml/badge.svg)](https://github.com/host-uk/core/actions/workflows/codescan.yml) +[![Go Test Coverage](https://forge.lthn.ai/core/cli/actions/workflows/coverage.yml/badge.svg)](https://forge.lthn.ai/core/cli/actions/workflows/coverage.yml) +[![Code Scanning](https://forge.lthn.ai/core/cli/actions/workflows/codescan.yml/badge.svg)](https://forge.lthn.ai/core/cli/actions/workflows/codescan.yml) [![Go Version](https://img.shields.io/github/go-mod/go-version/host-uk/core)](https://go.dev/) [![License](https://img.shields.io/badge/License-EUPL--1.2-blue.svg)](https://opensource.org/licenses/EUPL-1.2) Core is a Web3 Framework, written in Go using Wails.io to replace Electron and the bloat of browsers that, at their core, still live in their mum's basement. -- Repo: https://github.com/host-uk/core +- Repo: https://forge.lthn.ai/core/cli ## Vision @@ -26,7 +26,7 @@ Core is an **opinionated Web3 desktop application framework** providing: ```bash # 1. Install Core -go install github.com/host-uk/core/cmd/core@latest +go install forge.lthn.ai/core/cli/cmd/core@latest # 2. Verify environment core doctor @@ -44,7 +44,7 @@ For more details, see the [User Guide](docs/user-guide.md). ## Framework Quick Start (Go) ```go -import core "github.com/host-uk/core/pkg/framework/core" +import core "forge.lthn.ai/core/cli/pkg/framework/core" app, err := core.New( core.WithServiceLock(), @@ -210,7 +210,7 @@ app.RegisterService(application.NewService(coreService)) // Only Core is regist **Currently exposed** (see `cmd/core-gui/public/bindings/`): ```typescript // From frontend: -import { ACTION, Config, Service } from './bindings/github.com/host-uk/core/pkg/core' +import { ACTION, Config, Service } from './bindings/forge.lthn.ai/core/cli/pkg/core' ACTION(msg) // Broadcast IPC message Config() // Get config service reference @@ -259,7 +259,7 @@ Sub-services are accessed via Core's **IPC/ACTION system**, not direct Wails bin ```typescript // Frontend calls Core.ACTION() with typed messages -import { ACTION } from './bindings/github.com/host-uk/core/pkg/core' +import { ACTION } from './bindings/forge.lthn.ai/core/cli/pkg/core' // Open a window ACTION({ action: "display.open_window", name: "settings", options: { Title: "Settings", Width: 800 } }) diff --git a/Taskfile.yml b/Taskfile.yml index dbce0de8..4ada362f 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -15,7 +15,7 @@ vars: SEMVER_PRERELEASE: sh: '[ "{{.SEMVER_COMMITS}}" = "0" ] && echo "" || echo "dev.{{.SEMVER_COMMITS}}"' # ldflags - PKG: "github.com/host-uk/core/pkg/cli" + PKG: "forge.lthn.ai/core/cli/pkg/cli" LDFLAGS_BASE: >- -X {{.PKG}}.AppVersion={{.SEMVER_VERSION}} -X {{.PKG}}.BuildCommit={{.SEMVER_COMMIT}} diff --git a/cmd/bugseti/README.md b/cmd/bugseti/README.md index 8a4de64b..8f00cbbd 100644 --- a/cmd/bugseti/README.md +++ b/cmd/bugseti/README.md @@ -19,7 +19,7 @@ BugSETI is a system tray application that helps developers contribute to open so ```bash # Clone the repository -git clone https://github.com/host-uk/core.git +git clone https://forge.lthn.ai/core/cli.git cd core # Build BugSETI diff --git a/cmd/bugseti/build/linux/nfpm/nfpm.yaml b/cmd/bugseti/build/linux/nfpm/nfpm.yaml index 5d28a3be..7261762e 100644 --- a/cmd/bugseti/build/linux/nfpm/nfpm.yaml +++ b/cmd/bugseti/build/linux/nfpm/nfpm.yaml @@ -12,7 +12,7 @@ description: | it pulls OSS issues from GitHub, AI prepares context, you fix bugs, and it auto-submits PRs. vendor: "Lethean" -homepage: "https://github.com/host-uk/core" +homepage: "https://forge.lthn.ai/core/cli" license: "MIT" contents: diff --git a/cmd/bugseti/go.mod b/cmd/bugseti/go.mod index 509ef72f..0d869dd7 100644 --- a/cmd/bugseti/go.mod +++ b/cmd/bugseti/go.mod @@ -7,6 +7,9 @@ require ( forge.lthn.ai/core/cli/internal/bugseti v0.0.0 forge.lthn.ai/core/cli/internal/bugseti/updater v0.0.0 github.com/Snider/Borg v0.2.0 + forge.lthn.ai/core/cli v0.0.0 + forge.lthn.ai/core/cli/internal/bugseti v0.0.0 + forge.lthn.ai/core/cli/internal/bugseti/updater v0.0.0 github.com/wailsapp/wails/v3 v3.0.0-alpha.64 ) diff --git a/cmd/community/index.html b/cmd/community/index.html index 9da43fd2..0cc35d30 100644 --- a/cmd/community/index.html +++ b/cmd/community/index.html @@ -186,7 +186,7 @@
How it works Ecosystem - GitHub + GitHub Get BugSETI @@ -249,7 +249,7 @@ Download BugSETI - + View Source @@ -518,13 +518,13 @@ @@ -533,7 +533,7 @@
# or build from source
- $ git clone https://github.com/host-uk/core
+ $ git clone https://forge.lthn.ai/core/cli
$ cd core && go build ./cmd/bugseti
diff --git a/core-ide b/core-ide new file mode 100755 index 00000000..b933e6f5 Binary files /dev/null and b/core-ide differ diff --git a/docs/cmd/dev/work/example.md b/docs/cmd/dev/work/example.md index 74db3fb6..4d104701 100644 --- a/docs/cmd/dev/work/example.md +++ b/docs/cmd/dev/work/example.md @@ -26,8 +26,8 @@ core dev work --status repos: - name: core path: ./core - url: https://github.com/host-uk/core + url: https://forge.lthn.ai/core/cli - name: core-php path: ./core-php - url: https://github.com/host-uk/core-php + url: https://forge.lthn.ai/core/cli-php ``` diff --git a/docs/cmd/go/mod/graph/index.md b/docs/cmd/go/mod/graph/index.md index 2aa2619a..160c5534 100644 --- a/docs/cmd/go/mod/graph/index.md +++ b/docs/cmd/go/mod/graph/index.md @@ -32,7 +32,7 @@ core go mod graph | dot -Tpng -o deps.png ## Output ``` -github.com/host-uk/core github.com/stretchr/testify@v1.11.1 +forge.lthn.ai/core/cli github.com/stretchr/testify@v1.11.1 github.com/stretchr/testify@v1.11.1 github.com/davecgh/go-spew@v1.1.2 github.com/stretchr/testify@v1.11.1 github.com/pmezard/go-difflib@v1.0.1 ... diff --git a/docs/cmd/index.md b/docs/cmd/index.md index fce31835..de2c061f 100644 --- a/docs/cmd/index.md +++ b/docs/cmd/index.md @@ -23,7 +23,7 @@ Unified interface for Go/PHP development, multi-repo management, and deployment. ## Installation ```bash -go install github.com/host-uk/core/cmd/core@latest +go install forge.lthn.ai/core/cli/cmd/core@latest ``` Verify: `core doctor` diff --git a/docs/faq.md b/docs/faq.md index 54ba99c1..2c3b6e4d 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -21,7 +21,7 @@ It is both. The Core Framework (`pkg/core`) is a library for building Go desktop The recommended way is via Go: ```bash -go install github.com/host-uk/core/cmd/core@latest +go install forge.lthn.ai/core/cli/cmd/core@latest ``` Ensure your Go bin directory is in your PATH. See [Getting Started](getting-started.md) for more options. diff --git a/docs/getting-started.md b/docs/getting-started.md index ad374abf..486dbfa5 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -25,7 +25,7 @@ Optional (for specific features): ```bash # Install latest release -go install github.com/host-uk/core/cmd/core@latest +go install forge.lthn.ai/core/cli/cmd/core@latest # Verify installation core doctor @@ -39,21 +39,21 @@ export PATH="$PATH:$(go env GOPATH)/bin" ### Option 2: Download Binary -Download pre-built binaries from [GitHub Releases](https://github.com/host-uk/core/releases): +Download pre-built binaries from [GitHub Releases](https://forge.lthn.ai/core/cli/releases): ```bash # macOS (Apple Silicon) -curl -Lo core https://github.com/host-uk/core/releases/latest/download/core-darwin-arm64 +curl -Lo core https://forge.lthn.ai/core/cli/releases/latest/download/core-darwin-arm64 chmod +x core sudo mv core /usr/local/bin/ # macOS (Intel) -curl -Lo core https://github.com/host-uk/core/releases/latest/download/core-darwin-amd64 +curl -Lo core https://forge.lthn.ai/core/cli/releases/latest/download/core-darwin-amd64 chmod +x core sudo mv core /usr/local/bin/ # Linux (x86_64) -curl -Lo core https://github.com/host-uk/core/releases/latest/download/core-linux-amd64 +curl -Lo core https://forge.lthn.ai/core/cli/releases/latest/download/core-linux-amd64 chmod +x core sudo mv core /usr/local/bin/ ``` @@ -62,7 +62,7 @@ sudo mv core /usr/local/bin/ ```bash # Clone repository -git clone https://github.com/host-uk/core.git +git clone https://forge.lthn.ai/core/cli.git cd core # Build with Task (recommended) @@ -181,7 +181,7 @@ core doctor core --help # Full documentation -https://github.com/host-uk/core/tree/main/docs +https://forge.lthn.ai/core/cli/tree/main/docs ``` ## See Also diff --git a/docs/index.md b/docs/index.md index 83f647e8..bab97f1e 100644 --- a/docs/index.md +++ b/docs/index.md @@ -6,10 +6,10 @@ Core is a unified CLI for the host-uk ecosystem - build, release, and deploy Go, ```bash # Via Go (recommended) -go install github.com/host-uk/core/cmd/core@latest +go install forge.lthn.ai/core/cli/cmd/core@latest # Or download binary from releases -curl -Lo core https://github.com/host-uk/core/releases/latest/download/core-$(go env GOOS)-$(go env GOARCH) +curl -Lo core https://forge.lthn.ai/core/cli/releases/latest/download/core-$(go env GOOS)-$(go env GOARCH) chmod +x core && sudo mv core /usr/local/bin/ # Verify diff --git a/docs/mcp/angular-testing.md b/docs/mcp/angular-testing.md index 4f154bfc..2dcf37ae 100644 --- a/docs/mcp/angular-testing.md +++ b/docs/mcp/angular-testing.md @@ -364,7 +364,7 @@ import ( "log" "time" - "github.com/host-uk/core/pkg/webview" + "forge.lthn.ai/core/cli/pkg/webview" ) func main() { @@ -424,7 +424,7 @@ import ( "log" "time" - "github.com/host-uk/core/pkg/webview" + "forge.lthn.ai/core/cli/pkg/webview" ) func main() { diff --git a/docs/pkg-batch1-analysis.md b/docs/pkg-batch1-analysis.md index 00e218cf..ef2dc885 100644 --- a/docs/pkg-batch1-analysis.md +++ b/docs/pkg-batch1-analysis.md @@ -47,8 +47,8 @@ Here is the technical documentation for the Core framework packages. * **Framework Integration**: The `Service` struct embeds `framework.ServiceRuntime`, utilizing the Actor pattern (Queries and Tasks) to allow dynamic log level adjustment at runtime without restarting the application. ### 4. Dependencies -* `github.com/host-uk/core/pkg/io`: Used by `rotation.go` to handle file operations (renaming, deleting, writing) abstractly. -* `github.com/host-uk/core/pkg/framework`: Used by `service.go` to hook into the application lifecycle and message bus. +* `forge.lthn.ai/core/cli/pkg/io`: Used by `rotation.go` to handle file operations (renaming, deleting, writing) abstractly. +* `forge.lthn.ai/core/cli/pkg/framework`: Used by `service.go` to hook into the application lifecycle and message bus. * Standard Lib: `errors`, `fmt`, `os`, `sync`, `time`. ### 5. Test Coverage Notes @@ -88,8 +88,8 @@ Here is the technical documentation for the Core framework packages. ### 4. Dependencies * `github.com/spf13/viper`: Core logic for map merging and unmarshalling. * `gopkg.in/yaml.v3`: For marshalling data when saving. -* `github.com/host-uk/core/pkg/io`: For reading/writing config files. -* `github.com/host-uk/core/pkg/framework/core`: For service integration and error handling. +* `forge.lthn.ai/core/cli/pkg/io`: For reading/writing config files. +* `forge.lthn.ai/core/cli/pkg/framework/core`: For service integration and error handling. ### 5. Test Coverage Notes * **Precedence**: Verify that Environment variables override File values. @@ -122,7 +122,7 @@ Here is the technical documentation for the Core framework packages. ### 4. Dependencies * Standard Lib: `io`, `io/fs`, `os`, `path/filepath`, `strings`, `time`. -* `github.com/host-uk/core/pkg/io/local`: (Implied) The concrete implementation for OS disk access. +* `forge.lthn.ai/core/cli/pkg/io/local`: (Implied) The concrete implementation for OS disk access. ### 5. Test Coverage Notes * **Mock fidelity**: The `MockMedium` must behave exactly like the OS. E.g., `Rename` should fail if the source doesn't exist; `Delete` should fail if a directory is not empty. @@ -198,10 +198,10 @@ Here is the technical documentation for the Core framework packages. 4. Server validates signature against User Public Key. ### 4. Dependencies -* `github.com/host-uk/core/pkg/io`: For user database storage. -* `github.com/host-uk/core/pkg/crypt/lthn`: (Implied) Specific password hashing. -* `github.com/host-uk/core/pkg/crypt/pgp`: (Implied) OpenPGP operations. -* `github.com/host-uk/core/pkg/framework/core`: Error handling. +* `forge.lthn.ai/core/cli/pkg/io`: For user database storage. +* `forge.lthn.ai/core/cli/pkg/crypt/lthn`: (Implied) Specific password hashing. +* `forge.lthn.ai/core/cli/pkg/crypt/pgp`: (Implied) OpenPGP operations. +* `forge.lthn.ai/core/cli/pkg/framework/core`: Error handling. ### 5. Test Coverage Notes * **Flow Verification**: Full integration test simulating a client: Register -> Get Challenge -> Decrypt/Sign (Mock Client) -> Validate -> Get Token. diff --git a/docs/pkg-batch2-analysis.md b/docs/pkg-batch2-analysis.md index 9562e6c1..2cbfc92c 100644 --- a/docs/pkg-batch2-analysis.md +++ b/docs/pkg-batch2-analysis.md @@ -60,9 +60,9 @@ The `cli` package is a comprehensive application runtime and UI framework design ### 4. Dependencies - `github.com/spf13/cobra`: The underlying command routing engine. -- `github.com/host-uk/core/pkg/framework`: The dependency injection and service lifecycle container. -- `github.com/host-uk/core/pkg/i18n`: For translation and semantic grammar generation. -- `github.com/host-uk/core/pkg/log`: For structured logging. +- `forge.lthn.ai/core/cli/pkg/framework`: The dependency injection and service lifecycle container. +- `forge.lthn.ai/core/cli/pkg/i18n`: For translation and semantic grammar generation. +- `forge.lthn.ai/core/cli/pkg/log`: For structured logging. - `golang.org/x/term`: For TTY detection. ### 5. Test Coverage Notes @@ -162,8 +162,8 @@ The `workspace` package implements the `core.Workspace` interface, providing iso - **Key Management**: Delegates actual key generation to the core's `Crypt()` service but manages the storage of the resulting keys within the workspace layout. ### 4. Dependencies -- `github.com/host-uk/core/pkg/framework/core`: Interfaces. -- `github.com/host-uk/core/pkg/io`: File system abstraction (`io.Medium`). +- `forge.lthn.ai/core/cli/pkg/framework/core`: Interfaces. +- `forge.lthn.ai/core/cli/pkg/io`: File system abstraction (`io.Medium`). - `crypt` service (Runtime dependency): Required for `CreateWorkspace`. ### 5. Test Coverage Notes diff --git a/docs/pkg-batch3-analysis.md b/docs/pkg-batch3-analysis.md index dd22a659..36b7e2f8 100644 --- a/docs/pkg-batch3-analysis.md +++ b/docs/pkg-batch3-analysis.md @@ -87,8 +87,8 @@ type Builder interface { ### 4. Dependencies * `archive/tar`, `archive/zip`, `compress/gzip`: Standard library for archiving. * `github.com/Snider/Borg/pkg/compress`: External dependency for XZ compression support. -* `github.com/host-uk/core/pkg/io`: Internal interface for filesystem abstraction. -* `github.com/host-uk/core/pkg/config`: Internal centralized configuration loading. +* `forge.lthn.ai/core/cli/pkg/io`: Internal interface for filesystem abstraction. +* `forge.lthn.ai/core/cli/pkg/config`: Internal centralized configuration loading. ### 5. Test Coverage Notes * **Mocking IO**: Tests must implement a mock `io.Medium` to simulate file existence (`Detect`) and write operations (`Archive`) without touching the disk. @@ -158,7 +158,7 @@ type RunOptions struct { ### 4. Dependencies * `os/exec`: Essential for spawning the hypervisor processes. * `embed`: For built-in templates. -* `github.com/host-uk/core/pkg/io`: Filesystem access for state and logs. +* `forge.lthn.ai/core/cli/pkg/io`: Filesystem access for state and logs. ### 5. Test Coverage Notes * **Process Management**: Difficult to test `Run` in standard CI. Mocking `exec.Command` or the `Hypervisor` interface is required. @@ -224,7 +224,7 @@ func (r *Runner) RunParallel(ctx context.Context, specs []RunSpec) (*RunAllResul ### 4. Dependencies * `os/exec`: The underlying execution engine. -* `github.com/host-uk/core/pkg/framework`: Creates the `ServiceRuntime` and provides the IPC/Action bus. +* `forge.lthn.ai/core/cli/pkg/framework`: Creates the `ServiceRuntime` and provides the IPC/Action bus. ### 5. Test Coverage Notes * **Concurrency**: The `Runner` needs tests for race conditions during parallel execution. @@ -286,7 +286,7 @@ type JobHandler interface { * **Journaling**: Writes `jsonl` (JSON Lines) files partitioned by repository and date (`baseDir/owner/repo/YYYY-MM-DD.jsonl`), ensuring an append-only audit trail. ### 4. Dependencies -* `github.com/host-uk/core/pkg/log`: Internal logging. +* `forge.lthn.ai/core/cli/pkg/log`: Internal logging. * `encoding/json`: For journal serialization. ### 5. Test Coverage Notes diff --git a/docs/pkg-batch4-analysis.md b/docs/pkg-batch4-analysis.md index b931c5ea..346d8b7b 100644 --- a/docs/pkg-batch4-analysis.md +++ b/docs/pkg-batch4-analysis.md @@ -72,7 +72,7 @@ func NewService(opts ServiceOptions) func(*framework.Core) (any, error) ### Dependencies * `os/exec`: For invoking git commands. -* `github.com/host-uk/core/pkg/framework`: For service registration and message passing types. +* `forge.lthn.ai/core/cli/pkg/framework`: For service registration and message passing types. ### Test Coverage Notes * **Mocking**: Testing requires abstracting `exec.Command`. Since this package calls `exec.CommandContext` directly, tests likely require overriding a package-level variable or using a "fake exec" pattern during test initialization. @@ -135,7 +135,7 @@ func (repo *Repo) IsGitRepo() bool ### Dependencies * `gopkg.in/yaml.v3`: For parsing `repos.yaml`. -* `github.com/host-uk/core/pkg/io`: For filesystem abstraction (`io.Medium`). +* `forge.lthn.ai/core/cli/pkg/io`: For filesystem abstraction (`io.Medium`). ### Test Coverage Notes * **Circular Dependencies**: Critical test cases must define a registry with `A->B->A` dependencies to ensure `TopologicalOrder` returns a clear error and doesn't stack overflow. @@ -197,7 +197,7 @@ func (c *Client) ListUserRepos(...) ### Dependencies * `code.gitea.io/sdk/gitea` (for `pkg/gitea`) * `codeberg.org/mvdkleijn/forgejo-sdk` (for `pkg/forge`) -* `github.com/host-uk/core/pkg/config`: For persistent auth storage. +* `forge.lthn.ai/core/cli/pkg/config`: For persistent auth storage. ### Test Coverage Notes * **Draft Status**: The raw HTTP patch in `pkg/forge` needs integration testing against a real instance or a high-fidelity HTTP mock to ensure payload format matches Forgejo's API expectation. @@ -250,8 +250,8 @@ func IncrementVersion(current string) string * **SDK Generation**: Includes a specialized sub-pipeline (`RunSDK`) that handles OpenAPI diffing and client generation. ### Dependencies -* `github.com/host-uk/core/pkg/build`: For compiling artifacts. -* `github.com/host-uk/core/pkg/release/publishers`: Interface definitions for publishing targets. +* `forge.lthn.ai/core/cli/pkg/build`: For compiling artifacts. +* `forge.lthn.ai/core/cli/pkg/release/publishers`: Interface definitions for publishing targets. * `golang.org/x/text`: For title casing in changelogs. ### Test Coverage Notes diff --git a/docs/pkg-batch5-analysis.md b/docs/pkg-batch5-analysis.md index 9a78689d..5fe57261 100644 --- a/docs/pkg-batch5-analysis.md +++ b/docs/pkg-batch5-analysis.md @@ -51,8 +51,8 @@ func ListAgents(cfg *config.Config) (map[string]AgentConfig, error) * **Defaults Handling**: `LoadAgents` applies specific logic defaults (e.g., default queue directories, default models like "sonnet") to ensure the system works with minimal configuration. ### 4. Dependencies -* `github.com/host-uk/core/pkg/config`: For reading/writing the persistent configuration state. -* `github.com/host-uk/core/pkg/jobrunner/handlers`: To map local config structs to the runtime types used by the job dispatch system. +* `forge.lthn.ai/core/cli/pkg/config`: For reading/writing the persistent configuration state. +* `forge.lthn.ai/core/cli/pkg/jobrunner/handlers`: To map local config structs to the runtime types used by the job dispatch system. ### 5. Test Coverage Notes * **Configuration Persistence**: Tests should verify that `SaveAgent` correctly updates the underlying config file and that `LoadAgents` retrieves it accurately. diff --git a/docs/pkg-batch6-analysis.md b/docs/pkg-batch6-analysis.md index 80b19fe8..3847dc35 100644 --- a/docs/pkg-batch6-analysis.md +++ b/docs/pkg-batch6-analysis.md @@ -58,7 +58,7 @@ type TaskResult struct { Changed, Failed bool; Msg, Stdout string; ... } * **SSH Abstraction**: `ssh.go` wraps `golang.org/x/crypto/ssh` to handle connection pooling, key management, and `sudo` escalation (become). ### 4. Dependencies -* `github.com/host-uk/core/pkg/log`: structured logging. +* `forge.lthn.ai/core/cli/pkg/log`: structured logging. * `golang.org/x/crypto/ssh`: Underlying SSH transport. * `gopkg.in/yaml.v3`: YAML parsing. @@ -129,7 +129,7 @@ Re-exports `Core`, `Option`, `Message`, `Startable`, `Stoppable`, and constructo Purely structural; contains type aliases and variable assignments to expose the internal `core` package. ### 4. Dependencies -* `github.com/host-uk/core/pkg/framework/core` +* `forge.lthn.ai/core/cli/pkg/framework/core` ### 5. Test Coverage Notes No logic to test directly; coverage belongs in `pkg/framework/core`. diff --git a/docs/pkg/PACKAGE_STANDARDS.md b/docs/pkg/PACKAGE_STANDARDS.md index ddafd2cb..5dcb450e 100644 --- a/docs/pkg/PACKAGE_STANDARDS.md +++ b/docs/pkg/PACKAGE_STANDARDS.md @@ -40,7 +40,7 @@ package mypackage import ( "sync" - "github.com/host-uk/core/pkg/framework" + "forge.lthn.ai/core/cli/pkg/framework" ) // Service provides mypackage functionality with Core integration. @@ -120,7 +120,7 @@ import ( "sync" "sync/atomic" - "github.com/host-uk/core/pkg/framework" + "forge.lthn.ai/core/cli/pkg/framework" ) // Global default service diff --git a/docs/pkg/i18n/README.md b/docs/pkg/i18n/README.md index a70dfc3c..67775a9c 100644 --- a/docs/pkg/i18n/README.md +++ b/docs/pkg/i18n/README.md @@ -5,7 +5,7 @@ The `pkg/i18n` package provides internationalisation and localisation for Go CLI ## Quick Start ```go -import "github.com/host-uk/core/pkg/i18n" +import "forge.lthn.ai/core/cli/pkg/i18n" func main() { // Initialise with embedded locales diff --git a/docs/plans/2026-02-05-core-ide-job-runner-plan.md b/docs/plans/2026-02-05-core-ide-job-runner-plan.md index c0bbbb34..4b3be944 100644 --- a/docs/plans/2026-02-05-core-ide-job-runner-plan.md +++ b/docs/plans/2026-02-05-core-ide-job-runner-plan.md @@ -15,7 +15,7 @@ **Files:** - Create: `go.work` -**Context:** The repo has two real modules — the root (`github.com/host-uk/core`) and core-ide (`github.com/host-uk/core/internal/core-ide`). Without a workspace, core-ide can't import `pkg/jobrunner` from the root module during local development without fragile `replace` directives. A `go.work` file makes cross-module imports resolve locally, keeps each module's `go.mod` clean, and lets CI build each variant independently. +**Context:** The repo has two real modules — the root (`forge.lthn.ai/core/cli`) and core-ide (`forge.lthn.ai/core/cli/internal/core-ide`). Without a workspace, core-ide can't import `pkg/jobrunner` from the root module during local development without fragile `replace` directives. A `go.work` file makes cross-module imports resolve locally, keeps each module's `go.mod` clean, and lets CI build each variant independently. **Step 1: Create the workspace file** @@ -580,7 +580,7 @@ import ( "fmt" "time" - "github.com/host-uk/core/pkg/log" + "forge.lthn.ai/core/cli/pkg/log" ) // PollerConfig configures the job runner poller. @@ -732,7 +732,7 @@ func (p *Poller) AddHandler(h JobHandler) { _ = fmt.Sprintf // ensure fmt imported for future use ``` -Wait — remove that last line. The `fmt` import is only needed if used. Let me correct: the implementation above doesn't use `fmt` directly, so remove it from imports. The `log` package import path is `github.com/host-uk/core/pkg/log`. +Wait — remove that last line. The `fmt` import is only needed if used. Let me correct: the implementation above doesn't use `fmt` directly, so remove it from imports. The `log` package import path is `forge.lthn.ai/core/cli/pkg/log`. **Step 4: Run tests** @@ -755,7 +755,7 @@ git commit -m "feat(jobrunner): add Poller with multi-source dispatch and journa - Create: `pkg/jobrunner/github/signals.go` - Test: `pkg/jobrunner/github/source_test.go` -**Context:** This package lives in the root go.mod (`github.com/host-uk/core`), NOT in the core-ide module. It uses `oauth2` and the GitHub REST API (same pattern as `internal/cmd/updater/github.go`). Uses conditional requests (ETag/If-None-Match) to conserve rate limit. +**Context:** This package lives in the root go.mod (`forge.lthn.ai/core/cli`), NOT in the core-ide module. It uses `oauth2` and the GitHub REST API (same pattern as `internal/cmd/updater/github.go`). Uses conditional requests (ETag/If-None-Match) to conserve rate limit. **Step 1: Write the test** @@ -769,7 +769,7 @@ import ( "net/http/httptest" "testing" - "github.com/host-uk/core/pkg/jobrunner" + "forge.lthn.ai/core/cli/pkg/jobrunner" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -856,7 +856,7 @@ import ( "strings" "time" - "github.com/host-uk/core/pkg/jobrunner" + "forge.lthn.ai/core/cli/pkg/jobrunner" ) // ghIssue is the minimal structure from GitHub Issues API. @@ -985,8 +985,8 @@ import ( "os" "strings" - "github.com/host-uk/core/pkg/jobrunner" - "github.com/host-uk/core/pkg/log" + "forge.lthn.ai/core/cli/pkg/jobrunner" + "forge.lthn.ai/core/cli/pkg/log" "golang.org/x/oauth2" ) @@ -1176,7 +1176,7 @@ import ( "net/http/httptest" "testing" - "github.com/host-uk/core/pkg/jobrunner" + "forge.lthn.ai/core/cli/pkg/jobrunner" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -1259,7 +1259,7 @@ import ( "net/http" "time" - "github.com/host-uk/core/pkg/jobrunner" + "forge.lthn.ai/core/cli/pkg/jobrunner" ) // PublishDraft marks a draft PR as ready for review. @@ -1355,7 +1355,7 @@ import ( "net/http/httptest" "testing" - "github.com/host-uk/core/pkg/jobrunner" + "forge.lthn.ai/core/cli/pkg/jobrunner" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -1438,7 +1438,7 @@ import ( "net/http" "time" - "github.com/host-uk/core/pkg/jobrunner" + "forge.lthn.ai/core/cli/pkg/jobrunner" ) // SendFixCommand comments on a PR to request a fix. @@ -1559,7 +1559,7 @@ import ( "os/exec" "time" - "github.com/host-uk/core/pkg/jobrunner" + "forge.lthn.ai/core/cli/pkg/jobrunner" ) type EnableAutoMerge struct{} @@ -1657,7 +1657,7 @@ import ( "net/http/httptest" "testing" - "github.com/host-uk/core/pkg/jobrunner" + "forge.lthn.ai/core/cli/pkg/jobrunner" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -1758,7 +1758,7 @@ import ( "net/http" "time" - "github.com/host-uk/core/pkg/jobrunner" + "forge.lthn.ai/core/cli/pkg/jobrunner" ) // ResolveThreads resolves all unresolved review threads on a PR. @@ -1918,16 +1918,16 @@ git commit -m "feat(jobrunner): add resolve_threads handler with GraphQL" **Context:** core-ide currently always creates a Wails app. We need to branch: headless starts the poller + MCP bridge directly; desktop mode keeps the existing Wails app with poller as an optional service. -Note: core-ide has its own `go.mod` (`github.com/host-uk/core/internal/core-ide`). The jobrunner package lives in the root module. We need to add the root module as a dependency of core-ide, OR move the handler wiring into the root module. **Simplest approach:** core-ide imports `github.com/host-uk/core/pkg/jobrunner` — this requires adding the root module as a dependency in core-ide's go.mod. +Note: core-ide has its own `go.mod` (`forge.lthn.ai/core/cli/internal/core-ide`). The jobrunner package lives in the root module. We need to add the root module as a dependency of core-ide, OR move the handler wiring into the root module. **Simplest approach:** core-ide imports `forge.lthn.ai/core/cli/pkg/jobrunner` — this requires adding the root module as a dependency in core-ide's go.mod. **Step 1: Update core-ide go.mod** -Run: `cd /Users/snider/Code/host-uk/core/internal/core-ide && go get github.com/host-uk/core/pkg/jobrunner` +Run: `cd /Users/snider/Code/host-uk/core/internal/core-ide && go get forge.lthn.ai/core/cli/pkg/jobrunner` If this fails because the package isn't published yet, use a `replace` directive temporarily: ``` -replace github.com/host-uk/core => ../.. +replace forge.lthn.ai/core/cli => ../.. ``` Then `go mod tidy`. @@ -2020,7 +2020,7 @@ git commit -m "feat(core-ide): register job handlers as MCP tools" ```go // In startHeadless(), before starting poller: updaterSvc, err := updater.NewUpdateService(updater.UpdateServiceConfig{ - RepoURL: "https://github.com/host-uk/core", + RepoURL: "https://forge.lthn.ai/core/cli", Channel: "alpha", CheckOnStartup: updater.CheckAndUpdateOnStartup, }) diff --git a/docs/plans/2026-02-05-mcp-integration.md b/docs/plans/2026-02-05-mcp-integration.md index b1fb566f..c63285ad 100644 --- a/docs/plans/2026-02-05-mcp-integration.md +++ b/docs/plans/2026-02-05-mcp-integration.md @@ -81,8 +81,8 @@ import ( "context" "fmt" - ragcmd "github.com/host-uk/core/internal/cmd/rag" - "github.com/host-uk/core/pkg/rag" + ragcmd "forge.lthn.ai/core/cli/internal/cmd/rag" + "forge.lthn.ai/core/cli/pkg/rag" "github.com/modelcontextprotocol/go-sdk/mcp" ) @@ -368,7 +368,7 @@ import ( "fmt" "time" - "github.com/host-uk/core/pkg/ai" + "forge.lthn.ai/core/cli/pkg/ai" "github.com/modelcontextprotocol/go-sdk/mcp" ) @@ -608,9 +608,9 @@ import ( "os/signal" "syscall" - "github.com/host-uk/core/pkg/cli" - "github.com/host-uk/core/pkg/i18n" - "github.com/host-uk/core/pkg/mcp" + "forge.lthn.ai/core/cli/pkg/cli" + "forge.lthn.ai/core/cli/pkg/i18n" + "forge.lthn.ai/core/cli/pkg/mcp" ) func init() { @@ -695,7 +695,7 @@ Modify `internal/variants/full.go` to add: ```go import ( // ... existing imports ... - _ "github.com/host-uk/core/internal/cmd/mcpcmd" + _ "forge.lthn.ai/core/cli/internal/cmd/mcpcmd" ) ``` diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index e3c892eb..72a488d9 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -18,7 +18,7 @@ export PATH="$PATH:$(go env GOPATH)/bin" source ~/.bashrc # or ~/.zshrc ``` -### "go: module github.com/host-uk/core: no matching versions" +### "go: module forge.lthn.ai/core/cli: no matching versions" **Cause:** Go module proxy hasn't cached the latest version yet. @@ -26,7 +26,7 @@ source ~/.bashrc # or ~/.zshrc ```bash # Bypass proxy -GOPROXY=direct go install github.com/host-uk/core/cmd/core@latest +GOPROXY=direct go install forge.lthn.ai/core/cli/cmd/core@latest ``` --- @@ -340,7 +340,7 @@ This verifies all required tools are installed and configured. If you've found a bug: -1. Check existing issues: https://github.com/host-uk/core/issues +1. Check existing issues: https://forge.lthn.ai/core/cli/issues 2. Create a new issue with: - Core version (`core --version`) - OS and architecture (`go env GOOS GOARCH`) diff --git a/docs/workflows.md b/docs/workflows.md index 8c40372d..c0aca124 100644 --- a/docs/workflows.md +++ b/docs/workflows.md @@ -173,7 +173,7 @@ jobs: go-version: '1.23' - name: Install Core - run: go install github.com/host-uk/core/cmd/core@latest + run: go install forge.lthn.ai/core/cli/cmd/core@latest - name: Build run: core build --ci diff --git a/go.work b/go.work index 9738e225..3f8ef3d1 100644 --- a/go.work +++ b/go.work @@ -2,9 +2,6 @@ go 1.25.5 use ( . - ./cmd/bugseti - ./cmd/core-app - ./cmd/core-ide ./internal/bugseti ./internal/bugseti/updater ./internal/core-ide diff --git a/internal/bugseti/submit.go b/internal/bugseti/submit.go index 68e9e9c5..a7a38aae 100644 --- a/internal/bugseti/submit.go +++ b/internal/bugseti/submit.go @@ -313,7 +313,7 @@ func (s *SubmitService) generatePRBody(issue *Issue) string { body.WriteString("\n\n") body.WriteString("---\n\n") - body.WriteString("*Submitted via [BugSETI](https://bugseti.app) - Distributed Bug Fixing*\n") + body.WriteString("*Submitted via [BugSETI](https://forge.lthn.ai/core/cli) - Distributed Bug Fixing*\n") return body.String() } diff --git a/internal/core-ide/build/linux/core-ide.service b/internal/core-ide/build/linux/core-ide.service index cb5b5a30..8fe99c45 100644 --- a/internal/core-ide/build/linux/core-ide.service +++ b/internal/core-ide/build/linux/core-ide.service @@ -1,6 +1,6 @@ [Unit] Description=Core IDE Job Runner (Headless Mode) -Documentation=https://github.com/host-uk/core +Documentation=https://forge.lthn.ai/core/cli After=network-online.target Wants=network-online.target diff --git a/internal/core-ide/build/linux/core-ide.user.service b/internal/core-ide/build/linux/core-ide.user.service index 90e67880..f7d85b8e 100644 --- a/internal/core-ide/build/linux/core-ide.user.service +++ b/internal/core-ide/build/linux/core-ide.user.service @@ -1,6 +1,6 @@ [Unit] Description=Core IDE Job Runner (User Mode) -Documentation=https://github.com/host-uk/core +Documentation=https://forge.lthn.ai/core/cli After=network-online.target Wants=network-online.target diff --git a/internal/core-ide/frontend/package-lock.json b/internal/core-ide/frontend/package-lock.json index 11a549ac..ccce19ea 100644 --- a/internal/core-ide/frontend/package-lock.json +++ b/internal/core-ide/frontend/package-lock.json @@ -5495,17 +5495,6 @@ "node": ">= 0.4" } }, - "node_modules/hono": { - "version": "4.11.7", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.11.7.tgz", - "integrity": "sha512-l7qMiNee7t82bH3SeyUCt9UF15EVmaBvsppY2zQtrbIhl/yzBTny+YUxsVjSjQ6gaqaeVtZmGocom8TzBlA4Yw==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=16.9.0" - } - }, "node_modules/hosted-git-info": { "version": "9.0.2", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-9.0.2.tgz", diff --git a/internal/core-ide/go.mod b/internal/core-ide/go.mod index 221a2583..4ae71bcb 100644 --- a/internal/core-ide/go.mod +++ b/internal/core-ide/go.mod @@ -49,6 +49,8 @@ require ( github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.3 + forge.lthn.ai/core/cli v0.0.0 + forge.lthn.ai/core/cli-gui v0.0.0 github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jchv/go-winloader v0.0.0-20250406163304-c1995be93bd1 // indirect github.com/kevinburke/ssh_config v1.4.0 // indirect diff --git a/mkdocs.yml b/mkdocs.yml index acf8ed8f..f199b6fa 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -2,7 +2,7 @@ site_name: Core Framework site_url: https://core.help site_description: 'A Web3 Framework for building Go desktop applications with Wails v3' site_author: 'Snider' -repo_url: 'https://github.com/host-uk/core' +repo_url: 'https://forge.lthn.ai/core/cli' repo_name: 'host-uk/core' theme: diff --git a/pkg/devkit/devkit.go b/pkg/devkit/devkit.go new file mode 100644 index 00000000..a7dec8d2 --- /dev/null +++ b/pkg/devkit/devkit.go @@ -0,0 +1,560 @@ +// Package devkit provides a developer toolkit for common automation commands. +// Designed by Gemini 3 Pro (Hypnos) + Claude Opus (Charon), signed LEK-1 | lthn.ai | EUPL-1.2 +package devkit + +import ( + "bufio" + "bytes" + "fmt" + "os" + "os/exec" + "path/filepath" + "regexp" + "strconv" + "strings" + "time" +) + +// --- Code Quality --- + +// Finding represents a single issue found by a linting tool. +type Finding struct { + File string + Line int + Message string + Tool string +} + +// CoverageReport holds the test coverage percentage for a package. +type CoverageReport struct { + Package string + Percentage float64 +} + +// RaceCondition represents a data race detected by the Go race detector. +type RaceCondition struct { + File string + Line int + Desc string +} + +// TODO represents a tracked code comment like TODO, FIXME, or HACK. +type TODO struct { + File string + Line int + Type string + Message string +} + +// --- Security --- + +// Vulnerability represents a dependency vulnerability. +type Vulnerability struct { + ID string + Package string + Version string + Description string +} + +// SecretLeak represents a potential secret found in the codebase. +type SecretLeak struct { + File string + Line int + RuleID string + Match string +} + +// PermIssue represents a file permission issue. +type PermIssue struct { + File string + Permission string + Issue string +} + +// --- Git Operations --- + +// DiffSummary provides a summary of changes. +type DiffSummary struct { + FilesChanged int + Insertions int + Deletions int +} + +// Commit represents a single git commit. +type Commit struct { + Hash string + Author string + Date time.Time + Message string +} + +// --- Build & Dependencies --- + +// BuildResult holds the outcome of a single build target. +type BuildResult struct { + Target string + Path string + Error error +} + +// Graph represents a dependency graph. +type Graph struct { + Nodes []string + Edges map[string][]string +} + +// --- Metrics --- + +// ComplexFunc represents a function with its cyclomatic complexity score. +type ComplexFunc struct { + Package string + FuncName string + File string + Line int + Score int +} + +// Toolkit wraps common dev automation commands into structured Go APIs. +type Toolkit struct { + Dir string // Working directory for commands +} + +// New creates a Toolkit rooted at the given directory. +func New(dir string) *Toolkit { + return &Toolkit{Dir: dir} +} + +// Run executes a command and captures stdout, stderr, and exit code. +func (t *Toolkit) Run(name string, args ...string) (stdout, stderr string, exitCode int, err error) { + cmd := exec.Command(name, args...) + cmd.Dir = t.Dir + var stdoutBuf, stderrBuf bytes.Buffer + cmd.Stdout = &stdoutBuf + cmd.Stderr = &stderrBuf + + err = cmd.Run() + stdout = stdoutBuf.String() + stderr = stderrBuf.String() + + if err != nil { + if exitErr, ok := err.(*exec.ExitError); ok { + exitCode = exitErr.ExitCode() + } else { + exitCode = -1 + } + } + return +} + +// FindTODOs greps for TODO/FIXME/HACK comments within a directory. +func (t *Toolkit) FindTODOs(dir string) ([]TODO, error) { + pattern := `\b(TODO|FIXME|HACK)\b(\(.*\))?:` + stdout, stderr, exitCode, err := t.Run("git", "grep", "--line-number", "-E", pattern, "--", dir) + + if exitCode == 1 && stdout == "" { + return nil, nil + } + if err != nil && exitCode != 1 { + return nil, fmt.Errorf("git grep failed (exit %d): %s\n%s", exitCode, err, stderr) + } + + var todos []TODO + re := regexp.MustCompile(pattern) + + for _, line := range strings.Split(strings.TrimSpace(stdout), "\n") { + if line == "" { + continue + } + parts := strings.SplitN(line, ":", 3) + if len(parts) < 3 { + continue + } + lineNum, _ := strconv.Atoi(parts[1]) + match := re.FindStringSubmatch(parts[2]) + todoType := "" + if len(match) > 1 { + todoType = match[1] + } + msg := strings.TrimSpace(re.Split(parts[2], 2)[1]) + + todos = append(todos, TODO{ + File: parts[0], + Line: lineNum, + Type: todoType, + Message: msg, + }) + } + return todos, nil +} + +// AuditDeps runs govulncheck to find dependency vulnerabilities. +func (t *Toolkit) AuditDeps() ([]Vulnerability, error) { + stdout, stderr, exitCode, err := t.Run("govulncheck", "./...") + if err != nil && exitCode != 0 && !strings.Contains(stdout, "Vulnerability") { + return nil, fmt.Errorf("govulncheck failed (exit %d): %s\n%s", exitCode, err, stderr) + } + + var vulns []Vulnerability + scanner := bufio.NewScanner(strings.NewReader(stdout)) + var cur Vulnerability + inBlock := false + + for scanner.Scan() { + line := scanner.Text() + if strings.HasPrefix(line, "Vulnerability #") { + if cur.ID != "" { + vulns = append(vulns, cur) + } + fields := strings.Fields(line) + cur = Vulnerability{} + if len(fields) > 1 { + cur.ID = fields[1] + } + inBlock = true + } else if inBlock { + switch { + case strings.Contains(line, "Package:"): + cur.Package = strings.TrimSpace(strings.SplitN(line, ":", 2)[1]) + case strings.Contains(line, "Found in version:"): + cur.Version = strings.TrimSpace(strings.SplitN(line, ":", 2)[1]) + case line == "": + if cur.ID != "" { + vulns = append(vulns, cur) + cur = Vulnerability{} + } + inBlock = false + default: + if !strings.HasPrefix(line, " ") && cur.Description == "" { + cur.Description = strings.TrimSpace(line) + } + } + } + } + if cur.ID != "" { + vulns = append(vulns, cur) + } + return vulns, nil +} + +// DiffStat returns a summary of uncommitted changes. +func (t *Toolkit) DiffStat() (DiffSummary, error) { + stdout, stderr, exitCode, err := t.Run("git", "diff", "--stat") + if err != nil && exitCode != 0 { + return DiffSummary{}, fmt.Errorf("git diff failed (exit %d): %s\n%s", exitCode, err, stderr) + } + + var s DiffSummary + lines := strings.Split(strings.TrimSpace(stdout), "\n") + if len(lines) == 0 || lines[0] == "" { + return s, nil + } + + last := lines[len(lines)-1] + for _, part := range strings.Split(last, ",") { + part = strings.TrimSpace(part) + fields := strings.Fields(part) + if len(fields) < 2 { + continue + } + val, _ := strconv.Atoi(fields[0]) + switch { + case strings.Contains(part, "file"): + s.FilesChanged = val + case strings.Contains(part, "insertion"): + s.Insertions = val + case strings.Contains(part, "deletion"): + s.Deletions = val + } + } + return s, nil +} + +// UncommittedFiles returns paths of files with uncommitted changes. +func (t *Toolkit) UncommittedFiles() ([]string, error) { + stdout, stderr, exitCode, err := t.Run("git", "status", "--porcelain") + if err != nil && exitCode != 0 { + return nil, fmt.Errorf("git status failed: %s\n%s", err, stderr) + } + var files []string + for _, line := range strings.Split(strings.TrimSpace(stdout), "\n") { + if len(line) > 3 { + files = append(files, strings.TrimSpace(line[3:])) + } + } + return files, nil +} + +// Lint runs go vet on the given package pattern. +func (t *Toolkit) Lint(pkg string) ([]Finding, error) { + _, stderr, exitCode, err := t.Run("go", "vet", pkg) + if exitCode == 0 { + return nil, nil + } + if err != nil && exitCode != 2 { + return nil, fmt.Errorf("go vet failed: %w", err) + } + + var findings []Finding + for _, line := range strings.Split(strings.TrimSpace(stderr), "\n") { + if line == "" { + continue + } + parts := strings.SplitN(line, ":", 4) + if len(parts) < 4 { + continue + } + lineNum, _ := strconv.Atoi(parts[1]) + findings = append(findings, Finding{ + File: parts[0], + Line: lineNum, + Message: strings.TrimSpace(parts[3]), + Tool: "go vet", + }) + } + return findings, nil +} + +// ScanSecrets runs gitleaks to find potential secret leaks. +func (t *Toolkit) ScanSecrets(dir string) ([]SecretLeak, error) { + stdout, _, exitCode, err := t.Run("gitleaks", "detect", "--source", dir, "--report-format", "csv", "--no-git") + if exitCode == 0 { + return nil, nil + } + if err != nil && exitCode != 1 { + return nil, fmt.Errorf("gitleaks failed: %w", err) + } + + var leaks []SecretLeak + for _, line := range strings.Split(strings.TrimSpace(stdout), "\n") { + if line == "" || strings.HasPrefix(line, "RuleID") { + continue + } + parts := strings.SplitN(line, ",", 4) + if len(parts) < 4 { + continue + } + lineNum, _ := strconv.Atoi(parts[2]) + leaks = append(leaks, SecretLeak{ + RuleID: parts[0], + File: parts[1], + Line: lineNum, + Match: parts[3], + }) + } + return leaks, nil +} + +// ModTidy runs go mod tidy. +func (t *Toolkit) ModTidy() error { + _, stderr, exitCode, err := t.Run("go", "mod", "tidy") + if err != nil && exitCode != 0 { + return fmt.Errorf("go mod tidy failed: %s", stderr) + } + return nil +} + +// Build compiles the given targets. +func (t *Toolkit) Build(targets ...string) ([]BuildResult, error) { + var results []BuildResult + for _, target := range targets { + _, stderr, _, err := t.Run("go", "build", "-o", "/dev/null", target) + r := BuildResult{Target: target} + if err != nil { + r.Error = fmt.Errorf("%s", strings.TrimSpace(stderr)) + } + results = append(results, r) + } + return results, nil +} + +// TestCount returns the number of test functions in a package. +func (t *Toolkit) TestCount(pkg string) (int, error) { + stdout, stderr, exitCode, err := t.Run("go", "test", "-list", ".*", pkg) + if err != nil && exitCode != 0 { + return 0, fmt.Errorf("go test -list failed: %s\n%s", err, stderr) + } + count := 0 + for _, line := range strings.Split(strings.TrimSpace(stdout), "\n") { + if strings.HasPrefix(line, "Test") || strings.HasPrefix(line, "Benchmark") { + count++ + } + } + return count, nil +} + +// Coverage runs go test -cover and parses per-package coverage percentages. +func (t *Toolkit) Coverage(pkg string) ([]CoverageReport, error) { + if pkg == "" { + pkg = "./..." + } + stdout, stderr, exitCode, err := t.Run("go", "test", "-cover", pkg) + if err != nil && exitCode != 0 && !strings.Contains(stdout, "coverage:") { + return nil, fmt.Errorf("go test -cover failed (exit %d): %s\n%s", exitCode, err, stderr) + } + + var reports []CoverageReport + re := regexp.MustCompile(`ok\s+(\S+)\s+.*coverage:\s+([\d.]+)%`) + scanner := bufio.NewScanner(strings.NewReader(stdout)) + + for scanner.Scan() { + matches := re.FindStringSubmatch(scanner.Text()) + if len(matches) == 3 { + pct, _ := strconv.ParseFloat(matches[2], 64) + reports = append(reports, CoverageReport{ + Package: matches[1], + Percentage: pct, + }) + } + } + return reports, nil +} + +// RaceDetect runs go test -race and parses data race warnings. +func (t *Toolkit) RaceDetect(pkg string) ([]RaceCondition, error) { + if pkg == "" { + pkg = "./..." + } + _, stderr, _, err := t.Run("go", "test", "-race", pkg) + if err != nil && !strings.Contains(stderr, "WARNING: DATA RACE") { + return nil, fmt.Errorf("go test -race failed: %w", err) + } + + var races []RaceCondition + lines := strings.Split(stderr, "\n") + reFile := regexp.MustCompile(`\s+(.*\.go):(\d+)`) + + for i, line := range lines { + if strings.Contains(line, "WARNING: DATA RACE") { + rc := RaceCondition{Desc: "Data race detected"} + for j := i + 1; j < len(lines) && j < i+15; j++ { + if match := reFile.FindStringSubmatch(lines[j]); len(match) == 3 { + rc.File = strings.TrimSpace(match[1]) + rc.Line, _ = strconv.Atoi(match[2]) + break + } + } + races = append(races, rc) + } + } + return races, nil +} + +// Complexity runs gocyclo and returns functions exceeding the threshold. +func (t *Toolkit) Complexity(threshold int) ([]ComplexFunc, error) { + stdout, stderr, exitCode, err := t.Run("gocyclo", "-over", strconv.Itoa(threshold), ".") + if err != nil && exitCode == -1 { + return nil, fmt.Errorf("gocyclo not available: %s\n%s", err, stderr) + } + + var funcs []ComplexFunc + scanner := bufio.NewScanner(strings.NewReader(stdout)) + + for scanner.Scan() { + fields := strings.Fields(scanner.Text()) + if len(fields) < 4 { + continue + } + score, _ := strconv.Atoi(fields[0]) + fileParts := strings.Split(fields[3], ":") + line := 0 + if len(fileParts) > 1 { + line, _ = strconv.Atoi(fileParts[1]) + } + + funcs = append(funcs, ComplexFunc{ + Score: score, + Package: fields[1], + FuncName: fields[2], + File: fileParts[0], + Line: line, + }) + } + return funcs, nil +} + +// DepGraph runs go mod graph and builds a dependency graph. +func (t *Toolkit) DepGraph(pkg string) (*Graph, error) { + stdout, stderr, exitCode, err := t.Run("go", "mod", "graph") + if err != nil && exitCode != 0 { + return nil, fmt.Errorf("go mod graph failed (exit %d): %s\n%s", exitCode, err, stderr) + } + + graph := &Graph{Edges: make(map[string][]string)} + nodes := make(map[string]struct{}) + scanner := bufio.NewScanner(strings.NewReader(stdout)) + + for scanner.Scan() { + parts := strings.Fields(scanner.Text()) + if len(parts) >= 2 { + src, dst := parts[0], parts[1] + graph.Edges[src] = append(graph.Edges[src], dst) + nodes[src] = struct{}{} + nodes[dst] = struct{}{} + } + } + + for node := range nodes { + graph.Nodes = append(graph.Nodes, node) + } + return graph, nil +} + +// GitLog returns the last n commits from git history. +func (t *Toolkit) GitLog(n int) ([]Commit, error) { + stdout, stderr, exitCode, err := t.Run("git", "log", fmt.Sprintf("-n%d", n), "--format=%H|%an|%aI|%s") + if err != nil && exitCode != 0 { + return nil, fmt.Errorf("git log failed (exit %d): %s\n%s", exitCode, err, stderr) + } + + var commits []Commit + scanner := bufio.NewScanner(strings.NewReader(stdout)) + + for scanner.Scan() { + parts := strings.SplitN(scanner.Text(), "|", 4) + if len(parts) < 4 { + continue + } + date, _ := time.Parse(time.RFC3339, parts[2]) + commits = append(commits, Commit{ + Hash: parts[0], + Author: parts[1], + Date: date, + Message: parts[3], + }) + } + return commits, nil +} + +// CheckPerms walks a directory and flags files with overly permissive modes. +func (t *Toolkit) CheckPerms(dir string) ([]PermIssue, error) { + var issues []PermIssue + err := filepath.Walk(filepath.Join(t.Dir, dir), func(path string, info os.FileInfo, err error) error { + if err != nil { + return nil + } + if info.IsDir() { + return nil + } + mode := info.Mode().Perm() + if mode&0o002 != 0 { + issues = append(issues, PermIssue{ + File: path, + Permission: fmt.Sprintf("%04o", mode), + Issue: "World-writable", + }) + } else if mode&0o020 != 0 && mode&0o002 != 0 { + issues = append(issues, PermIssue{ + File: path, + Permission: fmt.Sprintf("%04o", mode), + Issue: "Group and world-writable", + }) + } + return nil + }) + if err != nil { + return nil, fmt.Errorf("walk failed: %w", err) + } + return issues, nil +} + +// LEK-1 | lthn.ai | EUPL-1.2 diff --git a/pkg/devkit/devkit_test.go b/pkg/devkit/devkit_test.go new file mode 100644 index 00000000..ffcdecdb --- /dev/null +++ b/pkg/devkit/devkit_test.go @@ -0,0 +1,270 @@ +// Designed by Gemini 3 Pro (Hypnos) + Claude Opus (Charon), signed LEK-1 | lthn.ai | EUPL-1.2 +package devkit + +import ( + "fmt" + "os" + "path/filepath" + "testing" + "time" +) + +// setupMockCmd creates a shell script in a temp dir that echoes predetermined +// content, and prepends that dir to PATH so Run() picks it up. +func setupMockCmd(t *testing.T, name, content string) { + t.Helper() + tmpDir := t.TempDir() + scriptPath := filepath.Join(tmpDir, name) + + script := fmt.Sprintf("#!/bin/sh\ncat <<'MOCK_EOF'\n%s\nMOCK_EOF\n", content) + if err := os.WriteFile(scriptPath, []byte(script), 0755); err != nil { + t.Fatalf("failed to write mock command %s: %v", name, err) + } + + oldPath := os.Getenv("PATH") + t.Setenv("PATH", tmpDir+string(os.PathListSeparator)+oldPath) +} + +// setupMockCmdExit creates a mock that echoes to stdout/stderr and exits with a code. +func setupMockCmdExit(t *testing.T, name, stdout, stderr string, exitCode int) { + t.Helper() + tmpDir := t.TempDir() + scriptPath := filepath.Join(tmpDir, name) + + script := fmt.Sprintf("#!/bin/sh\ncat <<'MOCK_EOF'\n%s\nMOCK_EOF\ncat <<'MOCK_ERR' >&2\n%s\nMOCK_ERR\nexit %d\n", stdout, stderr, exitCode) + if err := os.WriteFile(scriptPath, []byte(script), 0755); err != nil { + t.Fatalf("failed to write mock command %s: %v", name, err) + } + + oldPath := os.Getenv("PATH") + t.Setenv("PATH", tmpDir+string(os.PathListSeparator)+oldPath) +} + +func TestCoverage_Good(t *testing.T) { + output := `? example.com/skipped [no test files] +ok example.com/pkg1 0.5s coverage: 85.0% of statements +ok example.com/pkg2 0.2s coverage: 100.0% of statements` + + setupMockCmd(t, "go", output) + + tk := New(t.TempDir()) + reports, err := tk.Coverage("./...") + if err != nil { + t.Fatalf("Coverage failed: %v", err) + } + if len(reports) != 2 { + t.Fatalf("expected 2 reports, got %d", len(reports)) + } + if reports[0].Package != "example.com/pkg1" || reports[0].Percentage != 85.0 { + t.Errorf("report 0: want pkg1@85%%, got %s@%.1f%%", reports[0].Package, reports[0].Percentage) + } + if reports[1].Package != "example.com/pkg2" || reports[1].Percentage != 100.0 { + t.Errorf("report 1: want pkg2@100%%, got %s@%.1f%%", reports[1].Package, reports[1].Percentage) + } +} + +func TestCoverage_Bad(t *testing.T) { + // No coverage lines in output + setupMockCmd(t, "go", "FAIL\texample.com/broken [build failed]") + + tk := New(t.TempDir()) + reports, err := tk.Coverage("./...") + if err != nil { + t.Fatalf("Coverage should not error on partial output: %v", err) + } + if len(reports) != 0 { + t.Errorf("expected 0 reports from failed build, got %d", len(reports)) + } +} + +func TestGitLog_Good(t *testing.T) { + now := time.Now().Truncate(time.Second) + nowStr := now.Format(time.RFC3339) + + output := fmt.Sprintf("abc123|Alice|%s|Fix the bug\ndef456|Bob|%s|Add feature", nowStr, nowStr) + setupMockCmd(t, "git", output) + + tk := New(t.TempDir()) + commits, err := tk.GitLog(2) + if err != nil { + t.Fatalf("GitLog failed: %v", err) + } + if len(commits) != 2 { + t.Fatalf("expected 2 commits, got %d", len(commits)) + } + if commits[0].Hash != "abc123" { + t.Errorf("hash: want abc123, got %s", commits[0].Hash) + } + if commits[0].Author != "Alice" { + t.Errorf("author: want Alice, got %s", commits[0].Author) + } + if commits[0].Message != "Fix the bug" { + t.Errorf("message: want 'Fix the bug', got %q", commits[0].Message) + } + if !commits[0].Date.Equal(now) { + t.Errorf("date: want %v, got %v", now, commits[0].Date) + } +} + +func TestGitLog_Bad(t *testing.T) { + // Malformed lines should be skipped + setupMockCmd(t, "git", "incomplete|line\nabc|Bob|2025-01-01T00:00:00Z|Good commit") + + tk := New(t.TempDir()) + commits, err := tk.GitLog(5) + if err != nil { + t.Fatalf("GitLog failed: %v", err) + } + if len(commits) != 1 { + t.Errorf("expected 1 valid commit (skip malformed), got %d", len(commits)) + } +} + +func TestComplexity_Good(t *testing.T) { + output := "15 main ComplexFunc file.go:10:1\n20 pkg VeryComplex other.go:50:1" + setupMockCmd(t, "gocyclo", output) + + tk := New(t.TempDir()) + funcs, err := tk.Complexity(10) + if err != nil { + t.Fatalf("Complexity failed: %v", err) + } + if len(funcs) != 2 { + t.Fatalf("expected 2 funcs, got %d", len(funcs)) + } + if funcs[0].Score != 15 || funcs[0].FuncName != "ComplexFunc" || funcs[0].File != "file.go" || funcs[0].Line != 10 { + t.Errorf("func 0: unexpected %+v", funcs[0]) + } + if funcs[1].Score != 20 || funcs[1].Package != "pkg" { + t.Errorf("func 1: unexpected %+v", funcs[1]) + } +} + +func TestComplexity_Bad(t *testing.T) { + // No functions above threshold = empty output + setupMockCmd(t, "gocyclo", "") + + tk := New(t.TempDir()) + funcs, err := tk.Complexity(50) + if err != nil { + t.Fatalf("Complexity should not error on empty output: %v", err) + } + if len(funcs) != 0 { + t.Errorf("expected 0 funcs, got %d", len(funcs)) + } +} + +func TestDepGraph_Good(t *testing.T) { + output := "modA@v1 modB@v2\nmodA@v1 modC@v3\nmodB@v2 modD@v1" + setupMockCmd(t, "go", output) + + tk := New(t.TempDir()) + graph, err := tk.DepGraph("./...") + if err != nil { + t.Fatalf("DepGraph failed: %v", err) + } + if len(graph.Nodes) != 4 { + t.Errorf("expected 4 nodes, got %d: %v", len(graph.Nodes), graph.Nodes) + } + edgesA := graph.Edges["modA@v1"] + if len(edgesA) != 2 { + t.Errorf("expected 2 edges from modA@v1, got %d", len(edgesA)) + } +} + +func TestRaceDetect_Good(t *testing.T) { + // No races = clean run + setupMockCmd(t, "go", "ok\texample.com/safe\t0.1s") + + tk := New(t.TempDir()) + races, err := tk.RaceDetect("./...") + if err != nil { + t.Fatalf("RaceDetect failed on clean run: %v", err) + } + if len(races) != 0 { + t.Errorf("expected 0 races, got %d", len(races)) + } +} + +func TestRaceDetect_Bad(t *testing.T) { + stderrOut := `WARNING: DATA RACE +Read at 0x00c000123456 by goroutine 7: + /home/user/project/main.go:42 +Previous write at 0x00c000123456 by goroutine 6: + /home/user/project/main.go:38` + + setupMockCmdExit(t, "go", "", stderrOut, 1) + + tk := New(t.TempDir()) + races, err := tk.RaceDetect("./...") + if err != nil { + t.Fatalf("RaceDetect should parse races, not error: %v", err) + } + if len(races) != 1 { + t.Fatalf("expected 1 race, got %d", len(races)) + } + if races[0].File != "/home/user/project/main.go" || races[0].Line != 42 { + t.Errorf("race: unexpected %+v", races[0]) + } +} + +func TestDiffStat_Good(t *testing.T) { + output := ` file1.go | 10 +++++++--- + file2.go | 5 +++++ + 2 files changed, 12 insertions(+), 3 deletions(-)` + setupMockCmd(t, "git", output) + + tk := New(t.TempDir()) + s, err := tk.DiffStat() + if err != nil { + t.Fatalf("DiffStat failed: %v", err) + } + if s.FilesChanged != 2 { + t.Errorf("files: want 2, got %d", s.FilesChanged) + } + if s.Insertions != 12 { + t.Errorf("insertions: want 12, got %d", s.Insertions) + } + if s.Deletions != 3 { + t.Errorf("deletions: want 3, got %d", s.Deletions) + } +} + +func TestCheckPerms_Good(t *testing.T) { + dir := t.TempDir() + + // Create a world-writable file + badFile := filepath.Join(dir, "bad.txt") + if err := os.WriteFile(badFile, []byte("test"), 0644); err != nil { + t.Fatal(err) + } + if err := os.Chmod(badFile, 0666); err != nil { + t.Fatal(err) + } + // Create a safe file + goodFile := filepath.Join(dir, "good.txt") + if err := os.WriteFile(goodFile, []byte("test"), 0644); err != nil { + t.Fatal(err) + } + + tk := New("/") + issues, err := tk.CheckPerms(dir) + if err != nil { + t.Fatalf("CheckPerms failed: %v", err) + } + if len(issues) != 1 { + t.Fatalf("expected 1 issue (world-writable), got %d", len(issues)) + } + if issues[0].Issue != "World-writable" { + t.Errorf("issue: want 'World-writable', got %q", issues[0].Issue) + } +} + +func TestNew(t *testing.T) { + tk := New("/tmp") + if tk.Dir != "/tmp" { + t.Errorf("Dir: want /tmp, got %s", tk.Dir) + } +} + +// LEK-1 | lthn.ai | EUPL-1.2 diff --git a/pkg/i18n/locales/en_GB.json b/pkg/i18n/locales/en_GB.json index 64c579dc..6da52083 100644 --- a/pkg/i18n/locales/en_GB.json +++ b/pkg/i18n/locales/en_GB.json @@ -1146,277 +1146,129 @@ "error.gh_not_found": "'gh' CLI not found. Install from https://cli.github.com/", "error.registry_not_found": "No repos.yaml found", "error.repo_not_found": "Repository '{{.Name}}' not found", - "gram.article.definite": "the", - "gram.article.definite.feminine": "", - "gram.article.definite.masculine": "", - "gram.article.definite.neuter": "", - "gram.article.indefinite.default": "a", - "gram.article.indefinite.feminine": "", - "gram.article.indefinite.masculine": "", - "gram.article.indefinite.neuter": "", - "gram.article.indefinite.vowel": "an", - "gram.noun.artifact.one": "artifact", - "gram.noun.artifact.other": "artifacts", - "gram.noun.branch.gender": "", - "gram.noun.branch.one": "branch", - "gram.noun.branch.other": "branches", - "gram.noun.category.one": "category", - "gram.noun.category.other": "categories", - "gram.noun.change.gender": "", - "gram.noun.change.one": "change", - "gram.noun.change.other": "changes", - "gram.noun.check.one": "check", - "gram.noun.check.other": "checks", - "gram.noun.child.one": "child", - "gram.noun.child.other": "children", - "gram.noun.commit.gender": "", - "gram.noun.commit.one": "commit", - "gram.noun.commit.other": "commits", - "gram.noun.dependency.one": "dependency", - "gram.noun.dependency.other": "dependencies", - "gram.noun.directory.one": "directory", - "gram.noun.directory.other": "directories", - "gram.noun.failed.one": "failed", - "gram.noun.failed.other": "failed", - "gram.noun.file.gender": "", - "gram.noun.file.one": "file", - "gram.noun.file.other": "files", - "gram.noun.issue.one": "issue", - "gram.noun.issue.other": "issues", - "gram.noun.item.gender": "", - "gram.noun.item.one": "item", - "gram.noun.item.other": "items", - "gram.noun.package.one": "package", - "gram.noun.package.other": "packages", - "gram.noun.passed.one": "passed", - "gram.noun.passed.other": "passed", - "gram.noun.person.one": "person", - "gram.noun.person.other": "people", - "gram.noun.query.one": "query", - "gram.noun.query.other": "queries", - "gram.noun.repo.gender": "", - "gram.noun.repo.one": "repo", - "gram.noun.repo.other": "repos", - "gram.noun.repository.one": "repository", - "gram.noun.repository.other": "repositories", - "gram.noun.skipped.one": "skipped", - "gram.noun.skipped.other": "skipped", - "gram.noun.task.one": "task", - "gram.noun.task.other": "tasks", - "gram.noun.test.one": "test", - "gram.noun.test.other": "tests", - "gram.noun.vulnerability.one": "vulnerability", - "gram.noun.vulnerability.other": "vulnerabilities", - "gram.number.decimal": ".", - "gram.number.percent": "%s%%", - "gram.number.thousands": ",", - "gram.punct.label": ":", - "gram.punct.progress": "...", - "gram.verb.analyse.base": "", - "gram.verb.analyse.gerund": "", - "gram.verb.analyse.past": "", - "gram.verb.be.base": "be", - "gram.verb.be.gerund": "being", - "gram.verb.be.past": "was", - "gram.verb.begin.base": "begin", - "gram.verb.begin.gerund": "beginning", - "gram.verb.begin.past": "began", - "gram.verb.bring.base": "bring", - "gram.verb.bring.gerund": "bringing", - "gram.verb.bring.past": "brought", - "gram.verb.build.base": "build", - "gram.verb.build.gerund": "building", - "gram.verb.build.past": "built", - "gram.verb.buy.base": "buy", - "gram.verb.buy.gerund": "buying", - "gram.verb.buy.past": "bought", - "gram.verb.catch.base": "catch", - "gram.verb.catch.gerund": "catching", - "gram.verb.catch.past": "caught", - "gram.verb.check.base": "", - "gram.verb.check.gerund": "", - "gram.verb.check.past": "", - "gram.verb.choose.base": "choose", - "gram.verb.choose.gerund": "choosing", - "gram.verb.choose.past": "chose", - "gram.verb.commit.base": "commit", - "gram.verb.commit.gerund": "committing", - "gram.verb.commit.past": "committed", - "gram.verb.create.base": "", - "gram.verb.create.gerund": "", - "gram.verb.create.past": "", - "gram.verb.cut.base": "cut", - "gram.verb.cut.gerund": "cutting", - "gram.verb.cut.past": "cut", - "gram.verb.delete.base": "", - "gram.verb.delete.gerund": "", - "gram.verb.delete.past": "", - "gram.verb.do.base": "do", - "gram.verb.do.gerund": "doing", - "gram.verb.do.past": "did", - "gram.verb.find.base": "find", - "gram.verb.find.gerund": "finding", - "gram.verb.find.past": "found", - "gram.verb.format.base": "format", - "gram.verb.format.gerund": "formatting", - "gram.verb.format.past": "formatted", - "gram.verb.get.base": "get", - "gram.verb.get.gerund": "getting", - "gram.verb.get.past": "got", - "gram.verb.go.base": "go", - "gram.verb.go.gerund": "going", - "gram.verb.go.past": "went", - "gram.verb.have.base": "have", - "gram.verb.have.gerund": "having", - "gram.verb.have.past": "had", - "gram.verb.hit.base": "hit", - "gram.verb.hit.gerund": "hitting", - "gram.verb.hit.past": "hit", - "gram.verb.hold.base": "hold", - "gram.verb.hold.gerund": "holding", - "gram.verb.hold.past": "held", - "gram.verb.install.base": "", - "gram.verb.install.gerund": "", - "gram.verb.install.past": "", - "gram.verb.keep.base": "keep", - "gram.verb.keep.gerund": "keeping", - "gram.verb.keep.past": "kept", - "gram.verb.lead.base": "lead", - "gram.verb.lead.gerund": "leading", - "gram.verb.lead.past": "led", - "gram.verb.leave.base": "leave", - "gram.verb.leave.gerund": "leaving", - "gram.verb.leave.past": "left", - "gram.verb.lose.base": "lose", - "gram.verb.lose.gerund": "losing", - "gram.verb.lose.past": "lost", - "gram.verb.make.base": "make", - "gram.verb.make.gerund": "making", - "gram.verb.make.past": "made", - "gram.verb.meet.base": "meet", - "gram.verb.meet.gerund": "meeting", - "gram.verb.meet.past": "met", - "gram.verb.organise.base": "", - "gram.verb.organise.gerund": "", - "gram.verb.organise.past": "", - "gram.verb.pay.base": "pay", - "gram.verb.pay.gerund": "paying", - "gram.verb.pay.past": "paid", - "gram.verb.pull.base": "", - "gram.verb.pull.gerund": "", - "gram.verb.pull.past": "", - "gram.verb.push.base": "", - "gram.verb.push.gerund": "", - "gram.verb.push.past": "", - "gram.verb.put.base": "put", - "gram.verb.put.gerund": "putting", - "gram.verb.put.past": "put", - "gram.verb.realise.base": "", - "gram.verb.realise.gerund": "", - "gram.verb.realise.past": "", - "gram.verb.recognise.base": "", - "gram.verb.recognise.gerund": "", - "gram.verb.recognise.past": "", - "gram.verb.run.base": "run", - "gram.verb.run.gerund": "running", - "gram.verb.run.past": "ran", - "gram.verb.save.base": "", - "gram.verb.save.gerund": "", - "gram.verb.save.past": "", - "gram.verb.scan.base": "scan", - "gram.verb.scan.gerund": "scanning", - "gram.verb.scan.past": "scanned", - "gram.verb.sell.base": "sell", - "gram.verb.sell.gerund": "selling", - "gram.verb.sell.past": "sold", - "gram.verb.send.base": "send", - "gram.verb.send.gerund": "sending", - "gram.verb.send.past": "sent", - "gram.verb.set.base": "set", - "gram.verb.set.gerund": "setting", - "gram.verb.set.past": "set", - "gram.verb.shut.base": "shut", - "gram.verb.shut.gerund": "shutting", - "gram.verb.shut.past": "shut", - "gram.verb.sit.base": "sit", - "gram.verb.sit.gerund": "sitting", - "gram.verb.sit.past": "sat", - "gram.verb.spend.base": "spend", - "gram.verb.spend.gerund": "spending", - "gram.verb.spend.past": "spent", - "gram.verb.split.base": "split", - "gram.verb.split.gerund": "splitting", - "gram.verb.split.past": "split", - "gram.verb.stop.base": "stop", - "gram.verb.stop.gerund": "stopping", - "gram.verb.stop.past": "stopped", - "gram.verb.take.base": "take", - "gram.verb.take.gerund": "taking", - "gram.verb.take.past": "took", - "gram.verb.think.base": "think", - "gram.verb.think.gerund": "thinking", - "gram.verb.think.past": "thought", - "gram.verb.update.base": "", - "gram.verb.update.gerund": "", - "gram.verb.update.past": "", - "gram.verb.win.base": "win", - "gram.verb.win.gerund": "winning", - "gram.verb.win.past": "won", - "gram.verb.write.base": "write", - "gram.verb.write.gerund": "writing", - "gram.verb.write.past": "wrote", - "gram.word.api": "API", - "gram.word.app_url": "app URL", - "gram.word.blocked_by": "blocked by", - "gram.word.cgo": "CGO", - "gram.word.ci": "CI", - "gram.word.claimed_by": "claimed by", - "gram.word.coverage": "coverage", - "gram.word.cpus": "CPUs", - "gram.word.dry_run": "dry run", - "gram.word.failed": "failed", - "gram.word.filter": "filter", - "gram.word.go_mod": "go.mod", - "gram.word.html": "HTML", - "gram.word.id": "ID", - "gram.word.ok": "OK", - "gram.word.package": "package", - "gram.word.passed": "passed", - "gram.word.php": "PHP", - "gram.word.pid": "PID", - "gram.word.pnpm": "pnpm", - "gram.word.pr": "PR", - "gram.word.qa": "QA", - "gram.word.related_files": "related files", - "gram.word.sdk": "SDK", - "gram.word.skipped": "skipped", - "gram.word.ssh": "SSH", - "gram.word.ssl": "SSL", - "gram.word.test": "test", - "gram.word.up_to_date": "up to date", - "gram.word.url": "URL", - "gram.word.vite": "Vite", - "lang.de": "German", - "lang.en": "English", - "lang.es": "Spanish", - "lang.fr": "French", - "lang.zh": "Chinese", - "prompt.confirm": "Are you sure?", - "prompt.continue": "Continue?", - "prompt.discard": "Discard changes?", - "prompt.no": "n", - "prompt.overwrite": "Overwrite?", - "prompt.proceed": "Proceed?", - "prompt.yes": "y", - "time.ago.day.one": "{{.Count}} day ago", - "time.ago.day.other": "{{.Count}} days ago", - "time.ago.hour.one": "{{.Count}} hour ago", - "time.ago.hour.other": "{{.Count}} hours ago", - "time.ago.minute.one": "{{.Count}} minute ago", - "time.ago.minute.other": "{{.Count}} minutes ago", - "time.ago.second.one": "{{.Count}} second ago", - "time.ago.second.other": "{{.Count}} seconds ago", - "time.ago.week.one": "{{.Count}} week ago", - "time.ago.week.other": "{{.Count}} weeks ago", - "time.just_now": "just now" + + "gram": { + "verb": { + "be": { "base": "be", "past": "was", "gerund": "being" }, + "go": { "base": "go", "past": "went", "gerund": "going" }, + "do": { "base": "do", "past": "did", "gerund": "doing" }, + "have": { "base": "have", "past": "had", "gerund": "having" }, + "make": { "base": "make", "past": "made", "gerund": "making" }, + "get": { "base": "get", "past": "got", "gerund": "getting" }, + "run": { "base": "run", "past": "ran", "gerund": "running" }, + "write": { "base": "write", "past": "wrote", "gerund": "writing" }, + "build": { "base": "build", "past": "built", "gerund": "building" }, + "send": { "base": "send", "past": "sent", "gerund": "sending" }, + "find": { "base": "find", "past": "found", "gerund": "finding" }, + "take": { "base": "take", "past": "took", "gerund": "taking" }, + "begin": { "base": "begin", "past": "began", "gerund": "beginning" }, + "keep": { "base": "keep", "past": "kept", "gerund": "keeping" }, + "hold": { "base": "hold", "past": "held", "gerund": "holding" }, + "bring": { "base": "bring", "past": "brought", "gerund": "bringing" }, + "think": { "base": "think", "past": "thought", "gerund": "thinking" }, + "buy": { "base": "buy", "past": "bought", "gerund": "buying" }, + "catch": { "base": "catch", "past": "caught", "gerund": "catching" }, + "choose": { "base": "choose", "past": "chose", "gerund": "choosing" }, + "lose": { "base": "lose", "past": "lost", "gerund": "losing" }, + "win": { "base": "win", "past": "won", "gerund": "winning" }, + "meet": { "base": "meet", "past": "met", "gerund": "meeting" }, + "lead": { "base": "lead", "past": "led", "gerund": "leading" }, + "leave": { "base": "leave", "past": "left", "gerund": "leaving" }, + "spend": { "base": "spend", "past": "spent", "gerund": "spending" }, + "pay": { "base": "pay", "past": "paid", "gerund": "paying" }, + "sell": { "base": "sell", "past": "sold", "gerund": "selling" }, + "commit": { "base": "commit", "past": "committed", "gerund": "committing" }, + "stop": { "base": "stop", "past": "stopped", "gerund": "stopping" }, + "scan": { "base": "scan", "past": "scanned", "gerund": "scanning" }, + "format": { "base": "format", "past": "formatted", "gerund": "formatting" }, + "set": { "base": "set", "past": "set", "gerund": "setting" }, + "put": { "base": "put", "past": "put", "gerund": "putting" }, + "cut": { "base": "cut", "past": "cut", "gerund": "cutting" }, + "hit": { "base": "hit", "past": "hit", "gerund": "hitting" }, + "sit": { "base": "sit", "past": "sat", "gerund": "sitting" }, + "split": { "base": "split", "past": "split", "gerund": "splitting" }, + "shut": { "base": "shut", "past": "shut", "gerund": "shutting" }, + "check": { "base": "check", "past": "checked", "gerund": "checking" }, + "create": { "base": "create", "past": "created", "gerund": "creating" }, + "delete": { "base": "delete", "past": "deleted", "gerund": "deleting" }, + "install": { "base": "install", "past": "installed", "gerund": "installing" }, + "update": { "base": "update", "past": "updated", "gerund": "updating" }, + "pull": { "base": "pull", "past": "pulled", "gerund": "pulling" }, + "push": { "base": "push", "past": "pushed", "gerund": "pushing" }, + "save": { "base": "save", "past": "saved", "gerund": "saving" }, + "analyse": { "base": "analyse", "past": "analysed", "gerund": "analysing" }, + "organise": { "base": "organise", "past": "organised", "gerund": "organising" }, + "realise": { "base": "realise", "past": "realised", "gerund": "realising" }, + "recognise": { "base": "recognise", "past": "recognised", "gerund": "recognising" } + }, + "noun": { + "file": { "one": "file", "other": "files" }, + "repo": { "one": "repo", "other": "repos" }, + "repository": { "one": "repository", "other": "repositories" }, + "commit": { "one": "commit", "other": "commits" }, + "branch": { "one": "branch", "other": "branches" }, + "change": { "one": "change", "other": "changes" }, + "item": { "one": "item", "other": "items" }, + "issue": { "one": "issue", "other": "issues" }, + "task": { "one": "task", "other": "tasks" }, + "person": { "one": "person", "other": "people" }, + "child": { "one": "child", "other": "children" }, + "package": { "one": "package", "other": "packages" }, + "artifact": { "one": "artifact", "other": "artifacts" }, + "vulnerability": { "one": "vulnerability", "other": "vulnerabilities" }, + "dependency": { "one": "dependency", "other": "dependencies" }, + "directory": { "one": "directory", "other": "directories" }, + "category": { "one": "category", "other": "categories" }, + "query": { "one": "query", "other": "queries" }, + "check": { "one": "check", "other": "checks" }, + "test": { "one": "test", "other": "tests" } + }, + "article": { + "indefinite": { "default": "a", "vowel": "an" }, + "definite": "the" + }, + "word": { + "url": "URL", "id": "ID", "ok": "OK", "ci": "CI", "qa": "QA", + "php": "PHP", "sdk": "SDK", "html": "HTML", "cgo": "CGO", "pid": "PID", + "cpus": "CPUs", "ssh": "SSH", "ssl": "SSL", "api": "API", "pr": "PR", + "vite": "Vite", "pnpm": "pnpm", + "app_url": "app URL", "blocked_by": "blocked by", "claimed_by": "claimed by", + "related_files": "related files", "up_to_date": "up to date", + "dry_run": "dry run", "go_mod": "go.mod", + "coverage": "coverage", "failed": "failed", "filter": "filter", + "package": "package", "passed": "passed", "skipped": "skipped", "test": "test" + }, + "punct": { + "label": ":", + "progress": "..." + }, + "number": { + "thousands": ",", + "decimal": ".", + "percent": "%s%%" + } + }, + + "lang": { + "de": "German", "en": "English", "es": "Spanish", + "fr": "French", "ru": "Russian", "zh": "Chinese" + }, + + "prompt": { + "yes": "y", "no": "n", + "continue": "Continue?", "proceed": "Proceed?", + "confirm": "Are you sure?", "overwrite": "Overwrite?", + "discard": "Discard changes?" + }, + + "time": { + "just_now": "just now", + "ago": { + "second": { "one": "{{.Count}} second ago", "other": "{{.Count}} seconds ago" }, + "minute": { "one": "{{.Count}} minute ago", "other": "{{.Count}} minutes ago" }, + "hour": { "one": "{{.Count}} hour ago", "other": "{{.Count}} hours ago" }, + "day": { "one": "{{.Count}} day ago", "other": "{{.Count}} days ago" }, + "week": { "one": "{{.Count}} week ago", "other": "{{.Count}} weeks ago" } + } + } } diff --git a/pkg/i18n/locales/ru.json b/pkg/i18n/locales/ru.json index edb0385d..d01c67f0 100644 --- a/pkg/i18n/locales/ru.json +++ b/pkg/i18n/locales/ru.json @@ -1,1422 +1,150 @@ { - "cli.aborted": "", - "cli.fail": "", - "cli.pass": "", - "cmd.ai.claude.config.short": "", - "cmd.ai.claude.long": "", - "cmd.ai.claude.run.short": "", - "cmd.ai.claude.short": "", - "cmd.ai.label.blocked_by": "", - "cmd.ai.label.claimed_by": "", - "cmd.ai.label.created": "", - "cmd.ai.label.description": "", - "cmd.ai.label.id": "", - "cmd.ai.label.labels": "", - "cmd.ai.label.priority": "", - "cmd.ai.label.related_files": "", - "cmd.ai.label.title": "", - "cmd.ai.long": "", - "cmd.ai.metrics.flag.since": "", - "cmd.ai.metrics.long": "", - "cmd.ai.metrics.none_found": "", - "cmd.ai.metrics.short": "", - "cmd.ai.priority.critical": "", - "cmd.ai.priority.high": "", - "cmd.ai.priority.low": "", - "cmd.ai.priority.medium": "", - "cmd.ai.short": "", - "cmd.ai.status.blocked": "", - "cmd.ai.status.completed": "", - "cmd.ai.status.in_progress": "", - "cmd.ai.status.pending": "", - "cmd.ai.task.claiming": "", - "cmd.ai.task.flag.auto": "", - "cmd.ai.task.flag.claim": "", - "cmd.ai.task.flag.context": "", - "cmd.ai.task.id_required": "", - "cmd.ai.task.long": "", - "cmd.ai.task.no_pending": "", - "cmd.ai.task.short": "", - "cmd.ai.task_commit.flag.message": "", - "cmd.ai.task_commit.flag.push": "", - "cmd.ai.task_commit.flag.scope": "", - "cmd.ai.task_commit.long": "", - "cmd.ai.task_commit.no_changes": "", - "cmd.ai.task_commit.short": "", - "cmd.ai.task_complete.failed": "", - "cmd.ai.task_complete.flag.error": "", - "cmd.ai.task_complete.flag.failed": "", - "cmd.ai.task_complete.flag.output": "", - "cmd.ai.task_complete.long": "", - "cmd.ai.task_complete.short": "", - "cmd.ai.task_pr.branch_error": "", - "cmd.ai.task_pr.flag.base": "", - "cmd.ai.task_pr.flag.draft": "", - "cmd.ai.task_pr.flag.labels": "", - "cmd.ai.task_pr.flag.title": "", - "cmd.ai.task_pr.long": "", - "cmd.ai.task_pr.short": "", - "cmd.ai.task_update.flag.notes": "", - "cmd.ai.task_update.flag.progress": "", - "cmd.ai.task_update.flag.status": "", - "cmd.ai.task_update.flag_required": "", - "cmd.ai.task_update.long": "", - "cmd.ai.task_update.short": "", - "cmd.ai.tasks.flag.labels": "", - "cmd.ai.tasks.flag.limit": "", - "cmd.ai.tasks.flag.priority": "", - "cmd.ai.tasks.flag.project": "", - "cmd.ai.tasks.flag.status": "", - "cmd.ai.tasks.found": "", - "cmd.ai.tasks.hint": "", - "cmd.ai.tasks.long": "", - "cmd.ai.tasks.none_found": "", - "cmd.ai.tasks.short": "", - "cmd.build.building_project": "", - "cmd.build.built_artifacts": "", - "cmd.build.computing_checksums": "", - "cmd.build.creating_archives": "", - "cmd.build.error.archive_failed": "", - "cmd.build.error.checksum_failed": "", - "cmd.build.error.gpg_signing_failed": "", - "cmd.build.error.invalid_target": "", - "cmd.build.error.no_project_type": "", - "cmd.build.error.no_targets": "", - "cmd.build.error.node_not_implemented": "", - "cmd.build.error.notarization_failed": "", - "cmd.build.error.php_not_implemented": "", - "cmd.build.error.signing_failed": "", - "cmd.build.error.unsupported_type": "", - "cmd.build.flag.archive": "", - "cmd.build.flag.checksum": "", - "cmd.build.flag.ci": "", - "cmd.build.flag.config": "", - "cmd.build.flag.format": "", - "cmd.build.flag.image": "", - "cmd.build.flag.no_sign": "", - "cmd.build.flag.notarize": "", - "cmd.build.flag.output": "", - "cmd.build.flag.push": "", - "cmd.build.flag.targets": "", - "cmd.build.flag.type": "", - "cmd.build.from_path.compiling": "", - "cmd.build.from_path.copying_files": "", - "cmd.build.from_path.error.go_build": "", - "cmd.build.from_path.error.go_mod_tidy": "", - "cmd.build.from_path.error.invalid_path": "", - "cmd.build.from_path.error.must_be_directory": "", - "cmd.build.from_path.flag.path": "", - "cmd.build.from_path.generating_template": "", - "cmd.build.from_path.short": "", - "cmd.build.from_path.starting": "", - "cmd.build.from_path.success": "", - "cmd.build.label.archive": "", - "cmd.build.label.binary": "", - "cmd.build.label.build": "", - "cmd.build.label.checksum": "", - "cmd.build.label.ok": "", - "cmd.build.label.output": "", - "cmd.build.label.sign": "", - "cmd.build.label.targets": "", - "cmd.build.label.type": "", - "cmd.build.long": "", - "cmd.build.pwa.download_complete": "", - "cmd.build.pwa.downloading_to": "", - "cmd.build.pwa.error.no_manifest_tag": "", - "cmd.build.pwa.flag.url": "", - "cmd.build.pwa.found_manifest": "", - "cmd.build.pwa.no_manifest": "", - "cmd.build.pwa.short": "", - "cmd.build.pwa.starting": "", - "cmd.build.release.building_and_publishing": "", - "cmd.build.release.completed": "", - "cmd.build.release.dry_run_hint": "", - "cmd.build.release.error.no_config": "", - "cmd.build.release.flag.draft": "", - "cmd.build.release.flag.go_for_launch": "", - "cmd.build.release.flag.prerelease": "", - "cmd.build.release.flag.version": "", - "cmd.build.release.hint.create_config": "", - "cmd.build.release.label.artifacts": "", - "cmd.build.release.label.published": "", - "cmd.build.release.label.release": "", - "cmd.build.release.long": "", - "cmd.build.release.short": "", - "cmd.build.sdk.complete": "", - "cmd.build.sdk.dry_run_mode": "", - "cmd.build.sdk.flag.dry_run": "", - "cmd.build.sdk.flag.lang": "", - "cmd.build.sdk.flag.version": "", - "cmd.build.sdk.generated_label": "", - "cmd.build.sdk.generating": "", - "cmd.build.sdk.label": "", - "cmd.build.sdk.language_label": "", - "cmd.build.sdk.languages_label": "", - "cmd.build.sdk.long": "", - "cmd.build.sdk.short": "", - "cmd.build.sdk.would_generate": "", - "cmd.build.short": "", - "cmd.build.signing_binaries": "", - "cmd.ci.changelog.flag.from": "", - "cmd.ci.changelog.flag.to": "", - "cmd.ci.changelog.generating": "", - "cmd.ci.changelog.long": "", - "cmd.ci.changelog.no_tags": "", - "cmd.ci.changelog.short": "", - "cmd.ci.dry_run_hint": "", - "cmd.ci.error.no_publishers": "", - "cmd.ci.flag.draft": "", - "cmd.ci.flag.go_for_launch": "", - "cmd.ci.flag.prerelease": "", - "cmd.ci.flag.version": "", - "cmd.ci.go_for_launch": "", - "cmd.ci.init.already_initialized": "", - "cmd.ci.init.created_config": "", - "cmd.ci.init.edit_config": "", - "cmd.ci.init.initializing": "", - "cmd.ci.init.long": "", - "cmd.ci.init.next_steps": "", - "cmd.ci.init.run_ci": "", - "cmd.ci.init.short": "", - "cmd.ci.label.artifacts": "", - "cmd.ci.label.ci": "", - "cmd.ci.label.published": "", - "cmd.ci.long": "", - "cmd.ci.publish_completed": "", - "cmd.ci.publishing": "", - "cmd.ci.short": "", - "cmd.ci.version.long": "", - "cmd.ci.version.short": "", - "cmd.collect.bitcointalk.flag.pages": "", - "cmd.collect.bitcointalk.long": "", - "cmd.collect.bitcointalk.short": "", - "cmd.collect.dispatch.hooks.list.short": "", - "cmd.collect.dispatch.hooks.register.short": "", - "cmd.collect.dispatch.hooks.short": "", - "cmd.collect.dispatch.long": "", - "cmd.collect.dispatch.short": "", - "cmd.collect.excavate.flag.resume": "", - "cmd.collect.excavate.flag.scan_only": "", - "cmd.collect.excavate.long": "", - "cmd.collect.excavate.short": "", - "cmd.collect.flag.dry_run": "", - "cmd.collect.flag.output": "", - "cmd.collect.github.flag.issues_only": "", - "cmd.collect.github.flag.org": "", - "cmd.collect.github.flag.prs_only": "", - "cmd.collect.github.long": "", - "cmd.collect.github.short": "", - "cmd.collect.long": "", - "cmd.collect.market.flag.from": "", - "cmd.collect.market.flag.historical": "", - "cmd.collect.market.long": "", - "cmd.collect.market.short": "", - "cmd.collect.papers.flag.category": "", - "cmd.collect.papers.flag.query": "", - "cmd.collect.papers.flag.source": "", - "cmd.collect.papers.long": "", - "cmd.collect.papers.short": "", - "cmd.collect.process.long": "", - "cmd.collect.process.short": "", - "cmd.collect.short": "", - "cmd.deploy.long": "", - "cmd.deploy.short": "", - "cmd.dev.api.short": "", - "cmd.dev.apply.action": "", - "cmd.dev.apply.cancelled": "", - "cmd.dev.apply.confirm": "", - "cmd.dev.apply.dry_run_mode": "", - "cmd.dev.apply.error.both_command_script": "", - "cmd.dev.apply.error.command_failed": "", - "cmd.dev.apply.error.commit_needs_message": "", - "cmd.dev.apply.error.no_command": "", - "cmd.dev.apply.error.no_registry": "", - "cmd.dev.apply.error.no_repos": "", - "cmd.dev.apply.error.script_not_found": "", - "cmd.dev.apply.flag.co_author": "", - "cmd.dev.apply.flag.command": "", - "cmd.dev.apply.flag.commit": "", - "cmd.dev.apply.flag.continue": "", - "cmd.dev.apply.flag.dry_run": "", - "cmd.dev.apply.flag.message": "", - "cmd.dev.apply.flag.push": "", - "cmd.dev.apply.flag.repos": "", - "cmd.dev.apply.flag.script": "", - "cmd.dev.apply.flag.yes": "", - "cmd.dev.apply.long": "", - "cmd.dev.apply.no_changes": "", - "cmd.dev.apply.short": "", - "cmd.dev.apply.summary": "", - "cmd.dev.apply.targets": "", - "cmd.dev.apply.warning": "", - "cmd.dev.ci.failing": "", - "cmd.dev.ci.flag.branch": "", - "cmd.dev.ci.flag.failed": "", - "cmd.dev.ci.long": "", - "cmd.dev.ci.no_ci": "", - "cmd.dev.ci.passing": "", - "cmd.dev.ci.repos_checked": "", - "cmd.dev.ci.short": "", - "cmd.dev.commit.committing": "", - "cmd.dev.commit.flag.all": "", - "cmd.dev.commit.long": "", - "cmd.dev.commit.short": "", - "cmd.dev.committed": "", - "cmd.dev.committing": "", - "cmd.dev.confirm_claude_commit": "", - "cmd.dev.done_succeeded": "", - "cmd.dev.file_sync.dry_run_mode": "", - "cmd.dev.file_sync.error.no_registry": "", - "cmd.dev.file_sync.error.no_targets": "", - "cmd.dev.file_sync.error.source_not_found": "", - "cmd.dev.file_sync.flag.co_author": "", - "cmd.dev.file_sync.flag.dry_run": "", - "cmd.dev.file_sync.flag.message": "", - "cmd.dev.file_sync.flag.push": "", - "cmd.dev.file_sync.flag.to": "", - "cmd.dev.file_sync.long": "", - "cmd.dev.file_sync.no_changes": "", - "cmd.dev.file_sync.short": "", - "cmd.dev.file_sync.source": "", - "cmd.dev.file_sync.summary": "", - "cmd.dev.file_sync.targets": "", - "cmd.dev.health.ahead_label": "", - "cmd.dev.health.behind_label": "", - "cmd.dev.health.dirty_label": "", - "cmd.dev.health.errors": "", - "cmd.dev.health.errors_label": "", - "cmd.dev.health.flag.verbose": "", - "cmd.dev.health.long": "", - "cmd.dev.health.more": "", - "cmd.dev.health.repos": "", - "cmd.dev.health.short": "", - "cmd.dev.health.to_pull": "", - "cmd.dev.health.to_push": "", - "cmd.dev.impact.analysis_for": "", - "cmd.dev.impact.changes_affect": "", - "cmd.dev.impact.direct_dependents": "", - "cmd.dev.impact.long": "", - "cmd.dev.impact.no_dependents": "", - "cmd.dev.impact.requires_registry": "", - "cmd.dev.impact.short": "", - "cmd.dev.impact.transitive_dependents": "", - "cmd.dev.issues.flag.assignee": "", - "cmd.dev.issues.flag.limit": "", - "cmd.dev.issues.long": "", - "cmd.dev.issues.no_issues": "", - "cmd.dev.issues.open_issues": "", - "cmd.dev.issues.short": "", - "cmd.dev.long": "", - "cmd.dev.modified": "", - "cmd.dev.no_changes": "", - "cmd.dev.no_git_repos": "", - "cmd.dev.pull.all_up_to_date": "", - "cmd.dev.pull.commits_behind": "", - "cmd.dev.pull.done_pulled": "", - "cmd.dev.pull.flag.all": "", - "cmd.dev.pull.long": "", - "cmd.dev.pull.pulling": "", - "cmd.dev.pull.pulling_repos": "", - "cmd.dev.pull.repos_behind": "", - "cmd.dev.pull.short": "", - "cmd.dev.push.all_up_to_date": "", - "cmd.dev.push.confirm": "", - "cmd.dev.push.confirm_push": "", - "cmd.dev.push.diverged": "", - "cmd.dev.push.diverged_help": "", - "cmd.dev.push.done_pushed": "", - "cmd.dev.push.flag.force": "", - "cmd.dev.push.long": "", - "cmd.dev.push.pull_and_retry": "", - "cmd.dev.push.short": "", - "cmd.dev.push.uncommitted_changes_commit": "", - "cmd.dev.repos_with_changes": "", - "cmd.dev.reviews.approved": "", - "cmd.dev.reviews.changes_requested": "", - "cmd.dev.reviews.draft": "", - "cmd.dev.reviews.flag.all": "", - "cmd.dev.reviews.flag.author": "", - "cmd.dev.reviews.long": "", - "cmd.dev.reviews.no_prs": "", - "cmd.dev.reviews.open_prs": "", - "cmd.dev.reviews.short": "", - "cmd.dev.reviews.status_approved": "", - "cmd.dev.reviews.status_changes": "", - "cmd.dev.reviews.status_pending": "", - "cmd.dev.scanning_label": "", - "cmd.dev.short": "", - "cmd.dev.staged": "", - "cmd.dev.status.clean": "", - "cmd.dev.sync.long": "", - "cmd.dev.sync.short": "", - "cmd.dev.untracked": "", - "cmd.dev.vm.already_installed": "", - "cmd.dev.vm.boot.flag.cpus": "", - "cmd.dev.vm.boot.flag.fresh": "", - "cmd.dev.vm.boot.flag.memory": "", - "cmd.dev.vm.boot.long": "", - "cmd.dev.vm.boot.short": "", - "cmd.dev.vm.booting": "", - "cmd.dev.vm.check_updates": "", - "cmd.dev.vm.claude.flag.auth": "", - "cmd.dev.vm.claude.flag.model": "", - "cmd.dev.vm.claude.flag.no_auth": "", - "cmd.dev.vm.claude.long": "", - "cmd.dev.vm.claude.short": "", - "cmd.dev.vm.config_label": "", - "cmd.dev.vm.config_value": "", - "cmd.dev.vm.connect_with": "", - "cmd.dev.vm.container_label": "", - "cmd.dev.vm.cpus_label": "", - "cmd.dev.vm.downloading": "", - "cmd.dev.vm.downloading_update": "", - "cmd.dev.vm.install.long": "", - "cmd.dev.vm.install.short": "", - "cmd.dev.vm.install_with": "", - "cmd.dev.vm.installed_in": "", - "cmd.dev.vm.installed_label": "", - "cmd.dev.vm.installed_no": "", - "cmd.dev.vm.installed_yes": "", - "cmd.dev.vm.latest_label": "", - "cmd.dev.vm.memory_label": "", - "cmd.dev.vm.not_installed": "", - "cmd.dev.vm.not_running": "", - "cmd.dev.vm.progress_label": "", - "cmd.dev.vm.run_to_update": "", - "cmd.dev.vm.running": "", - "cmd.dev.vm.serve.flag.path": "", - "cmd.dev.vm.serve.flag.port": "", - "cmd.dev.vm.serve.long": "", - "cmd.dev.vm.serve.short": "", - "cmd.dev.vm.shell.flag.console": "", - "cmd.dev.vm.shell.long": "", - "cmd.dev.vm.shell.short": "", - "cmd.dev.vm.short": "", - "cmd.dev.vm.ssh_port": "", - "cmd.dev.vm.start_with": "", - "cmd.dev.vm.status.long": "", - "cmd.dev.vm.status.short": "", - "cmd.dev.vm.status_title": "", - "cmd.dev.vm.stop.long": "", - "cmd.dev.vm.stop.short": "", - "cmd.dev.vm.stopping": "", - "cmd.dev.vm.stopping_current": "", - "cmd.dev.vm.test.flag.name": "", - "cmd.dev.vm.test.long": "", - "cmd.dev.vm.test.short": "", - "cmd.dev.vm.up_to_date": "", - "cmd.dev.vm.update.flag.apply": "", - "cmd.dev.vm.update.long": "", - "cmd.dev.vm.update.short": "", - "cmd.dev.vm.update_available": "", - "cmd.dev.vm.updated_in": "", - "cmd.dev.vm.uptime_label": "", - "cmd.dev.work.all_up_to_date": "", - "cmd.dev.work.error_prefix": "", - "cmd.dev.work.flag.commit": "", - "cmd.dev.work.flag.status": "", - "cmd.dev.work.long": "", - "cmd.dev.work.short": "", - "cmd.dev.work.table_ahead": "", - "cmd.dev.work.table_modified": "", - "cmd.dev.work.table_staged": "", - "cmd.dev.work.table_untracked": "", - "cmd.dev.work.use_commit_flag": "", - "cmd.dev.workflow.dry_run_mode": "", - "cmd.dev.workflow.failed_count": "", - "cmd.dev.workflow.header.repo": "", - "cmd.dev.workflow.list.long": "", - "cmd.dev.workflow.list.short": "", - "cmd.dev.workflow.long": "", - "cmd.dev.workflow.no_workflows": "", - "cmd.dev.workflow.read_template_error": "", - "cmd.dev.workflow.run_without_dry_run": "", - "cmd.dev.workflow.short": "", - "cmd.dev.workflow.skipped_count": "", - "cmd.dev.workflow.sync.flag.dry_run": "", - "cmd.dev.workflow.sync.long": "", - "cmd.dev.workflow.sync.short": "", - "cmd.dev.workflow.synced": "", - "cmd.dev.workflow.synced_count": "", - "cmd.dev.workflow.template_not_found": "", - "cmd.dev.workflow.up_to_date": "", - "cmd.dev.workflow.would_sync": "", - "cmd.dev.workflow.would_sync_count": "", - "cmd.docs.list.coverage_summary": "", - "cmd.docs.list.header.changelog": "", - "cmd.docs.list.header.claude": "", - "cmd.docs.list.header.docs": "", - "cmd.docs.list.header.readme": "", - "cmd.docs.list.long": "", - "cmd.docs.list.short": "", - "cmd.docs.long": "", - "cmd.docs.short": "", - "cmd.docs.sync.confirm": "", - "cmd.docs.sync.dry_run_notice": "", - "cmd.docs.sync.files_count": "", - "cmd.docs.sync.flag.dry_run": "", - "cmd.docs.sync.flag.output": "", - "cmd.docs.sync.found_label": "", - "cmd.docs.sync.long": "", - "cmd.docs.sync.no_docs_found": "", - "cmd.docs.sync.repos_with_docs": "", - "cmd.docs.sync.short": "", - "cmd.docs.sync.synced_packages": "", - "cmd.docs.sync.total_summary": "", - "cmd.doctor.check.claude.description": "", - "cmd.doctor.check.claude.name": "", - "cmd.doctor.check.composer.description": "", - "cmd.doctor.check.composer.name": "", - "cmd.doctor.check.docker.description": "", - "cmd.doctor.check.docker.name": "", - "cmd.doctor.check.gh.description": "", - "cmd.doctor.check.gh.name": "", - "cmd.doctor.check.git.description": "", - "cmd.doctor.check.git.name": "", - "cmd.doctor.check.node.description": "", - "cmd.doctor.check.node.name": "", - "cmd.doctor.check.php.description": "", - "cmd.doctor.check.php.name": "", - "cmd.doctor.check.pnpm.description": "", - "cmd.doctor.check.pnpm.name": "", - "cmd.doctor.cli_auth": "", - "cmd.doctor.cli_auth_missing": "", - "cmd.doctor.github": "", - "cmd.doctor.install_linux_gh": "", - "cmd.doctor.install_linux_git": "", - "cmd.doctor.install_linux_header": "", - "cmd.doctor.install_linux_node": "", - "cmd.doctor.install_linux_php": "", - "cmd.doctor.install_linux_pnpm": "", - "cmd.doctor.install_macos": "", - "cmd.doctor.install_macos_cask": "", - "cmd.doctor.install_missing": "", - "cmd.doctor.install_other": "", - "cmd.doctor.issues": "", - "cmd.doctor.issues_error": "", - "cmd.doctor.long": "", - "cmd.doctor.no_repos_yaml": "", - "cmd.doctor.optional": "", - "cmd.doctor.ready": "", - "cmd.doctor.repos_cloned": "", - "cmd.doctor.repos_yaml_found": "", - "cmd.doctor.required": "", - "cmd.doctor.short": "", - "cmd.doctor.ssh_found": "", - "cmd.doctor.ssh_missing": "", - "cmd.doctor.verbose_flag": "", - "cmd.doctor.workspace": "", - "cmd.git.long": "", - "cmd.git.short": "", - "cmd.go.cov.short": "", - "cmd.go.fmt.flag.all": "", - "cmd.go.fmt.flag.check": "", - "cmd.go.fmt.no_changes": "", - "cmd.go.fmt.short": "", - "cmd.go.install.short": "", - "cmd.go.lint.flag.all": "", - "cmd.go.lint.no_changes": "", - "cmd.go.lint.short": "", - "cmd.go.long": "", - "cmd.go.mod.short": "", - "cmd.go.qa.short": "", - "cmd.go.short": "", - "cmd.go.test.short": "", - "cmd.go.work.short": "", - "cmd.monitor.error.no_repos": "", - "cmd.monitor.error.not_git_repo": "", - "cmd.monitor.flag.all": "", - "cmd.monitor.flag.json": "", - "cmd.monitor.flag.repo": "", - "cmd.monitor.flag.severity": "", - "cmd.monitor.found": "", - "cmd.monitor.long": "", - "cmd.monitor.no_findings": "", - "cmd.monitor.scanning": "", - "cmd.monitor.short": "", - "cmd.php.analyse.flag.level": "", - "cmd.php.analyse.flag.memory": "", - "cmd.php.analyse.long": "", - "cmd.php.analyse.no_analyser": "", - "cmd.php.analyse.short": "", - "cmd.php.audit.all_secure": "", - "cmd.php.audit.completed_errors": "", - "cmd.php.audit.error": "", - "cmd.php.audit.flag.fix": "", - "cmd.php.audit.found_vulns": "", - "cmd.php.audit.long": "", - "cmd.php.audit.scanning": "", - "cmd.php.audit.secure": "", - "cmd.php.audit.short": "", - "cmd.php.audit.vulnerabilities": "", - "cmd.php.build.building_docker": "", - "cmd.php.build.building_linuxkit": "", - "cmd.php.build.docker_run_with": "", - "cmd.php.build.extensions": "", - "cmd.php.build.flag.dockerfile": "", - "cmd.php.build.flag.format": "", - "cmd.php.build.flag.name": "", - "cmd.php.build.flag.no_cache": "", - "cmd.php.build.flag.output": "", - "cmd.php.build.flag.platform": "", - "cmd.php.build.flag.template": "", - "cmd.php.build.flag.type": "", - "cmd.php.build.format": "", - "cmd.php.build.frontend": "", - "cmd.php.build.laravel": "", - "cmd.php.build.long": "", - "cmd.php.build.octane": "", - "cmd.php.build.php_version": "", - "cmd.php.build.platform": "", - "cmd.php.build.short": "", - "cmd.php.ci.flag.fail_on": "", - "cmd.php.ci.flag.json": "", - "cmd.php.ci.flag.sarif": "", - "cmd.php.ci.flag.summary": "", - "cmd.php.ci.flag.upload_sarif": "", - "cmd.php.ci.long": "", - "cmd.php.ci.short": "", - "cmd.php.deploy.deploying": "", - "cmd.php.deploy.flag.force": "", - "cmd.php.deploy.flag.staging": "", - "cmd.php.deploy.flag.wait": "", - "cmd.php.deploy.long": "", - "cmd.php.deploy.short": "", - "cmd.php.deploy.triggered": "", - "cmd.php.deploy.warning_status": "", - "cmd.php.deploy_list.flag.limit": "", - "cmd.php.deploy_list.flag.staging": "", - "cmd.php.deploy_list.long": "", - "cmd.php.deploy_list.none_found": "", - "cmd.php.deploy_list.recent": "", - "cmd.php.deploy_list.short": "", - "cmd.php.deploy_rollback.flag.id": "", - "cmd.php.deploy_rollback.flag.staging": "", - "cmd.php.deploy_rollback.flag.wait": "", - "cmd.php.deploy_rollback.long": "", - "cmd.php.deploy_rollback.rolling_back": "", - "cmd.php.deploy_rollback.short": "", - "cmd.php.deploy_rollback.triggered": "", - "cmd.php.deploy_rollback.warning_status": "", - "cmd.php.deploy_status.flag.id": "", - "cmd.php.deploy_status.flag.staging": "", - "cmd.php.deploy_status.long": "", - "cmd.php.deploy_status.short": "", - "cmd.php.dev.all_stopped": "", - "cmd.php.dev.detected_services": "", - "cmd.php.dev.flag.domain": "", - "cmd.php.dev.flag.https": "", - "cmd.php.dev.flag.no_horizon": "", - "cmd.php.dev.flag.no_redis": "", - "cmd.php.dev.flag.no_reverb": "", - "cmd.php.dev.flag.no_vite": "", - "cmd.php.dev.flag.port": "", - "cmd.php.dev.long": "", - "cmd.php.dev.press_ctrl_c": "", - "cmd.php.dev.services_started": "", - "cmd.php.dev.short": "", - "cmd.php.dev.shutting_down": "", - "cmd.php.dev.starting": "", - "cmd.php.dev.stop_error": "", - "cmd.php.error.analysis_issues": "", - "cmd.php.error.audit_failed": "", - "cmd.php.error.critical_high_issues": "", - "cmd.php.error.deploy_failed": "", - "cmd.php.error.fmt_failed": "", - "cmd.php.error.fmt_issues": "", - "cmd.php.error.infection_failed": "", - "cmd.php.error.infection_not_installed": "", - "cmd.php.error.mkcert_not_installed": "", - "cmd.php.error.not_laravel": "", - "cmd.php.error.not_laravel_short": "", - "cmd.php.error.not_php": "", - "cmd.php.error.psalm_issues": "", - "cmd.php.error.psalm_not_installed": "", - "cmd.php.error.rector_failed": "", - "cmd.php.error.rector_not_installed": "", - "cmd.php.error.rollback_failed": "", - "cmd.php.error.security_failed": "", - "cmd.php.error.update_packages": "", - "cmd.php.error.vulns_found": "", - "cmd.php.fmt.flag.fix": "", - "cmd.php.fmt.formatting": "", - "cmd.php.fmt.long": "", - "cmd.php.fmt.no_formatter": "", - "cmd.php.fmt.no_issues": "", - "cmd.php.fmt.short": "", - "cmd.php.infection.complete": "", - "cmd.php.infection.flag.filter": "", - "cmd.php.infection.flag.min_covered_msi": "", - "cmd.php.infection.flag.min_msi": "", - "cmd.php.infection.flag.only_covered": "", - "cmd.php.infection.flag.threads": "", - "cmd.php.infection.install": "", - "cmd.php.infection.long": "", - "cmd.php.infection.not_found": "", - "cmd.php.infection.note": "", - "cmd.php.infection.short": "", - "cmd.php.label.app_url": "", - "cmd.php.label.audit": "", - "cmd.php.label.branch": "", - "cmd.php.label.commit": "", - "cmd.php.label.completed": "", - "cmd.php.label.deploy": "", - "cmd.php.label.duration": "", - "cmd.php.label.id": "", - "cmd.php.label.infection": "", - "cmd.php.label.info": "", - "cmd.php.label.message": "", - "cmd.php.label.php": "", - "cmd.php.label.psalm": "", - "cmd.php.label.rector": "", - "cmd.php.label.running": "", - "cmd.php.label.security": "", - "cmd.php.label.services": "", - "cmd.php.label.setup": "", - "cmd.php.label.vite": "", - "cmd.php.logs.flag.service": "", - "cmd.php.logs.long": "", - "cmd.php.logs.short": "", - "cmd.php.long": "", - "cmd.php.packages.link.done": "", - "cmd.php.packages.link.linking": "", - "cmd.php.packages.link.long": "", - "cmd.php.packages.link.short": "", - "cmd.php.packages.list.linked": "", - "cmd.php.packages.list.long": "", - "cmd.php.packages.list.none_found": "", - "cmd.php.packages.list.short": "", - "cmd.php.packages.list.unknown": "", - "cmd.php.packages.long": "", - "cmd.php.packages.short": "", - "cmd.php.packages.unlink.done": "", - "cmd.php.packages.unlink.long": "", - "cmd.php.packages.unlink.short": "", - "cmd.php.packages.unlink.unlinking": "", - "cmd.php.packages.update.done": "", - "cmd.php.packages.update.long": "", - "cmd.php.packages.update.short": "", - "cmd.php.packages.update.updating": "", - "cmd.php.psalm.analysing": "", - "cmd.php.psalm.analysing_fixing": "", - "cmd.php.psalm.flag.baseline": "", - "cmd.php.psalm.flag.level": "", - "cmd.php.psalm.flag.show_info": "", - "cmd.php.psalm.install": "", - "cmd.php.psalm.long": "", - "cmd.php.psalm.not_found": "", - "cmd.php.psalm.setup": "", - "cmd.php.psalm.short": "", - "cmd.php.qa.flag.full": "", - "cmd.php.qa.flag.quick": "", - "cmd.php.qa.long": "", - "cmd.php.qa.short": "", - "cmd.php.rector.analysing": "", - "cmd.php.rector.changes_suggested": "", - "cmd.php.rector.flag.clear_cache": "", - "cmd.php.rector.flag.diff": "", - "cmd.php.rector.flag.fix": "", - "cmd.php.rector.install": "", - "cmd.php.rector.long": "", - "cmd.php.rector.no_changes": "", - "cmd.php.rector.not_found": "", - "cmd.php.rector.refactoring": "", - "cmd.php.rector.setup": "", - "cmd.php.rector.short": "", - "cmd.php.security.checks_suffix": "", - "cmd.php.security.critical": "", - "cmd.php.security.flag.sarif": "", - "cmd.php.security.flag.severity": "", - "cmd.php.security.flag.url": "", - "cmd.php.security.high": "", - "cmd.php.security.long": "", - "cmd.php.security.low": "", - "cmd.php.security.medium": "", - "cmd.php.security.passed": "", - "cmd.php.security.short": "", - "cmd.php.security.summary": "", - "cmd.php.serve.flag.container": "", - "cmd.php.serve.flag.detach": "", - "cmd.php.serve.flag.env_file": "", - "cmd.php.serve.flag.https_port": "", - "cmd.php.serve.flag.name": "", - "cmd.php.serve.flag.port": "", - "cmd.php.serve.long": "", - "cmd.php.serve.name_required": "", - "cmd.php.serve.short": "", - "cmd.php.serve.stopped": "", - "cmd.php.shell.long": "", - "cmd.php.shell.opening": "", - "cmd.php.shell.short": "", - "cmd.php.short": "", - "cmd.php.ssl.cert_label": "", - "cmd.php.ssl.certs_created": "", - "cmd.php.ssl.certs_exist": "", - "cmd.php.ssl.flag.domain": "", - "cmd.php.ssl.install_linux": "", - "cmd.php.ssl.install_macos": "", - "cmd.php.ssl.key_label": "", - "cmd.php.ssl.mkcert_not_installed": "", - "cmd.php.ssl.setting_up": "", - "cmd.php.ssl.short": "", - "cmd.php.stan.short": "", - "cmd.php.status.detected_services": "", - "cmd.php.status.error": "", - "cmd.php.status.octane_server": "", - "cmd.php.status.package_manager": "", - "cmd.php.status.pid": "", - "cmd.php.status.port": "", - "cmd.php.status.running": "", - "cmd.php.status.short": "", - "cmd.php.status.ssl_certs": "", - "cmd.php.status.ssl_installed": "", - "cmd.php.status.ssl_not_setup": "", - "cmd.php.status.stopped": "", - "cmd.php.stop.short": "", - "cmd.php.stop.stopping": "", - "cmd.php.test.flag.coverage": "", - "cmd.php.test.flag.filter": "", - "cmd.php.test.flag.group": "", - "cmd.php.test.flag.junit": "", - "cmd.php.test.flag.parallel": "", - "cmd.php.test.long": "", - "cmd.php.test.short": "", - "cmd.pkg.error.auth_failed": "", - "cmd.pkg.error.gh_not_authenticated": "", - "cmd.pkg.error.invalid_repo_format": "", - "cmd.pkg.error.no_repos_yaml": "", - "cmd.pkg.error.no_repos_yaml_workspace": "", - "cmd.pkg.error.repo_required": "", - "cmd.pkg.error.search_failed": "", - "cmd.pkg.error.specify_package": "", - "cmd.pkg.install.add_to_registry": "", - "cmd.pkg.install.added_to_registry": "", - "cmd.pkg.install.already_exists": "", - "cmd.pkg.install.flag.add": "", - "cmd.pkg.install.flag.dir": "", - "cmd.pkg.install.installed": "", - "cmd.pkg.install.installing_label": "", - "cmd.pkg.install.long": "", - "cmd.pkg.install.short": "", - "cmd.pkg.list.install_missing": "", - "cmd.pkg.list.long": "", - "cmd.pkg.list.no_packages": "", - "cmd.pkg.list.short": "", - "cmd.pkg.list.summary": "", - "cmd.pkg.list.title": "", - "cmd.pkg.long": "", - "cmd.pkg.no_description": "", - "cmd.pkg.outdated.all_up_to_date": "", - "cmd.pkg.outdated.commits_behind": "", - "cmd.pkg.outdated.long": "", - "cmd.pkg.outdated.outdated_label": "", - "cmd.pkg.outdated.short": "", - "cmd.pkg.outdated.summary": "", - "cmd.pkg.outdated.update_with": "", - "cmd.pkg.search.cache_label": "", - "cmd.pkg.search.fetching_label": "", - "cmd.pkg.search.flag.limit": "", - "cmd.pkg.search.flag.org": "", - "cmd.pkg.search.flag.pattern": "", - "cmd.pkg.search.flag.refresh": "", - "cmd.pkg.search.flag.type": "", - "cmd.pkg.search.found_repos": "", - "cmd.pkg.search.gh_token_unset": "", - "cmd.pkg.search.gh_token_warning": "", - "cmd.pkg.search.long": "", - "cmd.pkg.search.no_repos_found": "", - "cmd.pkg.search.private_label": "", - "cmd.pkg.search.short": "", - "cmd.pkg.short": "", - "cmd.pkg.update.flag.all": "", - "cmd.pkg.update.long": "", - "cmd.pkg.update.not_installed": "", - "cmd.pkg.update.short": "", - "cmd.pkg.update.summary": "", - "cmd.pkg.update.update_label": "", - "cmd.pkg.update.updating": "", - "cmd.qa.docblock.coverage": "", - "cmd.qa.docblock.flag.threshold": "", - "cmd.qa.docblock.long": "", - "cmd.qa.docblock.missing_docs": "", - "cmd.qa.docblock.short": "", - "cmd.qa.docblock.use_verbose": "", - "cmd.qa.health.all_healthy": "", - "cmd.qa.health.cancelled": "", - "cmd.qa.health.count_disabled": "", - "cmd.qa.health.count_failing": "", - "cmd.qa.health.count_no_ci": "", - "cmd.qa.health.count_passing": "", - "cmd.qa.health.count_pending": "", - "cmd.qa.health.fetch_error": "", - "cmd.qa.health.flag.problems": "", - "cmd.qa.health.long": "", - "cmd.qa.health.no_ci_configured": "", - "cmd.qa.health.parse_error": "", - "cmd.qa.health.passing": "", - "cmd.qa.health.running": "", - "cmd.qa.health.short": "", - "cmd.qa.health.skipped": "", - "cmd.qa.health.summary": "", - "cmd.qa.health.tests_failing": "", - "cmd.qa.health.workflow_disabled": "", - "cmd.qa.issues.category.blocked": "", - "cmd.qa.issues.category.needs_response": "", - "cmd.qa.issues.category.ready": "", - "cmd.qa.issues.category.triage": "", - "cmd.qa.issues.fetching": "", - "cmd.qa.issues.flag.blocked": "", - "cmd.qa.issues.flag.limit": "", - "cmd.qa.issues.flag.mine": "", - "cmd.qa.issues.flag.triage": "", - "cmd.qa.issues.hint.blocked": "", - "cmd.qa.issues.hint.needs_response": "", - "cmd.qa.issues.hint.triage": "", - "cmd.qa.issues.long": "", - "cmd.qa.issues.no_issues": "", - "cmd.qa.issues.short": "", - "cmd.qa.long": "", - "cmd.qa.review.error.no_repo": "", - "cmd.qa.review.flag.mine": "", - "cmd.qa.review.flag.repo": "", - "cmd.qa.review.flag.requested": "", - "cmd.qa.review.long": "", - "cmd.qa.review.no_prs": "", - "cmd.qa.review.no_reviews": "", - "cmd.qa.review.review_requested": "", - "cmd.qa.review.short": "", - "cmd.qa.review.your_prs": "", - "cmd.qa.short": "", - "cmd.qa.watch.all_passed": "", - "cmd.qa.watch.commit": "", - "cmd.qa.watch.error.not_git_repo": "", - "cmd.qa.watch.error.repo_format": "", - "cmd.qa.watch.flag.commit": "", - "cmd.qa.watch.flag.repo": "", - "cmd.qa.watch.flag.timeout": "", - "cmd.qa.watch.long": "", - "cmd.qa.watch.short": "", - "cmd.qa.watch.timeout": "", - "cmd.qa.watch.waiting_for_workflows": "", - "cmd.qa.watch.workflows_failed": "", - "cmd.rag.collections.flag.delete": "", - "cmd.rag.collections.flag.list": "", - "cmd.rag.collections.flag.stats": "", - "cmd.rag.collections.long": "", - "cmd.rag.collections.short": "", - "cmd.rag.flag.model": "", - "cmd.rag.flag.ollama_host": "", - "cmd.rag.flag.ollama_port": "", - "cmd.rag.flag.qdrant_host": "", - "cmd.rag.flag.qdrant_port": "", - "cmd.rag.ingest.flag.chunk_overlap": "", - "cmd.rag.ingest.flag.chunk_size": "", - "cmd.rag.ingest.flag.collection": "", - "cmd.rag.ingest.flag.recreate": "", - "cmd.rag.ingest.long": "", - "cmd.rag.ingest.short": "", - "cmd.rag.long": "", - "cmd.rag.query.flag.category": "", - "cmd.rag.query.flag.collection": "", - "cmd.rag.query.flag.format": "", - "cmd.rag.query.flag.threshold": "", - "cmd.rag.query.flag.top": "", - "cmd.rag.query.long": "", - "cmd.rag.query.short": "", - "cmd.rag.short": "", - "cmd.sdk.diff.base_label": "", - "cmd.sdk.diff.breaking": "", - "cmd.sdk.diff.error.base_required": "", - "cmd.sdk.diff.flag.base": "", - "cmd.sdk.diff.flag.spec": "", - "cmd.sdk.diff.label": "", - "cmd.sdk.diff.long": "", - "cmd.sdk.diff.short": "", - "cmd.sdk.label.ok": "", - "cmd.sdk.label.sdk": "", - "cmd.sdk.long": "", - "cmd.sdk.short": "", - "cmd.sdk.validate.long": "", - "cmd.sdk.validate.short": "", - "cmd.sdk.validate.valid": "", - "cmd.sdk.validate.validating": "", - "cmd.security.alerts.long": "", - "cmd.security.alerts.short": "", - "cmd.security.deps.flag.vulnerable": "", - "cmd.security.deps.long": "", - "cmd.security.deps.short": "", - "cmd.security.flag.repo": "", - "cmd.security.flag.severity": "", - "cmd.security.flag.target": "", - "cmd.security.jobs.flag.copies": "", - "cmd.security.jobs.flag.dry_run": "", - "cmd.security.jobs.flag.issue_repo": "", - "cmd.security.jobs.flag.targets": "", - "cmd.security.jobs.long": "", - "cmd.security.jobs.short": "", - "cmd.security.long": "", - "cmd.security.scan.flag.tool": "", - "cmd.security.scan.long": "", - "cmd.security.scan.short": "", - "cmd.security.secrets.long": "", - "cmd.security.secrets.short": "", - "cmd.security.short": "", - "cmd.setup.already_exist_count": "", - "cmd.setup.already_exists": "", - "cmd.setup.bootstrap_mode": "", - "cmd.setup.cancelled": "", - "cmd.setup.cloned": "", - "cmd.setup.cloned_count": "", - "cmd.setup.cloning_current_dir": "", - "cmd.setup.complete": "", - "cmd.setup.creating_project_dir": "", - "cmd.setup.done": "", - "cmd.setup.exist": "", - "cmd.setup.flag.all": "", - "cmd.setup.flag.build": "", - "cmd.setup.flag.dry_run": "", - "cmd.setup.flag.name": "", - "cmd.setup.flag.only": "", - "cmd.setup.flag.registry": "", - "cmd.setup.github.all_up_to_date": "", - "cmd.setup.github.dry_run_mode": "", - "cmd.setup.github.error.config_not_found": "", - "cmd.setup.github.error.conflicting_flags": "", - "cmd.setup.github.error.not_authenticated": "", - "cmd.setup.github.flag.all": "", - "cmd.setup.github.flag.check": "", - "cmd.setup.github.flag.config": "", - "cmd.setup.github.flag.labels": "", - "cmd.setup.github.flag.protection": "", - "cmd.setup.github.flag.repo": "", - "cmd.setup.github.flag.security": "", - "cmd.setup.github.flag.webhooks": "", - "cmd.setup.github.long": "", - "cmd.setup.github.no_changes": "", - "cmd.setup.github.no_repos_specified": "", - "cmd.setup.github.repos_checked": "", - "cmd.setup.github.repos_with_changes": "", - "cmd.setup.github.run_without_check": "", - "cmd.setup.github.short": "", - "cmd.setup.github.to_create": "", - "cmd.setup.github.to_delete": "", - "cmd.setup.github.to_update": "", - "cmd.setup.github.usage_hint": "", - "cmd.setup.long": "", - "cmd.setup.nothing_to_clone": "", - "cmd.setup.org_label": "", - "cmd.setup.repo.created": "", - "cmd.setup.repo.detected_type": "", - "cmd.setup.repo.setting_up": "", - "cmd.setup.repo.would_create": "", - "cmd.setup.short": "", - "cmd.setup.to_clone": "", - "cmd.setup.wizard.confirm_clone": "", - "cmd.setup.wizard.git_repo_title": "", - "cmd.setup.wizard.package_selection": "", - "cmd.setup.wizard.project_name_desc": "", - "cmd.setup.wizard.project_name_title": "", - "cmd.setup.wizard.select_packages": "", - "cmd.setup.wizard.selection_hint": "", - "cmd.setup.wizard.what_to_do": "", - "cmd.setup.would_clone": "", - "cmd.setup.would_clone_list": "", - "cmd.setup.would_load_registry": "", - "cmd.test.coverage_by_package": "", - "cmd.test.error.no_go_mod": "", - "cmd.test.failed_packages": "", - "cmd.test.flag.json": "", - "cmd.test.flag.pkg": "", - "cmd.test.flag.race": "", - "cmd.test.flag.run": "", - "cmd.test.flag.short": "", - "cmd.test.flag.verbose": "", - "cmd.test.label.average": "", - "cmd.test.long": "", - "cmd.test.short": "", - "cmd.test.tests_failed": "", - "cmd.vm.error.id_and_cmd_required": "", - "cmd.vm.error.id_required": "", - "cmd.vm.error.linuxkit_not_found": "", - "cmd.vm.error.multiple_match": "", - "cmd.vm.error.no_image_found": "", - "cmd.vm.error.no_match": "", - "cmd.vm.error.template_required": "", - "cmd.vm.exec.long": "", - "cmd.vm.exec.short": "", - "cmd.vm.hint.stop": "", - "cmd.vm.hint.view_logs": "", - "cmd.vm.label.building": "", - "cmd.vm.label.container_stopped": "", - "cmd.vm.label.hypervisor": "", - "cmd.vm.label.name": "", - "cmd.vm.label.pid": "", - "cmd.vm.logs.long": "", - "cmd.vm.logs.short": "", - "cmd.vm.long": "", - "cmd.vm.ps.flag.all": "", - "cmd.vm.ps.header": "", - "cmd.vm.ps.long": "", - "cmd.vm.ps.no_containers": "", - "cmd.vm.ps.no_running": "", - "cmd.vm.ps.short": "", - "cmd.vm.run.error.image_required": "", - "cmd.vm.run.flag.cpus": "", - "cmd.vm.run.flag.detach": "", - "cmd.vm.run.flag.memory": "", - "cmd.vm.run.flag.name": "", - "cmd.vm.run.flag.ssh_port": "", - "cmd.vm.run.flag.template": "", - "cmd.vm.run.flag.var": "", - "cmd.vm.run.long": "", - "cmd.vm.run.short": "", - "cmd.vm.short": "", - "cmd.vm.stop.long": "", - "cmd.vm.stop.short": "", - "cmd.vm.stop.stopping": "", - "cmd.vm.templates.header": "", - "cmd.vm.templates.hint.run": "", - "cmd.vm.templates.hint.show": "", - "cmd.vm.templates.hint.vars": "", - "cmd.vm.templates.long": "", - "cmd.vm.templates.no_templates": "", - "cmd.vm.templates.short": "", - "cmd.vm.templates.show.long": "", - "cmd.vm.templates.show.short": "", - "cmd.vm.templates.title": "", - "cmd.vm.templates.vars.long": "", - "cmd.vm.templates.vars.none": "", - "cmd.vm.templates.vars.optional": "", - "cmd.vm.templates.vars.required": "", - "cmd.vm.templates.vars.short": "", - "common.count.commits": "", - "common.count.failed": "", - "common.count.files": "", - "common.count.passed": "", - "common.count.pending": "", - "common.count.repos_unpushed": "", - "common.count.skipped": "", - "common.count.succeeded": "", - "common.error.failed": "", - "common.error.json_sarif_exclusive": "", - "common.flag.coverage": "", - "common.flag.diff": "", - "common.flag.fix": "", - "common.flag.follow": "", - "common.flag.json": "", - "common.flag.registry": "", - "common.flag.sarif": "", - "common.flag.spec": "", - "common.flag.tag": "", - "common.flag.verbose": "", - "common.hint.fix_deps": "", - "common.hint.install_with": "", - "common.label.config": "", - "common.label.coverage": "", - "common.label.done": "", - "common.label.error": "", - "common.label.fix": "", - "common.label.image": "", - "common.label.info": "", - "common.label.install": "", - "common.label.package": "", - "common.label.repo": "", - "common.label.setup": "", - "common.label.spec": "", - "common.label.started": "", - "common.label.success": "", - "common.label.summary": "", - "common.label.template": "", - "common.label.test": "", - "common.label.warning": "", - "common.progress.checking": "", - "common.progress.checking_updates": "", - "common.progress.running": "", - "common.prompt.abort": "", - "common.result.all_passed": "", - "common.result.no_issues": "", - "common.status.clean": "", - "common.status.cloning": "", - "common.status.dirty": "", - "common.status.running": "", - "common.status.stopped": "", - "common.status.synced": "", - "common.status.up_to_date": "", - "common.success.completed": "", - "error.gh_not_found": "", - "error.registry_not_found": "", - "error.repo_not_found": "", - "gram.article.definite": "", - "gram.article.definite.feminine": "", - "gram.article.definite.masculine": "", - "gram.article.definite.neuter": "", - "gram.article.indefinite.default": "", - "gram.article.indefinite.feminine": "", - "gram.article.indefinite.masculine": "", - "gram.article.indefinite.neuter": "", - "gram.article.indefinite.vowel": "", - "gram.noun.artifact.one": "", - "gram.noun.artifact.other": "", - "gram.noun.branch.gender": "", - "gram.noun.branch.one": "", - "gram.noun.branch.other": "", - "gram.noun.category.one": "", - "gram.noun.category.other": "", - "gram.noun.change.gender": "", - "gram.noun.change.one": "", - "gram.noun.change.other": "", - "gram.noun.check.one": "", - "gram.noun.check.other": "", - "gram.noun.child.one": "", - "gram.noun.child.other": "", - "gram.noun.commit.gender": "", - "gram.noun.commit.one": "", - "gram.noun.commit.other": "", - "gram.noun.dependency.one": "", - "gram.noun.dependency.other": "", - "gram.noun.directory.one": "", - "gram.noun.directory.other": "", - "gram.noun.failed.one": "", - "gram.noun.failed.other": "", - "gram.noun.file.gender": "", - "gram.noun.file.one": "", - "gram.noun.file.other": "", - "gram.noun.issue.one": "", - "gram.noun.issue.other": "", - "gram.noun.item.gender": "", - "gram.noun.item.one": "", - "gram.noun.item.other": "", - "gram.noun.package.one": "", - "gram.noun.package.other": "", - "gram.noun.passed.one": "", - "gram.noun.passed.other": "", - "gram.noun.person.one": "", - "gram.noun.person.other": "", - "gram.noun.query.one": "", - "gram.noun.query.other": "", - "gram.noun.repo.gender": "", - "gram.noun.repo.one": "", - "gram.noun.repo.other": "", - "gram.noun.repository.one": "", - "gram.noun.repository.other": "", - "gram.noun.skipped.one": "", - "gram.noun.skipped.other": "", - "gram.noun.task.one": "", - "gram.noun.task.other": "", - "gram.noun.test.one": "", - "gram.noun.test.other": "", - "gram.noun.vulnerability.one": "", - "gram.noun.vulnerability.other": "", - "gram.number.decimal": "", - "gram.number.percent": "", - "gram.number.thousands": "", - "gram.punct.label": "", - "gram.punct.progress": "", - "gram.verb.analyse.base": "", - "gram.verb.analyse.gerund": "", - "gram.verb.analyse.past": "", - "gram.verb.be.base": "", - "gram.verb.be.gerund": "", - "gram.verb.be.past": "", - "gram.verb.begin.base": "", - "gram.verb.begin.gerund": "", - "gram.verb.begin.past": "", - "gram.verb.bring.base": "", - "gram.verb.bring.gerund": "", - "gram.verb.bring.past": "", - "gram.verb.build.base": "", - "gram.verb.build.gerund": "", - "gram.verb.build.past": "", - "gram.verb.buy.base": "", - "gram.verb.buy.gerund": "", - "gram.verb.buy.past": "", - "gram.verb.catch.base": "", - "gram.verb.catch.gerund": "", - "gram.verb.catch.past": "", - "gram.verb.check.base": "", - "gram.verb.check.gerund": "", - "gram.verb.check.past": "", - "gram.verb.choose.base": "", - "gram.verb.choose.gerund": "", - "gram.verb.choose.past": "", - "gram.verb.commit.base": "", - "gram.verb.commit.gerund": "", - "gram.verb.commit.past": "", - "gram.verb.create.base": "", - "gram.verb.create.gerund": "", - "gram.verb.create.past": "", - "gram.verb.cut.base": "", - "gram.verb.cut.gerund": "", - "gram.verb.cut.past": "", - "gram.verb.delete.base": "", - "gram.verb.delete.gerund": "", - "gram.verb.delete.past": "", - "gram.verb.do.base": "", - "gram.verb.do.gerund": "", - "gram.verb.do.past": "", - "gram.verb.find.base": "", - "gram.verb.find.gerund": "", - "gram.verb.find.past": "", - "gram.verb.format.base": "", - "gram.verb.format.gerund": "", - "gram.verb.format.past": "", - "gram.verb.get.base": "", - "gram.verb.get.gerund": "", - "gram.verb.get.past": "", - "gram.verb.go.base": "", - "gram.verb.go.gerund": "", - "gram.verb.go.past": "", - "gram.verb.have.base": "", - "gram.verb.have.gerund": "", - "gram.verb.have.past": "", - "gram.verb.hit.base": "", - "gram.verb.hit.gerund": "", - "gram.verb.hit.past": "", - "gram.verb.hold.base": "", - "gram.verb.hold.gerund": "", - "gram.verb.hold.past": "", - "gram.verb.install.base": "", - "gram.verb.install.gerund": "", - "gram.verb.install.past": "", - "gram.verb.keep.base": "", - "gram.verb.keep.gerund": "", - "gram.verb.keep.past": "", - "gram.verb.lead.base": "", - "gram.verb.lead.gerund": "", - "gram.verb.lead.past": "", - "gram.verb.leave.base": "", - "gram.verb.leave.gerund": "", - "gram.verb.leave.past": "", - "gram.verb.lose.base": "", - "gram.verb.lose.gerund": "", - "gram.verb.lose.past": "", - "gram.verb.make.base": "", - "gram.verb.make.gerund": "", - "gram.verb.make.past": "", - "gram.verb.meet.base": "", - "gram.verb.meet.gerund": "", - "gram.verb.meet.past": "", - "gram.verb.organise.base": "", - "gram.verb.organise.gerund": "", - "gram.verb.organise.past": "", - "gram.verb.pay.base": "", - "gram.verb.pay.gerund": "", - "gram.verb.pay.past": "", - "gram.verb.pull.base": "", - "gram.verb.pull.gerund": "", - "gram.verb.pull.past": "", - "gram.verb.push.base": "", - "gram.verb.push.gerund": "", - "gram.verb.push.past": "", - "gram.verb.put.base": "", - "gram.verb.put.gerund": "", - "gram.verb.put.past": "", - "gram.verb.realise.base": "", - "gram.verb.realise.gerund": "", - "gram.verb.realise.past": "", - "gram.verb.recognise.base": "", - "gram.verb.recognise.gerund": "", - "gram.verb.recognise.past": "", - "gram.verb.run.base": "", - "gram.verb.run.gerund": "", - "gram.verb.run.past": "", - "gram.verb.save.base": "", - "gram.verb.save.gerund": "", - "gram.verb.save.past": "", - "gram.verb.scan.base": "", - "gram.verb.scan.gerund": "", - "gram.verb.scan.past": "", - "gram.verb.sell.base": "", - "gram.verb.sell.gerund": "", - "gram.verb.sell.past": "", - "gram.verb.send.base": "", - "gram.verb.send.gerund": "", - "gram.verb.send.past": "", - "gram.verb.set.base": "", - "gram.verb.set.gerund": "", - "gram.verb.set.past": "", - "gram.verb.shut.base": "", - "gram.verb.shut.gerund": "", - "gram.verb.shut.past": "", - "gram.verb.sit.base": "", - "gram.verb.sit.gerund": "", - "gram.verb.sit.past": "", - "gram.verb.spend.base": "", - "gram.verb.spend.gerund": "", - "gram.verb.spend.past": "", - "gram.verb.split.base": "", - "gram.verb.split.gerund": "", - "gram.verb.split.past": "", - "gram.verb.stop.base": "", - "gram.verb.stop.gerund": "", - "gram.verb.stop.past": "", - "gram.verb.take.base": "", - "gram.verb.take.gerund": "", - "gram.verb.take.past": "", - "gram.verb.think.base": "", - "gram.verb.think.gerund": "", - "gram.verb.think.past": "", - "gram.verb.update.base": "", - "gram.verb.update.gerund": "", - "gram.verb.update.past": "", - "gram.verb.win.base": "", - "gram.verb.win.gerund": "", - "gram.verb.win.past": "", - "gram.verb.write.base": "", - "gram.verb.write.gerund": "", - "gram.verb.write.past": "", - "gram.word.api": "", - "gram.word.app_url": "", - "gram.word.blocked_by": "", - "gram.word.cgo": "", - "gram.word.ci": "", - "gram.word.claimed_by": "", - "gram.word.coverage": "", - "gram.word.cpus": "", - "gram.word.dry_run": "", - "gram.word.failed": "", - "gram.word.filter": "", - "gram.word.go_mod": "", - "gram.word.html": "", - "gram.word.id": "", - "gram.word.ok": "", - "gram.word.package": "", - "gram.word.passed": "", - "gram.word.php": "", - "gram.word.pid": "", - "gram.word.pnpm": "", - "gram.word.pr": "", - "gram.word.qa": "", - "gram.word.related_files": "", - "gram.word.sdk": "", - "gram.word.skipped": "", - "gram.word.ssh": "", - "gram.word.ssl": "", - "gram.word.test": "", - "gram.word.up_to_date": "", - "gram.word.url": "", - "gram.word.vite": "", - "lang.de": "", - "lang.en": "", - "lang.es": "", - "lang.fr": "", - "lang.zh": "", - "prompt.confirm": "", - "prompt.continue": "", - "prompt.discard": "", - "prompt.no": "", - "prompt.overwrite": "", - "prompt.proceed": "", - "prompt.yes": "", - "time.ago.day.one": "", - "time.ago.day.other": "", - "time.ago.hour.one": "", - "time.ago.hour.other": "", - "time.ago.minute.one": "", - "time.ago.minute.other": "", - "time.ago.second.one": "", - "time.ago.second.other": "", - "time.ago.week.one": "", - "time.ago.week.other": "", - "time.just_now": "" + "gram": { + "verb": { + "be": { "base": "быть", "past": "был", "gerund": "бытие" }, + "go": { "base": "идти", "past": "пошёл", "gerund": "переход" }, + "do": { "base": "делать", "past": "сделал", "gerund": "выполнение" }, + "have": { "base": "иметь", "past": "имел", "gerund": "наличие" }, + "make": { "base": "создать", "past": "создал", "gerund": "создание" }, + "get": { "base": "получить", "past": "получил", "gerund": "получение" }, + "run": { "base": "запустить", "past": "запустил", "gerund": "запуск" }, + "write": { "base": "записать", "past": "записал", "gerund": "запись" }, + "build": { "base": "собрать", "past": "собрал", "gerund": "сборка" }, + "send": { "base": "отправить", "past": "отправил", "gerund": "отправка" }, + "find": { "base": "найти", "past": "нашёл", "gerund": "поиск" }, + "take": { "base": "взять", "past": "взял", "gerund": "получение" }, + "begin": { "base": "начать", "past": "начал", "gerund": "начало" }, + "keep": { "base": "сохранить", "past": "сохранил", "gerund": "сохранение" }, + "hold": { "base": "удерживать", "past": "удержал", "gerund": "удержание" }, + "bring": { "base": "принести", "past": "принёс", "gerund": "доставка" }, + "think": { "base": "думать", "past": "думал", "gerund": "обдумывание" }, + "choose": { "base": "выбрать", "past": "выбрал", "gerund": "выбор" }, + "lose": { "base": "потерять", "past": "потерял", "gerund": "потеря" }, + "win": { "base": "победить", "past": "победил", "gerund": "победа" }, + "meet": { "base": "встретить", "past": "встретил", "gerund": "встреча" }, + "lead": { "base": "вести", "past": "вёл", "gerund": "ведение" }, + "leave": { "base": "покинуть", "past": "покинул", "gerund": "выход" }, + "spend": { "base": "потратить", "past": "потратил", "gerund": "расход" }, + "pay": { "base": "оплатить", "past": "оплатил", "gerund": "оплата" }, + "commit": { "base": "коммитить", "past": "закоммитил", "gerund": "коммит" }, + "stop": { "base": "остановить", "past": "остановил", "gerund": "остановка" }, + "scan": { "base": "сканировать", "past": "просканировал", "gerund": "сканирование" }, + "format": { "base": "форматировать", "past": "отформатировал", "gerund": "форматирование" }, + "set": { "base": "установить", "past": "установил", "gerund": "установка" }, + "check": { "base": "проверить", "past": "проверил", "gerund": "проверка" }, + "create": { "base": "создать", "past": "создал", "gerund": "создание" }, + "delete": { "base": "удалить", "past": "удалил", "gerund": "удаление" }, + "install": { "base": "установить", "past": "установил", "gerund": "установка" }, + "update": { "base": "обновить", "past": "обновил", "gerund": "обновление" }, + "pull": { "base": "загрузить", "past": "загрузил", "gerund": "загрузка" }, + "push": { "base": "отправить", "past": "отправил", "gerund": "отправка" }, + "save": { "base": "сохранить", "past": "сохранил", "gerund": "сохранение" }, + "analyse": { "base": "анализировать", "past": "проанализировал", "gerund": "анализ" }, + "organise": { "base": "организовать", "past": "организовал", "gerund": "организация" }, + "test": { "base": "тестировать", "past": "протестировал", "gerund": "тестирование" }, + "deploy": { "base": "развернуть", "past": "развернул", "gerund": "развёртывание" }, + "clone": { "base": "клонировать", "past": "клонировал", "gerund": "клонирование" }, + "compile": { "base": "компилировать", "past": "скомпилировал", "gerund": "компиляция" }, + "download": { "base": "скачать", "past": "скачал", "gerund": "загрузка" }, + "upload": { "base": "загрузить", "past": "загрузил", "gerund": "выгрузка" } + }, + "noun": { + "file": { "one": "файл", "other": "файлы", "gender": "masculine" }, + "repo": { "one": "репозиторий", "other": "репозитории", "gender": "masculine" }, + "repository": { "one": "репозиторий", "other": "репозитории", "gender": "masculine" }, + "commit": { "one": "коммит", "other": "коммиты", "gender": "masculine" }, + "branch": { "one": "ветка", "other": "ветки", "gender": "feminine" }, + "change": { "one": "изменение", "other": "изменения", "gender": "neuter" }, + "item": { "one": "элемент", "other": "элементы", "gender": "masculine" }, + "issue": { "one": "проблема", "other": "проблемы", "gender": "feminine" }, + "task": { "one": "задача", "other": "задачи", "gender": "feminine" }, + "person": { "one": "человек", "other": "люди", "gender": "masculine" }, + "child": { "one": "дочерний", "other": "дочерние", "gender": "masculine" }, + "package": { "one": "пакет", "other": "пакеты", "gender": "masculine" }, + "artifact": { "one": "артефакт", "other": "артефакты", "gender": "masculine" }, + "vulnerability": { "one": "уязвимость", "other": "уязвимости", "gender": "feminine" }, + "dependency": { "one": "зависимость", "other": "зависимости", "gender": "feminine" }, + "directory": { "one": "директория", "other": "директории", "gender": "feminine" }, + "category": { "one": "категория", "other": "категории", "gender": "feminine" }, + "query": { "one": "запрос", "other": "запросы", "gender": "masculine" }, + "check": { "one": "проверка", "other": "проверки", "gender": "feminine" }, + "test": { "one": "тест", "other": "тесты", "gender": "masculine" }, + "error": { "one": "ошибка", "other": "ошибки", "gender": "feminine" }, + "warning": { "one": "предупреждение", "other": "предупреждения", "gender": "neuter" }, + "service": { "one": "сервис", "other": "сервисы", "gender": "masculine" }, + "config": { "one": "конфигурация", "other": "конфигурации", "gender": "feminine" }, + "workflow": { "one": "процесс", "other": "процессы", "gender": "masculine" } + }, + "article": { + "indefinite": { "default": "", "vowel": "" }, + "definite": "" + }, + "word": { + "url": "URL", "id": "ID", "ok": "OK", "ci": "CI", "qa": "QA", + "php": "PHP", "sdk": "SDK", "html": "HTML", "cgo": "CGO", "pid": "PID", + "cpus": "ЦПУ", "ssh": "SSH", "ssl": "SSL", "api": "API", "pr": "PR", + "vite": "Vite", "pnpm": "pnpm", + "app_url": "URL приложения", "blocked_by": "заблокировано", + "claimed_by": "назначено", "related_files": "связанные файлы", + "up_to_date": "актуально", "dry_run": "пробный запуск", + "go_mod": "go.mod", "coverage": "покрытие", "failed": "не пройдено", + "filter": "фильтр", "package": "пакет", "passed": "пройдено", + "skipped": "пропущено", "test": "тест" + }, + "punct": { + "label": ":", + "progress": "..." + }, + "number": { + "thousands": " ", + "decimal": ",", + "percent": "%s%%" + } + }, + + "cli.aborted": "Прервано.", + "cli.fail": "ОШИБКА", + "cli.pass": "ОК", + + "lang": { + "de": "Немецкий", "en": "Английский", "es": "Испанский", + "fr": "Французский", "ru": "Русский", "zh": "Китайский" + }, + + "prompt": { + "yes": "д", "no": "н", + "continue": "Продолжить?", "proceed": "Выполнить?", + "confirm": "Вы уверены?", "overwrite": "Перезаписать?", + "discard": "Отменить изменения?" + }, + + "time": { + "just_now": "только что", + "ago": { + "second": { "one": "{{.Count}} секунду назад", "few": "{{.Count}} секунды назад", "many": "{{.Count}} секунд назад", "other": "{{.Count}} секунд назад" }, + "minute": { "one": "{{.Count}} минуту назад", "few": "{{.Count}} минуты назад", "many": "{{.Count}} минут назад", "other": "{{.Count}} минут назад" }, + "hour": { "one": "{{.Count}} час назад", "few": "{{.Count}} часа назад", "many": "{{.Count}} часов назад", "other": "{{.Count}} часов назад" }, + "day": { "one": "{{.Count}} день назад", "few": "{{.Count}} дня назад", "many": "{{.Count}} дней назад", "other": "{{.Count}} дней назад" }, + "week": { "one": "{{.Count}} неделю назад", "few": "{{.Count}} недели назад", "many": "{{.Count}} недель назад", "other": "{{.Count}} недель назад" } + } + }, + + "error.gh_not_found": "CLI 'gh' не найден. Установите: https://cli.github.com/", + "error.registry_not_found": "Файл repos.yaml не найден", + "error.repo_not_found": "Репозиторий '{{.Name}}' не найден", + + "common.label.done": "Готово", + "common.label.error": "Ошибка", + "common.label.info": "Инфо", + "common.label.success": "Успешно", + "common.label.warning": "Внимание", + "common.status.clean": "чисто", + "common.status.dirty": "изменено", + "common.status.running": "Работает", + "common.status.stopped": "Остановлено", + "common.status.up_to_date": "актуально", + "common.result.all_passed": "Все тесты пройдены", + "common.result.no_issues": "Проблем не найдено", + "common.prompt.abort": "Прервано.", + "common.success.completed": "{{.Action}} выполнено успешно" } diff --git a/pkg/i18n/locales/zh_CN.json b/pkg/i18n/locales/zh_CN.json index 0967ef42..eb246a23 100644 --- a/pkg/i18n/locales/zh_CN.json +++ b/pkg/i18n/locales/zh_CN.json @@ -1 +1,148 @@ -{} +{ + "gram": { + "verb": { + "be": { "base": "是", "past": "是", "gerund": "状态" }, + "go": { "base": "前往", "past": "前往", "gerund": "前往" }, + "do": { "base": "执行", "past": "执行", "gerund": "执行" }, + "have": { "base": "拥有", "past": "拥有", "gerund": "拥有" }, + "make": { "base": "创建", "past": "创建", "gerund": "创建" }, + "get": { "base": "获取", "past": "获取", "gerund": "获取" }, + "run": { "base": "运行", "past": "运行", "gerund": "运行" }, + "write": { "base": "写入", "past": "写入", "gerund": "写入" }, + "build": { "base": "构建", "past": "构建", "gerund": "构建" }, + "send": { "base": "发送", "past": "发送", "gerund": "发送" }, + "find": { "base": "查找", "past": "查找", "gerund": "查找" }, + "take": { "base": "获取", "past": "获取", "gerund": "获取" }, + "begin": { "base": "开始", "past": "开始", "gerund": "开始" }, + "keep": { "base": "保持", "past": "保持", "gerund": "保持" }, + "hold": { "base": "持有", "past": "持有", "gerund": "持有" }, + "bring": { "base": "带来", "past": "带来", "gerund": "带来" }, + "think": { "base": "思考", "past": "思考", "gerund": "思考" }, + "choose": { "base": "选择", "past": "选择", "gerund": "选择" }, + "lose": { "base": "丢失", "past": "丢失", "gerund": "丢失" }, + "win": { "base": "成功", "past": "成功", "gerund": "成功" }, + "meet": { "base": "匹配", "past": "匹配", "gerund": "匹配" }, + "lead": { "base": "引导", "past": "引导", "gerund": "引导" }, + "leave": { "base": "离开", "past": "离开", "gerund": "离开" }, + "commit": { "base": "提交", "past": "提交", "gerund": "提交" }, + "stop": { "base": "停止", "past": "停止", "gerund": "停止" }, + "scan": { "base": "扫描", "past": "扫描", "gerund": "扫描" }, + "format": { "base": "格式化", "past": "格式化", "gerund": "格式化" }, + "set": { "base": "设置", "past": "设置", "gerund": "设置" }, + "check": { "base": "检查", "past": "检查", "gerund": "检查" }, + "create": { "base": "创建", "past": "创建", "gerund": "创建" }, + "delete": { "base": "删除", "past": "删除", "gerund": "删除" }, + "install": { "base": "安装", "past": "安装", "gerund": "安装" }, + "update": { "base": "更新", "past": "更新", "gerund": "更新" }, + "pull": { "base": "拉取", "past": "拉取", "gerund": "拉取" }, + "push": { "base": "推送", "past": "推送", "gerund": "推送" }, + "save": { "base": "保存", "past": "保存", "gerund": "保存" }, + "analyse": { "base": "分析", "past": "分析", "gerund": "分析" }, + "organise": { "base": "整理", "past": "整理", "gerund": "整理" }, + "test": { "base": "测试", "past": "测试", "gerund": "测试" }, + "deploy": { "base": "部署", "past": "部署", "gerund": "部署" }, + "clone": { "base": "克隆", "past": "克隆", "gerund": "克隆" }, + "compile": { "base": "编译", "past": "编译", "gerund": "编译" }, + "download": { "base": "下载", "past": "下载", "gerund": "下载" }, + "upload": { "base": "上传", "past": "上传", "gerund": "上传" } + }, + "noun": { + "file": { "one": "文件", "other": "文件" }, + "repo": { "one": "仓库", "other": "仓库" }, + "repository": { "one": "仓库", "other": "仓库" }, + "commit": { "one": "提交", "other": "提交" }, + "branch": { "one": "分支", "other": "分支" }, + "change": { "one": "更改", "other": "更改" }, + "item": { "one": "项", "other": "项" }, + "issue": { "one": "问题", "other": "问题" }, + "task": { "one": "任务", "other": "任务" }, + "person": { "one": "人", "other": "人" }, + "child": { "one": "子项", "other": "子项" }, + "package": { "one": "包", "other": "包" }, + "artifact": { "one": "构件", "other": "构件" }, + "vulnerability": { "one": "漏洞", "other": "漏洞" }, + "dependency": { "one": "依赖", "other": "依赖" }, + "directory": { "one": "目录", "other": "目录" }, + "category": { "one": "分类", "other": "分类" }, + "query": { "one": "查询", "other": "查询" }, + "check": { "one": "检查", "other": "检查" }, + "test": { "one": "测试", "other": "测试" }, + "error": { "one": "错误", "other": "错误" }, + "warning": { "one": "警告", "other": "警告" }, + "service": { "one": "服务", "other": "服务" }, + "config": { "one": "配置", "other": "配置" }, + "workflow": { "one": "工作流", "other": "工作流" } + }, + "article": { + "indefinite": { "default": "", "vowel": "" }, + "definite": "" + }, + "word": { + "url": "URL", "id": "ID", "ok": "OK", "ci": "CI", "qa": "QA", + "php": "PHP", "sdk": "SDK", "html": "HTML", "cgo": "CGO", "pid": "PID", + "cpus": "CPU", "ssh": "SSH", "ssl": "SSL", "api": "API", "pr": "PR", + "vite": "Vite", "pnpm": "pnpm", + "app_url": "应用 URL", "blocked_by": "被阻塞", + "claimed_by": "已认领", "related_files": "相关文件", + "up_to_date": "已是最新", "dry_run": "模拟运行", + "go_mod": "go.mod", "coverage": "覆盖率", "failed": "失败", + "filter": "过滤器", "package": "包", "passed": "通过", + "skipped": "跳过", "test": "测试" + }, + "punct": { + "label": ":", + "progress": "..." + }, + "number": { + "thousands": ",", + "decimal": ".", + "percent": "%s%%" + } + }, + + "cli.aborted": "已中止。", + "cli.fail": "失败", + "cli.pass": "通过", + + "lang": { + "de": "德语", "en": "英语", "es": "西班牙语", + "fr": "法语", "ru": "俄语", "zh": "中文" + }, + + "prompt": { + "yes": "是", "no": "否", + "continue": "继续?", "proceed": "执行?", + "confirm": "确定吗?", "overwrite": "覆盖?", + "discard": "放弃更改?" + }, + + "time": { + "just_now": "刚刚", + "ago": { + "second": { "other": "{{.Count}} 秒前" }, + "minute": { "other": "{{.Count}} 分钟前" }, + "hour": { "other": "{{.Count}} 小时前" }, + "day": { "other": "{{.Count}} 天前" }, + "week": { "other": "{{.Count}} 周前" } + } + }, + + "error.gh_not_found": "未找到 'gh' CLI 工具。请安装:https://cli.github.com/", + "error.registry_not_found": "未找到 repos.yaml", + "error.repo_not_found": "未找到仓库 '{{.Name}}'", + + "common.label.done": "完成", + "common.label.error": "错误", + "common.label.info": "信息", + "common.label.success": "成功", + "common.label.warning": "警告", + "common.status.clean": "干净", + "common.status.dirty": "已修改", + "common.status.running": "运行中", + "common.status.stopped": "已停止", + "common.status.up_to_date": "已是最新", + "common.result.all_passed": "所有测试通过", + "common.result.no_issues": "未发现问题", + "common.prompt.abort": "已中止。", + "common.success.completed": "{{.Action}} 成功完成" +} diff --git a/scripts/setup-ubuntu.sh b/scripts/setup-ubuntu.sh index 368217e6..0ae13f0b 100755 --- a/scripts/setup-ubuntu.sh +++ b/scripts/setup-ubuntu.sh @@ -201,7 +201,7 @@ else # Install from releases ARCH=$(dpkg --print-architecture) - CORE_URL="https://github.com/host-uk/core/releases/latest/download/core-linux-${ARCH}" + CORE_URL="https://forge.lthn.ai/core/cli/releases/latest/download/core-linux-${ARCH}" curl -fsSL "$CORE_URL" -o /tmp/core chmod +x /tmp/core @@ -220,7 +220,7 @@ if [[ -z "${SKIP_GUI:-}" ]]; then log_info "Installing core-ide..." ARCH=$(dpkg --print-architecture) - IDE_URL="https://github.com/host-uk/core/releases/latest/download/core-ide-linux-${ARCH}.deb" + IDE_URL="https://forge.lthn.ai/core/cli/releases/latest/download/core-ide-linux-${ARCH}.deb" curl -fsSL "$IDE_URL" -o /tmp/core-ide.deb sudo dpkg -i /tmp/core-ide.deb || sudo apt-get install -f -y diff --git a/tasks/plans/2026-01-29-code-signing-impl.md b/tasks/plans/2026-01-29-code-signing-impl.md index 8f6f40c6..4345c348 100644 --- a/tasks/plans/2026-01-29-code-signing-impl.md +++ b/tasks/plans/2026-01-29-code-signing-impl.md @@ -491,7 +491,7 @@ In `pkg/build/config.go`, add to the `BuildConfig` struct: ```go // Add import -import "github.com/host-uk/core/pkg/build/signing" +import "forge.lthn.ai/core/cli/pkg/build/signing" // Add to BuildConfig struct after Targets field: // Sign contains code signing configuration. @@ -590,7 +590,7 @@ import ( "fmt" "runtime" - "github.com/host-uk/core/pkg/build" + "forge.lthn.ai/core/cli/pkg/build" ) // SignBinaries signs macOS binaries in the artifacts list. @@ -727,7 +727,7 @@ buildCmd.Action(func() error { Add to imports: ```go - "github.com/host-uk/core/pkg/build/signing" + "forge.lthn.ai/core/cli/pkg/build/signing" ``` **Step 4: Add signing after build, before archive** @@ -820,7 +820,7 @@ import ( "runtime" "testing" - "github.com/host-uk/core/pkg/build" + "forge.lthn.ai/core/cli/pkg/build" ) func TestSignBinaries_Good_SkipsNonDarwin(t *testing.T) { diff --git a/tasks/plans/2026-01-29-core-devops-impl.md b/tasks/plans/2026-01-29-core-devops-impl.md index e1b08d0c..e368bf93 100644 --- a/tasks/plans/2026-01-29-core-devops-impl.md +++ b/tasks/plans/2026-01-29-core-devops-impl.md @@ -19,17 +19,17 @@ **Step 1: Create go.mod** ```go -module github.com/host-uk/core/pkg/devops +module forge.lthn.ai/core/cli/pkg/devops go 1.25 require ( - github.com/host-uk/core/pkg/container v0.0.0 + forge.lthn.ai/core/cli/pkg/container v0.0.0 golang.org/x/crypto v0.32.0 gopkg.in/yaml.v3 v3.0.1 ) -replace github.com/host-uk/core/pkg/container => ../container +replace forge.lthn.ai/core/cli/pkg/container => ../container ``` **Step 2: Create devops.go with core types** @@ -45,7 +45,7 @@ import ( "path/filepath" "runtime" - "github.com/host-uk/core/pkg/container" + "forge.lthn.ai/core/cli/pkg/container" ) // DevOps manages the portable development environment. @@ -744,7 +744,7 @@ import ( "path/filepath" "time" - "github.com/host-uk/core/pkg/devops/sources" + "forge.lthn.ai/core/cli/pkg/devops/sources" ) // ImageManager handles image downloads and updates. @@ -1786,7 +1786,7 @@ import ( "strings" "github.com/charmbracelet/lipgloss" - "github.com/host-uk/core/pkg/devops" + "forge.lthn.ai/core/cli/pkg/devops" "github.com/leaanthony/clir" ) diff --git a/tasks/plans/2026-01-29-sdk-generation-impl.md b/tasks/plans/2026-01-29-sdk-generation-impl.md index 8e263f0c..734ed024 100644 --- a/tasks/plans/2026-01-29-sdk-generation-impl.md +++ b/tasks/plans/2026-01-29-sdk-generation-impl.md @@ -19,7 +19,7 @@ **Step 1: Create go.mod for sdk package** ```go -module github.com/host-uk/core/pkg/sdk +module forge.lthn.ai/core/cli/pkg/sdk go 1.25 @@ -1390,7 +1390,7 @@ Co-Authored-By: Claude Opus 4.5 " // Add to sdk.go, replacing the stub Generate method import ( - "github.com/host-uk/core/pkg/sdk/generators" + "forge.lthn.ai/core/cli/pkg/sdk/generators" ) // Generate generates SDKs for all configured languages. @@ -1494,7 +1494,7 @@ import ( "os" "github.com/charmbracelet/lipgloss" - "github.com/host-uk/core/pkg/sdk" + "forge.lthn.ai/core/cli/pkg/sdk" "github.com/leaanthony/clir" ) diff --git a/tasks/plans/2026-01-29-sdk-release-impl.md b/tasks/plans/2026-01-29-sdk-release-impl.md index 78d26e15..170541da 100644 --- a/tasks/plans/2026-01-29-sdk-release-impl.md +++ b/tasks/plans/2026-01-29-sdk-release-impl.md @@ -108,7 +108,7 @@ import ( "context" "fmt" - "github.com/host-uk/core/pkg/sdk" + "forge.lthn.ai/core/cli/pkg/sdk" ) // SDKRelease holds the result of an SDK release.