diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000..e9909896 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,3 @@ +# Every request must be reviewed and accepted by: + +* @VeryGoodOpenSource/codeowners diff --git a/.github/ISSUE_TEMPLATE/ config.yml b/.github/ISSUE_TEMPLATE/config.yml similarity index 100% rename from .github/ISSUE_TEMPLATE/ config.yml rename to .github/ISSUE_TEMPLATE/config.yml diff --git a/.github/cspell.json b/.github/cspell.json index 507a9e06..fc3dbc52 100644 --- a/.github/cspell.json +++ b/.github/cspell.json @@ -25,6 +25,7 @@ "frontmatter", "gemini", "kevmoo", + "lycheeignore", "mcp", "opencode", "prereqs", diff --git a/.github/workflows/check_links.yaml b/.github/workflows/check_links.yaml new file mode 100644 index 00000000..9e0b956b --- /dev/null +++ b/.github/workflows/check_links.yaml @@ -0,0 +1,30 @@ +name: check_links + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +on: + push: + branches: + - main + pull_request: + branches: + - main + schedule: + # Runs every Monday at 08:00 UTC + - cron: "0 8 * * 1" + +jobs: + check_links: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + + - name: šŸ”— Link Checker + uses: lycheeverse/lychee-action@v2 + with: + # The repository is private, so GitHub links need a token to resolve. + token: ${{ secrets.GITHUB_TOKEN }} + args: ./**/*.md + fail: true diff --git a/.github/workflows/pub_publish.yaml b/.github/workflows/pub_publish.yaml new file mode 100644 index 00000000..a37037f5 --- /dev/null +++ b/.github/workflows/pub_publish.yaml @@ -0,0 +1,35 @@ +name: pub_publish + +on: + push: + tags: + - "v[0-9]+.[0-9]+.[0-9]+*" # tag pattern on pub.dev: 'v{{version}}' + workflow_dispatch: + +jobs: + publish: + permissions: + id-token: write # Required for authentication using OIDC + runs-on: ubuntu-latest + + steps: + - name: šŸ“š Git Checkout + uses: actions/checkout@v7 + + - name: šŸŽÆ Setup Dart + uses: dart-lang/setup-dart@v1.8.1 + with: + sdk: "3.13.0" + + - name: šŸ“¦ Install Dependencies + run: dart pub get + + # plugin_source first: the CLI resolves it from pub.dev, so publishing + # the CLI against a version that is not there yet fails. + - name: šŸ“¢ Publish plugin_source + working-directory: packages/plugin_source + run: dart pub publish --force + + - name: šŸ“¢ Publish vgv_ai_cli + working-directory: packages/vgv_ai_cli + run: dart pub publish --force diff --git a/.github/workflows/release_please.yaml b/.github/workflows/release_please.yaml new file mode 100644 index 00000000..dfca753d --- /dev/null +++ b/.github/workflows/release_please.yaml @@ -0,0 +1,26 @@ +name: release_please + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +on: + workflow_dispatch: + push: + branches: + - main + +permissions: + contents: read + +jobs: + release_please: + runs-on: ubuntu-latest + + steps: + - name: šŸš€ Release Please + uses: googleapis/release-please-action@v5 + with: + token: ${{ secrets.RELEASE_PLEASE_TOKEN }} + manifest-file: ".release-please-manifest.json" + config-file: ".release-please-config.json" diff --git a/.github/workflows/vgv_ai_cli.yaml b/.github/workflows/vgv_ai_cli.yaml index 47cc2b5a..5f474cf7 100644 --- a/.github/workflows/vgv_ai_cli.yaml +++ b/.github/workflows/vgv_ai_cli.yaml @@ -80,26 +80,6 @@ jobs: exit 1 fi - verify-version: - runs-on: ubuntu-latest - steps: - - name: šŸ“š Git Checkout - uses: actions/checkout@v7 - - - name: šŸŽÆ Setup Dart - uses: dart-lang/setup-dart@v1.8.1 - with: - sdk: "3.13.0" - - - name: šŸ“¦ Install Dependencies - working-directory: packages/vgv_ai_cli - run: | - dart pub get - - - name: šŸ”Ž Verify version - working-directory: packages/vgv_ai_cli - run: dart run test --run-skipped -t version-verify - verify-pins: runs-on: ubuntu-latest steps: diff --git a/.gitignore b/.gitignore index 120d6c29..df2bf651 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,7 @@ coverage/ docs/ tasks/ + +# Mason +.mason/ +mason-lock.json diff --git a/.lycheeignore b/.lycheeignore new file mode 100644 index 00000000..36eb3f2b --- /dev/null +++ b/.lycheeignore @@ -0,0 +1,8 @@ +# Lychee ignore patterns +# See https://github.com/lycheeverse/lychee for documentation + +# Dart string interpolation quoted in docs, picked up as literal link text +\$\{ + +# Private sibling repositories the workflow token cannot read +^https://github\.com/VeryGoodOpenSource/vgv-wingspan diff --git a/.release-please-config.json b/.release-please-config.json new file mode 100644 index 00000000..427a5535 --- /dev/null +++ b/.release-please-config.json @@ -0,0 +1,34 @@ +{ + "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", + "changelog-sections": [ + { "type": "feat", "section": "Features" }, + { "type": "fix", "section": "Bug Fixes" }, + { "type": "refactor", "section": "Refactors" }, + { "type": "chore", "section": "Miscellaneous Chores" }, + { "type": "docs", "section": "Docs" } + ], + "pull-request-header": ":rotating_light: There are changes ready for release :rocket:\n\nℹ Merge this PR once the team confirms the release is ready.\n", + "group-pull-request-title-pattern": "chore: release ${branch}", + "include-component-in-tag": true, + "packages": { + "packages/vgv_ai_cli": { + "release-type": "dart", + "component": "vgv_ai_cli", + "changelog-path": "CHANGELOG.md", + "include-component-in-tag": false, + "extra-files": ["pubspec.yaml", "lib/src/version.dart"] + }, + "packages/plugin_source": { + "release-type": "dart", + "component": "plugin_source", + "changelog-path": "CHANGELOG.md" + } + }, + "plugins": [ + { + "type": "linked-versions", + "groupName": "vgv_ai", + "components": ["vgv_ai_cli", "plugin_source"] + } + ] +} diff --git a/.release-please-manifest.json b/.release-please-manifest.json new file mode 100644 index 00000000..a768163b --- /dev/null +++ b/.release-please-manifest.json @@ -0,0 +1,4 @@ +{ + "packages/vgv_ai_cli": "0.1.0", + "packages/plugin_source": "0.1.0" +} diff --git a/AGENTS.md b/AGENTS.md index d346f256..047948df 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -51,17 +51,11 @@ dart run test test/src/commands/update_command_test.dart # 'handles pub update errors' and 'handles pub update process errors') dart run test --plain-name 'handles pub update' -# Verify the generated version file is in sync (tagged, skipped by default) -dart run test --run-skipped -t version-verify - -# Regenerate lib/src/version.dart after bumping the package version -dart run build_runner build - # Run the CLI from source dart run bin/vgv_ai.dart --help ``` -**Full test run with coverage** is the one exception. With the VGV AI Flutter Plugin active, a hook denies `dart test`, `flutter test`, `very_good test`, `dart create`, `flutter create`, `very_good create`, and `very_good packages` when they are the first two tokens of a Bash command (note `very_good packages get` is blocked while `dart pub get` is not), so run it through the `very_good_cli` MCP `test` tool instead. That tool takes no file path and no name filter, which is why the single-test commands above use `dart run test` — a form the hook does not catch, and the one CI itself uses for `verify-version`. The CI step, from the reusable `dart_package.yml` workflow, is equivalent to: +**Full test run with coverage** is the one exception. With the VGV AI Flutter Plugin active, a hook denies `dart test`, `flutter test`, `very_good test`, `dart create`, `flutter create`, `very_good create`, and `very_good packages` when they are the first two tokens of a Bash command (note `very_good packages get` is blocked while `dart pub get` is not), so run it through the `very_good_cli` MCP `test` tool instead. That tool takes no file path and no name filter, which is why the single-test commands above use `dart run test` — a form the hook does not catch,. The CI step, from the reusable `dart_package.yml` workflow, is equivalent to: ```bash very_good dart test -j 4 --coverage --min-coverage 100 --optimization @@ -116,7 +110,11 @@ A result with one status enum, such as `EntryHealth` or `ReversedEntry`, is buil ### Generated version file -`lib/src/version.dart` is generated by `build_version` from the `version:` field in `pubspec.yaml`. **Never edit it by hand** — regenerate with `build_runner` after bumping the version. `test/ensure_build_test.dart` verifies it is in sync; it is tagged `version-verify` and skipped by default (see `dart_test.yaml`). +`lib/src/version.dart` carries the version release-please writes. **Never edit it by hand**, and never bump a version by hand either. + +Both packages release together. release-please bumps each package's own `pubspec.yaml`, and the `linked-versions` plugin holds them at the same version, so a fix in `plugin_source` releases the CLI too — which is how a pin bump reaches users. Two lines need the generic updater and carry an `x-release-please-version` marker: this file, and the `plugin_source:` constraint in the CLI's `pubspec.yaml`. Nothing else should ever get that marker. + +The CLI is tagged `vX.Y.Z` and `plugin_source` as `plugin_source-vX.Y.Z`; `pub_publish.yaml` fires on the former. ## Code Conventions @@ -147,7 +145,7 @@ This is a pure Dart CLI with no widgets, so the rule is: any skill gated on Flut Each workflow under `.github/workflows/` is path-filtered, and every reusable workflow comes from very_good_workflows through the floating `@v2` tag. -- `vgv_ai_cli.yaml` runs on changes to itself, `.github/cspell.json`, `packages/vgv_ai_cli/lib/**`, `packages/vgv_ai_cli/test/**`, `packages/vgv_ai_cli/pubspec.yaml`, `packages/plugin_source/lib/**`, `packages/plugin_source/pubspec.yaml`, `bricks/**` and `tool/**`. Its jobs are `semantic-pull-request`, `build` (the reusable `dart_package.yml` in `packages/vgv_ai_cli`), `spell-check`, `verify-bundle`, `verify-version` and `verify-pins`. +- `vgv_ai_cli.yaml` runs on changes to itself, `.github/cspell.json`, `packages/vgv_ai_cli/lib/**`, `packages/vgv_ai_cli/test/**`, `packages/vgv_ai_cli/pubspec.yaml`, `packages/plugin_source/lib/**`, `packages/plugin_source/pubspec.yaml`, `bricks/**` and `tool/**`. Its jobs are `semantic-pull-request`, `build` (the reusable `dart_package.yml` in `packages/vgv_ai_cli`), `spell-check`, `verify-bundle` and `verify-pins`. - `plugin_source.yaml` runs on changes to itself and `packages/plugin_source/**`. Its jobs are `semantic-pull-request` and `build` (the reusable `dart_package.yml` in `packages/plugin_source`). - Both `build` jobs also run the cognitive complexity check on their package's `lib`, which fails when any function scores above 15. Split a function that crosses it into smaller ones rather than raising the threshold. Run it locally with the `cognitive_complexity` scanner from [kevmoo/analytica.dart](https://github.com/kevmoo/analytica.dart/tree/main/packages/cognitive_complexity). - `license_check.yaml` runs on changes to itself and either package's `pubspec.yaml`. Dependency licenses are restricted to `MIT`, `BSD-3-Clause`, `BSD-2-Clause`, `Apache-2.0`. diff --git a/packages/plugin_source/LICENSE b/packages/plugin_source/LICENSE index 2c1c5f17..650d32a0 100644 --- a/packages/plugin_source/LICENSE +++ b/packages/plugin_source/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2026 +Copyright (c) 2026 Very Good Ventures Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/packages/plugin_source/pubspec.yaml b/packages/plugin_source/pubspec.yaml index 78428b37..9bb2b8b1 100644 --- a/packages/plugin_source/pubspec.yaml +++ b/packages/plugin_source/pubspec.yaml @@ -3,7 +3,8 @@ description: >- Resolves VGV Claude Code plugins to a directory on disk and parses them into a harness-neutral asset model. version: 0.1.0 -publish_to: none +repository: https://github.com/VeryGoodOpenSource/vgv_ai_cli +issue_tracker: https://github.com/VeryGoodOpenSource/vgv_ai_cli/issues resolution: workspace environment: sdk: ^3.13.0 diff --git a/packages/vgv_ai_cli/LICENSE b/packages/vgv_ai_cli/LICENSE index 2c1c5f17..650d32a0 100644 --- a/packages/vgv_ai_cli/LICENSE +++ b/packages/vgv_ai_cli/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2026 +Copyright (c) 2026 Very Good Ventures Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/packages/vgv_ai_cli/dart_test.yaml b/packages/vgv_ai_cli/dart_test.yaml index 4b64be76..b73075a3 100644 --- a/packages/vgv_ai_cli/dart_test.yaml +++ b/packages/vgv_ai_cli/dart_test.yaml @@ -1,5 +1,3 @@ tags: - version-verify: - skip: "Should only be run during pull request. Verifies if version file is updated." pinned-plugins: skip: "Clones the real pinned plugins over the network. Run in CI by verify-pins." diff --git a/packages/vgv_ai_cli/example/README.md b/packages/vgv_ai_cli/example/README.md new file mode 100644 index 00000000..10207b8d --- /dev/null +++ b/packages/vgv_ai_cli/example/README.md @@ -0,0 +1,3 @@ +# Example + +`vgv_ai` is used from the terminal. See [../README.md](../README.md) for usage. diff --git a/packages/vgv_ai_cli/lib/src/version.dart b/packages/vgv_ai_cli/lib/src/version.dart index 5b6bfb4d..39ea6999 100644 --- a/packages/vgv_ai_cli/lib/src/version.dart +++ b/packages/vgv_ai_cli/lib/src/version.dart @@ -1,2 +1,2 @@ -// Generated code. Do not modify. -const packageVersion = '0.1.0'; +// Managed by release-please. Do not edit by hand. +const packageVersion = '0.1.0'; // x-release-please-version diff --git a/packages/vgv_ai_cli/pubspec.yaml b/packages/vgv_ai_cli/pubspec.yaml index c60d0720..cf4226ee 100644 --- a/packages/vgv_ai_cli/pubspec.yaml +++ b/packages/vgv_ai_cli/pubspec.yaml @@ -1,9 +1,9 @@ name: vgv_ai_cli description: A CLI that configures Very Good AI coding agents and tooling version: 0.1.0 -# Not published. `plugin_source`, which this depends on, is `publish_to: none`, -# and the CLI is installed from source rather than pub.dev. -publish_to: none +repository: https://github.com/VeryGoodOpenSource/vgv_ai_cli +issue_tracker: https://github.com/VeryGoodOpenSource/vgv_ai_cli/issues +topics: [cli, ai, agents, tooling] resolution: workspace environment: sdk: ^3.13.0 @@ -18,15 +18,12 @@ dependencies: mason: ^0.1.0 mason_logger: ^0.3.6 path: ^1.9.1 - plugin_source: ^0.1.0 + plugin_source: ^0.1.0 # x-release-please-version pub_semver: ^2.2.1 pub_updater: ^0.6.0 toml: ^0.18.0 dev_dependencies: - build_runner: ^2.16.2 - build_verify: ^3.1.1 - build_version: ^2.1.3 mocktail: ^1.0.5 test: ^1.33.0 very_good_analysis: ^11.0.0 diff --git a/packages/vgv_ai_cli/test/ensure_build_test.dart b/packages/vgv_ai_cli/test/ensure_build_test.dart deleted file mode 100644 index 510db214..00000000 --- a/packages/vgv_ai_cli/test/ensure_build_test.dart +++ /dev/null @@ -1,12 +0,0 @@ -@Tags(['version-verify', 'skip_very_good_optimization']) -library; - -import 'package:build_verify/build_verify.dart'; -import 'package:test/test.dart'; - -void main() { - test( - 'ensure_build', - () => expectBuildClean(packageRelativeDirectory: 'packages/vgv_ai_cli'), - ); -} diff --git a/pubspec.lock b/pubspec.lock index 12a0bb19..e9835ab2 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -57,70 +57,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.2" - build: - dependency: transitive - description: - name: build - sha256: "8a5c5761af8e31748bba3c82f68925ace40f3225c3eea25be9beb57eca7cd7a8" - url: "https://pub.dev" - source: hosted - version: "4.0.11" - build_config: - dependency: transitive - description: - name: build_config - sha256: d466ed2dc9c6cd1d169948879b84ee061eb5e22c64a7c6089879c6296d272a8d - url: "https://pub.dev" - source: hosted - version: "1.3.3" - build_daemon: - dependency: transitive - description: - name: build_daemon - sha256: "39ab65f7c60c19af64b9ef96e6a5d3ab48355f7dddfd98a9079d55a8cb6628fc" - url: "https://pub.dev" - source: hosted - version: "4.1.7" - build_runner: - dependency: transitive - description: - name: build_runner - sha256: "6feadd32d90a68253c1f7b4fcff76adb4b41ad32a53f8bad835dc65f01ac9dc5" - url: "https://pub.dev" - source: hosted - version: "2.16.2" - build_verify: - dependency: transitive - description: - name: build_verify - sha256: "3b17b59b6d66f9d3e6014996f089902d56cec5760e051c353cc387b9da577652" - url: "https://pub.dev" - source: hosted - version: "3.1.1" - build_version: - dependency: transitive - description: - name: build_version - sha256: "1063066ec338c18f0629d01077c9315f92fae3e7e0e06d0dc10e8aa3145d44f5" - url: "https://pub.dev" - source: hosted - version: "2.1.3" - built_collection: - dependency: transitive - description: - name: built_collection - sha256: "44922ecebd8e3d0cef743dadd3b54df4e87e2a4c52a29465a1872aa9e192caa8" - url: "https://pub.dev" - source: hosted - version: "5.1.2" - built_value: - dependency: transitive - description: - name: built_value - sha256: f87ea98192116f7093cb214551ce1929caae0681fdba282b3d8b4462adee7bb7 - url: "https://pub.dev" - source: hosted - version: "8.13.0" checked_yaml: dependency: transitive description: @@ -185,14 +121,6 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.7" - dart_style: - dependency: transitive - description: - name: dart_style - sha256: "82ade9fc4273f29ed673e33166944465225b4f7fc5d4aaef48605cc751c18fc1" - url: "https://pub.dev" - source: hosted - version: "3.1.13" equatable: dependency: transitive description: @@ -225,14 +153,6 @@ packages: url: "https://pub.dev" source: hosted version: "7.0.1" - fixnum: - dependency: transitive - description: - name: fixnum - sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be - url: "https://pub.dev" - source: hosted - version: "1.1.1" frontend_server_client: dependency: transitive description: @@ -249,14 +169,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.0" - graphs: - dependency: transitive - description: - name: graphs - sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0" - url: "https://pub.dev" - source: hosted - version: "2.3.2" http: dependency: transitive description: @@ -441,14 +353,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.0" - pubspec_parse: - dependency: transitive - description: - name: pubspec_parse - sha256: c38b81cbf34450b67e0265d73433569d12e34782e30ed769c9cc99c9d5f2e796 - url: "https://pub.dev" - source: hosted - version: "1.6.0" shelf: dependency: transitive description: @@ -521,14 +425,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" - stream_transform: - dependency: transitive - description: - name: stream_transform - sha256: a00e5f18bffc764f923e7dec1038527f7fe7a1791361a7117f0358193f13d53a - url: "https://pub.dev" - source: hosted - version: "2.1.2" string_scanner: dependency: transitive description: