Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -288,23 +288,23 @@ Separately from resources, brief reports agent skills the project provides. Thes
<!-- brief:tools:start (generated by: brief list -readme tools) -->
## What it detects

54 language ecosystems with 547 tool definitions across 22 categories.
Language ecosystems and development tools across multiple categories.

**Languages:** Ada, C, C#, C++, COBOL, Clojure, Common Lisp, Crystal, D, Dart, Deno, Elixir, Elm, Emacs Lisp, Erlang, F#, Fortran, GDScript, Gleam, Go, Groovy, Haskell, Haxe, Java, JavaScript, Julia, Kotlin, Lua, Mojo, Nim, Nix, OCaml, Objective-C, Odin, PHP, Perl, Prolog, Python, R, Racket, Roc, Ruby, Rust, Scala, Scheme, Solidity, Swift, Tcl, TypeScript, V, VHDL, Verilog, Zig.

**Package Managers:** Alire, Bun, Bundler, Cabal, Cargo, CocoaPods, Composer, Conan, Conda, DUB, Deno Modules, Flit, Gleam Packages, Go Modules, Gradle, Hatch, Haxelib, Maven, Mix, Nix Flakes, NuGet, PDM, Pipenv, Pkg, Poetry, Quicklisp, Shards, Swift Package Manager, Yarn, cpanm, dotnet CLI, elm, fpm, npm, opam, pip, pnpm, pub, rebar3, sbt, setuptools, uv, vcpkg.
**Package Managers:** Alire, Bun, Bundler, Cabal, Cargo, CocoaPods, Composer, Conan, Conda, DUB, Deno Modules, Flit, Gleam Packages, Go Modules, Gradle, Hatch, Haxelib, Maven, Mix, Nix Flakes, NuGet, PDM, Pipenv, Pkg, Poetry, Quicklisp, Shards, Swift Package Manager, Yarn, cpanm, dotnet CLI, elm, fpm, npm, opam, pip, pnpm, pub, rebar3, renv, sbt, setuptools, uv, vcpkg.

**Test:** AVA, Alcotest, Artillery, Bats, Bruno, Catch2, Cucumber, Cypress, EUnit, ExUnit, Gatling, Ginkgo, Google Test, Hspec, Hurl, JUnit, Jasmine, Jest, Kotest, Lighthouse CI, Locust, MSW, Minitest, Mocha, Newman, PHPUnit, Pest, Playwright, REST Client, RSpec, ScalaTest, Selenium, Testify, Testing Library, Vitest, XCTest, axe-core, benchmark-ips, cargo test, clojure.test, criterion, crystal spec, dart test, deno test, dotnet test, gleam test, go test, hyperfine, k6, kotlin.test, pytest, pytest-benchmark, tape, testament, zig test.
**Test:** ASV, AVA, Alcotest, Artillery, Bats, BenchmarkTools.jl, Bruno, Catch2, Cucumber, Cypress, EUnit, ExUnit, Gatling, Ginkgo, Google Test, Hspec, Hurl, JUnit, Jasmine, Jest, Kotest, Lighthouse CI, Locust, MSW, Minitest, Mocha, Newman, PHPUnit, Pest, Playwright, REST Client, RSpec, ScalaTest, Selenium, Testify, Testing Library, Vitest, XCTest, axe-core, benchmark-ips, cargo test, clojure.test, criterion, crystal spec, dart test, deno test, dotnet test, gleam test, go test, hyperfine, k6, kotlin.test, nf-test, pytest, pytest-benchmark, tape, testament, testthat, tinytest, tox, vdiffr, zig test.

