diff --git a/.claude/agent-memory/archgate-developer/MEMORY.md b/.claude/agent-memory/archgate-developer/MEMORY.md index 5aae525f..9bc506af 100644 --- a/.claude/agent-memory/archgate-developer/MEMORY.md +++ b/.claude/agent-memory/archgate-developer/MEMORY.md @@ -56,11 +56,11 @@ Non-enforceable lessons — environment/CI/platform quirks no static rule can re - **Cross-command I/O sharing: export from the existing command file, don't create shared files** — When two commands need to share I/O functions (console.log with styleText), you CANNOT put them in `src/helpers/` (ARCH-002 forbids console.log in helpers) or create a new file under `src/commands//` without a register function (ARCH-001 requires register\*Command export, ARCH-016 requires docs heading). The correct pattern: export the shared functions from the command file that already defines them (e.g., `plugin/install.ts` exports `installForEditor()` and `printManualInstructions()`) and import them in the other command. Applied in `upgrade.ts` importing from `./plugin/install`. - **macOS `/var` → `/private/var` symlink breaks temp dir path comparisons in tests** — On macOS, `/var` is a symlink to `/private/var`. `mkdtempSync(join(tmpdir(), ...))` returns `/var/folders/...` but `process.cwd()` after `chdir()` resolves the symlink to `/private/var/folders/...`. Tests that compare `tempDir` against paths derived from `process.cwd()` or `findProjectRoot()` will fail. Fix: always wrap `mkdtempSync` with `realpathSync` in test setup: `tempDir = realpathSync(mkdtempSync(join(tmpdir(), "archgate-test-")))`. This normalizes the path upfront. Discovered in v0.38.0/v0.39.0 release builds — PR CI runs on ubuntu-latest only, so macOS-specific issues are invisible until the release workflow. - **jq on Windows Git Bash emits CRLF line endings** — `jq -r` output ends lines with `\r\n`. In sh scripts, command substitution strips only trailing newlines, so parsed values carry a trailing `\r` (and multi-line lists get `\r` on every entry except the last). Symptom: charset validations reject valid values, or URLs get an embedded CR. Fix: pipe jq (and grep/sed fallbacks) through `tr -d '\r'`. Bit us in `install.sh` resolve_version — the release-walk skipped every tag except the last one. -- **`archgate review-context` misses uncommitted changes when a base ref is detected** — `getFilesChangedSinceRef` (src/engine/git-files.ts) runs `git diff base...HEAD`, which only sees COMMITTED changes. During a normal dev session (Write/Edit tools, nothing committed), `review-context` lists the branch's committed files but silently omits the working-tree edits actually under review. Workaround: scope reviewer sub-agents manually from `git status` / `git diff --name-only main`. Tracked in issue #403; candidate CLI fix: union `base...HEAD` with `getChangedFiles()` (staged+unstaged). - **Don't test that well-known tools exist on PATH** — Tests like `expect(resolveCommand("bun")).toBe("bun")` assert CI environment state, not application logic. They fail when the runner installs tools via shims (e.g., proto on macOS ARM64 where `Bun.which` returns null). Delete such tests entirely — the "returns null for non-existent command" tests already cover `resolveCommand`'s actual logic, and WSL-specific tests cover the `.exe` fallback path. ## Translation Quality +- **Docs have TWO locales: `nb/` AND `pt-br/`** — Editing any English docs page requires updating BOTH `docs/src/content/docs/nb/` and `docs/src/content/docs/pt-br/` in the same changeset (GEN-002 `i18n-translation-drift` is an error-severity rule). Don't stop at nb. Also: locale pages can silently lack whole sections present in English (e.g., a section might exist in English but be entirely absent from a locale page) — the drift rule only checks that the file was touched, not content parity, so compare section structure when editing. - **Norwegian (nb/) diacritical patterns to scan for** — When reviewing or editing `docs/src/content/docs/nb/` translations, scan for three corruption patterns: (1) stripped diacriticals (`monster` for `mønster`, `a` for `å`), (2) ASCII approximations (`aa` for `å`, `oe` for `ø`, `ae` for `æ`), (3) HTML entities (`å` for `å`, `ø` for `ø`, `æ` for `æ`). GEN-002 mandates correct characters but automated rules only check structural i18n (page parity, link prefixes, translation drift) — diacritical correctness requires manual/AI review. Common Norwegian words to watch: må, når, på, også, både, får, bør, før, første, følger, kjører, mønster, nøkkel, verktøy, nødvendig, støtter, foreslår, påvirkning, forårsaker, primær, erklæring, miljø, overføring. ## Validation Pipeline diff --git a/docs/public/llms-full.txt b/docs/public/llms-full.txt index 9db1a34c..f7678702 100644 --- a/docs/public/llms-full.txt +++ b/docs/public/llms-full.txt @@ -849,11 +849,11 @@ The `check` function receives a `RuleContext` object that provides everything a ### Project Information -| Property | Type | Description | -| ------------------ | ---------- | ---------------------------------------------------------------------------------- | -| `ctx.projectRoot` | `string` | Absolute path to the project root directory | -| `ctx.scopedFiles` | `string[]` | Files matching the ADR's `files` globs, or all project files if no globs are set | -| `ctx.changedFiles` | `string[]` | Files changed in git (auto-detected from branch diff, or from `--staged`/`--base`) | +| Property | Type | Description | +| ------------------ | ---------- | ----------------------------------------------------------------------------------- | +| `ctx.projectRoot` | `string` | Absolute path to the project root directory | +| `ctx.scopedFiles` | `string[]` | Files matching the ADR's `files` globs, or all project files if no globs are set | +| `ctx.changedFiles` | `string[]` | Files changed in git (branch diff plus uncommitted changes, or `--staged`/`--base`) | ### File Operations @@ -957,7 +957,7 @@ Rules execute with the following guarantees: - **Parallel across ADRs** -- Rules from different ADRs run concurrently for faster execution. - **Sequential within an ADR** -- Rules belonging to the same ADR run one after another, so earlier rules can establish context for later ones. - **Scoped files are pre-resolved** -- The `ctx.scopedFiles` array is populated before your `check` function is called, based on the ADR's `files` globs. -- **Changed files auto-detected** -- `ctx.changedFiles` is automatically populated with the branch diff against the base branch (e.g., `main`). Use `--staged` for pre-commit hooks (staged files only) or `--base ` for an explicit base. This enables cross-file dependency rules to work locally, not just in CI. +- **Changed files auto-detected** -- `ctx.changedFiles` is automatically populated with the branch diff against the base branch (e.g., `main`) plus uncommitted working-tree changes (staged, unstaged, and untracked non-ignored files). Use `--staged` for pre-commit hooks (staged files only) or `--base ` for an explicit base. This enables cross-file dependency rules to work locally, not just in CI. The editor plugins for [Claude Code](/guides/claude-code-plugin/) and [Cursor](/guides/cursor-integration/) run `archgate check` automatically after every code change. The agent reads the applicable ADRs, writes compliant code, and validates -- no manual check commands needed. [Sign up for beta access](https://plugins.archgate.dev). @@ -2795,7 +2795,7 @@ Use `ctx.scopedFiles` when your rule should only apply to files the ADR governs. ### ctx.changedFiles -An array of file paths that differ from the base branch. Auto-detected by default, or populated from `--staged` / `--base `. Useful for incremental checking and cross-file dependency rules. +An array of file paths that differ from the base branch, including uncommitted working-tree changes (staged, unstaged, and untracked non-ignored files). Auto-detected by default, or populated from `--staged` / `--base `. Useful for incremental checking and cross-file dependency rules. ```typescript // Incremental checking -- only validate changed files @@ -2981,7 +2981,7 @@ ARCH-006/no-unapproved-deps } ``` -2. **Use `ctx.changedFiles` for incremental checking.** `ctx.changedFiles` is auto-populated with the branch diff (or staged files with `--staged`). Filter `ctx.scopedFiles` against it to check only what changed, or use it directly for cross-file dependency rules. +2. **Use `ctx.changedFiles` for incremental checking.** `ctx.changedFiles` is auto-populated with the branch diff plus uncommitted working-tree changes (or staged files with `--staged`). Filter `ctx.scopedFiles` against it to check only what changed, or use it directly for cross-file dependency rules. 3. **Keep rules focused on one concern.** A rule that checks both naming conventions and import patterns should be split into two rules with separate IDs. @@ -3818,17 +3818,17 @@ archgate check --ci ## Changed files detection -By default, `archgate check` auto-detects the base branch and populates `ctx.changedFiles` with the branch diff (`git diff ...HEAD`). This enables cross-file dependency rules to work locally -- not just in CI. +By default, `archgate check` auto-detects the base branch and populates `ctx.changedFiles` with the branch diff (`git diff ...HEAD`) plus any uncommitted working-tree changes (staged, unstaged, and untracked non-ignored files). This enables cross-file dependency rules to work locally -- not just in CI -- and ensures edits that haven't been committed yet are still checked. The base ref is resolved in priority order: -| Priority | Source | `changedFiles` populated with | -| -------- | ------------------------------------ | -------------------------------- | -| 1 | `--staged` | Git staging area only | -| 2 | `--base ` | `git diff ...HEAD` | -| 3 | `.archgate/config.json` `baseBranch` | `git diff ...HEAD` | -| 4 | Git auto-detect | `git diff ...HEAD` | -| 5 | Detection fails | Empty (full-scan mode) | +| Priority | Source | `changedFiles` populated with | +| -------- | ------------------------------------ | ------------------------------------------------------- | +| 1 | `--staged` | Git staging area only | +| 2 | `--base ` | `git diff ...HEAD` + working-tree changes | +| 3 | `.archgate/config.json` `baseBranch` | `git diff ...HEAD` + working-tree changes | +| 4 | Git auto-detect | `git diff ...HEAD` + working-tree changes | +| 5 | Detection fails | Empty (full-scan mode) | Auto-detection tries `origin/HEAD`, then `origin/main`, `origin/master`, local `main`, and local `master`. To set a project default, add `baseBranch` to `.archgate/config.json`: @@ -4854,7 +4854,7 @@ Files matching the ADR's `files` glob patterns from its frontmatter. If the ADR changedFiles: string[]; ``` -Files that have been modified according to git. By default, this is auto-populated with the branch diff against the detected base branch (e.g., `origin/main`). When `--staged` is used, this contains only staged files. When `--base ` is used, this contains all files changed since that ref. Empty when base detection fails or no changes are found. Use this to build cross-file dependency rules (e.g., "if file A changed, file B must also change"). +Files that have been modified according to git. By default, this is auto-populated with the branch diff against the detected base branch (e.g., `origin/main`) plus any uncommitted working-tree changes (staged, unstaged, and untracked non-ignored files). When `--staged` is used, this contains only staged files. When `--base ` is used, this contains all files changed since that ref plus uncommitted working-tree changes. Empty when base detection fails or no changes are found. Use this to build cross-file dependency rules (e.g., "if file A changed, file B must also change"). #### report diff --git a/docs/src/content/docs/concepts/rules.mdx b/docs/src/content/docs/concepts/rules.mdx index 032d64d0..0a40b3fc 100644 --- a/docs/src/content/docs/concepts/rules.mdx +++ b/docs/src/content/docs/concepts/rules.mdx @@ -55,11 +55,11 @@ The `check` function receives a `RuleContext` object that provides everything a ### Project Information -| Property | Type | Description | -| ------------------ | ---------- | ---------------------------------------------------------------------------------- | -| `ctx.projectRoot` | `string` | Absolute path to the project root directory | -| `ctx.scopedFiles` | `string[]` | Files matching the ADR's `files` globs, or all project files if no globs are set | -| `ctx.changedFiles` | `string[]` | Files changed in git (auto-detected from branch diff, or from `--staged`/`--base`) | +| Property | Type | Description | +| ------------------ | ---------- | ----------------------------------------------------------------------------------- | +| `ctx.projectRoot` | `string` | Absolute path to the project root directory | +| `ctx.scopedFiles` | `string[]` | Files matching the ADR's `files` globs, or all project files if no globs are set | +| `ctx.changedFiles` | `string[]` | Files changed in git (branch diff plus uncommitted changes, or `--staged`/`--base`) | ### File Operations @@ -163,7 +163,7 @@ Rules execute with the following guarantees: - **Parallel across ADRs** -- Rules from different ADRs run concurrently for faster execution. - **Sequential within an ADR** -- Rules belonging to the same ADR run one after another, so earlier rules can establish context for later ones. - **Scoped files are pre-resolved** -- The `ctx.scopedFiles` array is populated before your `check` function is called, based on the ADR's `files` globs. -- **Changed files auto-detected** -- `ctx.changedFiles` is automatically populated with the branch diff against the base branch (e.g., `main`). Use `--staged` for pre-commit hooks (staged files only) or `--base ` for an explicit base. This enables cross-file dependency rules to work locally, not just in CI. +- **Changed files auto-detected** -- `ctx.changedFiles` is automatically populated with the branch diff against the base branch (e.g., `main`) plus uncommitted working-tree changes (staged, unstaged, and untracked non-ignored files). Use `--staged` for pre-commit hooks (staged files only) or `--base ` for an explicit base. This enables cross-file dependency rules to work locally, not just in CI. :::tip[Run checks automatically with editor plugins] The editor plugins for [Claude Code](/guides/claude-code-plugin/) and [Cursor](/guides/cursor-integration/) run `archgate check` automatically after every code change. The agent reads the applicable ADRs, writes compliant code, and validates -- no manual check commands needed. [Sign up for beta access](https://plugins.archgate.dev). diff --git a/docs/src/content/docs/guides/writing-rules.mdx b/docs/src/content/docs/guides/writing-rules.mdx index 18582316..f3ef0532 100644 --- a/docs/src/content/docs/guides/writing-rules.mdx +++ b/docs/src/content/docs/guides/writing-rules.mdx @@ -99,7 +99,7 @@ Use `ctx.scopedFiles` when your rule should only apply to files the ADR governs. ### ctx.changedFiles -An array of file paths that differ from the base branch. Auto-detected by default, or populated from `--staged` / `--base `. Useful for incremental checking and cross-file dependency rules. +An array of file paths that differ from the base branch, including uncommitted working-tree changes (staged, unstaged, and untracked non-ignored files). Auto-detected by default, or populated from `--staged` / `--base `. Useful for incremental checking and cross-file dependency rules. ```typescript // Incremental checking -- only validate changed files @@ -285,7 +285,7 @@ ARCH-006/no-unapproved-deps } ``` -2. **Use `ctx.changedFiles` for incremental checking.** `ctx.changedFiles` is auto-populated with the branch diff (or staged files with `--staged`). Filter `ctx.scopedFiles` against it to check only what changed, or use it directly for cross-file dependency rules. +2. **Use `ctx.changedFiles` for incremental checking.** `ctx.changedFiles` is auto-populated with the branch diff plus uncommitted working-tree changes (or staged files with `--staged`). Filter `ctx.scopedFiles` against it to check only what changed, or use it directly for cross-file dependency rules. 3. **Keep rules focused on one concern.** A rule that checks both naming conventions and import patterns should be split into two rules with separate IDs. diff --git a/docs/src/content/docs/nb/concepts/rules.mdx b/docs/src/content/docs/nb/concepts/rules.mdx index 1234e575..554a7559 100644 --- a/docs/src/content/docs/nb/concepts/rules.mdx +++ b/docs/src/content/docs/nb/concepts/rules.mdx @@ -59,7 +59,7 @@ Når `archgate check` kjøres, betyr exit code 1 at minst ett brudd med alvorlig | ------------------ | ---------- | -------------------------------------------------------------------------------------------- | | `ctx.projectRoot` | `string` | Absolutt sti til prosjektets rotmappe | | `ctx.scopedFiles` | `string[]` | Filer som matcher ADR-ens `files`-glober, eller alle prosjektfiler hvis ingen glober er satt | -| `ctx.changedFiles` | `string[]` | Filer endret i git (auto-oppdaget fra branch-diff, eller fra `--staged`/`--base`) | +| `ctx.changedFiles` | `string[]` | Filer endret i git (branch-diff pluss ikke-committede endringer, eller `--staged`/`--base`) | ### Filoperasjoner @@ -163,7 +163,7 @@ Regler kjøres med følgende garantier: - **Parallelt mellom ADR-er** -- Regler fra forskjellige ADR-er kjøres samtidig for raskere kjøring. - **Sekvensielt innenfor en ADR** -- Regler som tilhører samme ADR kjøres etter hverandre, slik at tidligere regler kan etablere kontekst for senere. - **Avgrensede filer er forhåndsløst** -- `ctx.scopedFiles`-arrayet er fylt ut før `check`-funksjonen din kalles, basert på ADR-ens `files`-glober. -- **Endrede filer auto-oppdaget** -- `ctx.changedFiles` fylles automatisk med branch-diffen mot base-branchen (f.eks. `main`). Bruk `--staged` for pre-commit hooks (kun staged-filer) eller `--base ` for en eksplisitt base. Dette gjør at kryss-fil-avhengighetsregler fungerer lokalt, ikke bare i CI. +- **Endrede filer auto-oppdaget** -- `ctx.changedFiles` fylles automatisk med branch-diffen mot base-branchen (f.eks. `main`) pluss ikke-committede endringer i arbeidstreet (stagede, ustagede og usporede ikke-ignorerte filer). Bruk `--staged` for pre-commit hooks (kun staged-filer) eller `--base ` for en eksplisitt base. Dette gjør at kryss-fil-avhengighetsregler fungerer lokalt, ikke bare i CI. :::tip[Kjør sjekker automatisk med editorplugins] Editorpluginene for [Claude Code](/guides/claude-code-plugin/) og [Cursor](/guides/cursor-integration/) kjører `archgate check` automatisk etter hver kodeendring. Agenten leser de gjeldende ADR-ene, skriver samsvarende kode og validerer -- ingen manuelle sjekkkommandoer nødvendig. [Registrer deg for beta-tilgang](https://plugins.archgate.dev). diff --git a/docs/src/content/docs/nb/guides/writing-rules.mdx b/docs/src/content/docs/nb/guides/writing-rules.mdx index 4e18568f..28405801 100644 --- a/docs/src/content/docs/nb/guides/writing-rules.mdx +++ b/docs/src/content/docs/nb/guides/writing-rules.mdx @@ -99,7 +99,7 @@ Bruk `ctx.scopedFiles` når regelen din bare skal gjelde filer ADR-en styrer. Fo ### ctx.changedFiles -En matrise med filstier som skiller seg fra grunngrenen. Auto-detektert som standard, eller fylt fra `--staged` / `--base `. Nyttig for inkrementell sjekking og regler for avhengigheter mellom filer. +En matrise med filstier som skiller seg fra grunngrenen, inkludert ikke-committede endringer i arbeidstreet (stagede, ustagede og usporede ikke-ignorerte filer). Auto-detektert som standard, eller fylt fra `--staged` / `--base `. Nyttig for inkrementell sjekking og regler for avhengigheter mellom filer. ```typescript // Incremental checking -- only validate changed files @@ -285,7 +285,7 @@ ARCH-006/no-unapproved-deps } ``` -2. **Bruk `ctx.changedFiles` for inkrementell sjekking.** `ctx.changedFiles` fylles automatisk med grenforskjellen (eller stagede filer med `--staged`). Filtrer `ctx.scopedFiles` mot den for å bare sjekke det som er endret, eller bruk den direkte for regler om avhengigheter mellom filer. +2. **Bruk `ctx.changedFiles` for inkrementell sjekking.** `ctx.changedFiles` fylles automatisk med grenforskjellen pluss ikke-committede endringer i arbeidstreet (eller stagede filer med `--staged`). Filtrer `ctx.scopedFiles` mot den for å bare sjekke det som er endret, eller bruk den direkte for regler om avhengigheter mellom filer. 3. **Hold reglene fokusert på ett anliggende.** En regel som sjekker både navnekonvensjoner og importmønstre bør deles i to regler med separate ID-er. diff --git a/docs/src/content/docs/nb/reference/cli/check.mdx b/docs/src/content/docs/nb/reference/cli/check.mdx index a5eeb27a..4b5e1f0f 100644 --- a/docs/src/content/docs/nb/reference/cli/check.mdx +++ b/docs/src/content/docs/nb/reference/cli/check.mdx @@ -95,17 +95,17 @@ archgate check --ci ## Deteksjon av endrede filer -Som standard autodetekterer `archgate check` hovedgrenen og fyller `ctx.changedFiles` med grendifferansen (`git diff ...HEAD`). Dette gjør at regler for avhengigheter på tvers av filer fungerer lokalt -- ikke bare i CI. +Som standard autodetekterer `archgate check` hovedgrenen og fyller `ctx.changedFiles` med grendifferansen (`git diff ...HEAD`) pluss eventuelle ikke-committede endringer i arbeidstreet (stagede, ustagede og usporede ikke-ignorerte filer). Dette gjør at regler for avhengigheter på tvers av filer fungerer lokalt -- ikke bare i CI -- og sikrer at endringer som ennå ikke er committet, også sjekkes. Basisreferansen løses i denne prioritetsrekkefølgen: -| Prioritet | Kilde | `changedFiles` fylles med | -| --------- | ------------------------------------ | -------------------------------- | -| 1 | `--staged` | Kun git-stagingområdet | -| 2 | `--base ` | `git diff ...HEAD` | -| 3 | `.archgate/config.json` `baseBranch` | `git diff ...HEAD` | -| 4 | Git-autodeteksjon | `git diff ...HEAD` | -| 5 | Deteksjon mislykkes | Tom (fullskanmodus) | +| Prioritet | Kilde | `changedFiles` fylles med | +| --------- | ------------------------------------ | ------------------------------------------------------- | +| 1 | `--staged` | Kun git-stagingområdet | +| 2 | `--base ` | `git diff ...HEAD` + arbeidstre-endringer | +| 3 | `.archgate/config.json` `baseBranch` | `git diff ...HEAD` + arbeidstre-endringer | +| 4 | Git-autodeteksjon | `git diff ...HEAD` + arbeidstre-endringer | +| 5 | Deteksjon mislykkes | Tom (fullskanmodus) | Autodeteksjon prøver `origin/HEAD`, deretter `origin/main`, `origin/master`, lokal `main` og lokal `master`. For å sette en prosjektstandard, legg til `baseBranch` i `.archgate/config.json`: diff --git a/docs/src/content/docs/nb/reference/rule-api.mdx b/docs/src/content/docs/nb/reference/rule-api.mdx index 8b489597..a375a532 100644 --- a/docs/src/content/docs/nb/reference/rule-api.mdx +++ b/docs/src/content/docs/nb/reference/rule-api.mdx @@ -93,7 +93,7 @@ Filer som matcher ADR-ens `files`-globmønstre fra frontmatter. Hvis ADR-en ikke changedFiles: string[]; ``` -Filer som har blitt endret ifølge git. Som standard fylles denne automatisk med branch-diffen mot den detekterte basisgrenen (f.eks. `origin/main`). Når `--staged` brukes, inneholder den kun stagede filer. Når `--base ` brukes, inneholder den alle filer som er endret siden den referansen. Tom når basisdeteksjon feiler eller ingen endringer finnes. Bruk denne til å bygge regler for avhengigheter mellom filer (f.eks. "hvis fil A endret seg, må fil B også endres"). +Filer som har blitt endret ifølge git. Som standard fylles denne automatisk med branch-diffen mot den detekterte basisgrenen (f.eks. `origin/main`) pluss eventuelle ikke-committede endringer i arbeidstreet (stagede, ustagede og usporede ikke-ignorerte filer). Når `--staged` brukes, inneholder den kun stagede filer. Når `--base ` brukes, inneholder den alle filer som er endret siden den referansen pluss ikke-committede endringer i arbeidstreet. Tom når basisdeteksjon feiler eller ingen endringer finnes. Bruk denne til å bygge regler for avhengigheter mellom filer (f.eks. "hvis fil A endret seg, må fil B også endres"). #### report diff --git a/docs/src/content/docs/pt-br/concepts/rules.mdx b/docs/src/content/docs/pt-br/concepts/rules.mdx index bc36532a..0c698080 100644 --- a/docs/src/content/docs/pt-br/concepts/rules.mdx +++ b/docs/src/content/docs/pt-br/concepts/rules.mdx @@ -59,7 +59,7 @@ A função `check` recebe um objeto `RuleContext` que fornece tudo que uma regra | ------------------ | ---------- | ------------------------------------------------------------------------------------------------------ | | `ctx.projectRoot` | `string` | Caminho absoluto para o diretório raiz do projeto | | `ctx.scopedFiles` | `string[]` | Arquivos que correspondem aos globs `files` do ADR, ou todos os arquivos se não houver globs definidos | -| `ctx.changedFiles` | `string[]` | Arquivos alterados no git (auto-detectado a partir do diff da branch, ou via `--staged`/`--base`) | +| `ctx.changedFiles` | `string[]` | Arquivos alterados no git (diff da branch mais alterações não commitadas, ou `--staged`/`--base`) | ### Operações de Arquivo @@ -163,7 +163,7 @@ As regras são executadas com as seguintes garantias: - **Paralelo entre ADRs** -- Regras de diferentes ADRs são executadas concorrentemente para maior velocidade. - **Sequencial dentro de um ADR** -- Regras pertencentes ao mesmo ADR são executadas uma após a outra, para que regras anteriores possam estabelecer contexto para as posteriores. - **Arquivos no escopo são pré-resolvidos** -- O array `ctx.scopedFiles` é preenchido antes que sua função `check` seja chamada, com base nos globs `files` do ADR. -- **Arquivos alterados auto-detectados** -- `ctx.changedFiles` é automaticamente preenchido com o diff da branch contra a branch base (ex: `main`). Use `--staged` para hooks de pre-commit (apenas arquivos staged) ou `--base ` para uma base explícita. Isso permite que regras de dependência entre arquivos funcionem localmente, não apenas no CI. +- **Arquivos alterados auto-detectados** -- `ctx.changedFiles` é automaticamente preenchido com o diff da branch contra a branch base (ex: `main`) mais as alterações não commitadas da árvore de trabalho (arquivos staged, não staged e não rastreados que não sejam ignorados). Use `--staged` para hooks de pre-commit (apenas arquivos staged) ou `--base ` para uma base explícita. Isso permite que regras de dependência entre arquivos funcionem localmente, não apenas no CI. :::tip[Execute verificações automaticamente com plugins de editor] Os plugins de editor para [Claude Code](/guides/claude-code-plugin/) e [Cursor](/guides/cursor-integration/) executam `archgate check` automaticamente após cada alteração de código. O agente lê os ADRs aplicáveis, escreve código em conformidade e valida -- sem necessidade de executar comandos de verificação manualmente. [Inscreva-se para acesso beta](https://plugins.archgate.dev). diff --git a/docs/src/content/docs/pt-br/guides/writing-rules.mdx b/docs/src/content/docs/pt-br/guides/writing-rules.mdx index e0823ae7..972978d3 100644 --- a/docs/src/content/docs/pt-br/guides/writing-rules.mdx +++ b/docs/src/content/docs/pt-br/guides/writing-rules.mdx @@ -99,7 +99,7 @@ Use `ctx.scopedFiles` quando sua regra deve se aplicar apenas aos arquivos que o ### ctx.changedFiles -Um array de caminhos de arquivo que diferem da branch base. Auto-detectado por padrão, ou preenchido via `--staged` / `--base `. Útil para verificação incremental e regras de dependência entre arquivos. +Um array de caminhos de arquivo que diferem da branch base, incluindo alterações não commitadas da árvore de trabalho (arquivos staged, não staged e não rastreados que não sejam ignorados). Auto-detectado por padrão, ou preenchido via `--staged` / `--base `. Útil para verificação incremental e regras de dependência entre arquivos. ```typescript // Verificação incremental -- validar apenas arquivos alterados @@ -285,7 +285,7 @@ ARCH-006/no-unapproved-deps } ``` -2. **Use `ctx.changedFiles` para verificação incremental.** `ctx.changedFiles` é auto-preenchido com o diff da branch (ou arquivos staged com `--staged`). Filtre `ctx.scopedFiles` com ele para verificar apenas o que mudou, ou use-o diretamente para regras de dependência entre arquivos. +2. **Use `ctx.changedFiles` para verificação incremental.** `ctx.changedFiles` é auto-preenchido com o diff da branch mais as alterações não commitadas da árvore de trabalho (ou arquivos staged com `--staged`). Filtre `ctx.scopedFiles` com ele para verificar apenas o que mudou, ou use-o diretamente para regras de dependência entre arquivos. 3. **Mantenha as regras focadas em uma única preocupação.** Uma regra que verifica tanto convenções de nomenclatura quanto padrões de import deve ser dividida em duas regras com IDs separados. diff --git a/docs/src/content/docs/pt-br/reference/cli/check.mdx b/docs/src/content/docs/pt-br/reference/cli/check.mdx index d28f816e..f0a61896 100644 --- a/docs/src/content/docs/pt-br/reference/cli/check.mdx +++ b/docs/src/content/docs/pt-br/reference/cli/check.mdx @@ -93,6 +93,26 @@ Obter anotações do GitHub Actions: archgate check --ci ``` +## Detecção de arquivos alterados + +Por padrão, `archgate check` autodetecta a branch base e preenche `ctx.changedFiles` com o diff da branch (`git diff ...HEAD`) mais quaisquer alterações não commitadas da árvore de trabalho (arquivos staged, não staged e não rastreados que não sejam ignorados). Isso permite que regras de dependência entre arquivos funcionem localmente -- não apenas no CI -- e garante que edições ainda não commitadas também sejam verificadas. + +A referência base é resolvida nesta ordem de prioridade: + +| Prioridade | Fonte | `changedFiles` preenchido com | +| ---------- | ------------------------------------ | ------------------------------------------------------------------- | +| 1 | `--staged` | Apenas a área de staging do git | +| 2 | `--base ` | `git diff ...HEAD` + alterações da árvore de trabalho | +| 3 | `.archgate/config.json` `baseBranch` | `git diff ...HEAD` + alterações da árvore de trabalho | +| 4 | Autodetecção do git | `git diff ...HEAD` + alterações da árvore de trabalho | +| 5 | Detecção falha | Vazio (modo de varredura completa) | + +A autodetecção tenta `origin/HEAD`, depois `origin/main`, `origin/master`, `main` local e `master` local. Para definir um padrão do projeto, adicione `baseBranch` ao `.archgate/config.json`: + +```json +{ "baseBranch": "main" } +``` + ## Diagnósticos Durante a execução, `archgate check` emite avisos para configurações incorretas comuns que podem causar resultados lentos ou inesperados: diff --git a/docs/src/content/docs/pt-br/reference/rule-api.mdx b/docs/src/content/docs/pt-br/reference/rule-api.mdx index 1cab467d..65dddce2 100644 --- a/docs/src/content/docs/pt-br/reference/rule-api.mdx +++ b/docs/src/content/docs/pt-br/reference/rule-api.mdx @@ -93,7 +93,7 @@ Arquivos que correspondem aos padrões glob de `files` do frontmatter do ADR. Se changedFiles: string[]; ``` -Arquivos que foram modificados de acordo com o git. Por padrão, é auto-preenchido com o diff da branch contra a branch base detectada (ex: `origin/main`). Quando `--staged` é usado, contém apenas arquivos staged. Quando `--base ` é usado, contém todos os arquivos alterados desde aquela ref. Vazio quando a detecção falha ou nenhuma alteração é encontrada. Use para construir regras de dependência entre arquivos (ex: "se o arquivo A mudou, o arquivo B também deve mudar"). +Arquivos modificados conforme o Git. Por padrão, é autopreenchido com o diff da branch em relação à branch base detectada (ex.: `origin/main`) mais quaisquer alterações não commitadas da árvore de trabalho (arquivos staged, não staged e não rastreados que não sejam ignorados). Quando `--staged` é usado, contém apenas arquivos staged. Quando `--base ` é usado, contém todos os arquivos alterados desde essa ref mais as alterações não commitadas da árvore de trabalho. Fica vazio quando a detecção falha ou nenhuma alteração é encontrada. Use para construir regras de dependência entre arquivos (ex.: "se o arquivo A mudou, o arquivo B também deve mudar"). #### report diff --git a/docs/src/content/docs/reference/cli/check.mdx b/docs/src/content/docs/reference/cli/check.mdx index d96324eb..119be872 100644 --- a/docs/src/content/docs/reference/cli/check.mdx +++ b/docs/src/content/docs/reference/cli/check.mdx @@ -95,17 +95,17 @@ archgate check --ci ## Changed files detection -By default, `archgate check` auto-detects the base branch and populates `ctx.changedFiles` with the branch diff (`git diff ...HEAD`). This enables cross-file dependency rules to work locally -- not just in CI. +By default, `archgate check` auto-detects the base branch and populates `ctx.changedFiles` with the branch diff (`git diff ...HEAD`) plus any uncommitted working-tree changes (staged, unstaged, and untracked non-ignored files). This enables cross-file dependency rules to work locally -- not just in CI -- and ensures edits that haven't been committed yet are still checked. The base ref is resolved in priority order: -| Priority | Source | `changedFiles` populated with | -| -------- | ------------------------------------ | -------------------------------- | -| 1 | `--staged` | Git staging area only | -| 2 | `--base ` | `git diff ...HEAD` | -| 3 | `.archgate/config.json` `baseBranch` | `git diff ...HEAD` | -| 4 | Git auto-detect | `git diff ...HEAD` | -| 5 | Detection fails | Empty (full-scan mode) | +| Priority | Source | `changedFiles` populated with | +| -------- | ------------------------------------ | ------------------------------------------------------- | +| 1 | `--staged` | Git staging area only | +| 2 | `--base ` | `git diff ...HEAD` + working-tree changes | +| 3 | `.archgate/config.json` `baseBranch` | `git diff ...HEAD` + working-tree changes | +| 4 | Git auto-detect | `git diff ...HEAD` + working-tree changes | +| 5 | Detection fails | Empty (full-scan mode) | Auto-detection tries `origin/HEAD`, then `origin/main`, `origin/master`, local `main`, and local `master`. To set a project default, add `baseBranch` to `.archgate/config.json`: diff --git a/docs/src/content/docs/reference/rule-api.mdx b/docs/src/content/docs/reference/rule-api.mdx index 0953b8e7..18ba6cb0 100644 --- a/docs/src/content/docs/reference/rule-api.mdx +++ b/docs/src/content/docs/reference/rule-api.mdx @@ -93,7 +93,7 @@ Files matching the ADR's `files` glob patterns from its frontmatter. If the ADR changedFiles: string[]; ``` -Files that have been modified according to git. By default, this is auto-populated with the branch diff against the detected base branch (e.g., `origin/main`). When `--staged` is used, this contains only staged files. When `--base ` is used, this contains all files changed since that ref. Empty when base detection fails or no changes are found. Use this to build cross-file dependency rules (e.g., "if file A changed, file B must also change"). +Files that have been modified according to git. By default, this is auto-populated with the branch diff against the detected base branch (e.g., `origin/main`) plus any uncommitted working-tree changes (staged, unstaged, and untracked non-ignored files). When `--staged` is used, this contains only staged files. When `--base ` is used, this contains all files changed since that ref plus uncommitted working-tree changes. Empty when base detection fails or no changes are found. Use this to build cross-file dependency rules (e.g., "if file A changed, file B must also change"). #### report diff --git a/src/engine/git-files.ts b/src/engine/git-files.ts index 04c3a8b1..f96e9019 100644 --- a/src/engine/git-files.ts +++ b/src/engine/git-files.ts @@ -262,22 +262,36 @@ export async function resolveBaseRef( } /** - * Get files changed between a base ref and HEAD. - * Uses three-dot diff (`base...HEAD`) to find the merge-base automatically. + * Get files changed between a base ref and the working tree. + * + * Unions three sources so uncommitted work is never silently omitted + * (see archgate/cli#403): + * 1. `git diff base...HEAD` — committed branch changes (three-dot diff + * finds the merge-base automatically) + * 2. staged + unstaged edits to tracked files + * 3. untracked (non-gitignored) files + * + * Returns an empty array when the ref cannot be diffed (bad ref or not + * a git repo), matching the previous behavior. */ export async function getFilesChangedSinceRef( projectRoot: string, ref: string ): Promise { try { - const result = await runGit( - ["diff", "--name-only", `${ref}...HEAD`], - projectRoot - ); + const [committed, workingTree, untracked] = await Promise.all([ + runGit(["diff", "--name-only", `${ref}...HEAD`], projectRoot), + getChangedFiles(projectRoot), + runGit(["ls-files", "--others", "--exclude-standard"], projectRoot), + ]); const files = [ - ...new Set(result.trim().split("\n").filter(Boolean)), + ...new Set([ + ...committed.trim().split("\n").filter(Boolean), + ...workingTree, + ...untracked.trim().split("\n").filter(Boolean), + ]), ].sort(); - logDebug(`Files changed since ${ref}:`, files.length); + logDebug(`Files changed since ${ref} (incl. working tree):`, files.length); return files; } catch { logDebug(`Failed to get files changed since ${ref}`); diff --git a/tests/engine/git-files.test.ts b/tests/engine/git-files.test.ts index 6ad9e4c3..97a9b0db 100644 --- a/tests/engine/git-files.test.ts +++ b/tests/engine/git-files.test.ts @@ -230,6 +230,60 @@ describe("git-files", () => { expect(files).toEqual([]); }); + // Regression: archgate/cli#403 — base...HEAD only sees committed + // changes, so uncommitted working-tree edits were silently omitted + // whenever a base ref was detected (i.e., almost always). + test("includes uncommitted edits to tracked files (regression archgate/cli#403)", async () => { + await git(["init", "--initial-branch=main"], tempDir); + await git(["config", "user.email", "test@test.com"], tempDir); + await git(["config", "user.name", "Test"], tempDir); + writeFileSync(join(tempDir, "base.ts"), "export const x = 1;"); + await git(["add", "base.ts"], tempDir); + await git(["commit", "-m", "init"], tempDir); + await git(["checkout", "-b", "feature"], tempDir); + writeFileSync(join(tempDir, "committed.ts"), "export const y = 2;"); + await git(["add", "committed.ts"], tempDir); + await git(["commit", "-m", "add committed file"], tempDir); + // Unstaged edit to a tracked file — not committed, not staged + writeFileSync(join(tempDir, "base.ts"), "export const x = 99;"); + const files = await getFilesChangedSinceRef(tempDir, "main"); + expect(files).toContain("committed.ts"); + expect(files).toContain("base.ts"); + }, 15_000); + + test("includes staged-but-uncommitted files", async () => { + await git(["init", "--initial-branch=main"], tempDir); + await git(["config", "user.email", "test@test.com"], tempDir); + await git(["config", "user.name", "Test"], tempDir); + writeFileSync(join(tempDir, "base.ts"), "export const x = 1;"); + await git(["add", "base.ts"], tempDir); + await git(["commit", "-m", "init"], tempDir); + await git(["checkout", "-b", "feature"], tempDir); + writeFileSync(join(tempDir, "staged.ts"), "export const s = 1;"); + await git(["add", "staged.ts"], tempDir); + const files = await getFilesChangedSinceRef(tempDir, "main"); + expect(files).toContain("staged.ts"); + }, 15_000); + + test("includes untracked files but not gitignored ones", async () => { + await git(["init", "--initial-branch=main"], tempDir); + await git(["config", "user.email", "test@test.com"], tempDir); + await git(["config", "user.name", "Test"], tempDir); + writeFileSync(join(tempDir, ".gitignore"), "dist/\n"); + writeFileSync(join(tempDir, "base.ts"), "export const x = 1;"); + await git(["add", "."], tempDir); + await git(["commit", "-m", "init"], tempDir); + await git(["checkout", "-b", "feature"], tempDir); + // Untracked new file — never staged + writeFileSync(join(tempDir, "untracked.ts"), "export const u = 1;"); + // Gitignored file — must stay excluded + mkdirSync(join(tempDir, "dist"), { recursive: true }); + writeFileSync(join(tempDir, "dist", "out.js"), "var u = 1;"); + const files = await getFilesChangedSinceRef(tempDir, "main"); + expect(files).toContain("untracked.ts"); + expect(files).not.toContain("dist/out.js"); + }, 15_000); + test("returns multiple changed files sorted", async () => { await git(["init", "--initial-branch=main"], tempDir); await git(["config", "user.email", "test@test.com"], tempDir); diff --git a/tests/integration/review-context.test.ts b/tests/integration/review-context.test.ts index 8f19ad80..f4a2a49a 100644 --- a/tests/integration/review-context.test.ts +++ b/tests/integration/review-context.test.ts @@ -190,6 +190,52 @@ describe("review-context integration", () => { expect(ctx.allChangedFiles).not.toContain("src/base.ts"); }, 30_000); + // Regression: archgate/cli#403 — with a base ref detected, review-context + // only listed committed branch changes and silently omitted uncommitted + // working-tree edits (the files actually under review in an agent session). + test("--base includes uncommitted working-tree changes (regression archgate/cli#403)", async () => { + scaffoldProject(dir); + writeAdr( + dir, + "ARCH-022.md", + makeAdr({ + id: "ARCH-022", + title: "Working Tree ADR", + domain: "architecture", + rules: false, + body: "## Decision\nTest.\n\n## Do's and Don'ts\nDo test.", + }) + ); + await git(["init", "--initial-branch=main"], dir); + await git(["config", "user.email", "test@test.com"], dir); + await git(["config", "user.name", "Test"], dir); + + mkdirSync(join(dir, "src"), { recursive: true }); + writeFileSync(join(dir, "src", "base.ts"), "export const x = 1;\n"); + await commitAll(dir, "initial commit"); + + await git(["checkout", "-b", "feature"], dir); + writeFileSync(join(dir, "src", "committed.ts"), "export const c = 3;\n"); + await commitAll(dir, "committed change"); + + // Uncommitted edit to a tracked file + a brand-new untracked file — + // the typical state of an AI-agent dev session before any commit. + writeFileSync(join(dir, "src", "base.ts"), "export const x = 99;\n"); + writeFileSync(join(dir, "src", "untracked.ts"), "export const u = 5;\n"); + + const { exitCode, stdout } = await runCli( + ["review-context", "--base", "main"], + dir, + { GIT_CONFIG_NOSYSTEM: "", GIT_CONFIG_GLOBAL: "" } + ); + expect(exitCode).toBe(0); + + const ctx = JSON.parse(stdout) as { allChangedFiles: string[] }; + expect(ctx.allChangedFiles).toContain("src/committed.ts"); + expect(ctx.allChangedFiles).toContain("src/base.ts"); + expect(ctx.allChangedFiles).toContain("src/untracked.ts"); + }, 30_000); + test("--staged takes precedence over --base for review-context", async () => { scaffoldProject(dir); writeAdr(