**Lint:** Ameba, Biome, Checkstyle, Clippy, Credo, ESLint, Flake8, HLint, Husky, Lefthook, Overcommit, PHP_CodeSniffer, PMD, Pylint, Revive, Roslyn Analyzers, RuboCop, Ruff, ShellCheck, SpotBugs, Stylelint, SwiftLint, Vale, WartRemover, actionlint, clang-tidy, clj-kondo, commitlint, cspell, dart analyze, deno lint, detekt, elvis, golangci-lint, hadolint, markdownlint, oxlint, pre-commit, typos.
**Lint:** Ameba, Biome, Checkstyle, Clippy, Credo, ESLint, Flake8, Fortitude, HLint, Husky, Lefthook, Overcommit, PHP_CodeSniffer, PMD, Pylint, Revive, Roslyn Analyzers, RuboCop, Ruff, ShellCheck, SpotBugs, Stylelint, SwiftLint, Vale, WartRemover, actionlint, clang-tidy, clj-kondo, commitlint, cspell, dart analyze, deno lint, detekt, elvis, golangci-lint, hadolint, lintr, markdownlint, oxlint, pre-commit, typos.

**Format:** Black, Ormolu, PHP CS Fixer, Prettier, Spotless, StandardRB, SwiftFormat, clang-format, cljfmt, crystal tool format, dart format, deno fmt, dotnet format, dprint, erlfmt, gleam format, gofmt, google-java-format, isort, ktlint, mix format, nimpretty, ocamlformat, rustfmt, scalafmt, yapf, zig fmt.
**Format:** Black, JuliaFormatter, Ormolu, PHP CS Fixer, Prettier, Runic, Spotless, StandardRB, SwiftFormat, clang-format, cljfmt, crystal tool format, dart format, deno fmt, dotnet format, dprint, erlfmt, gleam format, gofmt, google-java-format, isort, ktlint, mix format, nimpretty, ocamlformat, rustfmt, scalafmt, styler, yapf, zig fmt.

**Typecheck:** Dialyxir, Dialyzer, Flow, PHPStan, Pyright, Sorbet, Steep, mypy, tsc.

**Docs:** Docsify, Docusaurus, Dokka, Doxygen, ExDoc, Hugo, Javadoc, Jekyll, MkDocs, Nextra, Read the Docs, Redoc, Sphinx, Starlight, Storybook, Swagger UI, TypeDoc, VitePress, Yard, Zensical, cargo doc, dart doc, deno doc, mdBook, phpDocumentor, pkgsite.
**Docs:** Docsify, Documenter.jl, Docusaurus, Dokka, Doxygen, ExDoc, Hugo, Javadoc, Jekyll, MkDocs, MultiQC, MyST-Parser, Nextra, Quarto, R Markdown, Read the Docs, Redoc, Sphinx, Starlight, Storybook, Swagger UI, TypeDoc, VitePress, Yard, Zensical, cargo doc, dart doc, deno doc, knitr, mdBook, phpDocumentor, pkgdown, pkgsite, roxygen2.

**Build:** Actix Web, AdonisJS, Angular, Astro, Autotools, Axum, CMake, Django, Dune, Echo, Electron, Eleventy, Ember.js, Express, FastAPI, Fastify, Fiber, Flask, Flutter, Foundry, Gatsby, Gin, GoReleaser, Hardhat, Hono, Invoke, Just, Koa, Laravel, Less, Mage, Make, Meson, NestJS, Next.js, Nuxt, Parcel, Phoenix, PostCSS, Qwik, Rails, Rake, React Native, Remix, Rocket, Rollup, Rspack, SWC, Sass, Sinatra, Spin, Spring Boot, Svelte, SvelteKit, Symfony, Task, Tauri, Vite, Vue, Webpack, cross, esbuild, tsup.
**Build:** Actix Web, AdonisJS, Angular, Astro, Autotools, Axum, CMake, Django, Dune, Echo, Electron, Eleventy, Ember.js, Express, FastAPI, Fastify, Fiber, Flask, Flutter, Foundry, Gatsby, Gin, GoReleaser, Hardhat, Hono, Invoke, Just, Koa, Laravel, Less, Mage, Make, Meson, NestJS, Next.js, Nextflow, Nuxt, Parcel, Phoenix, PostCSS, Qwik, Rails, Rake, React Native, Remix, Rocket, Rollup, Rspack, SWC, Sass, Sinatra, Snakemake, Spin, Spring Boot, Svelte, SvelteKit, Symfony, Task, Tauri, Vite, Vue, Webpack, cibuildwheel, cross, esbuild, nf-core, targets, tsup.

**Native Ext:** Maturin, Neon, Rustler, meson-python, mkmf, napi-rs, node-gyp, phpize, rb-sys, setuptools Extension, setuptools-rust.

Expand All @@ -320,17 +320,17 @@ Separately from resources, brief reports agent skills the project provides. Thes

**Container:** Cloud Native Buildpacks, Dev Container, Docker, Docker Compose, Podman.

**Infra:** AWS CDK, Ansible, CloudFormation, Helm, Kubernetes, Kustomize, Packer, Pulumi, Serverless Framework, Terraform, Vagrant.
**Infra:** AWS CDK, Ansible, CloudFormation, DVC, Dockstore, Helm, Kubernetes, Kustomize, Packer, Pulumi, Serverless Framework, Terraform, Vagrant.

**Monorepo:** Bazel, Cargo workspaces, Go workspace, Lerna, Moon, Nx, Pants, Rush, Turborepo, Yarn workspaces, pnpm workspaces.

**Environment:** Flipper, JetBrains IDE, LaunchDarkly, Mise, Pixi, Unleash, VS Code, Volta, asdf, direnv, dotenv, pyenv.
**Environment:** Flipper, JetBrains IDE, Jupyter, LaunchDarkly, Mise, Pixi, Unleash, VS Code, Volta, asdf, direnv, dotenv, pyenv.

**i18n:** Crowdin, Fluent, FormatJS, Lingui, Rails i18n, Transifex, gettext, i18next, vue-i18n.

**Release:** Changesets, cargo-release, conventional-changelog, git-cliff, np, release-please, semantic-release, standard-version, twine.

**Coverage:** Codecov, Coveralls, Excoveralls, JaCoCo, Sentry, SimpleCov, c8, cargo-tarpaulin, coverage.py, go test -cover, nyc.
**Coverage:** Codecov, Coveralls, Excoveralls, JaCoCo, Sentry, SimpleCov, c8, cargo-tarpaulin, coverage.py, covr, go test -cover, nyc.

**Dep Updates:** Dependabot, Git Submodules, Renovate.

Expand Down
51 changes: 51 additions & 0 deletions cmd/brief/list_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package main

import (
"os"
"strings"
"testing"

"github.com/git-pkgs/brief"
"github.com/git-pkgs/brief/kb"
)

func TestWriteToolsReadmeOmitsKnowledgeBaseTotals(t *testing.T) {
var out strings.Builder
writeToolsReadme(&out, &kb.KnowledgeBase{})

const introduction = "Language ecosystems and development tools across multiple categories."
if !strings.Contains(out.String(), introduction) {
t.Errorf("README output does not contain count-free introduction %q", introduction)
}
if strings.Contains(out.String(), "language ecosystems with") {
t.Errorf("README output contains numeric knowledge-base totals: %q", out.String())
}
}

func TestToolsReadmeMatchesGeneratedOutput(t *testing.T) {
knowledgeBase, err := kb.Load(brief.KnowledgeFS)
if err != nil {
t.Fatalf("load knowledge base: %v", err)
}
var generated strings.Builder
writeToolsReadme(&generated, knowledgeBase)

readme, err := os.ReadFile("../../README.md")
if err != nil {
t.Fatalf("read README: %v", err)
}
readmeText := strings.ReplaceAll(string(readme), "\r\n", "\n")
const start = "<!-- brief:tools:start (generated by: brief list -readme tools) -->\n"
const end = "<!-- brief:tools:end -->"
_, afterStart, ok := strings.Cut(readmeText, start)
if !ok {
t.Fatal("README tools start marker is missing")
}
section, _, ok := strings.Cut(afterStart, end)
if !ok {
t.Fatal("README tools end marker is missing")
}
if section != generated.String() {
t.Error("README tools block differs from `brief list -readme tools` output")
}
}
24 changes: 11 additions & 13 deletions cmd/brief/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/json"
"flag"
"fmt"
"io"
"os"
"reflect"
"runtime/debug"
Expand Down Expand Up @@ -232,6 +233,10 @@ func listTools(knowledgeBase *kb.KnowledgeBase) {
}

func listToolsReadme(knowledgeBase *kb.KnowledgeBase) {
writeToolsReadme(os.Stdout, knowledgeBase)
}

func writeToolsReadme(out io.Writer, knowledgeBase *kb.KnowledgeBase) {
// Group tools by category, deduplicating names.
seen := make(map[string]map[string]bool)
byCategory := make(map[string][]string)
Expand All @@ -255,24 +260,17 @@ func listToolsReadme(knowledgeBase *kb.KnowledgeBase) {

languages := byCategory["language"]

ecosystems := knowledgeBase.AllEcosystems()
totalTools := 0
for _, names := range byCategory {
totalTools += len(names)
}

_, _ = fmt.Fprintf(os.Stdout, "## What it detects\n\n")
_, _ = fmt.Fprintf(os.Stdout, "%d language ecosystems with %d tool definitions across %d categories.\n\n",
len(ecosystems), totalTools, len(byCategory))
_, _ = fmt.Fprint(out, "## What it detects\n\n")
_, _ = fmt.Fprint(out, "Language ecosystems and development tools across multiple categories.\n\n")

// Languages
if len(languages) > 0 {
_, _ = fmt.Fprintf(os.Stdout, "**Languages:** %s.\n\n", strings.Join(languages, ", "))
_, _ = fmt.Fprintf(out, "**Languages:** %s.\n\n", strings.Join(languages, ", "))
}

// Package managers
if pms := byCategory["package_manager"]; len(pms) > 0 {
_, _ = fmt.Fprintf(os.Stdout, "**Package Managers:** %s.\n\n", strings.Join(pms, ", "))
_, _ = fmt.Fprintf(out, "**Package Managers:** %s.\n\n", strings.Join(pms, ", "))
}

// Tool categories in display order.
Expand All @@ -285,10 +283,10 @@ func listToolsReadme(knowledgeBase *kb.KnowledgeBase) {
if label == "" {
label = cat
}
_, _ = fmt.Fprintf(os.Stdout, "**%s:** %s.\n\n", label, strings.Join(names, ", "))
_, _ = fmt.Fprintf(out, "**%s:** %s.\n\n", label, strings.Join(names, ", "))
}

_, _ = fmt.Fprintf(os.Stdout, "Run `brief list tools` for the full list.\n")
_, _ = fmt.Fprint(out, "Run `brief list tools` for the full list.\n")
}

func listEcosystems(knowledgeBase *kb.KnowledgeBase) {
Expand Down
12 changes: 11 additions & 1 deletion detect/detect.go
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,12 @@ func (e *Engine) detectCategory(category string) []brief.Detection {
// matchTool checks if a tool definition matches the project.
// Returns the confidence level, or empty string if no match.
func (e *Engine) matchTool(tool *kb.ToolDef) brief.Confidence {
for _, pattern := range tool.Detect.ExcludeFiles {
if e.exists(pattern) {
return ""
}
}

best := brief.Confidence("")

for _, pattern := range tool.Detect.Files {
Expand All @@ -488,7 +494,7 @@ func (e *Engine) matchTool(tool *kb.ToolDef) brief.Confidence {
}

for file, patterns := range tool.Detect.FileContains {
if e.contains(file, patterns) {
if e.contentSignalMatches(file, patterns, tool.Detect.ExcludeFileContains[file]) {
best = brief.ConfidenceHigh
}
}
Expand All @@ -511,6 +517,10 @@ func (e *Engine) matchTool(tool *kb.ToolDef) brief.Confidence {
return best
}

func (e *Engine) contentSignalMatches(file string, patterns, excluded []string) bool {
return e.contains(file, patterns) && (len(excluded) == 0 || !e.contains(file, excluded))
}

// exists checks if a file, directory, or glob pattern matches something at the project root.
// A trailing "/" means the pattern must match a directory. Glob patterns without
// a trailing "/" only match regular files so that a NEWS.d/ directory does not
Expand Down
Loading