diff --git a/.changeset/config.json b/.changeset/config.json
index 50cbb51321..30fa697402 100644
--- a/.changeset/config.json
+++ b/.changeset/config.json
@@ -2,7 +2,7 @@
"$schema": "https://unpkg.com/@changesets/config/schema.json",
"changelog": [
"@changesets/changelog-github",
- { "repo": "Fission-AI/OpenSpec" }
+ { "repo": "fkmatsuda/BR-OpenSpec" }
],
"commit": false,
"fixed": [],
diff --git a/.coderabbit.yaml b/.coderabbit.yaml
index 38237f23d2..afeb8c61a3 100644
--- a/.coderabbit.yaml
+++ b/.coderabbit.yaml
@@ -1,6 +1,6 @@
# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
# Minimal configuration for getting started
-language: "en-US"
+language: "pt-BR"
reviews:
profile: "chill"
high_level_summary: true
diff --git a/.devcontainer/README.md b/.devcontainer/README.md
index 989fa527f1..4dc7691ad1 100644
--- a/.devcontainer/README.md
+++ b/.devcontainer/README.md
@@ -1,6 +1,6 @@
# Dev Container Setup
-This directory contains the VS Code dev container configuration for OpenSpec development.
+This directory contains the VS Code dev container configuration for BR-OpenSpec development.
## What's Included
diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index c381b61fa0..cd92b9c55d 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -1,5 +1,5 @@
{
- "name": "OpenSpec Development",
+ "name": "BR-OpenSpec Development",
"image": "mcr.microsoft.com/devcontainers/typescript-node:1-20-bookworm",
// Additional tools and features
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index e066888eaf..ce2ceea4d4 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -1,2 +1,2 @@
# Default code ownership
-* @TabishB
+* @fkmatsuda
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index fe2f3a5341..bdb92220b5 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -215,7 +215,7 @@ jobs:
- name: Test binary execution
run: |
VERSION=$(nix run . -- --version)
- echo "OpenSpec version: $VERSION"
+ echo "BR-OpenSpec version: $VERSION"
if [ -z "$VERSION" ]; then
echo "Error: Version command returned empty output"
exit 1
diff --git a/.github/workflows/release-prepare.yml b/.github/workflows/release-prepare.yml
index 0a58d8e87c..38949dcdb1 100644
--- a/.github/workflows/release-prepare.yml
+++ b/.github/workflows/release-prepare.yml
@@ -15,7 +15,7 @@ concurrency:
jobs:
prepare:
- if: github.repository == 'Fission-AI/OpenSpec'
+ if: github.repository == 'fkmatsuda/BR-OpenSpec'
runs-on: ubuntu-latest
steps:
# Generate GitHub App token first - used for checkout and changesets
diff --git a/AGENTS.md b/AGENTS.md
index e69de29bb2..b26674e325 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -0,0 +1,257 @@
+# BR-OpenSpec — Agent Guide
+
+## Project Overview
+
+BR-OpenSpec is an AI-native system for spec-driven development. It is a Node.js CLI tool (published as `@fkmatsuda/br-openspec` on npm) that helps teams align on what to build before writing code. Each change gets its own folder with a proposal, specs, design, and tasks. BR-OpenSpec generates AI assistant integrations (skills, slash commands, and config files) for 25+ tools including Claude Code, Cursor, GitHub Copilot, Gemini CLI, Codex, and many others.
+
+The project uses its own spec-driven workflow. You will find active changes under `openspec/changes/` and archived changes under `openspec/changes/archive/`. The project's own specs live in `openspec/specs/`.
+
+## Technology Stack
+
+- **Runtime**: Node.js ≥20.19.0 (ESM modules only)
+- **Language**: TypeScript 5.9+
+- **Package Manager**: pnpm 9
+- **CLI Framework**: Commander.js
+- **Validation**: Zod
+- **Config / Frontmatter**: YAML
+- **Prompts**: @inquirer/prompts (must be dynamically imported — see Code Style)
+- **Styling**: chalk, ora spinners
+- **Telemetry**: PostHog (anonymous, opt-out)
+
+## Build & Development Commands
+
+All commands are run via pnpm:
+
+```bash
+# Install dependencies
+pnpm install
+
+# Build (compiles TypeScript to dist/ via custom build.js)
+pnpm run build
+
+# Watch mode for development
+pnpm run dev
+
+# Develop CLI locally (builds then runs bin/openspec.js)
+pnpm run dev:cli
+
+# Run tests
+pnpm test
+
+# Run tests in watch mode
+pnpm run test:watch
+
+# Run tests with coverage
+pnpm run test:coverage
+
+# Run linting
+pnpm lint
+
+# Type check without emitting
+pnpm exec tsc --noEmit
+```
+
+The build script (`build.js`) cleans `dist/` and invokes `tsc` directly. There is no bundler — the published package uses the raw compiled JavaScript from `dist/`.
+
+## Project Structure
+
+```
+src/
+ cli/ # CLI entry point (Commander.js program setup)
+ commands/ # Command implementations (change, config, schema, show, spec, tools, validate, workflow)
+ core/ # Core business logic
+ archive.ts
+ artifact-graph/ # Artifact graph engine for workflow schemas
+ available-tools.ts
+ command-generation/ # Adapter-based command/skill generation for 25+ AI tools
+ completions/ # Shell completion generation (bash, zsh, fish, powershell)
+ config.ts # AI tool registry and constants
+ config-prompts.ts
+ config-schema.ts
+ global-config.ts # XDG-compliant global config management
+ init.ts # Project initialization command
+ profiles.ts # Workflow profiles (core vs custom)
+ project-config.ts
+ schemas/ # Zod schemas for validation
+ shared/ # Shared skill generation and tool detection
+ templates/ # Workflow template definitions
+ tools-manager.ts
+ update.ts
+ validation/ # Spec/change validation engine
+ prompts/ # Custom prompt components (searchable multi-select)
+ telemetry/ # Anonymous usage analytics (PostHog)
+ ui/ # ASCII art, welcome screens, palette
+ utils/ # File system, interactive mode detection, task progress, etc.
+ index.ts # Public API exports
+
+test/ # Mirror of src/ structure; Vitest tests
+openspec/ # The project's own spec-driven content
+ changes/ # Active and archived change proposals
+ explorations/ # Design explorations
+ specs/ # Living specifications
+ config.yaml # Project-level BR-OpenSpec config
+schemas/ # Built-in workflow schemas (e.g., spec-driven)
+docs/ # Markdown documentation (English + pt-BR)
+```
+
+## Code Style Guidelines
+
+- **ESM only**: All imports must use `.js` extensions (e.g., `import { foo } from './bar.js'`).
+- **Dynamic imports for @inquirer**: `@inquirer/core` and `@inquirer/prompts` **must** be loaded with `import()` at runtime. Static imports of these packages are forbidden by ESLint because they have side effects that can hang the Node.js event loop when stdin is piped (see issue #367). The only exception is `src/core/init.ts`, which is itself dynamically imported from the CLI startup path.
+- **Cross-platform paths**: Always use `path.join()` or `path.resolve()`. Never hardcode `/` or `\`. Tests must use `path.join()` for expected path values.
+- **Constants over magic strings**: Reuse existing constants (e.g., `OPENSPEC_DIR_NAME`, `AI_TOOLS`) rather than inventing new detection mechanisms.
+- **Explicit lookups preferred**: Prefer explicit list lookups over pattern matching or regex when generating or tracking artifacts.
+- **TypeScript strict mode**: Enabled. `any` is allowed in existing code but should be avoided in new code.
+- **Conventional commits**: Use `type(scope): subject` format for commit messages.
+
+## Testing Strategy
+
+- **Framework**: Vitest 3.x with `globals: true`
+- **Pool**: `forks` (process isolation required because tests spawn CLI child processes and make `process.cwd()` assumptions)
+- **Max workers**: Capped at 4 (or via `VITEST_MAX_WORKERS` env var) to prevent runaway CPU/memory in CI
+- **Test timeout**: 10 seconds default; 3 second teardown timeout
+- **Coverage**: `@vitest/coverage-v8`, outputs text/json/html; excludes `dist/`, `bin/`, `test/`, config files
+- **Global setup**: `vitest.setup.ts` ensures the CLI is built before tests run
+- **E2E tests**: Use `test/helpers/run-cli.ts` to spawn the compiled CLI in a child process and capture stdout/stderr
+- **Mocking**: Vitest mocks are used heavily for `@inquirer/prompts`, file system modules, and UI components
+
+## CI / CD
+
+### GitHub Actions Workflows
+
+- **`.github/workflows/ci.yml`**: Runs on PRs, merge groups, and pushes to `main`
+ - `test_pr`: Build + test on Ubuntu (PRs)
+ - `test_matrix`: Build + test on Ubuntu, macOS, and Windows (pushes to `main`)
+ - `lint`: Build, type check (`tsc --noEmit`), lint, and verify `dist/cli/index.js` exists
+ - `nix-flake-validate`: Validates Nix flake build (only when Nix-related files change)
+ - `validate-changesets`: Ensures changesets are valid for PRs
+ - `required-checks-pr` / `required-checks-main`: Aggregates all required checks
+
+- **`.github/workflows/release-prepare.yml`**: Runs on pushes to `main`
+ - Uses Changesets action to open/update a "Version Packages" PR
+ - Publishes to npm via OIDC trusted publishing (no long-lived npm token)
+ - Requires a GitHub App token for checkout so that CI runs on the version PR
+
+### Release Process
+
+- Uses [Changesets](https://github.com/changesets/changesets) for versioning and changelog generation
+- Run `pnpm changeset` to add a changeset
+- The release PR is auto-created; merging it triggers the publish
+- `pnpm run release:ci` is the publish script (verifies version then runs `changeset publish`)
+
+## Deployment & Distribution
+
+- **npm**: Published as `@fkmatsuda/br-openspec`
+- **Nix**: `flake.nix` provides packages, apps, and dev shells for `x86_64-linux`, `aarch64-linux`, `x86_64-darwin`, `aarch64-darwin`
+- **Global install**: `npm install -g @fkmatsuda/br-openspec@latest`
+- **Entry points**:
+ - CLI: `bin/openspec.js` → `dist/cli/index.js`
+ - Library: `dist/index.js` / `dist/index.d.ts`
+
+## Security & Privacy
+
+- **Telemetry**: Anonymous usage stats sent to PostHog. Only command names and version are tracked. No arguments, paths, content, or PII.
+ - Opt-out: `export OPENSPEC_TELEMETRY=0` or `export DO_NOT_TRACK=1`
+ - Auto-disabled in CI (`CI=true`)
+- **npm publishing**: Uses OIDC trusted publishing from GitHub Actions (no static tokens in repo)
+- **Sensitive files**: `.env` files are gitignored. No API keys or secrets should be committed.
+
+## Development Conventions
+
+- **Spec-driven**: The project eats its own dog food. Changes should have a proposal and specs in `openspec/changes/` when they are significant.
+- **Profile system**: Workflows are delivered based on profiles (`core` = streamlined, `custom` = user-selected). The global config controls delivery method (`skills`, `commands`, or `both`).
+- **AI tool adapters**: Each supported AI tool has an adapter in `src/core/command-generation/adapters/`. New tool support requires adding an adapter and registering it in the factory.
+- **Shell completions**: New CLI commands should update completion generators in `src/core/completions/`.
+- **Legacy cleanup**: The init command detects and optionally cleans up legacy file layouts.
+- **Windows awareness**: Any file system or path logic must work on Windows. CI tests on `windows-latest` with PowerShell.
+
+## Useful Environment Variables
+
+- `OPENSPEC_TELEMETRY=0` — Disable telemetry
+- `DO_NOT_TRACK=1` — Disable telemetry (standard)
+- `VITEST_MAX_WORKERS=N` — Override test parallelism
+- `OPENSPEC_INTERACTIVE=0` — Force non-interactive mode (used in tests)
+- `OPENSPEC_CONCURRENCY=N` — Max concurrent validations (default 6)
+- `NO_COLOR=1` — Disable colored output (also `--no-color` flag)
+- `XDG_CONFIG_HOME` — Override global config directory
+
+## Key Files for Agents
+
+| File | Purpose |
+|------|---------|
+| `src/cli/index.ts` | CLI entry point; all commands are registered here |
+| `src/core/config.ts` | AI tool registry (`AI_TOOLS` constant) |
+| `src/core/global-config.ts` | XDG-compliant user config |
+| `src/core/profiles.ts` | Workflow profile definitions |
+| `src/core/init.ts` | Project initialization logic |
+| `src/core/validation/validator.ts` | Spec/change validation engine |
+| `test/helpers/run-cli.ts` | E2E test helper for CLI spawning |
+| `openspec/config.yaml` | This project's own OpenSpec configuration |
+| `build.js` | Build script (tsc wrapper) |
+| `vitest.config.ts` | Test configuration |
+| `eslint.config.js` | ESLint configuration (typescript-eslint) |
+
+## Upstream Sync Strategy (BR-OpenSpec Fork)
+
+BR-OpenSpec is a fork of the original OpenSpec project. All user-facing messages, UI text, workflow templates, and command descriptions are maintained in Brazilian Portuguese (`pt-BR`). When syncing with upstream, follow this process:
+
+### 1. Setup
+
+Ensure the upstream remote is configured:
+```bash
+git remote add upstream https://github.com/original/openspec.git # adjust URL as needed
+git fetch upstream
+```
+
+### 2. Create a Sync Branch
+
+```bash
+git checkout -b sync/upstream-$(date +%Y%m%d)
+git merge upstream/main --no-edit
+```
+
+### 3. Resolve Conflicts in Messages Catalog
+
+The central message catalog lives at `src/messages/index.ts`. When merging:
+- Preserve existing Portuguese translations
+- Add new English keys from upstream to the appropriate sections
+- Translate new keys to Brazilian Portuguese immediately
+- Maintain the existing domain-based organization (CLI_DESCRIPTIONS, CLI_MESSAGES, CHANGE_MESSAGES, etc.)
+
+### 4. Identify and Translate New User-Facing Strings
+
+After merge, find newly introduced hardcoded English strings:
+```bash
+git diff upstream/main..HEAD --name-only | grep "^src/"
+```
+
+Look for new occurrences of `console.log`, `console.error`, `console.warn`, `.description(`, and `message:` in modified files. Replace them with references to `src/messages/index.ts`.
+
+### 5. Update Project Name References
+
+New upstream code may reference "OpenSpec" instead of "BR-OpenSpec" in user-facing text. Update these in `src/messages/index.ts` and other user-facing locations. Do NOT change: `openspec` (CLI command), `openspec-` (prefixes), `OPENSPEC_` (constants), or technical URLs.
+
+### 6. Update Tests
+
+Run the full test suite:
+```bash
+pnpm test
+```
+
+Update test expectations in `test/` to match the Portuguese translations. Only change string assertions — never test logic.
+
+### 7. Validate
+
+```bash
+pnpm run build
+pnpm exec tsc --noEmit
+pnpm lint
+```
+
+### 8. Workflow Template
+
+An upstream sync workflow template is available at `src/core/templates/workflows/upstream-sync.ts` for agent-assisted syncs. It provides step-by-step instructions for the entire process.
+
+### Key Principle
+
+**Never leave English user-facing strings in `src/` after a sync.** All messages displayed to Brazilian users must be in `pt-BR`, centralized in `src/messages/index.ts`, and tested.
diff --git a/DEPLOY.md b/DEPLOY.md
new file mode 100644
index 0000000000..7547d0f51d
--- /dev/null
+++ b/DEPLOY.md
@@ -0,0 +1,189 @@
+# Configuração de Deploy e CI/CD
+
+Este documento descreve as configurações necessárias para que os workflows do GitHub Actions e o deploy para npm funcionem corretamente no fork BR-OpenSpec.
+
+---
+
+## 1. Ambiente Local para Testes
+
+### Requisitos
+
+- **Node.js**: ≥ 20.19.0 (recomendado 24.x para compatibilidade com OIDC)
+- **pnpm**: 9.x (lockfile compatível)
+- **TypeScript**: 5.9+
+
+### Comandos de Verificação
+
+```bash
+# Verificar versões
+node --version # v20.19.0 ou superior
+pnpm --version # 9.x
+
+# Instalar dependências
+pnpm install --frozen-lockfile
+
+# Build
+pnpm run build
+
+# Testes
+pnpm test
+
+# Type check
+pnpm exec tsc --noEmit
+
+# Lint
+pnpm lint
+```
+
+### Ambiente Atual do Workspace
+
+- Node.js: v24.14.0 ✅
+- pnpm: 10.33.2 ⚠️ (lockfile do projeto é para pnpm 9; funciona mas pode gerar warnings)
+- TypeScript: 5.9.3 ✅
+
+> **Nota**: O lockfile (`pnpm-lock.yaml`) foi gerado com pnpm 9. Se usar pnpm 10, pode ser necessário rodar `pnpm install` sem `--frozen-lockfile` para atualizar o lockfile, ou usar `COREPACK_ENABLE_AUTO_PIN=0` para evitar conflitos.
+
+---
+
+## 2. Configurações do Repositório GitHub
+
+### 2.1 Secrets Necessários
+
+Acesse **Settings → Secrets and variables → Actions** no repositório `fkmatsuda/BR-OpenSpec`.
+
+#### Secrets (Encrypted)
+
+| Secret | Descrição | Obrigatório |
+|--------|-----------|-------------|
+| `APP_PRIVATE_KEY` | Private key do GitHub App para geração de token. Usado no workflow `release-prepare.yml` para criar/atualizar o PR de versionamento. | **Sim** (para release automático) |
+
+#### Variables (Não-encriptadas)
+
+| Variable | Descrição | Obrigatório |
+|----------|-----------|-------------|
+| `APP_ID` | ID do GitHub App instalado no repositório. Usado junto com `APP_PRIVATE_KEY`. | **Sim** (para release automático) |
+
+### 2.2 GitHub App para Release
+
+O workflow `release-prepare.yml` usa um GitHub App para gerar tokens que permitem:
+- Criar/atualizar o PR "Version Packages"
+- Disparar CI no PR de versionamento (o `GITHUB_TOKEN` padrão não dispara workflows)
+
+#### Como Configurar
+
+1. **Criar GitHub App** (ou usar uma existente):
+ - Acesse **Settings → Developer settings → GitHub Apps → New GitHub App**
+ - Nome: `BR-OpenSpec Release Bot` (ou qualquer nome)
+ - Homepage URL: `https://github.com/fkmatsuda/BR-OpenSpec`
+ - **Desmarque** "Active" em Webhook (não precisamos)
+ - Permissões necessárias:
+ - **Contents**: Read and write
+ - **Pull requests**: Read and write
+ - **Actions**: Read (opcional, para verificar CI)
+
+2. **Gerar Private Key**:
+ - Na página do App, vá em **Private keys → Generate a private key**
+ - Baixe o arquivo `.pem`
+ - Converta para formato que o action aceite (base64 ou texto direto)
+
+3. **Instalar o App no Repositório**:
+ - Na página do App, vá em **Install App**
+ - Selecione `fkmatsuda/BR-OpenSpec`
+ - Anote o **App ID** (número visível na URL ou página do app)
+
+4. **Configurar Secrets e Variables**:
+ - `APP_ID`: cole o número do App ID
+ - `APP_PRIVATE_KEY`: cole o conteúdo do arquivo `.pem` (incluindo `-----BEGIN RSA PRIVATE KEY-----`)
+
+### 2.3 npm OIDC Trusted Publishing
+
+O deploy para npm usa **OIDC** (OpenID Connect) — não precisa de token `NPM_TOKEN`!
+
+#### Configuração no npm
+
+1. Acesse [npmjs.com](https://www.npmjs.com/) → seu pacote `@fkmatsuda/br-openspec`
+2. Vá em **Settings → Publish with provenance**
+3. Configure **Trusted Publishers**:
+ - **Link to GitHub**: `fkmatsuda/BR-OpenSpec`
+ - **Workflow name**: `release-prepare.yml`
+ - **Environment** (opcional): deixe em branco ou crie `production`
+
+#### Como Funciona
+
+- O workflow `release-prepare.yml` roda em pushes para `main`
+- Usa `permissions: id-token: write` para gerar um token OIDC
+- O npm verifica a assinatura do GitHub Actions e publica o pacote
+- Nenhum token longo-vivo é necessário
+
+---
+
+## 3. Workflows do GitHub Actions
+
+### `ci.yml`
+
+Executado em:
+- Pull requests para `main`
+- Merge groups
+- Pushes para `main`
+
+Jobs:
+- `test_pr`: Testes em Ubuntu (PRs)
+- `test_matrix`: Testes em Ubuntu, macOS e Windows (pushes para `main`)
+- `lint`: Build, type check, lint e verificação de artefatos
+- `nix-flake-validate`: Validação do build Nix (quando arquivos Nix mudam)
+- `validate-changesets`: Valida se changesets estão corretos
+- `required-checks-pr` / `required-checks-main`: Agregadores de status
+
+### `release-prepare.yml`
+
+Executado em:
+- Pushes para `main`
+
+Funcionalidade:
+- Usa Changesets para criar/atualizar o PR "Version Packages"
+- Publica no npm via OIDC quando o PR é mergeado
+- Requer: `APP_ID` e `APP_PRIVATE_KEY`
+
+---
+
+## 4. Checklist Pré-Deploy
+
+Antes de fazer merge para `main` e disparar o release:
+
+- [ ] `pnpm test` passa localmente (1439 testes)
+- [ ] `pnpm run build` gera `dist/cli/index.js`
+- [ ] `pnpm exec tsc --noEmit` não reporta erros
+- [ ] `pnpm lint` passa
+- [ ] Changeset foi adicionado (`pnpm changeset`)
+- [ ] `package.json` version está correta
+- [ ] Secrets `APP_ID` e `APP_PRIVATE_KEY` configurados
+- [ ] npm Trusted Publisher configurado para `fkmatsuda/BR-OpenSpec`
+
+---
+
+## 5. Troubleshooting
+
+### "Error: Resource not accessible by integration" no release
+
+- Verifique se o GitHub App está instalado no repositório
+- Verifique se `APP_PRIVATE_KEY` está correta e não expirou
+
+### "npm ERR! 403 Forbidden" no publish
+
+- Verifique se o pacote `@fkmatsuda/br-openspec` existe no npm
+- Verifique se o Trusted Publisher está configurado corretamente
+- Verifique se a versão no `package.json` é nova (não publicada antes)
+
+### Testes falham no Windows (CI)
+
+- O projeto usa `path.join()` e `path.resolve()` para compatibilidade cross-platform
+- Se falhar, verifique se há hardcoded `/` ou `\` no código
+
+---
+
+## 6. Referências
+
+- [Changesets Documentation](https://github.com/changesets/changesets)
+- [npm OIDC Trusted Publishing](https://docs.npmjs.com/generating-provenance-statements)
+- [GitHub App Tokens](https://github.com/actions/create-github-app-token)
+- [pnpm Workspace](https://pnpm.io/workspaces)
diff --git a/LICENSE b/LICENSE
index 84c125ae7b..743476f365 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2024 OpenSpec Contributors
+Copyright (c) 2024 BR-OpenSpec Contributors
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/MAINTAINERS.md b/MAINTAINERS.md
index d27e1ef466..deeac5fbe4 100644
--- a/MAINTAINERS.md
+++ b/MAINTAINERS.md
@@ -1,17 +1,9 @@
# Maintainers
-People who maintain and guide OpenSpec.
+People who maintain and guide BR-OpenSpec.
## Core Maintainers
| Name | GitHub | Role |
|------|--------|------|
-| Tabish Bidiwale | [@TabishB](https://github.com/TabishB) | Lead maintainer |
-
-## Advisors
-
-Advisors help shape technical direction and provide guidance to the project.
-
-| Name | GitHub | Focus |
-|------|--------|-------|
-| Hari Krishnan | [@harikrishnan83](https://github.com/harikrishnan83) | Technical direction |
+| fkmatsuda | [@fkmatsuda](https://github.com/fkmatsuda) | Lead maintainer |
diff --git a/README.md b/README.md
index 1d010ca8df..b25361aa50 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
-OpenSpec Dashboard
+BR-OpenSpec Dashboard
@@ -81,10 +82,10 @@ AI: Archived to openspec/changes/archive/2025-01-23-add-dark-mode/
**Requires Node.js 20.19.0 or higher.**
-Install OpenSpec globally:
+Install BR-OpenSpec globally:
```bash
-npm install -g @fission-ai/openspec@latest
+npm install -g @fkmatsuda/br-openspec@latest
```
Then navigate to your project directory and initialize:
@@ -115,9 +116,9 @@ If you want the expanded workflow (`/opsx:new`, `/opsx:continue`, `/opsx:ff`, `/
→ **[Customization](docs/customization.md)**: make it yours
-## Why OpenSpec?
+## Why BR-OpenSpec?
-AI coding assistants are powerful but unpredictable when requirements live only in chat history. OpenSpec adds a lightweight spec layer so you agree on what to build before any code is written.
+AI coding assistants are powerful but unpredictable when requirements live only in chat history. BR-OpenSpec adds a lightweight spec layer so you agree on what to build before any code is written.
- **Agree before you build** — human and AI align on specs before code gets written
- **Stay organized** — each change gets its own folder with proposal, specs, design, and tasks
@@ -126,18 +127,18 @@ AI coding assistants are powerful but unpredictable when requirements live only
### How we compare
-**vs. [Spec Kit](https://github.com/github/spec-kit)** (GitHub) — Thorough but heavyweight. Rigid phase gates, lots of Markdown, Python setup. OpenSpec is lighter and lets you iterate freely.
+**vs. [Spec Kit](https://github.com/github/spec-kit)** (GitHub) — Thorough but heavyweight. Rigid phase gates, lots of Markdown, Python setup. BR-OpenSpec is lighter and lets you iterate freely.
-**vs. [Kiro](https://kiro.dev)** (AWS) — Powerful but you're locked into their IDE and limited to Claude models. OpenSpec works with the tools you already use.
+**vs. [Kiro](https://kiro.dev)** (AWS) — Powerful but you're locked into their IDE and limited to Claude models. BR-OpenSpec works with the tools you already use.
-**vs. nothing** — AI coding without specs means vague prompts and unpredictable results. OpenSpec brings predictability without the ceremony.
+**vs. nothing** — AI coding without specs means vague prompts and unpredictable results. BR-OpenSpec brings predictability without the ceremony.
-## Updating OpenSpec
+## Updating BR-OpenSpec
**Upgrade the package**
```bash
-npm install -g @fission-ai/openspec@latest
+npm install -g @fkmatsuda/br-openspec@latest
```
**Refresh agent instructions**
@@ -148,19 +149,29 @@ Run this inside each project to regenerate AI guidance and ensure the latest sla
openspec update
```
+**Manage IDE/Code Agent configurations**
+
+Add or remove supported IDE and Code Agent integrations without re-running `init`:
+
+```bash
+openspec tools # interactive checklist
+openspec tools --add claude,cursor
+openspec tools --remove windsurf
+```
+
## Usage Notes
-**Model selection**: OpenSpec works best with high-reasoning models. We recommend Opus 4.5 and GPT 5.2 for both planning and implementation.
+**Model selection**: BR-OpenSpec works best with high-reasoning models. We recommend Opus 4.5 and GPT 5.2 for both planning and implementation.
-**Context hygiene**: OpenSpec benefits from a clean context window. Clear your context before starting implementation and maintain good context hygiene throughout your session.
+**Context hygiene**: BR-OpenSpec benefits from a clean context window. Clear your context before starting implementation and maintain good context hygiene throughout your session.
## Contributing
**Small fixes** — Bug fixes, typo corrections, and minor improvements can be submitted directly as PRs.
-**Larger changes** — For new features, significant refactors, or architectural changes, please submit an OpenSpec change proposal first so we can align on intent and goals before implementation begins.
+**Larger changes** — For new features, significant refactors, or architectural changes, please submit a BR-OpenSpec change proposal first so we can align on intent and goals before implementation begins.
-When writing proposals, keep the OpenSpec philosophy in mind: we serve a wide variety of users across different coding agents, models, and use cases. Changes should work well for everyone.
+When writing proposals, keep the BR-OpenSpec philosophy in mind: we serve a wide variety of users across different coding agents, models, and use cases. Changes should work well for everyone.
**AI-generated code is welcome** — as long as it's been tested and verified. PRs containing AI-generated code should mention the coding agent and model used (e.g., "Generated with Claude Code using claude-opus-4-5-20251101").
@@ -177,7 +188,7 @@ When writing proposals, keep the OpenSpec philosophy in mind: we serve a wide va
Telemetry
-OpenSpec collects anonymous usage stats.
+BR-OpenSpec collects anonymous usage stats.
We collect only command names and version to understand usage patterns. No arguments, paths, content, or PII. Automatically disabled in CI.
diff --git a/README.pt-BR.md b/README.pt-BR.md
new file mode 100644
index 0000000000..2963ae7e2a
--- /dev/null
+++ b/README.pt-BR.md
@@ -0,0 +1,212 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+O framework de spec mais querido.
+
+[](https://github.com/fkmatsuda/BR-OpenSpec/stargazers)
+[](https://www.npmjs.com/package/@fkmatsuda/br-openspec)
+[](https://github.com/fkmatsuda/BR-OpenSpec/graphs/contributors)
+
+
+
+Nossa filosofia:
+
+> Esta filosofia foi definida pelo projeto original [OpenSpec](https://github.com/tab-tools/openspec) e o BR-OpenSpec fará o possível para honrá-la em cada decisão.
+
+```text
+→ fluido, não rígido
+→ iterativo, não em cascata
+→ simples, não complexo
+→ feito para brownfield, não apenas greenfield
+→ escalável de projetos pessoais a empresas
+```
+
+> [!TIP]
+> **Novo fluxo de trabalho disponível!** Reconstruímos o BR-OpenSpec com um novo fluxo de trabalho guiado por artefatos.
+>
+> Execute `/opsx:propose "sua ideia"` para começar. → [Saiba mais aqui](docs/pt-BR/opsx.md)
+
+
+ Siga @0xTab no X para atualizações.
+
+
+
+
+## Veja em ação
+
+```text
+Você: /opsx:propose add-dark-mode
+IA: Criado openspec/changes/add-dark-mode/
+ ✓ proposal.md — por que estamos fazendo isso, o que está mudando
+ ✓ specs/ — requisitos e cenários
+ ✓ design.md — abordagem técnica
+ ✓ tasks.md — checklist de implementação
+ Pronto para implementação!
+
+Você: /opsx:apply
+IA: Implementando tarefas...
+ ✓ 1.1 Adicionar provedor de contexto de tema
+ ✓ 1.2 Criar componente de alternância
+ ✓ 2.1 Adicionar variáveis CSS
+ ✓ 2.2 Conectar localStorage
+ Todas as tarefas concluídas!
+
+Você: /opsx:archive
+IA: Arquivado em openspec/changes/archive/2025-01-23-add-dark-mode/
+ Specs atualizadas. Pronto para a próxima funcionalidade.
+```
+
+
+Dashboard do BR-OpenSpec
+
+
+
+
+
+
+
+## Início Rápido
+
+**Requer Node.js 20.19.0 ou superior.**
+
+Instale o BR-OpenSpec globalmente:
+
+```bash
+npm install -g @fkmatsuda/br-openspec@latest
+```
+
+Em seguida, navegue até o diretório do seu projeto e inicialize:
+
+```bash
+cd your-project
+openspec init
+```
+
+Agora diga à sua IA: `/opsx:propose `
+
+Se você quiser o fluxo de trabalho expandido (`/opsx:new`, `/opsx:continue`, `/opsx:ff`, `/opsx:verify`, `/opsx:sync`, `/opsx:bulk-archive`, `/opsx:onboard`), selecione-o com `openspec config profile` e aplique com `openspec update`.
+
+> [!NOTE]
+> Não tem certeza se sua ferramenta é suportada? [Veja a lista completa](docs/pt-BR/supported-tools.md) – suportamos mais de 25 ferramentas e crescendo.
+>
+> Também funciona com pnpm, yarn, bun e nix. [Veja as opções de instalação](docs/pt-BR/installation.md).
+
+## Documentação
+
+→ **[Primeiros Passos](docs/pt-BR/getting-started.md)**: primeiros passos
+→ **[Fluxos de Trabalho](docs/pt-BR/workflows.md)**: combinações e padrões
+→ **[Comandos](docs/pt-BR/commands.md)**: slash commands e skills
+→ **[CLI](docs/pt-BR/cli.md)**: referência do terminal
+→ **[Ferramentas Suportadas](docs/pt-BR/supported-tools.md)**: integrações e caminhos de instalação
+→ **[Conceitos](docs/pt-BR/concepts.md)**: como tudo se encaixa
+→ **[Multi-Idioma](docs/pt-BR/multi-language.md)**: suporte a múltiplos idiomas
+→ **[Personalização](docs/pt-BR/customization.md)**: faça do seu jeito
+
+
+## Por que o BR-OpenSpec?
+
+Assistentes de codificação com IA são poderosos, mas imprevisíveis quando os requisitos vivem apenas no histórico do chat. O BR-OpenSpec adiciona uma camada leve de especificação para que você concorde sobre o que construir antes de qualquer código ser escrito.
+
+> **Por que este fork?** O BR-OpenSpec é mantido em **Português Brasileiro** e destina-se a quem implementa e mantém projetos com domínios de negócio primariamente em pt-BR, bem como a quem não tem o inglês como língua nativa. Ter specs, propostas e tarefas no idioma do time e do negócio reduz o risco de interpretações erradas e acelera o alinhamento entre humanos e IA.
+
+- **Alinhe antes de construir** — humano e IA alinham as specs antes de o código ser escrito
+- **Mantenha-se organizado** — cada mudança tem sua própria pasta com proposta, specs, design e tarefas
+- **Trabalhe com fluidez** — atualize qualquer artefato a qualquer momento, sem fases rígidas
+- **Use suas ferramentas** — funciona com mais de 20 assistentes de IA via slash commands
+
+### Como nos comparamos
+
+**vs. [Spec Kit](https://github.com/github/spec-kit)** (GitHub) — Completo, mas pesado. Fases rígidas, muito Markdown, configuração em Python. O BR-OpenSpec é mais leve e permite iterar livremente.
+
+**vs. [Kiro](https://kiro.dev)** (AWS) — Poderoso, mas você fica preso à IDE deles e limitado aos modelos Claude. O BR-OpenSpec funciona com as ferramentas que você já usa.
+
+**vs. nada** — Codificação com IA sem specs significa prompts vagos e resultados imprevisíveis. O BR-OpenSpec traz previsibilidade sem a burocracia.
+
+## Atualizando o BR-OpenSpec
+
+**Atualize o pacote**
+
+```bash
+npm install -g @fkmatsuda/br-openspec@latest
+```
+
+**Atualize as instruções do agente**
+
+Execute dentro de cada projeto para regenerar a orientação da IA e garantir que os slash commands mais recentes estejam ativos:
+
+```bash
+openspec update
+```
+
+**Gerenciar configurações de IDE/Code Agent**
+
+Adicione ou remova integrações de IDE e Code Agent suportadas sem precisar executar `init` novamente:
+
+```bash
+openspec tools # lista interativa
+openspec tools --add claude,cursor
+openspec tools --remove windsurf
+```
+
+## Notas de Uso
+
+**Seleção de modelo**: O BR-OpenSpec funciona melhor com modelos de alto raciocínio. Recomendamos Opus 4.5 e GPT 5.2 tanto para planejamento quanto para implementação.
+
+**Higiene de contexto**: O BR-OpenSpec se beneficia de uma janela de contexto limpa. Limpe seu contexto antes de iniciar a implementação e mantenha uma boa higiene de contexto ao longo da sua sessão.
+
+## Contribuindo
+
+**Pequenas correções** — Correções de bugs, erros de digitação e melhorias menores podem ser enviadas diretamente como PRs.
+
+**Mudanças maiores** — Para novas funcionalidades, refatorações significativas ou mudanças arquiteturais, envie primeiro uma proposta de mudança do BR-OpenSpec para que possamos alinhar a intenção e os objetivos antes de começar a implementação.
+
+Ao escrever propostas, tenha em mente a filosofia do BR-OpenSpec: servimos a uma grande variedade de usuários em diferentes agentes de codificação, modelos e casos de uso. As mudanças devem funcionar bem para todos.
+
+**Código gerado por IA é bem-vindo** — desde que tenha sido testado e verificado. PRs contendo código gerado por IA devem mencionar o agente de codificação e o modelo usado (ex.: "Gerado com Claude Code usando claude-opus-4-5-20251101").
+
+### Desenvolvimento
+
+- Instalar dependências: `pnpm install`
+- Compilar: `pnpm run build`
+- Testar: `pnpm test`
+- Desenvolver CLI localmente: `pnpm run dev` ou `pnpm run dev:cli`
+- Commits convencionais (uma linha): `type(scope): subject`
+
+## Outros
+
+
+Telemetria
+
+O BR-OpenSpec coleta estatísticas de uso anônimas.
+
+Coletamos apenas nomes de comandos e versão para entender padrões de uso. Sem argumentos, caminhos, conteúdo ou PII. Desativado automaticamente em CI.
+
+**Desativar:** `export OPENSPEC_TELEMETRY=0` ou `export DO_NOT_TRACK=1`
+
+
+
+
+Mantenedores e Consultores
+
+Veja [MAINTAINERS.md](MAINTAINERS.md) para a lista de mantenedores principais e consultores que ajudam a guiar o projeto.
+
+
+
+
+
+## Licença
+
+MIT
diff --git a/README_OLD.md b/README_OLD.md
index e0f7f39a82..17ad184936 100644
--- a/README_OLD.md
+++ b/README_OLD.md
@@ -1,5 +1,5 @@
-
+
@@ -10,12 +10,11 @@
Spec-driven development for AI coding assistants.
-
-
-
+
+
+
-
@@ -23,7 +22,7 @@
- Follow @0xTab on X for updates · Join the OpenSpec Discord for help and questions.
+ Follow @0xTab on X for updates.
@@ -143,7 +142,7 @@ These tools automatically read workflow instructions from `openspec/AGENTS.md`.
**Option A: Using npm**
```bash
-npm install -g @fission-ai/openspec@latest
+npm install -g @fkmatsuda/br-openspec@latest
```
Verify installation:
@@ -155,12 +154,12 @@ openspec --version
Run OpenSpec directly without installation:
```bash
-nix run github:Fission-AI/OpenSpec -- init
+nix run github:fkmatsuda/BR-OpenSpec -- init
```
Or install to your profile:
```bash
-nix profile install github:Fission-AI/OpenSpec
+nix profile install github:fkmatsuda/BR-OpenSpec
```
Or add to your development environment in `flake.nix`:
@@ -168,7 +167,7 @@ Or add to your development environment in `flake.nix`:
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
- openspec.url = "github:Fission-AI/OpenSpec";
+ openspec.url = "github:fkmatsuda/BR-OpenSpec";
};
outputs = { nixpkgs, openspec, ... }: {
@@ -403,7 +402,7 @@ Run `openspec update` whenever someone switches tools so your agents pick up the
1. **Upgrade the package**
```bash
- npm install -g @fission-ai/openspec@latest
+ npm install -g @fkmatsuda/br-openspec@latest
```
2. **Refresh agent instructions**
- Run `openspec update` inside each project to regenerate AI guidance and ensure the latest slash commands are active.
diff --git a/docs/cli.md b/docs/cli.md
index ddcdaa0a41..4cc7d5da05 100644
--- a/docs/cli.md
+++ b/docs/cli.md
@@ -1,12 +1,12 @@
# CLI Reference
-The OpenSpec CLI (`openspec`) provides terminal commands for project setup, validation, status inspection, and management. These commands complement the AI slash commands (like `/opsx:propose`) documented in [Commands](commands.md).
+The BR-OpenSpec CLI (`openspec`) provides terminal commands for project setup, validation, status inspection, and management. These commands complement the AI slash commands (like `/opsx:propose`) documented in [Commands](commands.md).
## Summary
| Category | Commands | Purpose |
|----------|----------|---------|
-| **Setup** | `init`, `update` | Initialize and update OpenSpec in your project |
+| **Setup** | `init`, `update` | Initialize and update BR-OpenSpec in your project |
| **Browsing** | `list`, `view`, `show` | Explore changes and specs |
| **Validation** | `validate` | Check changes and specs for issues |
| **Lifecycle** | `archive` | Finalize completed changes |
@@ -65,7 +65,7 @@ These options work with all commands:
### `openspec init`
-Initialize OpenSpec in your project. Creates the folder structure and configures AI tool integrations.
+Initialize BR-OpenSpec in your project. Creates the folder structure and configures AI tool integrations.
Default behavior uses global config defaults: profile `core`, delivery `both`, workflows `propose, explore, apply, archive`.
@@ -89,7 +89,7 @@ openspec init [path] [options]
`--profile custom` uses whatever workflows are currently selected in global config (`openspec config profile`).
-**Supported tool IDs (`--tools`):** `amazon-q`, `antigravity`, `auggie`, `claude`, `cline`, `codex`, `codebuddy`, `continue`, `costrict`, `crush`, `cursor`, `factory`, `gemini`, `github-copilot`, `iflow`, `kilocode`, `kiro`, `opencode`, `pi`, `qoder`, `qwen`, `roocode`, `trae`, `windsurf`
+**Supported tool IDs (`--tools`):** `amazon-q`, `antigravity`, `auggie`, `bob`, `claude`, `cline`, `codex`, `codebuddy`, `continue`, `costrict`, `crush`, `cursor`, `factory`, `forgecode`, `gemini`, `github-copilot`, `iflow`, `junie`, `kilocode`, `kimi`, `kiro`, `lingma`, `opencode`, `pi`, `qoder`, `qwen`, `roocode`, `trae`, `windsurf`
**Examples:**
@@ -131,7 +131,7 @@ openspec/
### `openspec update`
-Update OpenSpec instruction files after upgrading the CLI. Re-generates AI tool configuration files using your current global profile, selected workflows, and delivery mode.
+Update BR-OpenSpec instruction files after upgrading the CLI. Re-generates AI tool configuration files using your current global profile, selected workflows, and delivery mode.
```
openspec update [path] [options]
@@ -153,7 +153,7 @@ openspec update [path] [options]
```bash
# Update instruction files after npm upgrade
-npm update @fission-ai/openspec
+npm update @fkmatsuda/br-openspec
openspec update
```
@@ -743,7 +743,7 @@ openspec schema which spec-driven
```
spec-driven resolves from: package
- Source: /usr/local/lib/node_modules/@fission-ai/openspec/schemas/spec-driven
+ Source: /usr/local/lib/node_modules/@fkmatsuda/br-openspec/schemas/spec-driven
```
**Schema precedence:**
@@ -758,7 +758,7 @@ spec-driven resolves from: package
### `openspec config`
-View and modify global OpenSpec configuration.
+View and modify global BR-OpenSpec configuration.
```
openspec config [options]
@@ -818,7 +818,7 @@ openspec config profile core
- Keep current settings (exit)
If you keep current settings, no changes are written and no update prompt is shown.
-If there are no config changes but the current project files are out of sync with your global profile/delivery, OpenSpec will show a warning and suggest running `openspec update`.
+If there are no config changes but the current project files are out of sync with your global profile/delivery, BR-OpenSpec will show a warning and suggest running `openspec update`.
Pressing `Ctrl+C` also cancels the flow cleanly (no stack trace) and exits with code `130`.
In the workflow checklist, `[x]` means the workflow is selected in global config. To apply those selections to project files, run `openspec update` (or choose `Apply changes to this project now?` when prompted inside a project).
@@ -842,7 +842,7 @@ openspec config profile
### `openspec feedback`
-Submit feedback about OpenSpec. Creates a GitHub issue.
+Submit feedback about BR-OpenSpec. Creates a GitHub issue.
```
openspec feedback [options]
@@ -873,7 +873,7 @@ openspec feedback "Add support for custom artifact types" \
### `openspec completion`
-Manage shell completions for the OpenSpec CLI.
+Manage shell completions for the BR-OpenSpec CLI.
```
openspec completion [shell]
diff --git a/docs/commands.md b/docs/commands.md
index fd4bb7fe13..e428222602 100644
--- a/docs/commands.md
+++ b/docs/commands.md
@@ -1,6 +1,6 @@
# Commands
-This is the reference for OpenSpec's slash commands. These commands are invoked in your AI coding assistant's chat interface (e.g., Claude Code, Cursor, Windsurf).
+This is the reference for BR-OpenSpec's slash commands. These commands are invoked in your AI coding assistant's chat interface (e.g., Claude Code, Cursor, Windsurf).
For workflow patterns and when to use each command, see [Workflows](workflows.md). For CLI commands, see [CLI](cli.md).
@@ -550,7 +550,7 @@ AI: ✓ Archived add-dark-mode
### `/opsx:onboard`
-Guided onboarding through the complete OpenSpec workflow. An interactive tutorial using your actual codebase.
+Guided onboarding through the complete BR-OpenSpec workflow. An interactive tutorial using your actual codebase.
**Syntax:**
```
@@ -582,7 +582,7 @@ Guided onboarding through the complete OpenSpec workflow. An interactive tutoria
```
You: /opsx:onboard
-AI: Welcome to OpenSpec!
+AI: Welcome to BR-OpenSpec!
I'll walk you through the complete workflow using your actual codebase.
We'll find something small to improve, create a proper change for it,
@@ -618,6 +618,7 @@ Different AI tools use slightly different command syntax. Use the format that ma
| Cursor | `/opsx-propose`, `/opsx-apply` |
| Windsurf | `/opsx-propose`, `/opsx-apply` |
| Copilot (IDE) | `/opsx-propose`, `/opsx-apply` |
+| Kimi Code CLI | Skill-based invocations such as `/skill:openspec-propose`, `/skill:openspec-apply-change` (no generated `opsx-*` command files) |
| Trae | Skill-based invocations such as `/openspec-propose`, `/openspec-apply-change` (no generated `opsx-*` command files) |
The intent is the same across tools, but how commands are surfaced can differ by integration.
@@ -677,10 +678,10 @@ The specified schema doesn't exist.
### Commands not recognized
-The AI tool doesn't recognize OpenSpec commands.
+The AI tool doesn't recognize BR-OpenSpec commands.
**Solutions:**
-- Ensure OpenSpec is initialized: `openspec init`
+- Ensure BR-OpenSpec is initialized: `openspec init`
- Regenerate skills: `openspec update`
- Check that `.claude/skills/` directory exists (for Claude Code)
- Restart your AI tool to pick up new skills
diff --git a/docs/concepts.md b/docs/concepts.md
index b929a588a7..5d0526ed9c 100644
--- a/docs/concepts.md
+++ b/docs/concepts.md
@@ -1,10 +1,10 @@
# Concepts
-This guide explains the core ideas behind OpenSpec and how they fit together. For practical usage, see [Getting Started](getting-started.md) and [Workflows](workflows.md).
+This guide explains the core ideas behind BR-OpenSpec and how they fit together. For practical usage, see [Getting Started](getting-started.md) and [Workflows](workflows.md).
## Philosophy
-OpenSpec is built around four principles:
+BR-OpenSpec is built around four principles:
```
fluid not rigid — no phase gates, work on what makes sense
@@ -15,17 +15,17 @@ brownfield-first — works with existing codebases, not just greenfield
### Why These Principles Matter
-**Fluid not rigid.** Traditional spec systems lock you into phases: first you plan, then you implement, then you're done. OpenSpec is more flexible — you can create artifacts in any order that makes sense for your work.
+**Fluid not rigid.** Traditional spec systems lock you into phases: first you plan, then you implement, then you're done. BR-OpenSpec is more flexible — you can create artifacts in any order that makes sense for your work.
-**Iterative not waterfall.** Requirements change. Understanding deepens. What seemed like a good approach at the start might not hold up after you see the codebase. OpenSpec embraces this reality.
+**Iterative not waterfall.** Requirements change. Understanding deepens. What seemed like a good approach at the start might not hold up after you see the codebase. BR-OpenSpec embraces this reality.
-**Easy not complex.** Some spec frameworks require extensive setup, rigid formats, or heavyweight processes. OpenSpec stays out of your way. Initialize in seconds, start working immediately, customize only if you need to.
+**Easy not complex.** Some spec frameworks require extensive setup, rigid formats, or heavyweight processes. BR-OpenSpec stays out of your way. Initialize in seconds, start working immediately, customize only if you need to.
-**Brownfield-first.** Most software work isn't building from scratch — it's modifying existing systems. OpenSpec's delta-based approach makes it easy to specify changes to existing behavior, not just describe new systems.
+**Brownfield-first.** Most software work isn't building from scratch — it's modifying existing systems. BR-OpenSpec's delta-based approach makes it easy to specify changes to existing behavior, not just describe new systems.
## The Big Picture
-OpenSpec organizes your work into two main areas:
+BR-OpenSpec organizes your work into two main areas:
```
┌────────────────────────────────────────────────────────────────────┐
@@ -154,7 +154,7 @@ Quick test:
### Keep It Lightweight: Progressive Rigor
-OpenSpec aims to avoid bureaucracy. Use the lightest level that still makes the change verifiable.
+BR-OpenSpec aims to avoid bureaucracy. Use the lightest level that still makes the change verifiable.
**Lite spec (default):**
- Short behavior-first requirements
@@ -345,7 +345,7 @@ Tasks are the **implementation checklist** — concrete steps with checkboxes.
## Delta Specs
-Delta specs are the key concept that makes OpenSpec work for brownfield development. They describe **what's changing** rather than restating the entire spec.
+Delta specs are the key concept that makes BR-OpenSpec work for brownfield development. They describe **what's changing** rather than restating the entire spec.
### The Format
diff --git a/docs/customization.md b/docs/customization.md
index ee4596e5b0..7808452dac 100644
--- a/docs/customization.md
+++ b/docs/customization.md
@@ -1,6 +1,6 @@
# Customization
-OpenSpec provides three levels of customization:
+BR-OpenSpec provides three levels of customization:
| Level | What it does | Best for |
|-------|--------------|----------|
@@ -12,7 +12,7 @@ OpenSpec provides three levels of customization:
## Project Configuration
-The `openspec/config.yaml` file is the easiest way to customize OpenSpec for your team. It lets you:
+The `openspec/config.yaml` file is the easiest way to customize BR-OpenSpec for your team. It lets you:
- **Set a default schema** - Skip `--schema` on every command
- **Inject project context** - AI sees your tech stack, conventions, etc.
@@ -82,7 +82,7 @@ Tech stack: TypeScript, React, Node.js, PostgreSQL
### Schema Resolution Order
-When OpenSpec needs a schema, it checks in this order:
+When BR-OpenSpec needs a schema, it checks in this order:
1. CLI flag: `--schema `
2. Change metadata (`.openspec.yaml` in the change folder)
@@ -269,7 +269,7 @@ Path: /path/to/project/openspec/schemas/my-workflow
---
-> **Note:** OpenSpec also supports user-level schemas at `~/.local/share/openspec/schemas/` for sharing across projects, but project-level schemas in `openspec/schemas/` are recommended since they're version-controlled with your code.
+> **Note:** BR-OpenSpec also supports user-level schemas at `~/.local/share/openspec/schemas/` for sharing across projects, but project-level schemas in `openspec/schemas/` are recommended since they're version-controlled with your code.
---
diff --git a/docs/getting-started.md b/docs/getting-started.md
index 6f4b888627..db42a1a1f8 100644
--- a/docs/getting-started.md
+++ b/docs/getting-started.md
@@ -1,10 +1,10 @@
# Getting Started
-This guide explains how OpenSpec works after you've installed and initialized it. For installation instructions, see the [main README](../README.md#quick-start).
+This guide explains how BR-OpenSpec works after you've installed and initialized it. For installation instructions, see the [main README](../README.md#quick-start).
## How It Works
-OpenSpec helps you and your AI coding assistant agree on what to build before any code is written.
+BR-OpenSpec helps you and your AI coding assistant agree on what to build before any code is written.
**Default quick path (core profile):**
@@ -20,7 +20,7 @@ OpenSpec helps you and your AI coding assistant agree on what to build before an
The default global profile is `core`, which includes `propose`, `explore`, `apply`, and `archive`. You can enable the expanded workflow commands with `openspec config profile` and then `openspec update`.
-## What OpenSpec Creates
+## What BR-OpenSpec Creates
After running `openspec init`, your project has this structure:
@@ -70,7 +70,7 @@ You can always go back and refine earlier artifacts as you learn more during imp
## How Delta Specs Work
-Delta specs are the key concept in OpenSpec. They show what's changing relative to your current specs.
+Delta specs are the key concept in BR-OpenSpec. They show what's changing relative to your current specs.
### The Format
@@ -250,4 +250,4 @@ openspec view
- [Workflows](workflows.md) - Common patterns and when to use each command
- [Commands](commands.md) - Full reference for all slash commands
- [Concepts](concepts.md) - Deeper understanding of specs, changes, and schemas
-- [Customization](customization.md) - Make OpenSpec work your way
+- [Customization](customization.md) - Make BR-OpenSpec work your way
diff --git a/docs/installation.md b/docs/installation.md
index 78910513c9..d3f3f5d91f 100644
--- a/docs/installation.md
+++ b/docs/installation.md
@@ -9,39 +9,39 @@
### npm
```bash
-npm install -g @fission-ai/openspec@latest
+npm install -g @fkmatsuda/br-openspec@latest
```
### pnpm
```bash
-pnpm add -g @fission-ai/openspec@latest
+pnpm add -g @fkmatsuda/br-openspec@latest
```
### yarn
```bash
-yarn global add @fission-ai/openspec@latest
+yarn global add @fkmatsuda/br-openspec@latest
```
### bun
```bash
-bun add -g @fission-ai/openspec@latest
+bun add -g @fkmatsuda/br-openspec@latest
```
## Nix
-Run OpenSpec directly without installation:
+Run BR-OpenSpec directly without installation:
```bash
-nix run github:Fission-AI/OpenSpec -- init
+nix run github:fkmatsuda/BR-OpenSpec -- init
```
Or install to your profile:
```bash
-nix profile install github:Fission-AI/OpenSpec
+nix profile install github:fkmatsuda/BR-OpenSpec
```
Or add to your development environment in `flake.nix`:
@@ -50,7 +50,7 @@ Or add to your development environment in `flake.nix`:
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
- openspec.url = "github:Fission-AI/OpenSpec";
+ openspec.url = "github:fkmatsuda/BR-OpenSpec";
};
outputs = { nixpkgs, openspec, ... }: {
@@ -69,7 +69,7 @@ openspec --version
## Next Steps
-After installing, initialize OpenSpec in your project:
+After installing, initialize BR-OpenSpec in your project:
```bash
cd your-project
diff --git a/docs/migration-guide.md b/docs/migration-guide.md
index 5091ce4380..e9c0aa82f7 100644
--- a/docs/migration-guide.md
+++ b/docs/migration-guide.md
@@ -1,6 +1,6 @@
# Migrating to OPSX
-This guide helps you transition from the legacy OpenSpec workflow to OPSX. The migration is designed to be smooth—your existing work is preserved, and the new system offers more flexibility.
+This guide helps you transition from the legacy BR-OpenSpec workflow to OPSX. The migration is designed to be smooth—your existing work is preserved, and the new system offers more flexibility.
## What's Changing?
@@ -27,17 +27,17 @@ The migration process is designed with preservation in mind:
- **Active changes in `openspec/changes/`** — Completely preserved. You can continue them with OPSX commands.
- **Archived changes** — Untouched. Your history remains intact.
- **Main specs in `openspec/specs/`** — Untouched. These are your source of truth.
-- **Your content in CLAUDE.md, AGENTS.md, etc.** — Preserved. Only the OpenSpec marker blocks are removed; everything you wrote stays.
+- **Your content in CLAUDE.md, AGENTS.md, etc.** — Preserved. Only the BR-OpenSpec marker blocks are removed; everything you wrote stays.
### What Gets Removed
-Only OpenSpec-managed files that are being replaced:
+Only BR-OpenSpec-managed files that are being replaced:
| What | Why |
|------|-----|
| Legacy slash command directories/files | Replaced by the new skills system |
| `openspec/AGENTS.md` | Obsolete workflow trigger |
-| OpenSpec markers in `CLAUDE.md`, `AGENTS.md`, etc. | No longer needed |
+| BR-OpenSpec markers in `CLAUDE.md`, `AGENTS.md`, etc. | No longer needed |
**Legacy command locations by tool** (examples—your tool may vary):
@@ -51,7 +51,7 @@ Only OpenSpec-managed files that are being replaced:
The migration detects whichever tools you have configured and cleans up their legacy files.
-The removal list may seem long, but these are all files that OpenSpec originally created. Your own content is never deleted.
+The removal list may seem long, but these are all files that BR-OpenSpec originally created. Your own content is never deleted.
### What Needs Your Attention
@@ -67,7 +67,7 @@ One file requires manual migration:
The old `project.md` was passive—agents might read it, might not, might forget what they read. We found reliability was inconsistent.
-The new `config.yaml` context is **actively injected into every OpenSpec planning request**. This means your project conventions, tech stack, and rules are always present when the AI is creating artifacts. Higher reliability.
+The new `config.yaml` context is **actively injected into every BR-OpenSpec planning request**. This means your project conventions, tech stack, and rules are always present when the AI is creating artifacts. Higher reliability.
**The tradeoff:**
@@ -98,9 +98,9 @@ openspec init
The init command detects legacy files and guides you through cleanup:
```
-Upgrading to the new OpenSpec
+Upgrading to the new BR-OpenSpec
-OpenSpec now uses agent skills, the emerging standard across coding
+BR-OpenSpec now uses agent skills, the emerging standard across coding
agents. This simplifies your setup while keeping everything working
as before.
@@ -110,7 +110,7 @@ No user content to preserve:
• openspec/AGENTS.md
Files to update
-OpenSpec markers will be removed, your content preserved:
+BR-OpenSpec markers will be removed, your content preserved:
• CLAUDE.md
• AGENTS.md
@@ -119,7 +119,7 @@ Needs your attention
We won't delete this file. It may contain useful project context.
The new openspec/config.yaml has a "context:" section for planning
- context. This is included in every OpenSpec request and works more
+ context. This is included in every BR-OpenSpec request and works more
reliably than the old project.md approach.
Review project.md, move any useful content to config.yaml's context
@@ -131,7 +131,7 @@ Needs your attention
**What happens when you say yes:**
1. Legacy slash command directories are removed
-2. OpenSpec markers are stripped from `CLAUDE.md`, `AGENTS.md`, etc. (your content stays)
+2. BR-OpenSpec markers are stripped from `CLAUDE.md`, `AGENTS.md`, etc. (your content stays)
3. `openspec/AGENTS.md` is deleted
4. New skills are installed in `.claude/skills/`
5. `openspec/config.yaml` is created with a default schema
@@ -260,7 +260,7 @@ When migrating, be selective. Ask yourself: "Does the AI need this for *every* p
If you're unsure how to distill your project.md, ask your AI assistant:
```
-I'm migrating from OpenSpec's old project.md to the new config.yaml format.
+I'm migrating from BR-OpenSpec's old project.md to the new config.yaml format.
Here's my current project.md:
[paste your project.md content]
@@ -562,8 +562,8 @@ project/
│ ├── openspec-explore/
│ ├── openspec-apply-change/
│ └── ... # expanded profile adds new/continue/ff/etc.
-├── CLAUDE.md # OpenSpec markers removed, your content preserved
-└── AGENTS.md # OpenSpec markers removed, your content preserved
+├── CLAUDE.md # BR-OpenSpec markers removed, your content preserved
+└── AGENTS.md # BR-OpenSpec markers removed, your content preserved
```
### What's Gone
@@ -571,7 +571,7 @@ project/
- `.claude/commands/openspec/` — replaced by `.claude/skills/`
- `openspec/AGENTS.md` — obsolete
- `openspec/project.md` — migrate to `config.yaml`, then delete
-- OpenSpec marker blocks in `CLAUDE.md`, `AGENTS.md`, etc.
+- BR-OpenSpec marker blocks in `CLAUDE.md`, `AGENTS.md`, etc.
### Command Cheatsheet
@@ -590,6 +590,5 @@ project/
## Getting Help
-- **Discord**: [discord.gg/YctCnvvshC](https://discord.gg/YctCnvvshC)
-- **GitHub Issues**: [github.com/Fission-AI/OpenSpec/issues](https://github.com/Fission-AI/OpenSpec/issues)
+- **GitHub Issues**: [github.com/fkmatsuda/BR-OpenSpec/issues](https://github.com/fkmatsuda/BR-OpenSpec/issues)
- **Documentation**: [docs/opsx.md](opsx.md) for the full OPSX reference
diff --git a/docs/multi-language.md b/docs/multi-language.md
index 0dfb91a9af..0e98313c04 100644
--- a/docs/multi-language.md
+++ b/docs/multi-language.md
@@ -1,6 +1,6 @@
# Multi-Language Guide
-Configure OpenSpec to generate artifacts in languages other than English.
+Configure BR-OpenSpec to generate artifacts in languages other than English.
## Quick Setup
diff --git a/docs/opsx.md b/docs/opsx.md
index 9607b7d06d..de9475b3ed 100644
--- a/docs/opsx.md
+++ b/docs/opsx.md
@@ -1,16 +1,14 @@
# OPSX Workflow
-> Feedback welcome on [Discord](https://discord.gg/YctCnvvshC).
-
## What Is It?
-OPSX is now the standard workflow for OpenSpec.
+OPSX is now the standard workflow for BR-OpenSpec.
-It's a **fluid, iterative workflow** for OpenSpec changes. No more rigid phases — just actions you can take anytime.
+It's a **fluid, iterative workflow** for BR-OpenSpec changes. No more rigid phases — just actions you can take anytime.
## Why This Exists
-The legacy OpenSpec workflow works, but it's **locked down**:
+The legacy BR-OpenSpec workflow works, but it's **locked down**:
- **Instructions are hardcoded** — buried in TypeScript, you can't change them
- **All-or-nothing** — one big command creates everything, can't test individual pieces
@@ -39,7 +37,7 @@ Legacy workflow: OPSX:
**This is for everyone:**
- **Teams** — create workflows that match how you actually work
- **Power users** — tweak prompts to get better AI outputs for your codebase
-- **OpenSpec contributors** — experiment with new approaches without releases
+- **BR-OpenSpec contributors** — experiment with new approaches without releases
We're all still learning what works best. OPSX lets us learn together.
@@ -65,7 +63,7 @@ openspec init
This creates skills in `.claude/skills/` (or equivalent) that AI coding assistants auto-detect.
-By default, OpenSpec uses the `core` workflow profile (`propose`, `explore`, `apply`, `archive`). If you want the expanded workflow commands (`new`, `continue`, `ff`, `verify`, `sync`, `bulk-archive`, `onboard`), configure them with `openspec config profile` and apply with `openspec update`.
+By default, BR-OpenSpec uses the `core` workflow profile (`propose`, `explore`, `apply`, `archive`). If you want the expanded workflow commands (`new`, `continue`, `ff`, `verify`, `sync`, `bulk-archive`, `onboard`), configure them with `openspec config profile` and apply with `openspec update`.
During setup, you'll be prompted to create a **project config** (`openspec/config.yaml`). This is optional but recommended.
@@ -656,4 +654,4 @@ openspec schema validate my-workflow
This is rough. That's intentional — we're learning what works.
-Found a bug? Have ideas? Join us on [Discord](https://discord.gg/YctCnvvshC) or open an issue on [GitHub](https://github.com/Fission-AI/openspec/issues).
+Found a bug? Have ideas? Open an issue on [GitHub](https://github.com/fkmatsuda/BR-OpenSpec/issues).
diff --git a/docs/pt-BR/cli.md b/docs/pt-BR/cli.md
new file mode 100644
index 0000000000..d9b4a32b0f
--- /dev/null
+++ b/docs/pt-BR/cli.md
@@ -0,0 +1,936 @@
+# Referência da CLI
+
+A CLI do BR-OpenSpec (`openspec`) fornece comandos de terminal para configuração de projetos, validação, inspeção de status e gerenciamento. Esses comandos complementam os comandos AI com barra (como `/opsx:propose`) documentados em [Comandos](commands.md).
+
+## Resumo
+
+| Categoria | Comandos | Finalidade |
+|-----------|----------|------------|
+| **Configuração** | `init`, `update` | Inicializar e atualizar o BR-OpenSpec no seu projeto |
+| **Navegação** | `list`, `view`, `show` | Explorar mudanças e specs |
+| **Validação** | `validate` | Verificar mudanças e specs em busca de problemas |
+| **Ciclo de vida** | `archive` | Finalizar mudanças concluídas |
+| **Fluxo de trabalho** | `status`, `instructions`, `templates`, `schemas` | Suporte ao fluxo de trabalho orientado a artefatos |
+| **Schemas** | `schema init`, `schema fork`, `schema validate`, `schema which` | Criar e gerenciar fluxos de trabalho personalizados |
+| **Configuração** | `config` | Visualizar e modificar configurações |
+| **Utilitários** | `feedback`, `completion` | Feedback e integração com o shell |
+
+---
+
+## Comandos Humanos vs Comandos de Agente
+
+A maioria dos comandos da CLI é projetada para **uso humano** em um terminal. Alguns comandos também suportam **uso por agentes/scripts** via saída JSON.
+
+### Comandos Exclusivos para Humanos
+
+Estes comandos são interativos e projetados para uso no terminal:
+
+| Comando | Finalidade |
+|---------|------------|
+| `openspec init` | Inicializar projeto (prompts interativos) |
+| `openspec view` | Painel interativo |
+| `openspec config edit` | Abrir configuração no editor |
+| `openspec feedback` | Enviar feedback via GitHub |
+| `openspec completion install` | Instalar completions do shell |
+
+### Comandos Compatíveis com Agentes
+
+Estes comandos suportam saída `--json` para uso programático por agentes de IA e scripts:
+
+| Comando | Uso Humano | Uso por Agente |
+|---------|------------|----------------|
+| `openspec list` | Navegar mudanças/specs | `--json` para dados estruturados |
+| `openspec show - ` | Ler conteúdo | `--json` para parsing |
+| `openspec validate` | Verificar problemas | `--all --json` para validação em massa |
+| `openspec status` | Ver progresso de artefatos | `--json` para status estruturado |
+| `openspec instructions` | Obter próximos passos | `--json` para instruções do agente |
+| `openspec templates` | Encontrar caminhos de templates | `--json` para resolução de caminhos |
+| `openspec schemas` | Listar schemas disponíveis | `--json` para descoberta de schemas |
+
+---
+
+## Opções Globais
+
+Estas opções funcionam com todos os comandos:
+
+| Opção | Descrição |
+|-------|-----------|
+| `--version`, `-V` | Exibir número da versão |
+| `--no-color` | Desabilitar saída colorida |
+| `--help`, `-h` | Exibir ajuda para o comando |
+
+---
+
+## Comandos de Configuração
+
+### `openspec init`
+
+Inicializar o BR-OpenSpec no seu projeto. Cria a estrutura de pastas e configura as integrações com ferramentas de IA.
+
+O comportamento padrão usa os valores globais de configuração: perfil `core`, entrega `both`, fluxos de trabalho `propose, explore, apply, archive`.
+
+```
+openspec init [path] [options]
+```
+
+**Argumentos:**
+
+| Argumento | Obrigatório | Descrição |
+|-----------|-------------|-----------|
+| `path` | Não | Diretório de destino (padrão: diretório atual) |
+
+**Opções:**
+
+| Opção | Descrição |
+|-------|-----------|
+| `--tools
` | Configurar ferramentas de IA de forma não interativa. Use `all`, `none` ou lista separada por vírgulas |
+| `--force` | Limpar arquivos legados automaticamente sem solicitar confirmação |
+| `--profile ` | Substituir o perfil global para esta execução do init (`core` ou `custom`) |
+
+`--profile custom` usa os fluxos de trabalho atualmente selecionados na configuração global (`openspec config profile`).
+
+**IDs de ferramentas suportados (`--tools`):** `amazon-q`, `antigravity`, `auggie`, `claude`, `cline`, `codex`, `codebuddy`, `continue`, `costrict`, `crush`, `cursor`, `factory`, `gemini`, `github-copilot`, `iflow`, `kilocode`, `kimi`, `kiro`, `opencode`, `pi`, `qoder`, `qwen`, `roocode`, `trae`, `windsurf`
+
+**Exemplos:**
+
+```bash
+# Inicialização interativa
+openspec init
+
+# Inicializar em um diretório específico
+openspec init ./my-project
+
+# Não interativo: configurar para Claude e Cursor
+openspec init --tools claude,cursor
+
+# Configurar para todas as ferramentas suportadas
+openspec init --tools all
+
+# Substituir perfil para esta execução
+openspec init --profile core
+
+# Ignorar prompts e limpar arquivos legados automaticamente
+openspec init --force
+```
+
+**O que é criado:**
+
+```
+openspec/
+├── specs/ # Suas especificações (fonte de verdade)
+├── changes/ # Mudanças propostas
+└── config.yaml # Configuração do projeto
+
+.claude/skills/ # Skills do Claude Code (se claude selecionado)
+.cursor/skills/ # Skills do Cursor (se cursor selecionado)
+.cursor/commands/ # Comandos OPSX do Cursor (se entrega incluir commands)
+... (outras configurações de ferramentas)
+```
+
+---
+
+### `openspec update`
+
+Atualizar os arquivos de instrução do BR-OpenSpec após atualizar a CLI. Regenera os arquivos de configuração de ferramentas de IA usando seu perfil global atual, fluxos de trabalho selecionados e modo de entrega.
+
+```
+openspec update [path] [options]
+```
+
+**Argumentos:**
+
+| Argumento | Obrigatório | Descrição |
+|-----------|-------------|-----------|
+| `path` | Não | Diretório de destino (padrão: diretório atual) |
+
+**Opções:**
+
+| Opção | Descrição |
+|-------|-----------|
+| `--force` | Forçar atualização mesmo quando os arquivos estão atualizados |
+
+**Exemplo:**
+
+```bash
+# Atualizar arquivos de instrução após atualização via npm
+npm update @fkmatsuda/br-openspec
+openspec update
+```
+
+---
+
+## Comandos de Navegação
+
+### `openspec list`
+
+Listar mudanças ou specs no seu projeto.
+
+```
+openspec list [options]
+```
+
+**Opções:**
+
+| Opção | Descrição |
+|-------|-----------|
+| `--specs` | Listar specs em vez de mudanças |
+| `--changes` | Listar mudanças (padrão) |
+| `--sort ` | Ordenar por `recent` (padrão) ou `name` |
+| `--json` | Saída em formato JSON |
+
+**Exemplos:**
+
+```bash
+# Listar todas as mudanças ativas
+openspec list
+
+# Listar todas as specs
+openspec list --specs
+
+# Saída JSON para scripts
+openspec list --json
+```
+
+**Saída (texto):**
+
+```
+Active changes:
+ add-dark-mode UI theme switching support
+ fix-login-bug Session timeout handling
+```
+
+---
+
+### `openspec view`
+
+Exibir um painel interativo para explorar specs e mudanças.
+
+```
+openspec view
+```
+
+Abre uma interface baseada em terminal para navegar pelas especificações e mudanças do seu projeto.
+
+---
+
+### `openspec show`
+
+Exibir detalhes de uma mudança ou spec.
+
+```
+openspec show [item-name] [options]
+```
+
+**Argumentos:**
+
+| Argumento | Obrigatório | Descrição |
+|-----------|-------------|-----------|
+| `item-name` | Não | Nome da mudança ou spec (solicita se omitido) |
+
+**Opções:**
+
+| Opção | Descrição |
+|-------|-----------|
+| `--type ` | Especificar tipo: `change` ou `spec` (detectado automaticamente se não houver ambiguidade) |
+| `--json` | Saída em formato JSON |
+| `--no-interactive` | Desabilitar prompts |
+
+**Opções específicas para mudanças:**
+
+| Opção | Descrição |
+|-------|-----------|
+| `--deltas-only` | Exibir apenas specs delta (modo JSON) |
+
+**Opções específicas para specs:**
+
+| Opção | Descrição |
+|-------|-----------|
+| `--requirements` | Exibir apenas requisitos, excluir cenários (modo JSON) |
+| `--no-scenarios` | Excluir conteúdo de cenários (modo JSON) |
+| `-r, --requirement ` | Exibir requisito específico por índice base 1 (modo JSON) |
+
+**Exemplos:**
+
+```bash
+# Seleção interativa
+openspec show
+
+# Exibir uma mudança específica
+openspec show add-dark-mode
+
+# Exibir uma spec específica
+openspec show auth --type spec
+
+# Saída JSON para parsing
+openspec show add-dark-mode --json
+```
+
+---
+
+## Comandos de Validação
+
+### `openspec validate`
+
+Validar mudanças e specs em busca de problemas estruturais.
+
+```
+openspec validate [item-name] [options]
+```
+
+**Argumentos:**
+
+| Argumento | Obrigatório | Descrição |
+|-----------|-------------|-----------|
+| `item-name` | Não | Item específico a validar (solicita se omitido) |
+
+**Opções:**
+
+| Opção | Descrição |
+|-------|-----------|
+| `--all` | Validar todas as mudanças e specs |
+| `--changes` | Validar todas as mudanças |
+| `--specs` | Validar todas as specs |
+| `--type ` | Especificar tipo quando o nome for ambíguo: `change` ou `spec` |
+| `--strict` | Habilitar modo de validação estrita |
+| `--json` | Saída em formato JSON |
+| `--concurrency ` | Máximo de validações paralelas (padrão: 6, ou variável de ambiente `OPENSPEC_CONCURRENCY`) |
+| `--no-interactive` | Desabilitar prompts |
+
+**Exemplos:**
+
+```bash
+# Validação interativa
+openspec validate
+
+# Validar uma mudança específica
+openspec validate add-dark-mode
+
+# Validar todas as mudanças
+openspec validate --changes
+
+# Validar tudo com saída JSON (para CI/scripts)
+openspec validate --all --json
+
+# Validação estrita com paralelismo aumentado
+openspec validate --all --strict --concurrency 12
+```
+
+**Saída (texto):**
+
+```
+Validating add-dark-mode...
+ ✓ proposal.md valid
+ ✓ specs/ui/spec.md valid
+ ⚠ design.md: missing "Technical Approach" section
+
+1 warning found
+```
+
+**Saída (JSON):**
+
+```json
+{
+ "version": "1.0.0",
+ "results": {
+ "changes": [
+ {
+ "name": "add-dark-mode",
+ "valid": true,
+ "warnings": ["design.md: missing 'Technical Approach' section"]
+ }
+ ]
+ },
+ "summary": {
+ "total": 1,
+ "valid": 1,
+ "invalid": 0
+ }
+}
+```
+
+---
+
+## Comandos de Ciclo de Vida
+
+### `openspec archive`
+
+Arquivar uma mudança concluída e mesclar as specs delta nas specs principais.
+
+```
+openspec archive [change-name] [options]
+```
+
+**Argumentos:**
+
+| Argumento | Obrigatório | Descrição |
+|-----------|-------------|-----------|
+| `change-name` | Não | Mudança a arquivar (solicita se omitido) |
+
+**Opções:**
+
+| Opção | Descrição |
+|-------|-----------|
+| `-y, --yes` | Ignorar prompts de confirmação |
+| `--skip-specs` | Ignorar atualizações de specs (para mudanças de infraestrutura/ferramental/apenas documentação) |
+| `--no-validate` | Ignorar validação (requer confirmação) |
+
+**Exemplos:**
+
+```bash
+# Arquivamento interativo
+openspec archive
+
+# Arquivar mudança específica
+openspec archive add-dark-mode
+
+# Arquivar sem prompts (CI/scripts)
+openspec archive add-dark-mode --yes
+
+# Arquivar uma mudança de ferramental que não afeta specs
+openspec archive update-ci-config --skip-specs
+```
+
+**O que é feito:**
+
+1. Valida a mudança (a menos que `--no-validate` seja informado)
+2. Solicita confirmação (a menos que `--yes` seja informado)
+3. Mescla as specs delta em `openspec/specs/`
+4. Move a pasta da mudança para `openspec/changes/archive/YYYY-MM-DD-/`
+
+---
+
+## Comandos de Fluxo de Trabalho
+
+Esses comandos suportam o fluxo de trabalho OPSX orientado a artefatos. São úteis tanto para humanos verificarem o progresso quanto para agentes determinarem os próximos passos.
+
+### `openspec status`
+
+Exibir o status de conclusão dos artefatos de uma mudança.
+
+```
+openspec status [options]
+```
+
+**Opções:**
+
+| Opção | Descrição |
+|-------|-----------|
+| `--change ` | Nome da mudança (solicita se omitido) |
+| `--schema ` | Substituição de schema (detectado automaticamente a partir da configuração da mudança) |
+| `--json` | Saída em formato JSON |
+
+**Exemplos:**
+
+```bash
+# Verificação interativa de status
+openspec status
+
+# Status para mudança específica
+openspec status --change add-dark-mode
+
+# JSON para uso por agente
+openspec status --change add-dark-mode --json
+```
+
+**Saída (texto):**
+
+```
+Change: add-dark-mode
+Schema: spec-driven
+Progress: 2/4 artifacts complete
+
+[x] proposal
+[ ] design
+[x] specs
+[-] tasks (blocked by: design)
+```
+
+**Saída (JSON):**
+
+```json
+{
+ "changeName": "add-dark-mode",
+ "schemaName": "spec-driven",
+ "isComplete": false,
+ "applyRequires": ["tasks"],
+ "artifacts": [
+ {"id": "proposal", "outputPath": "proposal.md", "status": "done"},
+ {"id": "design", "outputPath": "design.md", "status": "ready"},
+ {"id": "specs", "outputPath": "specs/**/*.md", "status": "done"},
+ {"id": "tasks", "outputPath": "tasks.md", "status": "blocked", "missingDeps": ["design"]}
+ ]
+}
+```
+
+---
+
+### `openspec instructions`
+
+Obter instruções enriquecidas para criar um artefato ou aplicar tarefas. Usado por agentes de IA para entender o que criar a seguir.
+
+```
+openspec instructions [artifact] [options]
+```
+
+**Argumentos:**
+
+| Argumento | Obrigatório | Descrição |
+|-----------|-------------|-----------|
+| `artifact` | Não | ID do artefato: `proposal`, `specs`, `design`, `tasks` ou `apply` |
+
+**Opções:**
+
+| Opção | Descrição |
+|-------|-----------|
+| `--change ` | Nome da mudança (obrigatório no modo não interativo) |
+| `--schema ` | Substituição de schema |
+| `--json` | Saída em formato JSON |
+
+**Caso especial:** Use `apply` como artefato para obter instruções de implementação de tarefas.
+
+**Exemplos:**
+
+```bash
+# Obter instruções para o próximo artefato
+openspec instructions --change add-dark-mode
+
+# Obter instruções para um artefato específico
+openspec instructions design --change add-dark-mode
+
+# Obter instruções de aplicação/implementação
+openspec instructions apply --change add-dark-mode
+
+# JSON para consumo pelo agente
+openspec instructions design --change add-dark-mode --json
+```
+
+**A saída inclui:**
+
+- Conteúdo do template para o artefato
+- Contexto do projeto a partir da configuração
+- Conteúdo dos artefatos de dependência
+- Regras por artefato definidas na configuração
+
+---
+
+### `openspec templates`
+
+Exibir os caminhos de templates resolvidos para todos os artefatos em um schema.
+
+```
+openspec templates [options]
+```
+
+**Opções:**
+
+| Opção | Descrição |
+|-------|-----------|
+| `--schema ` | Schema a inspecionar (padrão: `spec-driven`) |
+| `--json` | Saída em formato JSON |
+
+**Exemplos:**
+
+```bash
+# Exibir caminhos de templates para o schema padrão
+openspec templates
+
+# Exibir templates para schema personalizado
+openspec templates --schema my-workflow
+
+# JSON para uso programático
+openspec templates --json
+```
+
+**Saída (texto):**
+
+```
+Schema: spec-driven
+
+Templates:
+ proposal → ~/.openspec/schemas/spec-driven/templates/proposal.md
+ specs → ~/.openspec/schemas/spec-driven/templates/specs.md
+ design → ~/.openspec/schemas/spec-driven/templates/design.md
+ tasks → ~/.openspec/schemas/spec-driven/templates/tasks.md
+```
+
+---
+
+### `openspec schemas`
+
+Listar os schemas de fluxo de trabalho disponíveis com suas descrições e fluxos de artefatos.
+
+```
+openspec schemas [options]
+```
+
+**Opções:**
+
+| Opção | Descrição |
+|-------|-----------|
+| `--json` | Saída em formato JSON |
+
+**Exemplo:**
+
+```bash
+openspec schemas
+```
+
+**Saída:**
+
+```
+Available schemas:
+
+ spec-driven (package)
+ The default spec-driven development workflow
+ Flow: proposal → specs → design → tasks
+
+ my-custom (project)
+ Custom workflow for this project
+ Flow: research → proposal → tasks
+```
+
+---
+
+## Comandos de Schema
+
+Comandos para criar e gerenciar schemas de fluxo de trabalho personalizados.
+
+### `openspec schema init`
+
+Criar um novo schema local de projeto.
+
+```
+openspec schema init [options]
+```
+
+**Argumentos:**
+
+| Argumento | Obrigatório | Descrição |
+|-----------|-------------|-----------|
+| `name` | Sim | Nome do schema (kebab-case) |
+
+**Opções:**
+
+| Opção | Descrição |
+|-------|-----------|
+| `--description ` | Descrição do schema |
+| `--artifacts ` | IDs de artefatos separados por vírgula (padrão: `proposal,specs,design,tasks`) |
+| `--default` | Definir como schema padrão do projeto |
+| `--no-default` | Não solicitar para definir como padrão |
+| `--force` | Sobrescrever schema existente |
+| `--json` | Saída em formato JSON |
+
+**Exemplos:**
+
+```bash
+# Criação interativa de schema
+openspec schema init research-first
+
+# Não interativo com artefatos específicos
+openspec schema init rapid \
+ --description "Rapid iteration workflow" \
+ --artifacts "proposal,tasks" \
+ --default
+```
+
+**O que é criado:**
+
+```
+openspec/schemas//
+├── schema.yaml # Definição do schema
+└── templates/
+ ├── proposal.md # Template para cada artefato
+ ├── specs.md
+ ├── design.md
+ └── tasks.md
+```
+
+---
+
+### `openspec schema fork`
+
+Copiar um schema existente para o seu projeto para personalização.
+
+```
+openspec schema fork [name] [options]
+```
+
+**Argumentos:**
+
+| Argumento | Obrigatório | Descrição |
+|-----------|-------------|-----------|
+| `source` | Sim | Schema a copiar |
+| `name` | Não | Novo nome do schema (padrão: `-custom`) |
+
+**Opções:**
+
+| Opção | Descrição |
+|-------|-----------|
+| `--force` | Sobrescrever destino existente |
+| `--json` | Saída em formato JSON |
+
+**Exemplo:**
+
+```bash
+# Fazer fork do schema spec-driven embutido
+openspec schema fork spec-driven my-workflow
+```
+
+---
+
+### `openspec schema validate`
+
+Validar a estrutura e os templates de um schema.
+
+```
+openspec schema validate [name] [options]
+```
+
+**Argumentos:**
+
+| Argumento | Obrigatório | Descrição |
+|-----------|-------------|-----------|
+| `name` | Não | Schema a validar (valida todos se omitido) |
+
+**Opções:**
+
+| Opção | Descrição |
+|-------|-----------|
+| `--verbose` | Exibir etapas detalhadas de validação |
+| `--json` | Saída em formato JSON |
+
+**Exemplo:**
+
+```bash
+# Validar um schema específico
+openspec schema validate my-workflow
+
+# Validar todos os schemas
+openspec schema validate
+```
+
+---
+
+### `openspec schema which`
+
+Mostrar de onde um schema é resolvido (útil para depurar precedência).
+
+```
+openspec schema which [name] [options]
+```
+
+**Argumentos:**
+
+| Argumento | Obrigatório | Descrição |
+|-----------|-------------|-----------|
+| `name` | Não | Nome do schema |
+
+**Opções:**
+
+| Opção | Descrição |
+|-------|-----------|
+| `--all` | Listar todos os schemas com suas origens |
+| `--json` | Saída em formato JSON |
+
+**Exemplo:**
+
+```bash
+# Verificar de onde um schema vem
+openspec schema which spec-driven
+```
+
+**Saída:**
+
+```
+spec-driven resolves from: package
+ Source: /usr/local/lib/node_modules/@fkmatsuda/br-openspec/schemas/spec-driven
+```
+
+**Precedência de schemas:**
+
+1. Projeto: `openspec/schemas//`
+2. Usuário: `~/.local/share/openspec/schemas//`
+3. Pacote: Schemas embutidos
+
+---
+
+## Comandos de Configuração
+
+### `openspec config`
+
+Visualizar e modificar a configuração global do BR-OpenSpec.
+
+```
+openspec config [options]
+```
+
+**Subcomandos:**
+
+| Subcomando | Descrição |
+|------------|-----------|
+| `path` | Exibir localização do arquivo de configuração |
+| `list` | Exibir todas as configurações atuais |
+| `get ` | Obter um valor específico |
+| `set ` | Definir um valor |
+| `unset ` | Remover uma chave |
+| `reset` | Redefinir para os padrões |
+| `edit` | Abrir no `$EDITOR` |
+| `profile [preset]` | Configurar perfil de fluxo de trabalho interativamente ou via preset |
+
+**Exemplos:**
+
+```bash
+# Exibir caminho do arquivo de configuração
+openspec config path
+
+# Listar todas as configurações
+openspec config list
+
+# Obter um valor específico
+openspec config get telemetry.enabled
+
+# Definir um valor
+openspec config set telemetry.enabled false
+
+# Definir um valor de string explicitamente
+openspec config set user.name "My Name" --string
+
+# Remover uma configuração personalizada
+openspec config unset user.name
+
+# Redefinir toda a configuração
+openspec config reset --all --yes
+
+# Editar configuração no seu editor
+openspec config edit
+
+# Configurar perfil com assistente baseado em ações
+openspec config profile
+
+# Preset rápido: alternar fluxos de trabalho para core (mantém o modo de entrega)
+openspec config profile core
+```
+
+`openspec config profile` começa com um resumo do estado atual e permite que você escolha:
+- Alterar entrega + fluxos de trabalho
+- Alterar apenas a entrega
+- Alterar apenas os fluxos de trabalho
+- Manter as configurações atuais (sair)
+
+Se você mantiver as configurações atuais, nenhuma alteração é salva e nenhum prompt de atualização é exibido.
+Se não houver alterações de configuração, mas os arquivos do projeto atual estiverem fora de sincronia com o seu perfil/entrega global, o BR-OpenSpec exibirá um aviso e sugerirá executar `openspec update`.
+Pressionar `Ctrl+C` também cancela o fluxo de forma limpa (sem rastreamento de pilha) e sai com o código `130`.
+Na lista de verificação de fluxos de trabalho, `[x]` significa que o fluxo de trabalho está selecionado na configuração global. Para aplicar essas seleções aos arquivos do projeto, execute `openspec update` (ou escolha `Apply changes to this project now?` quando solicitado dentro de um projeto).
+
+**Exemplos interativos:**
+
+```bash
+# Atualização apenas de entrega
+openspec config profile
+# escolha: Change delivery only
+# escolha a entrega: Skills only
+
+# Atualização apenas de fluxos de trabalho
+openspec config profile
+# escolha: Change workflows only
+# alterne os fluxos de trabalho na lista de verificação e confirme
+```
+
+---
+
+## Comandos Utilitários
+
+### `openspec feedback`
+
+Enviar feedback sobre o BR-OpenSpec. Cria uma issue no GitHub.
+
+```
+openspec feedback [options]
+```
+
+**Argumentos:**
+
+| Argumento | Obrigatório | Descrição |
+|-----------|-------------|-----------|
+| `message` | Sim | Mensagem de feedback |
+
+**Opções:**
+
+| Opção | Descrição |
+|-------|-----------|
+| `--body ` | Descrição detalhada |
+
+**Requisitos:** A CLI do GitHub (`gh`) deve estar instalada e autenticada.
+
+**Exemplo:**
+
+```bash
+openspec feedback "Add support for custom artifact types" \
+ --body "I'd like to define my own artifact types beyond the built-in ones."
+```
+
+---
+
+### `openspec completion`
+
+Gerenciar completions do shell para a CLI do BR-OpenSpec.
+
+```
+openspec completion [shell]
+```
+
+**Subcomandos:**
+
+| Subcomando | Descrição |
+|------------|-----------|
+| `generate [shell]` | Exibir script de completion no stdout |
+| `install [shell]` | Instalar completion para o seu shell |
+| `uninstall [shell]` | Remover completions instaladas |
+
+**Shells suportados:** `bash`, `zsh`, `fish`, `powershell`
+
+**Exemplos:**
+
+```bash
+# Instalar completions (detecta o shell automaticamente)
+openspec completion install
+
+# Instalar para um shell específico
+openspec completion install zsh
+
+# Gerar script para instalação manual
+openspec completion generate bash > ~/.bash_completion.d/openspec
+
+# Desinstalar
+openspec completion uninstall
+```
+
+---
+
+## Códigos de Saída
+
+| Código | Significado |
+|--------|-------------|
+| `0` | Sucesso |
+| `1` | Erro (falha de validação, arquivos ausentes, etc.) |
+
+---
+
+## Variáveis de Ambiente
+
+| Variável | Descrição |
+|----------|-----------|
+| `OPENSPEC_TELEMETRY` | Definir como `0` para desabilitar telemetria |
+| `DO_NOT_TRACK` | Definir como `1` para desabilitar telemetria (sinal DNT padrão) |
+| `OPENSPEC_CONCURRENCY` | Concorrência padrão para validação em massa (padrão: 6) |
+| `EDITOR` ou `VISUAL` | Editor para `openspec config edit` |
+| `NO_COLOR` | Desabilitar saída colorida quando definido |
+
+---
+
+## Documentação Relacionada
+
+- [Comandos](commands.md) - Comandos AI com barra (`/opsx:propose`, `/opsx:apply`, etc.)
+- [Fluxos de Trabalho](workflows.md) - Padrões comuns e quando usar cada comando
+- [Personalização](customization.md) - Criar schemas e templates personalizados
+- [Primeiros Passos](getting-started.md) - Guia de configuração inicial
diff --git a/docs/pt-BR/commands.md b/docs/pt-BR/commands.md
new file mode 100644
index 0000000000..5f09cf27d1
--- /dev/null
+++ b/docs/pt-BR/commands.md
@@ -0,0 +1,705 @@
+# Comandos
+
+Esta é a referência dos comandos slash do BR-OpenSpec. Esses comandos são invocados na interface de chat do seu assistente de codificação com IA (ex.: Claude Code, Cursor, Windsurf).
+
+Para padrões de fluxo de trabalho e quando usar cada comando, consulte [Workflows](workflows.md). Para comandos CLI, consulte [CLI](cli.md).
+
+## Referência Rápida
+
+### Caminho Rápido Padrão (perfil `core`)
+
+| Comando | Finalidade |
+|---------|---------|
+| `/opsx:propose` | Criar uma mudança e gerar artefatos de planejamento em um único passo |
+| `/opsx:explore` | Explorar ideias antes de se comprometer com uma mudança |
+| `/opsx:apply` | Implementar tarefas da mudança |
+| `/opsx:archive` | Arquivar uma mudança concluída |
+
+### Comandos de Fluxo de Trabalho Expandido (seleção de workflow personalizado)
+
+| Comando | Finalidade |
+|---------|---------|
+| `/opsx:new` | Iniciar uma estrutura inicial para uma nova mudança |
+| `/opsx:continue` | Criar o próximo artefato com base nas dependências |
+| `/opsx:ff` | Fast-forward: criar todos os artefatos de planejamento de uma vez |
+| `/opsx:verify` | Validar se a implementação corresponde aos artefatos |
+| `/opsx:sync` | Mesclar delta specs nas specs principais |
+| `/opsx:bulk-archive` | Arquivar múltiplas mudanças de uma vez |
+| `/opsx:onboard` | Tutorial guiado pelo fluxo de trabalho completo |
+
+O perfil global padrão é `core`. Para habilitar os comandos de fluxo de trabalho expandido, execute `openspec config profile`, selecione os workflows e, em seguida, execute `openspec update` no seu projeto.
+
+---
+
+## Referência de Comandos
+
+### `/opsx:propose`
+
+Criar uma nova mudança e gerar artefatos de planejamento em um único passo. Este é o comando de início padrão no perfil `core`.
+
+**Sintaxe:**
+```text
+/opsx:propose [change-name-or-description]
+```
+
+**Argumentos:**
+| Argumento | Obrigatório | Descrição |
+|----------|----------|-------------|
+| `change-name-or-description` | Não | Nome em kebab-case ou descrição da mudança em linguagem natural |
+
+**O que faz:**
+- Cria `openspec/changes//`
+- Gera os artefatos necessários antes da implementação (para `spec-driven`: proposal, specs, design, tasks)
+- Para quando a mudança estiver pronta para `/opsx:apply`
+
+**Exemplo:**
+```text
+You: /opsx:propose add-dark-mode
+
+AI: Created openspec/changes/add-dark-mode/
+ ✓ proposal.md
+ ✓ specs/ui/spec.md
+ ✓ design.md
+ ✓ tasks.md
+ Ready for implementation. Run /opsx:apply.
+```
+
+**Dicas:**
+- Use para o caminho mais rápido de ponta a ponta
+- Se quiser controle passo a passo sobre os artefatos, habilite os workflows expandidos e use `/opsx:new` + `/opsx:continue`
+
+---
+
+### `/opsx:explore`
+
+Explorar ideias, investigar problemas e esclarecer requisitos antes de se comprometer com uma mudança.
+
+**Sintaxe:**
+```
+/opsx:explore [topic]
+```
+
+**Argumentos:**
+| Argumento | Obrigatório | Descrição |
+|----------|----------|-------------|
+| `topic` | Não | O que você deseja explorar ou investigar |
+
+**O que faz:**
+- Abre uma conversa exploratória sem estrutura necessária
+- Investiga a base de código para responder perguntas
+- Compara opções e abordagens
+- Cria diagramas visuais para esclarecer o raciocínio
+- Pode transicionar para `/opsx:propose` (padrão) ou `/opsx:new` (fluxo de trabalho expandido) quando as ideias se consolidam
+
+**Exemplo:**
+```text
+You: /opsx:explore
+
+AI: What would you like to explore?
+
+You: How should we handle authentication for the mobile app?
+
+AI: Let me investigate your current auth setup...
+ [Analyzes codebase]
+
+ I see you're using session-based auth for the web app.
+ For mobile, we have three main options:
+
+ 1. JWT tokens (stateless, works offline)
+ 2. OAuth2 (if you need third-party login)
+ 3. Extend current sessions (simpler, but requires connectivity)
+
+ Your API already has CORS configured. Which direction interests you?
+
+You: Let's go with JWT. Can we start a change for that?
+
+AI: Ready when you are. Run /opsx:propose add-jwt-auth to begin.
+```
+
+**Dicas:**
+- Use quando os requisitos não estão claros ou você precisa investigar
+- Nenhum artefato é criado durante a exploração
+- Bom para comparar múltiplas abordagens antes de decidir
+- Pode ler arquivos e pesquisar na base de código
+
+---
+
+### `/opsx:new`
+
+Iniciar uma estrutura inicial para uma nova mudança. Cria a pasta da mudança e aguarda que você gere os artefatos com `/opsx:continue` ou `/opsx:ff`.
+
+Este comando faz parte do conjunto de fluxo de trabalho expandido (não incluído no perfil `core` padrão).
+
+**Sintaxe:**
+```
+/opsx:new [change-name] [--schema ]
+```
+
+**Argumentos:**
+| Argumento | Obrigatório | Descrição |
+|----------|----------|-------------|
+| `change-name` | Não | Nome para a pasta da mudança (solicitado se não fornecido) |
+| `--schema` | Não | Schema de fluxo de trabalho a usar (padrão: da configuração ou `spec-driven`) |
+
+**O que faz:**
+- Cria o diretório `openspec/changes//`
+- Cria o arquivo de metadados `.openspec.yaml` na pasta da mudança
+- Exibe o primeiro template de artefato pronto para criação
+- Solicita o nome da mudança e o schema se não fornecidos
+
+**O que cria:**
+```
+openspec/changes//
+└── .openspec.yaml # Change metadata (schema, created date)
+```
+
+**Exemplo:**
+```
+You: /opsx:new add-dark-mode
+
+AI: Created openspec/changes/add-dark-mode/
+ Schema: spec-driven
+
+ Ready to create: proposal
+ Use /opsx:continue to create it, or /opsx:ff to create all artifacts.
+```
+
+**Dicas:**
+- Use nomes descritivos: `add-feature`, `fix-bug`, `refactor-module`
+- Evite nomes genéricos como `update`, `changes`, `wip`
+- O schema também pode ser definido na configuração do projeto (`openspec/config.yaml`)
+
+---
+
+### `/opsx:continue`
+
+Criar o próximo artefato na cadeia de dependências. Cria um artefato de cada vez para progresso incremental.
+
+**Sintaxe:**
+```
+/opsx:continue [change-name]
+```
+
+**Argumentos:**
+| Argumento | Obrigatório | Descrição |
+|----------|----------|-------------|
+| `change-name` | Não | Qual mudança continuar (inferida do contexto se não fornecida) |
+
+**O que faz:**
+- Consulta o grafo de dependência dos artefatos
+- Mostra quais artefatos estão prontos versus bloqueados
+- Cria o primeiro artefato disponível
+- Lê os arquivos de dependência para contexto
+- Mostra o que fica disponível após a criação
+
+**Exemplo:**
+```
+You: /opsx:continue
+
+AI: Change: add-dark-mode
+
+ Artifact status:
+ ✓ proposal (done)
+ ◆ specs (ready)
+ ◆ design (ready)
+ ○ tasks (blocked - needs: specs)
+
+ Creating specs...
+
+ [Reads proposal.md, creates specs based on requirements]
+
+ ✓ Created openspec/changes/add-dark-mode/specs/ui/spec.md
+
+ Now available: tasks
+ Run /opsx:continue to create the next artifact.
+```
+
+**Dicas:**
+- Use quando quiser revisar cada artefato antes de prosseguir
+- Bom para mudanças complexas onde você quer controle
+- Múltiplos artefatos podem ficar prontos simultaneamente
+- Você pode editar os artefatos criados antes de continuar
+
+---
+
+### `/opsx:ff`
+
+Avançar rapidamente pela criação de artefatos. Cria todos os artefatos de planejamento de uma vez.
+
+**Sintaxe:**
+```
+/opsx:ff [change-name]
+```
+
+**Argumentos:**
+| Argumento | Obrigatório | Descrição |
+|----------|----------|-------------|
+| `change-name` | Não | Qual mudança avançar rapidamente (inferida do contexto se não fornecida) |
+
+**O que faz:**
+- Cria todos os artefatos na ordem de dependência
+- Acompanha o progresso por meio de uma lista de tarefas
+- Para quando todos os artefatos `apply-required` estiverem completos
+- Lê cada dependência antes de criar o próximo artefato
+
+**Exemplo:**
+```
+You: /opsx:ff add-dark-mode
+
+AI: Fast-forwarding add-dark-mode...
+
+ ✓ Creating proposal.md
+ ✓ Creating specs/ui/spec.md
+ ✓ Creating design.md
+ ✓ Creating tasks.md
+
+ All planning artifacts complete!
+ Ready for implementation. Run /opsx:apply to begin.
+```
+
+**Dicas:**
+- Use quando você tem uma ideia clara do que está construindo
+- Mais rápido que `/opsx:continue` para mudanças diretas
+- Você ainda pode editar os artefatos depois
+- Bom para funcionalidades pequenas a médias
+
+---
+
+### `/opsx:apply`
+
+Implementar tarefas da mudança. Percorre a lista de tarefas, escrevendo código e marcando os itens como concluídos.
+
+**Sintaxe:**
+```
+/opsx:apply [change-name]
+```
+
+**Argumentos:**
+| Argumento | Obrigatório | Descrição |
+|----------|----------|-------------|
+| `change-name` | Não | Qual mudança implementar (inferida do contexto se não fornecida) |
+
+**O que faz:**
+- Lê `tasks.md` e identifica tarefas incompletas
+- Percorre as tarefas uma a uma
+- Escreve código, cria arquivos, executa testes conforme necessário
+- Marca as tarefas como concluídas com checkboxes `[x]`
+
+**Exemplo:**
+```
+You: /opsx:apply
+
+AI: Implementing add-dark-mode...
+
+ Reading tasks.md:
+ - [ ] 1.1 Create ThemeContext
+ - [ ] 1.2 Add CSS custom properties
+ - [ ] 1.3 Implement localStorage persistence
+
+ Working on 1.1: Create ThemeContext...
+ [Creates src/context/ThemeContext.tsx]
+
+ ✓ 1.1 Complete
+
+ Working on 1.2: Add CSS custom properties...
+ [Updates src/styles/globals.css]
+
+ ✓ 1.2 Complete
+ ...
+```
+
+**Dicas:**
+- Pode retomar de onde parou se interrompido
+- Use para mudanças paralelas especificando o nome da mudança
+- O estado de conclusão é rastreado nos checkboxes do `tasks.md`
+
+---
+
+### `/opsx:verify`
+
+Validar que a implementação corresponde aos artefatos da mudança. Verifica completude, correção e coerência.
+
+**Sintaxe:**
+```
+/opsx:verify [change-name]
+```
+
+**Argumentos:**
+| Argumento | Obrigatório | Descrição |
+|----------|----------|-------------|
+| `change-name` | Não | Qual mudança verificar (inferida do contexto se não fornecida) |
+
+**O que faz:**
+- Verifica três dimensões da qualidade da implementação
+- Pesquisa na base de código por evidências de implementação
+- Relata problemas categorizados como CRITICAL, WARNING ou SUGGESTION
+- Não bloqueia o arquivamento, mas expõe problemas
+
+**Dimensões de verificação:**
+
+| Dimensão | O que valida |
+|-----------|-------------------|
+| **Completude** | Todas as tarefas concluídas, todos os requisitos implementados, cenários cobertos |
+| **Correção** | Implementação corresponde à intenção da spec, casos extremos tratados |
+| **Coerência** | Decisões de design refletidas no código, padrões consistentes |
+
+**Exemplo:**
+```
+You: /opsx:verify
+
+AI: Verifying add-dark-mode...
+
+ COMPLETENESS
+ ✓ All 8 tasks in tasks.md are checked
+ ✓ All requirements in specs have corresponding code
+ ⚠ Scenario "System preference detection" has no test coverage
+
+ CORRECTNESS
+ ✓ Implementation matches spec intent
+ ✓ Edge cases from scenarios are handled
+ ✓ Error states match spec definitions
+
+ COHERENCE
+ ✓ Design decisions reflected in code structure
+ ✓ Naming conventions consistent with design.md
+ ⚠ Design mentions "CSS variables" but implementation uses Tailwind classes
+
+ SUMMARY
+ ─────────────────────────────
+ Critical issues: 0
+ Warnings: 2
+ Ready to archive: Yes (with warnings)
+
+ Recommendations:
+ 1. Add test for system preference detection
+ 2. Update design.md to reflect Tailwind usage, or refactor to use CSS variables
+```
+
+**Dicas:**
+- Execute antes de arquivar para detectar inconsistências cedo
+- Avisos não bloqueiam o arquivamento, mas indicam possíveis problemas
+- Bom para revisar o trabalho da IA antes de confirmar
+- Pode revelar divergências entre os artefatos e a implementação
+
+---
+
+### `/opsx:sync`
+
+**Comando opcional.** Mesclar delta specs de uma mudança nas specs principais. O arquivamento pedirá para sincronizar se necessário, portanto, normalmente você não precisa executar isso manualmente.
+
+**Sintaxe:**
+```
+/opsx:sync [change-name]
+```
+
+**Argumentos:**
+| Argumento | Obrigatório | Descrição |
+|----------|----------|-------------|
+| `change-name` | Não | Qual mudança sincronizar (inferida do contexto se não fornecida) |
+
+**O que faz:**
+- Lê as delta specs da pasta da mudança
+- Analisa as seções ADDED/MODIFIED/REMOVED/RENAMED
+- Mescla as alterações no diretório principal `openspec/specs/`
+- Preserva o conteúdo existente não mencionado no delta
+- Não arquiva a mudança (permanece ativa)
+
+**Exemplo:**
+```text
+You: /opsx:sync
+
+AI: Syncing add-dark-mode delta specs...
+
+ Reading: openspec/changes/add-dark-mode/specs/ui/spec.md
+ Target: openspec/specs/ui/spec.md
+
+ Changes to apply:
+ ✓ ADDED: Theme Selection requirement (2 scenarios)
+ ✓ ADDED: Accessibility requirement (1 scenario)
+
+ Merging...
+ ✓ openspec/specs/ui/spec.md updated
+
+ Change remains active. Run /opsx:archive when ready to complete.
+```
+
+**Quando usar manualmente:**
+
+| Cenário | Usar sync? |
+|----------|-----------|
+| Mudança de longa duração, quer specs no principal antes de arquivar | Sim |
+| Múltiplas mudanças paralelas precisam das specs base atualizadas | Sim |
+| Quer visualizar/revisar a mesclagem separadamente | Sim |
+| Mudança rápida, indo direto para o arquivamento | Não (o archive cuida disso) |
+
+**Dicas:**
+- O sync é inteligente, não é cópia e cola
+- Pode adicionar cenários a requisitos existentes sem duplicar
+- A mudança permanece ativa após o sync (não arquivada)
+- A maioria dos usuários nunca precisará chamar isso diretamente—o archive solicita se necessário
+
+---
+
+### `/opsx:archive`
+
+Arquivar uma mudança concluída. Finaliza a mudança e a move para a pasta de histórico.
+
+**Sintaxe:**
+```
+/opsx:archive [change-name]
+```
+
+**Argumentos:**
+| Argumento | Obrigatório | Descrição |
+|----------|----------|-------------|
+| `change-name` | Não | Qual mudança arquivar (inferida do contexto se não fornecida) |
+
+**O que faz:**
+- Verifica o status de conclusão dos artefatos
+- Verifica a conclusão das tarefas (avisa se incompleta)
+- Oferece sincronizar as delta specs se ainda não foram sincronizadas
+- Move a pasta da mudança para `openspec/changes/archive/YYYY-MM-DD-/`
+- Preserva todos os artefatos para auditoria
+
+**Exemplo:**
+```text
+You: /opsx:archive
+
+AI: Archiving add-dark-mode...
+
+ Artifact status:
+ ✓ proposal.md exists
+ ✓ specs/ exists
+ ✓ design.md exists
+ ✓ tasks.md exists (8/8 tasks complete)
+
+ Delta specs: Not yet synced
+ → Sync now? (recommended)
+
+You: Yes
+
+AI: ✓ Synced specs to openspec/specs/ui/spec.md
+ ✓ Moved to openspec/changes/archive/2025-01-24-add-dark-mode/
+
+ Change archived successfully.
+```
+
+**Dicas:**
+- O archive não bloqueará em tarefas incompletas, mas avisará
+- As delta specs podem ser sincronizadas durante o arquivamento ou antes
+- As mudanças arquivadas são preservadas para o histórico
+- Use `/opsx:verify` primeiro para detectar problemas
+
+---
+
+### `/opsx:bulk-archive`
+
+Arquivar múltiplas mudanças concluídas de uma vez. Lida com conflitos de specs entre mudanças.
+
+**Sintaxe:**
+```
+/opsx:bulk-archive [change-names...]
+```
+
+**Argumentos:**
+| Argumento | Obrigatório | Descrição |
+|----------|----------|-------------|
+| `change-names` | Não | Mudanças específicas para arquivar (solicita seleção se não fornecidas) |
+
+**O que faz:**
+- Lista todas as mudanças concluídas
+- Valida cada mudança antes de arquivar
+- Detecta conflitos de specs entre mudanças
+- Resolve conflitos verificando o que está realmente implementado
+- Arquiva em ordem cronológica
+
+**Exemplo:**
+```
+You: /opsx:bulk-archive
+
+AI: Found 3 completed changes:
+ - add-dark-mode (8/8 tasks complete)
+ - fix-login-bug (3/3 tasks complete)
+ - update-footer (2/2 tasks complete)
+
+ Checking for spec conflicts...
+ ⚠ add-dark-mode and update-footer both touch specs/ui/
+
+ Inspecting codebase to resolve...
+ Both changes are implemented. Will merge in chronological order:
+ 1. add-dark-mode (created Jan 20)
+ 2. update-footer (created Jan 22)
+
+ Archive all 3 changes?
+
+You: Yes
+
+AI: ✓ Archived add-dark-mode
+ ✓ Archived fix-login-bug
+ ✓ Archived update-footer
+ Specs merged: add-dark-mode → update-footer
+```
+
+**Dicas:**
+- Bom para fluxos de trabalho paralelos
+- A resolução de conflitos é agêntica (verifica a base de código)
+- As mudanças são arquivadas na ordem de criação
+- Solicita confirmação antes de sobrescrever conteúdo de spec
+
+---
+
+### `/opsx:onboard`
+
+Integração guiada pelo fluxo de trabalho completo do BR-OpenSpec. Um tutorial interativo usando sua base de código real.
+
+**Sintaxe:**
+```
+/opsx:onboard
+```
+
+**O que faz:**
+- Percorre um ciclo completo de fluxo de trabalho com narração
+- Escaneia sua base de código em busca de oportunidades reais de melhoria
+- Cria uma mudança real com artefatos reais
+- Implementa trabalho real (mudanças pequenas e seguras)
+- Arquiva a mudança concluída
+- Explica cada passo conforme acontece
+
+**Fases:**
+1. Boas-vindas e análise da base de código
+2. Encontrando uma oportunidade de melhoria
+3. Criando uma mudança (`/opsx:new`)
+4. Escrevendo a proposta
+5. Criando specs
+6. Escrevendo o design
+7. Criando tarefas
+8. Implementando tarefas (`/opsx:apply`)
+9. Verificando a implementação
+10. Arquivando a mudança
+11. Resumo e próximos passos
+
+**Exemplo:**
+```
+You: /opsx:onboard
+
+AI: Bem-vindo ao BR-OpenSpec!
+
+ I'll walk you through the complete workflow using your actual codebase.
+ We'll find something small to improve, create a proper change for it,
+ implement it, and archive it.
+
+ Let me scan your codebase for opportunities...
+
+ [Analyzes codebase]
+
+ I found a few things we could work on:
+ 1. Add input validation to the contact form
+ 2. Improve error messages in the auth flow
+ 3. Add loading states to async buttons
+
+ Which interests you? (or suggest something else)
+```
+
+**Dicas:**
+- Melhor para novos usuários aprendendo o fluxo de trabalho
+- Usa código real, não exemplos simplificados
+- Cria uma mudança real que você pode manter ou descartar
+- Leva de 15 a 30 minutos para concluir
+
+---
+
+## Sintaxe de Comando por Ferramenta de IA
+
+Diferentes ferramentas de IA usam sintaxes de comando ligeiramente diferentes. Use o formato que corresponde à sua ferramenta:
+
+| Ferramenta | Exemplo de Sintaxe |
+|------|----------------|
+| Claude Code | `/opsx:propose`, `/opsx:apply` |
+| Cursor | `/opsx-propose`, `/opsx-apply` |
+| Windsurf | `/opsx-propose`, `/opsx-apply` |
+| Copilot (IDE) | `/opsx-propose`, `/opsx-apply` |
+| Kimi Code CLI | Invocações baseadas em skills como `/skill:openspec-propose`, `/skill:openspec-apply-change` (sem arquivos de comando `opsx-*` gerados) |
+| Trae | Invocações baseadas em skills como `/openspec-propose`, `/openspec-apply-change` (sem arquivos de comando `opsx-*` gerados) |
+
+A intenção é a mesma em todas as ferramentas, mas como os comandos são exibidos pode variar por integração.
+
+> **Nota:** Os comandos do GitHub Copilot (`.github/prompts/*.prompt.md`) estão disponíveis apenas em extensões de IDE (VS Code, JetBrains, Visual Studio). O GitHub Copilot CLI atualmente não suporta arquivos de prompt personalizados — consulte [Ferramentas Suportadas](supported-tools.md) para detalhes e alternativas.
+
+---
+
+## Comandos Legados
+
+Estes comandos usam o fluxo de trabalho mais antigo "tudo de uma vez". Eles ainda funcionam, mas os comandos OPSX são recomendados.
+
+| Comando | O que faz |
+|---------|--------------|
+| `/openspec:proposal` | Criar todos os artefatos de uma vez (proposal, specs, design, tasks) |
+| `/openspec:apply` | Implementar a mudança |
+| `/openspec:archive` | Arquivar a mudança |
+
+**Quando usar comandos legados:**
+- Projetos existentes usando o fluxo de trabalho antigo
+- Mudanças simples onde você não precisa de criação incremental de artefatos
+- Preferência pela abordagem tudo ou nada
+
+**Migrando para o OPSX:**
+Mudanças legadas podem ser continuadas com comandos OPSX. A estrutura de artefatos é compatível.
+
+---
+
+## Solução de Problemas
+
+### "Change not found"
+
+O comando não conseguiu identificar em qual mudança trabalhar.
+
+**Soluções:**
+- Especifique o nome da mudança explicitamente: `/opsx:apply add-dark-mode`
+- Verifique se a pasta da mudança existe: `openspec list`
+- Verifique se você está no diretório correto do projeto
+
+### "No artifacts ready"
+
+Todos os artefatos estão completos ou bloqueados por dependências ausentes.
+
+**Soluções:**
+- Execute `openspec status --change ` para ver o que está bloqueando
+- Verifique se os artefatos necessários existem
+- Crie primeiro os artefatos de dependência ausentes
+
+### "Schema not found"
+
+O schema especificado não existe.
+
+**Soluções:**
+- Liste os schemas disponíveis: `openspec schemas`
+- Verifique a ortografia do nome do schema
+- Crie o schema se for personalizado: `openspec schema init `
+
+### Comandos não reconhecidos
+
+A ferramenta de IA não reconhece os comandos do BR-OpenSpec.
+
+**Soluções:**
+- Certifique-se de que o BR-OpenSpec está inicializado: `openspec init`
+- Regenere as skills: `openspec update`
+- Verifique se o diretório `.claude/skills/` existe (para Claude Code)
+- Reinicie sua ferramenta de IA para carregar as novas skills
+
+### Artefatos não sendo gerados corretamente
+
+A IA cria artefatos incompletos ou incorretos.
+
+**Soluções:**
+- Adicione contexto do projeto em `openspec/config.yaml`
+- Adicione regras por artefato para orientações específicas
+- Forneça mais detalhes na descrição da mudança
+- Use `/opsx:continue` em vez de `/opsx:ff` para mais controle
+
+---
+
+## Próximos Passos
+
+- [Workflows](workflows.md) - Padrões comuns e quando usar cada comando
+- [CLI](cli.md) - Comandos de terminal para gerenciamento e validação
+- [Customização](customization.md) - Criar schemas e workflows personalizados
diff --git a/docs/pt-BR/concepts.md b/docs/pt-BR/concepts.md
new file mode 100644
index 0000000000..28897e73b4
--- /dev/null
+++ b/docs/pt-BR/concepts.md
@@ -0,0 +1,628 @@
+# Conceitos
+
+Este guia explica as ideias centrais do BR-OpenSpec e como elas se encaixam. Para uso prático, consulte [Primeiros Passos](getting-started.md) e [Fluxos de Trabalho](workflows.md).
+
+## Filosofia
+
+O BR-OpenSpec é construído em torno de quatro princípios:
+
+```
+fluid not rigid — no phase gates, work on what makes sense
+iterative not waterfall — learn as you build, refine as you go
+easy not complex — lightweight setup, minimal ceremony
+brownfield-first — works with existing codebases, not just greenfield
+```
+
+### Por Que Esses Princípios Importam
+
+**Fluido, não rígido.** Sistemas de spec tradicionais prendem você em fases: primeiro você planeja, depois implementa, depois termina. O BR-OpenSpec é mais flexível — você pode criar artefatos em qualquer ordem que faça sentido para o seu trabalho.
+
+**Iterativo, não waterfall.** Os requisitos mudam. O entendimento se aprofunda. O que parecia uma boa abordagem no início pode não se sustentar após você ver o código. O BR-OpenSpec abraça essa realidade.
+
+**Fácil, não complexo.** Alguns frameworks de spec exigem configuração extensa, formatos rígidos ou processos pesados. O BR-OpenSpec fica fora do seu caminho. Inicialize em segundos, comece a trabalhar imediatamente, personalize apenas se precisar.
+
+**Brownfield-first.** A maior parte do trabalho de software não é construir do zero — é modificar sistemas existentes. A abordagem baseada em deltas do BR-OpenSpec facilita a especificação de mudanças no comportamento existente, não apenas a descrição de novos sistemas.
+
+## O Panorama Geral
+
+O BR-OpenSpec organiza seu trabalho em duas áreas principais:
+
+```
+┌────────────────────────────────────────────────────────────────────┐
+│ openspec/ │
+│ │
+│ ┌─────────────────────┐ ┌───────────────────────────────┐ │
+│ │ specs/ │ │ changes/ │ │
+│ │ │ │ │ │
+│ │ Fonte de verdade │◄─────│ Modificações propostas │ │
+│ │ Como seu sistema │ merge│ Cada mudança = uma pasta │ │
+│ │ funciona agora │ │ Contém artefatos + deltas │ │
+│ │ │ │ │ │
+│ └─────────────────────┘ └───────────────────────────────┘ │
+│ │
+└────────────────────────────────────────────────────────────────────┘
+```
+
+**Specs** são a fonte de verdade — descrevem como seu sistema se comporta atualmente.
+
+**Mudanças** são modificações propostas — ficam em pastas separadas até que você esteja pronto para mesclá-las.
+
+Essa separação é fundamental. Você pode trabalhar em múltiplas mudanças em paralelo sem conflitos. Você pode revisar uma mudança antes que ela afete as specs principais. E quando você arquiva uma mudança, seus deltas se mesclam de forma limpa na fonte de verdade.
+
+## Specs
+
+As specs descrevem o comportamento do seu sistema usando requisitos e cenários estruturados.
+
+### Estrutura
+
+```
+openspec/specs/
+├── auth/
+│ └── spec.md # Authentication behavior
+├── payments/
+│ └── spec.md # Payment processing
+├── notifications/
+│ └── spec.md # Notification system
+└── ui/
+ └── spec.md # UI behavior and themes
+```
+
+Organize as specs por domínio — agrupamentos lógicos que fazem sentido para o seu sistema. Padrões comuns:
+
+- **Por área de funcionalidade**: `auth/`, `payments/`, `search/`
+- **Por componente**: `api/`, `frontend/`, `workers/`
+- **Por contexto delimitado**: `ordering/`, `fulfillment/`, `inventory/`
+
+### Formato da Spec
+
+Uma spec contém requisitos, e cada requisito possui cenários:
+
+```markdown
+# Auth Specification
+
+## Purpose
+Authentication and session management for the application.
+
+## Requirements
+
+### Requirement: User Authentication
+The system SHALL issue a JWT token upon successful login.
+
+#### Scenario: Valid credentials
+- GIVEN a user with valid credentials
+- WHEN the user submits login form
+- THEN a JWT token is returned
+- AND the user is redirected to dashboard
+
+#### Scenario: Invalid credentials
+- GIVEN invalid credentials
+- WHEN the user submits login form
+- THEN an error message is displayed
+- AND no token is issued
+
+### Requirement: Session Expiration
+The system MUST expire sessions after 30 minutes of inactivity.
+
+#### Scenario: Idle timeout
+- GIVEN an authenticated session
+- WHEN 30 minutes pass without activity
+- THEN the session is invalidated
+- AND the user must re-authenticate
+```
+
+**Elementos principais:**
+
+| Elemento | Finalidade |
+|---------|---------|
+| `## Purpose` | Descrição de alto nível do domínio desta spec |
+| `### Requirement:` | Um comportamento específico que o sistema deve ter |
+| `#### Scenario:` | Um exemplo concreto do requisito em ação |
+| SHALL/MUST/SHOULD | Palavras-chave RFC 2119 que indicam a força do requisito |
+
+### Por Que Estruturar Specs Dessa Forma
+
+**Requisitos são o "quê"** — eles declaram o que o sistema deve fazer sem especificar a implementação.
+
+**Cenários são o "quando"** — eles fornecem exemplos concretos que podem ser verificados. Bons cenários:
+- São testáveis (você poderia escrever um teste automatizado para eles)
+- Cobrem tanto o caminho feliz quanto os casos extremos
+- Usam Given/When/Then ou formato estruturado similar
+
+**Palavras-chave RFC 2119** (SHALL, MUST, SHOULD, MAY) comunicam a intenção:
+- **MUST/SHALL** — requisito absoluto
+- **SHOULD** — recomendado, mas existem exceções
+- **MAY** — opcional
+
+### O Que Uma Spec É (e Não É)
+
+Uma spec é um **contrato de comportamento**, não um plano de implementação.
+
+Conteúdo adequado para uma spec:
+- Comportamento observável do qual usuários ou sistemas downstream dependem
+- Entradas, saídas e condições de erro
+- Restrições externas (segurança, privacidade, confiabilidade, compatibilidade)
+- Cenários que podem ser testados ou explicitamente validados
+
+Evite em specs:
+- Nomes internos de classes/funções
+- Escolhas de bibliotecas ou frameworks
+- Detalhes de implementação passo a passo
+- Planos de execução detalhados (esses pertencem a `design.md` ou `tasks.md`)
+
+Teste rápido:
+- Se a implementação pode mudar sem alterar o comportamento externamente visível, provavelmente não pertence à spec.
+
+### Mantenha Leve: Rigor Progressivo
+
+O BR-OpenSpec visa evitar burocracia. Use o nível mais leve que ainda torne a mudança verificável.
+
+**Spec lite (padrão):**
+- Requisitos curtos com foco no comportamento
+- Escopo e não-objetivos claros
+- Algumas verificações concretas de aceitação
+
+**Spec completa (para maior risco):**
+- Mudanças entre equipes ou entre repositórios
+- Mudanças de API/contrato, migrações, preocupações de segurança/privacidade
+- Mudanças onde a ambiguidade provavelmente causará retrabalho caro
+
+A maioria das mudanças deve permanecer no modo Lite.
+
+### Colaboração Humano + Agente
+
+Em muitas equipes, humanos exploram e agentes rascunham artefatos. O ciclo pretendido é:
+
+1. O humano fornece intenção, contexto e restrições.
+2. O agente converte isso em requisitos e cenários com foco no comportamento.
+3. O agente mantém detalhes de implementação em `design.md` e `tasks.md`, não em `spec.md`.
+4. A validação confirma estrutura e clareza antes da implementação.
+
+Isso mantém as specs legíveis para humanos e consistentes para agentes.
+
+## Mudanças
+
+Uma mudança é uma modificação proposta ao seu sistema, empacotada como uma pasta com tudo o que é necessário para entendê-la e implementá-la.
+
+### Estrutura de uma Mudança
+
+```
+openspec/changes/add-dark-mode/
+├── proposal.md # Why and what
+├── design.md # How (technical approach)
+├── tasks.md # Implementation checklist
+├── .openspec.yaml # Change metadata (optional)
+└── specs/ # Delta specs
+ └── ui/
+ └── spec.md # What's changing in ui/spec.md
+```
+
+Cada mudança é autocontida. Ela possui:
+- **Artefatos** — documentos que capturam intenção, design e tarefas
+- **Delta specs** — especificações do que está sendo adicionado, modificado ou removido
+- **Metadados** — configuração opcional para essa mudança específica
+
+### Por Que Mudanças São Pastas
+
+Empacotar uma mudança como uma pasta tem vários benefícios:
+
+1. **Tudo junto.** Proposta, design, tarefas e specs ficam em um só lugar. Sem precisar procurar em locais diferentes.
+
+2. **Trabalho paralelo.** Múltiplas mudanças podem existir simultaneamente sem conflitos. Trabalhe em `add-dark-mode` enquanto `fix-auth-bug` também está em andamento.
+
+3. **Histórico limpo.** Quando arquivadas, as mudanças vão para `changes/archive/` com todo o contexto preservado. Você pode olhar para trás e entender não apenas o que mudou, mas por quê.
+
+4. **Fácil de revisar.** Uma pasta de mudança é fácil de revisar — abra-a, leia a proposta, verifique o design, veja os deltas de spec.
+
+## Artefatos
+
+Artefatos são os documentos dentro de uma mudança que orientam o trabalho.
+
+### O Fluxo de Artefatos
+
+```
+proposta ──────► specs ──────► design ──────► tarefas ──────► implementar
+ │ │ │ │
+ por quê o quê como passos
+ + escopo muda abordagem a seguir
+```
+
+Os artefatos constroem uns sobre os outros. Cada artefato fornece contexto para o próximo.
+
+### Tipos de Artefatos
+
+#### Proposta (`proposal.md`)
+
+A proposta captura **intenção**, **escopo** e **abordagem** em alto nível.
+
+```markdown
+# Proposal: Add Dark Mode
+
+## Intent
+Users have requested a dark mode option to reduce eye strain
+during nighttime usage and match system preferences.
+
+## Scope
+In scope:
+- Theme toggle in settings
+- System preference detection
+- Persist preference in localStorage
+
+Out of scope:
+- Custom color themes (future work)
+- Per-page theme overrides
+
+## Approach
+Use CSS custom properties for theming with a React context
+for state management. Detect system preference on first load,
+allow manual override.
+```
+
+**Quando atualizar a proposta:**
+- O escopo muda (redução ou expansão)
+- A intenção fica mais clara (melhor entendimento do problema)
+- A abordagem muda fundamentalmente
+
+#### Specs (delta specs em `specs/`)
+
+Delta specs descrevem **o que está mudando** em relação às specs atuais. Veja [Delta Specs](#delta-specs) abaixo.
+
+#### Design (`design.md`)
+
+O design captura a **abordagem técnica** e as **decisões de arquitetura**.
+
+````markdown
+# Design: Add Dark Mode
+
+## Technical Approach
+Theme state managed via React Context to avoid prop drilling.
+CSS custom properties enable runtime switching without class toggling.
+
+## Architecture Decisions
+
+### Decision: Context over Redux
+Using React Context for theme state because:
+- Simple binary state (light/dark)
+- No complex state transitions
+- Avoids adding Redux dependency
+
+### Decision: CSS Custom Properties
+Using CSS variables instead of CSS-in-JS because:
+- Works with existing stylesheet
+- No runtime overhead
+- Browser-native solution
+
+## Data Flow
+```
+ThemeProvider (context)
+ │
+ ▼
+ThemeToggle ◄──► localStorage
+ │
+ ▼
+CSS Variables (applied to :root)
+```
+
+## File Changes
+- `src/contexts/ThemeContext.tsx` (new)
+- `src/components/ThemeToggle.tsx` (new)
+- `src/styles/globals.css` (modified)
+````
+
+**Quando atualizar o design:**
+- A implementação revela que a abordagem não funcionará
+- Uma solução melhor é descoberta
+- Dependências ou restrições mudam
+
+#### Tarefas (`tasks.md`)
+
+Tarefas são o **checklist de implementação** — passos concretos com caixas de seleção.
+
+```markdown
+# Tasks
+
+## 1. Theme Infrastructure
+- [ ] 1.1 Create ThemeContext with light/dark state
+- [ ] 1.2 Add CSS custom properties for colors
+- [ ] 1.3 Implement localStorage persistence
+- [ ] 1.4 Add system preference detection
+
+## 2. UI Components
+- [ ] 2.1 Create ThemeToggle component
+- [ ] 2.2 Add toggle to settings page
+- [ ] 2.3 Update Header to include quick toggle
+
+## 3. Styling
+- [ ] 3.1 Define dark theme color palette
+- [ ] 3.2 Update components to use CSS variables
+- [ ] 3.3 Test contrast ratios for accessibility
+```
+
+**Boas práticas para tarefas:**
+- Agrupe tarefas relacionadas sob títulos
+- Use numeração hierárquica (1.1, 1.2, etc.)
+- Mantenha as tarefas pequenas o suficiente para concluir em uma sessão
+- Marque as tarefas conforme forem concluídas
+
+## Delta Specs
+
+Delta specs são o conceito-chave que faz o BR-OpenSpec funcionar para desenvolvimento brownfield. Elas descrevem **o que está mudando** em vez de repetir toda a spec.
+
+### O Formato
+
+```markdown
+# Delta for Auth
+
+## ADDED Requirements
+
+### Requirement: Two-Factor Authentication
+The system MUST support TOTP-based two-factor authentication.
+
+#### Scenario: 2FA enrollment
+- GIVEN a user without 2FA enabled
+- WHEN the user enables 2FA in settings
+- THEN a QR code is displayed for authenticator app setup
+- AND the user must verify with a code before activation
+
+#### Scenario: 2FA login
+- GIVEN a user with 2FA enabled
+- WHEN the user submits valid credentials
+- THEN an OTP challenge is presented
+- AND login completes only after valid OTP
+
+## MODIFIED Requirements
+
+### Requirement: Session Expiration
+The system MUST expire sessions after 15 minutes of inactivity.
+(Previously: 30 minutes)
+
+#### Scenario: Idle timeout
+- GIVEN an authenticated session
+- WHEN 15 minutes pass without activity
+- THEN the session is invalidated
+
+## REMOVED Requirements
+
+### Requirement: Remember Me
+(Deprecated in favor of 2FA. Users should re-authenticate each session.)
+```
+
+### Seções do Delta
+
+| Seção | Significado | O Que Acontece ao Arquivar |
+|---------|---------|------------------------|
+| `## ADDED Requirements` | Novo comportamento | Adicionado à spec principal |
+| `## MODIFIED Requirements` | Comportamento alterado | Substitui o requisito existente |
+| `## REMOVED Requirements` | Comportamento descontinuado | Removido da spec principal |
+
+### Por Que Deltas em Vez de Specs Completas
+
+**Clareza.** Um delta mostra exatamente o que está mudando. Lendo uma spec completa, você teria que fazer o diff mentalmente em relação à versão atual.
+
+**Evitar conflitos.** Duas mudanças podem tocar o mesmo arquivo de spec sem conflitar, desde que modifiquem requisitos diferentes.
+
+**Eficiência na revisão.** Os revisores veem a mudança, não o contexto inalterado. Foco no que importa.
+
+**Adequação ao brownfield.** A maior parte do trabalho modifica comportamento existente. Deltas tornam as modificações prioritárias, não uma reflexão tardia.
+
+## Schemas
+
+Schemas definem os tipos de artefatos e suas dependências para um fluxo de trabalho.
+
+### Como os Schemas Funcionam
+
+```yaml
+# openspec/schemas/spec-driven/schema.yaml
+name: spec-driven
+artifacts:
+ - id: proposal
+ generates: proposal.md
+ requires: [] # No dependencies, can create first
+
+ - id: specs
+ generates: specs/**/*.md
+ requires: [proposal] # Needs proposal before creating
+
+ - id: design
+ generates: design.md
+ requires: [proposal] # Can create in parallel with specs
+
+ - id: tasks
+ generates: tasks.md
+ requires: [specs, design] # Needs both specs and design first
+```
+
+**Os artefatos formam um grafo de dependências:**
+
+```
+ proposal
+ (nó raiz)
+ │
+ ┌─────────────┴─────────────┐
+ │ │
+ ▼ ▼
+ specs design
+ (requires: (requires:
+ proposal) proposal)
+ │ │
+ └─────────────┬─────────────┘
+ │
+ ▼
+ tasks
+ (requires:
+ specs, design)
+```
+
+**Dependências são habilitadores, não bloqueadores.** Elas mostram o que é possível criar, não o que você deve criar a seguir. Você pode pular o design se não precisar dele. Você pode criar specs antes ou depois do design — ambos dependem apenas da proposta.
+
+### Schemas Embutidos
+
+**spec-driven** (padrão)
+
+O fluxo de trabalho padrão para desenvolvimento orientado a specs:
+
+```
+proposal → specs → design → tasks → implement
+```
+
+Ideal para: A maioria dos trabalhos de funcionalidade em que você quer concordar com as specs antes da implementação.
+
+### Schemas Personalizados
+
+Crie schemas personalizados para o fluxo de trabalho da sua equipe:
+
+```bash
+# Create from scratch
+openspec schema init research-first
+
+# Or fork an existing one
+openspec schema fork spec-driven research-first
+```
+
+**Exemplo de schema personalizado:**
+
+```yaml
+# openspec/schemas/research-first/schema.yaml
+name: research-first
+artifacts:
+ - id: research
+ generates: research.md
+ requires: [] # Do research first
+
+ - id: proposal
+ generates: proposal.md
+ requires: [research] # Proposal informed by research
+
+ - id: tasks
+ generates: tasks.md
+ requires: [proposal] # Skip specs/design, go straight to tasks
+```
+
+Consulte [Personalização](customization.md) para detalhes completos sobre como criar e usar schemas personalizados.
+
+## Arquivamento
+
+Arquivar conclui uma mudança ao mesclar seus delta specs nas specs principais e preservar a mudança no histórico.
+
+### O Que Acontece Quando Você Arquiva
+
+```
+Antes de arquivar:
+
+openspec/
+├── specs/
+│ └── auth/
+│ └── spec.md ◄────────────────┐
+└── changes/ │
+ └── add-2fa/ │
+ ├── proposal.md │
+ ├── design.md │ merge
+ ├── tasks.md │
+ └── specs/ │
+ └── auth/ │
+ └── spec.md ─────────┘
+
+
+Após arquivar:
+
+openspec/
+├── specs/
+│ └── auth/
+│ └── spec.md # Agora inclui os requisitos de 2FA
+└── changes/
+ └── archive/
+ └── 2025-01-24-add-2fa/ # Preservado no histórico
+ ├── proposal.md
+ ├── design.md
+ ├── tasks.md
+ └── specs/
+ └── auth/
+ └── spec.md
+```
+
+### O Processo de Arquivamento
+
+1. **Mesclar os deltas.** Cada seção do delta spec (ADDED/MODIFIED/REMOVED) é aplicada à spec principal correspondente.
+
+2. **Mover para o arquivo.** A pasta da mudança vai para `changes/archive/` com um prefixo de data para ordenação cronológica.
+
+3. **Preservar o contexto.** Todos os artefatos permanecem intactos no arquivo. Você sempre pode olhar para trás para entender por que uma mudança foi feita.
+
+### Por Que o Arquivamento Importa
+
+**Estado limpo.** As mudanças ativas (`changes/`) mostram apenas o trabalho em andamento. O trabalho concluído sai do caminho.
+
+**Trilha de auditoria.** O arquivo preserva o contexto completo de cada mudança — não apenas o que mudou, mas a proposta explicando por quê, o design explicando como, e as tarefas mostrando o trabalho realizado.
+
+**Evolução das specs.** As specs crescem organicamente conforme as mudanças são arquivadas. Cada arquivamento mescla seus deltas, construindo uma especificação abrangente ao longo do tempo.
+
+## Como Tudo Se Encaixa
+
+```
+┌──────────────────────────────────────────────────────────────────────────────┐
+│ FLUXO DO OPENSPEC │
+│ │
+│ ┌────────────────┐ │
+│ │ 1. INICIAR │ /opsx:propose (core) or /opsx:new (expanded) │
+│ │ MUDANÇA │ │
+│ └───────┬────────┘ │
+│ │ │
+│ ▼ │
+│ ┌────────────────┐ │
+│ │ 2. CRIAR │ /opsx:ff or /opsx:continue (expanded workflow) │
+│ │ ARTEFATOS │ Creates proposal → specs → design → tasks │
+│ │ │ (based on schema dependencies) │
+│ └───────┬────────┘ │
+│ │ │
+│ ▼ │
+│ ┌────────────────┐ │
+│ │ 3. IMPLEMENTAR│ /opsx:apply │
+│ │ TAREFAS │ Trabalhe nas tarefas, marcando-as como concluídas │
+│ │ │◄──── Atualize artefatos conforme aprender │
+│ └───────┬────────┘ │
+│ │ │
+│ ▼ │
+│ ┌────────────────┐ │
+│ │ 4. VERIFICAR │ /opsx:verify (optional) │
+│ │ TRABALHO │ Verifique se a implementação corresponde às specs │
+│ └───────┬────────┘ │
+│ │ │
+│ ▼ │
+│ ┌────────────────┐ ┌──────────────────────────────────────────────┐ │
+│ │ 5. ARQUIVAR │────►│ Delta specs mesclados nas specs principais │ │
+│ │ MUDANÇA │ │ Pasta da mudança vai para archive/ │ │
+│ └────────────────┘ │ Specs agora são a fonte de verdade atualiz.│ │
+│ └──────────────────────────────────────────────┘ │
+│ │
+└──────────────────────────────────────────────────────────────────────────────┘
+```
+
+**O ciclo virtuoso:**
+
+1. As specs descrevem o comportamento atual
+2. As mudanças propõem modificações (como deltas)
+3. A implementação torna as mudanças reais
+4. O arquivamento mescla os deltas nas specs
+5. As specs agora descrevem o novo comportamento
+6. A próxima mudança parte das specs atualizadas
+
+## Glossário
+
+| Termo | Definição |
+|------|------------|
+| **Artefato** | Um documento dentro de uma mudança (proposta, design, tarefas ou delta specs) |
+| **Arquivamento** | O processo de concluir uma mudança e mesclar seus deltas nas specs principais |
+| **Mudança** | Uma modificação proposta ao sistema, empacotada como uma pasta com artefatos |
+| **Delta spec** | Uma spec que descreve mudanças (ADDED/MODIFIED/REMOVED) em relação às specs atuais |
+| **Domínio** | Um agrupamento lógico de specs (por exemplo, `auth/`, `payments/`) |
+| **Requisito** | Um comportamento específico que o sistema deve ter |
+| **Cenário** | Um exemplo concreto de um requisito, tipicamente no formato Given/When/Then |
+| **Schema** | Uma definição de tipos de artefatos e suas dependências |
+| **Spec** | Uma especificação que descreve o comportamento do sistema, contendo requisitos e cenários |
+| **Fonte de verdade** | O diretório `openspec/specs/`, contendo o comportamento atual acordado |
+
+## Próximos Passos
+
+- [Primeiros Passos](getting-started.md) - Primeiros passos práticos
+- [Fluxos de Trabalho](workflows.md) - Padrões comuns e quando usar cada um
+- [Comandos](commands.md) - Referência completa de comandos
+- [Personalização](customization.md) - Criar schemas personalizados e configurar seu projeto
diff --git a/docs/pt-BR/customization.md b/docs/pt-BR/customization.md
new file mode 100644
index 0000000000..f9403b5b1f
--- /dev/null
+++ b/docs/pt-BR/customization.md
@@ -0,0 +1,342 @@
+# Personalização
+
+O BR-OpenSpec oferece três níveis de personalização:
+
+| Nível | O que faz | Ideal para |
+|-------|-----------|------------|
+| **Configuração de Projeto** | Define padrões, injeta contexto/regras | A maioria das equipes |
+| **Schemas Personalizados** | Define seus próprios artefatos de fluxo de trabalho | Equipes com processos únicos |
+| **Substituições Globais** | Compartilha schemas entre todos os projetos | Usuários avançados |
+
+---
+
+## Configuração do Projeto
+
+O arquivo `openspec/config.yaml` é a maneira mais fácil de personalizar o BR-OpenSpec para sua equipe. Ele permite:
+
+- **Definir um schema padrão** - Evita usar `--schema` em todo comando
+- **Injetar contexto do projeto** - A IA vê sua stack tecnológica, convenções, etc.
+- **Adicionar regras por artefato** - Regras personalizadas para artefatos específicos
+
+### Configuração Rápida
+
+```bash
+openspec init
+```
+
+Isso guia você pela criação de uma configuração de forma interativa. Ou crie manualmente:
+
+```yaml
+# openspec/config.yaml
+schema: spec-driven
+
+context: |
+ Tech stack: TypeScript, React, Node.js, PostgreSQL
+ API style: RESTful, documented in docs/api.md
+ Testing: Jest + React Testing Library
+ We value backwards compatibility for all public APIs
+
+rules:
+ proposal:
+ - Include rollback plan
+ - Identify affected teams
+ specs:
+ - Use Given/When/Then format
+ - Reference existing patterns before inventing new ones
+```
+
+### Como Funciona
+
+**Schema padrão:**
+
+```bash
+# Sem config
+openspec new change my-feature --schema spec-driven
+
+# Com config - schema é automático
+openspec new change my-feature
+```
+
+**Injeção de contexto e regras:**
+
+Ao gerar qualquer artefato, seu contexto e regras são injetados no prompt da IA:
+
+```xml
+
+Tech stack: TypeScript, React, Node.js, PostgreSQL
+...
+
+
+
+- Include rollback plan
+- Identify affected teams
+
+
+
+[Schema's built-in template]
+
+```
+
+- **Contexto** aparece em TODOS os artefatos
+- **Regras** aparecem APENAS para o artefato correspondente
+
+### Ordem de Resolução do Schema
+
+Quando o BR-OpenSpec precisa de um schema, ele verifica nesta ordem:
+
+1. Flag CLI: `--schema `
+2. Metadados da mudança (`.openspec.yaml` na pasta da mudança)
+3. Configuração do projeto (`openspec/config.yaml`)
+4. Padrão (`spec-driven`)
+
+---
+
+## Schemas Personalizados
+
+Quando a configuração do projeto não é suficiente, crie seu próprio schema com um fluxo de trabalho completamente personalizado. Schemas personalizados ficam no diretório `openspec/schemas/` do seu projeto e são versionados junto com seu código.
+
+```text
+your-project/
+├── openspec/
+│ ├── config.yaml # Project config
+│ ├── schemas/ # Custom schemas live here
+│ │ └── my-workflow/
+│ │ ├── schema.yaml
+│ │ └── templates/
+│ └── changes/ # Your changes
+└── src/
+```
+
+### Bifurcar um Schema Existente
+
+A maneira mais rápida de personalizar é fazer fork de um schema embutido:
+
+```bash
+openspec schema fork spec-driven my-workflow
+```
+
+Isso copia o schema `spec-driven` inteiro para `openspec/schemas/my-workflow/`, onde você pode editá-lo livremente.
+
+**O que você obtém:**
+
+```text
+openspec/schemas/my-workflow/
+├── schema.yaml # Workflow definition
+└── templates/
+ ├── proposal.md # Template for proposal artifact
+ ├── spec.md # Template for specs
+ ├── design.md # Template for design
+ └── tasks.md # Template for tasks
+```
+
+Agora edite `schema.yaml` para alterar o fluxo de trabalho, ou edite os templates para mudar o que a IA gera.
+
+### Criar um Schema do Zero
+
+Para um fluxo de trabalho completamente novo:
+
+```bash
+# Interativo
+openspec schema init research-first
+
+# Não interativo
+openspec schema init rapid \
+ --description "Rapid iteration workflow" \
+ --artifacts "proposal,tasks" \
+ --default
+```
+
+### Estrutura do Schema
+
+Um schema define os artefatos do seu fluxo de trabalho e como eles dependem uns dos outros:
+
+```yaml
+# openspec/schemas/my-workflow/schema.yaml
+name: my-workflow
+version: 1
+description: My team's custom workflow
+
+artifacts:
+ - id: proposal
+ generates: proposal.md
+ description: Initial proposal document
+ template: proposal.md
+ instruction: |
+ Create a proposal that explains WHY this change is needed.
+ Focus on the problem, not the solution.
+ requires: []
+
+ - id: design
+ generates: design.md
+ description: Technical design
+ template: design.md
+ instruction: |
+ Create a design document explaining HOW to implement.
+ requires:
+ - proposal # Can't create design until proposal exists
+
+ - id: tasks
+ generates: tasks.md
+ description: Implementation checklist
+ template: tasks.md
+ requires:
+ - design
+
+apply:
+ requires: [tasks]
+ tracks: tasks.md
+```
+
+**Campos principais:**
+
+| Campo | Finalidade |
+|-------|-----------|
+| `id` | Identificador único, usado em comandos e regras |
+| `generates` | Nome do arquivo de saída (suporta globs como `specs/**/*.md`) |
+| `template` | Arquivo de template no diretório `templates/` |
+| `instruction` | Instruções para a IA ao criar este artefato |
+| `requires` | Dependências — quais artefatos devem existir primeiro |
+
+### Templates
+
+Templates são arquivos markdown que guiam a IA. Eles são injetados no prompt ao criar aquele artefato.
+
+```markdown
+
+## Why
+
+
+
+## What Changes
+
+
+
+## Impact
+
+
+```
+
+Templates podem incluir:
+- Cabeçalhos de seção que a IA deve preencher
+- Comentários HTML com orientações para a IA
+- Formatos de exemplo mostrando a estrutura esperada
+
+### Validar Seu Schema
+
+Antes de usar um schema personalizado, valide-o:
+
+```bash
+openspec schema validate my-workflow
+```
+
+Isso verifica:
+- A sintaxe do `schema.yaml` está correta
+- Todos os templates referenciados existem
+- Não há dependências circulares
+- Os IDs dos artefatos são válidos
+
+### Usar Seu Schema Personalizado
+
+Uma vez criado, use seu schema com:
+
+```bash
+# Especificar no comando
+openspec new change feature --schema my-workflow
+
+# Ou definir como padrão em config.yaml
+schema: my-workflow
+```
+
+### Depurar a Resolução do Schema
+
+Não tem certeza de qual schema está sendo usado? Verifique com:
+
+```bash
+# Ver de onde um schema específico é resolvido
+openspec schema which my-workflow
+
+# Listar todos os schemas disponíveis
+openspec schema which --all
+```
+
+A saída mostra se vem do seu projeto, diretório do usuário ou do pacote:
+
+```text
+Schema: my-workflow
+Source: project
+Path: /path/to/project/openspec/schemas/my-workflow
+```
+
+---
+
+> **Nota:** O BR-OpenSpec também suporta schemas em nível de usuário em `~/.local/share/openspec/schemas/` para compartilhamento entre projetos, mas schemas em nível de projeto em `openspec/schemas/` são recomendados por serem versionados junto com seu código.
+
+---
+
+## Exemplos
+
+### Fluxo de Trabalho de Iteração Rápida
+
+Um fluxo de trabalho mínimo para iterações rápidas:
+
+```yaml
+# openspec/schemas/rapid/schema.yaml
+name: rapid
+version: 1
+description: Fast iteration with minimal overhead
+
+artifacts:
+ - id: proposal
+ generates: proposal.md
+ description: Quick proposal
+ template: proposal.md
+ instruction: |
+ Create a brief proposal for this change.
+ Focus on what and why, skip detailed specs.
+ requires: []
+
+ - id: tasks
+ generates: tasks.md
+ description: Implementation checklist
+ template: tasks.md
+ requires: [proposal]
+
+apply:
+ requires: [tasks]
+ tracks: tasks.md
+```
+
+### Adicionando um Artefato de Revisão
+
+Faça fork do padrão e adicione uma etapa de revisão:
+
+```bash
+openspec schema fork spec-driven with-review
+```
+
+Depois edite `schema.yaml` para adicionar:
+
+```yaml
+ - id: review
+ generates: review.md
+ description: Pre-implementation review checklist
+ template: review.md
+ instruction: |
+ Create a review checklist based on the design.
+ Include security, performance, and testing considerations.
+ requires:
+ - design
+
+ - id: tasks
+ # ... existing tasks config ...
+ requires:
+ - specs
+ - design
+ - review # Now tasks require review too
+```
+
+---
+
+## Veja Também
+
+- [Referência CLI: Comandos de Schema](cli.md#schema-commands) - Documentação completa dos comandos
diff --git a/docs/pt-BR/getting-started.md b/docs/pt-BR/getting-started.md
new file mode 100644
index 0000000000..967f98502e
--- /dev/null
+++ b/docs/pt-BR/getting-started.md
@@ -0,0 +1,253 @@
+# Primeiros Passos
+
+Este guia explica como o BR-OpenSpec funciona após você tê-lo instalado e inicializado. Para instruções de instalação, consulte o [README principal](../../README.pt-BR.md#quick-start).
+
+## Como Funciona
+
+O BR-OpenSpec ajuda você e seu assistente de codificação com IA a chegarem a um acordo sobre o que construir antes de qualquer código ser escrito.
+
+**Caminho rápido padrão (perfil `core`):**
+
+```text
+/opsx:propose ──► /opsx:apply ──► /opsx:archive
+```
+
+**Caminho expandido (seleção de workflow personalizado):**
+
+```text
+/opsx:new ──► /opsx:ff or /opsx:continue ──► /opsx:apply ──► /opsx:verify ──► /opsx:archive
+```
+
+O perfil global padrão é `core`, que inclui `propose`, `explore`, `apply` e `archive`. Você pode habilitar os comandos de workflow expandido com `openspec config profile` e depois `openspec update`.
+
+## O Que o BR-OpenSpec Cria
+
+Após executar `openspec init`, seu projeto terá esta estrutura:
+
+```
+openspec/
+├── specs/ # Fonte de verdade (o comportamento do seu sistema)
+│ └── /
+│ └── spec.md
+├── changes/ # Atualizações propostas (uma pasta por mudança)
+│ └── /
+│ ├── proposal.md
+│ ├── design.md
+│ ├── tasks.md
+│ └── specs/ # Delta specs (o que está mudando)
+│ └── /
+│ └── spec.md
+└── config.yaml # Configuração do projeto (opcional)
+```
+
+**Dois diretórios principais:**
+
+- **`specs/`** - A fonte de verdade. Essas specs descrevem como o seu sistema se comporta atualmente. Organizadas por domínio (ex.: `specs/auth/`, `specs/payments/`).
+
+- **`changes/`** - Modificações propostas. Cada mudança tem sua própria pasta com todos os artefatos relacionados. Quando uma mudança é concluída, suas specs são mescladas no diretório principal `specs/`.
+
+## Entendendo os Artefatos
+
+Cada pasta de mudança contém artefatos que orientam o trabalho:
+
+| Artefato | Propósito |
+|----------|-----------|
+| `proposal.md` | O "por quê" e o "o quê" — captura a intenção, o escopo e a abordagem |
+| `specs/` | Delta specs mostrando requisitos ADICIONADOS/MODIFICADOS/REMOVIDOS |
+| `design.md` | O "como" — abordagem técnica e decisões de arquitetura |
+| `tasks.md` | Lista de verificação de implementação com checkboxes |
+
+**Os artefatos se constroem uns sobre os outros:**
+
+```
+proposta ──► specs ──► design ──► tarefas ──► implementação
+ ▲ ▲ ▲ │
+ └───────────┴──────────┴────────────────────────┘
+ atualizar conforme você aprende
+```
+
+Você sempre pode voltar e refinar artefatos anteriores à medida que aprende mais durante a implementação.
+
+## Como as Delta Specs Funcionam
+
+As delta specs são o conceito central do BR-OpenSpec. Elas mostram o que está mudando em relação às suas specs atuais.
+
+### O Formato
+
+As delta specs usam seções para indicar o tipo de mudança:
+
+```markdown
+# Delta for Auth
+
+## ADDED Requirements
+
+### Requirement: Two-Factor Authentication
+The system MUST require a second factor during login.
+
+#### Scenario: OTP required
+- GIVEN a user with 2FA enabled
+- WHEN the user submits valid credentials
+- THEN an OTP challenge is presented
+
+## MODIFIED Requirements
+
+### Requirement: Session Timeout
+The system SHALL expire sessions after 30 minutes of inactivity.
+(Previously: 60 minutes)
+
+#### Scenario: Idle timeout
+- GIVEN an authenticated session
+- WHEN 30 minutes pass without activity
+- THEN the session is invalidated
+
+## REMOVED Requirements
+
+### Requirement: Remember Me
+(Deprecated in favor of 2FA)
+```
+
+### O Que Acontece ao Arquivar
+
+Quando você arquiva uma mudança:
+
+1. Os requisitos **ADDED** são anexados à spec principal
+2. Os requisitos **MODIFIED** substituem a versão existente
+3. Os requisitos **REMOVED** são excluídos da spec principal
+
+A pasta da mudança é movida para `openspec/changes/archive/` como histórico de auditoria.
+
+## Exemplo: Sua Primeira Mudança
+
+Vamos percorrer o processo de adição do modo escuro a uma aplicação.
+
+### 1. Iniciar a Mudança (Padrão)
+
+```text
+Você: /opsx:propose add-dark-mode
+
+IA: Criado openspec/changes/add-dark-mode/
+ ✓ proposal.md — por que estamos fazendo isso, o que está mudando
+ ✓ specs/ — requisitos e cenários
+ ✓ design.md — abordagem técnica
+ ✓ tasks.md — lista de verificação de implementação
+ Pronto para implementação!
+```
+
+Se você habilitou o perfil de workflow expandido, também pode fazer isso em duas etapas: `/opsx:new` e depois `/opsx:ff` (ou `/opsx:continue` de forma incremental).
+
+### 2. O Que é Criado
+
+**proposal.md** — Captura a intenção:
+
+```markdown
+# Proposal: Add Dark Mode
+
+## Intent
+Users have requested a dark mode option to reduce eye strain
+during nighttime usage.
+
+## Scope
+- Add theme toggle in settings
+- Support system preference detection
+- Persist preference in localStorage
+
+## Approach
+Use CSS custom properties for theming with a React context
+for state management.
+```
+
+**specs/ui/spec.md** — Delta mostrando os novos requisitos:
+
+```markdown
+# Delta for UI
+
+## ADDED Requirements
+
+### Requirement: Theme Selection
+The system SHALL allow users to choose between light and dark themes.
+
+#### Scenario: Manual toggle
+- GIVEN a user on any page
+- WHEN the user clicks the theme toggle
+- THEN the theme switches immediately
+- AND the preference persists across sessions
+
+#### Scenario: System preference
+- GIVEN a user with no saved preference
+- WHEN the application loads
+- THEN the system's preferred color scheme is used
+```
+
+**tasks.md** — Lista de verificação de implementação:
+
+```markdown
+# Tasks
+
+## 1. Theme Infrastructure
+- [ ] 1.1 Create ThemeContext with light/dark state
+- [ ] 1.2 Add CSS custom properties for colors
+- [ ] 1.3 Implement localStorage persistence
+
+## 2. UI Components
+- [ ] 2.1 Create ThemeToggle component
+- [ ] 2.2 Add toggle to settings page
+- [ ] 2.3 Update Header to include quick toggle
+
+## 3. Styling
+- [ ] 3.1 Define dark theme color palette
+- [ ] 3.2 Update components to use CSS variables
+```
+
+### 3. Implementar
+
+```
+Você: /opsx:apply
+
+IA: Executando as tarefas...
+ ✓ 1.1 ThemeContext criado com estado light/dark
+ ✓ 1.2 Propriedades CSS customizadas adicionadas ao globals.css
+ ✓ 1.3 Persistência com localStorage implementada
+ ✓ 2.1 Componente ThemeToggle criado
+ ...
+ Todas as tarefas concluídas!
+```
+
+Durante a implementação, se você descobrir que o design precisa de ajuste, basta atualizar o artefato e continuar.
+
+### 4. Arquivar
+
+```
+Você: /opsx:archive
+
+IA: Arquivando add-dark-mode...
+ ✓ Specs mescladas em openspec/specs/ui/spec.md
+ ✓ Movido para openspec/changes/archive/2025-01-24-add-dark-mode/
+ Concluído! Pronto para o próximo recurso.
+```
+
+Suas delta specs agora fazem parte das specs principais, documentando como o seu sistema funciona.
+
+## Verificando e Revisando
+
+Use a CLI para conferir suas mudanças:
+
+```bash
+# Listar mudanças ativas
+openspec list
+
+# Ver detalhes de uma mudança
+openspec show add-dark-mode
+
+# Validar a formatação das specs
+openspec validate add-dark-mode
+
+# Dashboard interativo
+openspec view
+```
+
+## Próximos Passos
+
+- [Fluxos de Trabalho](workflows.md) — Padrões comuns e quando usar cada comando
+- [Comandos](commands.md) — Referência completa de todos os comandos slash
+- [Conceitos](concepts.md) — Compreensão mais profunda de specs, mudanças e schemas
+- [Personalização](customization.md) — Faça o BR-OpenSpec funcionar do seu jeito
diff --git a/docs/pt-BR/installation.md b/docs/pt-BR/installation.md
new file mode 100644
index 0000000000..4bb884ec6c
--- /dev/null
+++ b/docs/pt-BR/installation.md
@@ -0,0 +1,79 @@
+# Instalação
+
+## Pré-requisitos
+
+- **Node.js 20.19.0 ou superior** — Verifique sua versão: `node --version`
+
+## Gerenciadores de Pacotes
+
+### npm
+
+```bash
+npm install -g @fkmatsuda/br-openspec@latest
+```
+
+### pnpm
+
+```bash
+pnpm add -g @fkmatsuda/br-openspec@latest
+```
+
+### yarn
+
+```bash
+yarn global add @fkmatsuda/br-openspec@latest
+```
+
+### bun
+
+```bash
+bun add -g @fkmatsuda/br-openspec@latest
+```
+
+## Nix
+
+Execute o BR-OpenSpec diretamente sem instalação:
+
+```bash
+nix run github:fkmatsuda/BR-OpenSpec -- init
+```
+
+Ou instale no seu perfil:
+
+```bash
+nix profile install github:fkmatsuda/BR-OpenSpec
+```
+
+Ou adicione ao seu ambiente de desenvolvimento em `flake.nix`:
+
+```nix
+{
+ inputs = {
+ nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
+ openspec.url = "github:fkmatsuda/BR-OpenSpec";
+ };
+
+ outputs = { nixpkgs, openspec, ... }: {
+ devShells.x86_64-linux.default = nixpkgs.legacyPackages.x86_64-linux.mkShell {
+ buildInputs = [ openspec.packages.x86_64-linux.default ];
+ };
+ };
+}
+```
+
+## Verificar Instalação
+
+```bash
+openspec --version
+```
+
+## Próximos Passos
+
+Após instalar, inicialize o BR-OpenSpec no seu projeto:
+
+```bash
+cd your-project
+openspec init
+```
+
+Veja [Primeiros Passos](../getting-started.md) para um guia completo.
diff --git a/docs/pt-BR/migration-guide.md b/docs/pt-BR/migration-guide.md
new file mode 100644
index 0000000000..b274190b4c
--- /dev/null
+++ b/docs/pt-BR/migration-guide.md
@@ -0,0 +1,594 @@
+# Migrando para o OPSX
+
+Este guia ajuda você a fazer a transição do fluxo de trabalho legado do BR-OpenSpec para o OPSX. A migração foi projetada para ser suave—seu trabalho existente é preservado, e o novo sistema oferece mais flexibilidade.
+
+## O Que Está Mudando?
+
+O OPSX substitui o antigo fluxo de trabalho baseado em fases por uma abordagem fluida e baseada em ações. Aqui está a principal mudança:
+
+| Aspecto | Legado | OPSX |
+|--------|--------|------|
+| **Comandos** | `/openspec:proposal`, `/openspec:apply`, `/openspec:archive` | Padrão: `/opsx:propose`, `/opsx:apply`, `/opsx:archive` (comandos de fluxo de trabalho expandido opcionais) |
+| **Fluxo de trabalho** | Criar todos os artefatos de uma vez | Criar incrementalmente ou tudo de uma vez—sua escolha |
+| **Retroceder** | Fases bloqueantes difíceis | Natural—atualize qualquer artefato a qualquer momento |
+| **Personalização** | Estrutura fixa | Orientado por schema, totalmente personalizável |
+| **Configuração** | `CLAUDE.md` com marcadores + `project.md` | Configuração limpa em `openspec/config.yaml` |
+
+**A mudança de filosofia:** O trabalho não é linear. O OPSX para de fingir que é.
+
+---
+
+## Antes de Começar
+
+### Seu Trabalho Existente Está Seguro
+
+O processo de migração foi projetado com preservação em mente:
+
+- **Mudanças ativas em `openspec/changes/`** — Completamente preservadas. Você pode continuá-las com comandos OPSX.
+- **Mudanças arquivadas** — Intocadas. Seu histórico permanece intacto.
+- **Specs principais em `openspec/specs/`** — Intocadas. Estas são sua fonte de verdade.
+- **Seu conteúdo em CLAUDE.md, AGENTS.md, etc.** — Preservado. Apenas os blocos de marcadores do BR-OpenSpec são removidos; tudo o que você escreveu permanece.
+
+### O Que Será Removido
+
+Apenas os arquivos gerenciados pelo BR-OpenSpec que estão sendo substituídos:
+
+| O quê | Por quê |
+|------|-----|
+| Diretórios/arquivos de comandos slash legados | Substituídos pelo novo sistema de skills |
+| `openspec/AGENTS.md` | Gatilho de fluxo de trabalho obsoleto |
+| Marcadores do BR-OpenSpec em `CLAUDE.md`, `AGENTS.md`, etc. | Não são mais necessários |
+
+**Localizações de comandos legados por ferramenta** (exemplos—sua ferramenta pode variar):
+
+- Claude Code: `.claude/commands/openspec/`
+- Cursor: `.cursor/commands/openspec-*.md`
+- Windsurf: `.windsurf/workflows/openspec-*.md`
+- Cline: `.clinerules/workflows/openspec-*.md`
+- Roo: `.roo/commands/openspec-*.md`
+- GitHub Copilot: `.github/prompts/openspec-*.prompt.md` (somente extensões de IDE; não suportado no Copilot CLI)
+- E outros (Augment, Continue, Amazon Q, etc.)
+
+A migração detecta quais ferramentas você tem configuradas e limpa seus arquivos legados.
+
+A lista de remoção pode parecer longa, mas todos esses arquivos foram criados originalmente pelo BR-OpenSpec. Seu próprio conteúdo nunca é excluído.
+
+### O Que Precisa da Sua Atenção
+
+Um arquivo requer migração manual:
+
+**`openspec/project.md`** — Este arquivo não é excluído automaticamente porque pode conter contexto do projeto que você escreveu. Você precisará:
+
+1. Revisar seu conteúdo
+2. Mover contexto útil para `openspec/config.yaml` (veja as orientações abaixo)
+3. Excluir o arquivo quando estiver pronto
+
+**Por que fizemos essa mudança:**
+
+O antigo `project.md` era passivo—os agentes podiam lê-lo, ou não, ou esquecer o que leram. Descobrimos que a confiabilidade era inconsistente.
+
+O contexto do novo `config.yaml` é **ativamente injetado em cada requisição de planejamento do BR-OpenSpec**. Isso significa que as convenções do seu projeto, tech stack e regras estão sempre presentes quando a IA está criando artefatos. Maior confiabilidade.
+
+**A troca:**
+
+Como o contexto é injetado em cada requisição, você vai querer ser conciso. Foque no que realmente importa:
+- Tech stack e convenções principais
+- Restrições não óbvias que a IA precisa saber
+- Regras que frequentemente eram ignoradas antes
+
+Não se preocupe em acertar de primeira. Ainda estamos aprendendo o que funciona melhor aqui, e continuaremos melhorando como a injeção de contexto funciona conforme experimentamos.
+
+---
+
+## Executando a Migração
+
+Tanto `openspec init` quanto `openspec update` detectam arquivos legados e guiam você pelo mesmo processo de limpeza. Use o que melhor se adaptar à sua situação:
+
+- Novas instalações padrão ao perfil `core` (`propose`, `explore`, `apply`, `archive`).
+- Instalações migradas preservam seus fluxos de trabalho instalados anteriormente gravando um perfil `custom` quando necessário.
+
+### Usando `openspec init`
+
+Execute isso se quiser adicionar novas ferramentas ou reconfigurar quais ferramentas estão configuradas:
+
+```bash
+openspec init
+```
+
+O comando init detecta arquivos legados e guia você pelo processo de limpeza:
+
+```
+Upgrading to the new BR-OpenSpec
+
+BR-OpenSpec now uses agent skills, the emerging standard across coding
+agents. This simplifies your setup while keeping everything working
+as before.
+
+Files to remove
+No user content to preserve:
+ • .claude/commands/openspec/
+ • openspec/AGENTS.md
+
+Files to update
+BR-OpenSpec markers will be removed, your content preserved:
+ • CLAUDE.md
+ • AGENTS.md
+
+Needs your attention
+ • openspec/project.md
+ We won't delete this file. It may contain useful project context.
+
+ The new openspec/config.yaml has a "context:" section for planning
+ context. This is included in every BR-OpenSpec request and works more
+ reliably than the old project.md approach.
+
+ Review project.md, move any useful content to config.yaml's context
+ section, then delete the file when ready.
+
+? Upgrade and clean up legacy files? (Y/n)
+```
+
+**O que acontece quando você diz sim:**
+
+1. Os diretórios de comandos slash legados são removidos
+2. Os marcadores do BR-OpenSpec são removidos de `CLAUDE.md`, `AGENTS.md`, etc. (seu conteúdo permanece)
+3. `openspec/AGENTS.md` é excluído
+4. Novas skills são instaladas em `.claude/skills/`
+5. `openspec/config.yaml` é criado com um schema padrão
+
+### Usando `openspec update`
+
+Execute isso se quiser apenas migrar e atualizar suas ferramentas existentes para a versão mais recente:
+
+```bash
+openspec update
+```
+
+O comando update também detecta e limpa artefatos legados, depois atualiza as skills/comandos gerados para corresponder ao seu perfil atual e configurações de entrega.
+
+### Ambientes Não Interativos / CI
+
+Para migrações automatizadas:
+
+```bash
+openspec init --force --tools claude
+```
+
+O flag `--force` pula as solicitações e aceita automaticamente a limpeza.
+
+---
+
+## Migrando project.md para config.yaml
+
+O antigo `openspec/project.md` era um arquivo markdown de formato livre para contexto do projeto. O novo `openspec/config.yaml` é estruturado e—fundamentalmente—**injetado em cada requisição de planejamento** para que suas convenções estejam sempre presentes quando a IA trabalha.
+
+### Antes (project.md)
+
+```markdown
+# Project Context
+
+This is a TypeScript monorepo using React and Node.js.
+We use Jest for testing and follow strict ESLint rules.
+Our API is RESTful and documented in docs/api.md.
+
+## Conventions
+
+- All public APIs must maintain backwards compatibility
+- New features should include tests
+- Use Given/When/Then format for specifications
+```
+
+### Depois (config.yaml)
+
+```yaml
+schema: spec-driven
+
+context: |
+ Tech stack: TypeScript, React, Node.js
+ Testing: Jest with React Testing Library
+ API: RESTful, documented in docs/api.md
+ We maintain backwards compatibility for all public APIs
+
+rules:
+ proposal:
+ - Include rollback plan for risky changes
+ specs:
+ - Use Given/When/Then format for scenarios
+ - Reference existing patterns before inventing new ones
+ design:
+ - Include sequence diagrams for complex flows
+```
+
+### Principais Diferenças
+
+| project.md | config.yaml |
+|------------|-------------|
+| Markdown de formato livre | YAML estruturado |
+| Um bloco único de texto | Contexto separado e regras por artefato |
+| Incerto quando é usado | O contexto aparece em TODOS os artefatos; as regras aparecem apenas nos artefatos correspondentes |
+| Sem seleção de schema | O campo explícito `schema:` define o fluxo de trabalho padrão |
+
+### O Que Manter, O Que Descartar
+
+Ao migrar, seja seletivo. Pergunte a si mesmo: "A IA precisa disso para *cada* requisição de planejamento?"
+
+**Bons candidatos para `context:`**
+- Tech stack (linguagens, frameworks, bancos de dados)
+- Padrões arquiteturais principais (monorepo, microsserviços, etc.)
+- Restrições não óbvias ("não podemos usar a biblioteca X porque...")
+- Convenções críticas que frequentemente são ignoradas
+
+**Mova para `rules:` em vez disso**
+- Formatação específica de artefato ("use Given/When/Then nas specs")
+- Critérios de revisão ("propostas devem incluir planos de rollback")
+- Eles aparecem apenas para o artefato correspondente, mantendo outras requisições mais leves
+
+**Omita completamente**
+- Boas práticas gerais que a IA já conhece
+- Explicações detalhadas que poderiam ser resumidas
+- Contexto histórico que não afeta o trabalho atual
+
+### Passos da Migração
+
+1. **Crie o config.yaml** (se ainda não foi criado pelo init):
+ ```yaml
+ schema: spec-driven
+ ```
+
+2. **Adicione seu contexto** (seja conciso—isso vai em cada requisição):
+ ```yaml
+ context: |
+ Your project background goes here.
+ Focus on what the AI genuinely needs to know.
+ ```
+
+3. **Adicione regras por artefato** (opcional):
+ ```yaml
+ rules:
+ proposal:
+ - Your proposal-specific guidance
+ specs:
+ - Your spec-writing rules
+ ```
+
+4. **Exclua o project.md** depois de ter movido tudo o que é útil.
+
+**Não complique.** Comece com o essencial e itere. Se perceber que a IA está perdendo algo importante, adicione. Se o contexto parecer inflado, reduza. Este é um documento vivo.
+
+### Precisa de Ajuda? Use Este Prompt
+
+Se não tiver certeza de como condensar seu project.md, pergunte ao seu assistente de IA:
+
+```
+I'm migrating from BR-OpenSpec's old project.md to the new config.yaml format.
+
+Here's my current project.md:
+[paste your project.md content]
+
+Please help me create a config.yaml with:
+1. A concise `context:` section (this gets injected into every planning request, so keep it tight—focus on tech stack, key constraints, and conventions that often get ignored)
+2. `rules:` for specific artifacts if any content is artifact-specific (e.g., "use Given/When/Then" belongs in specs rules, not global context)
+
+Leave out anything generic that AI models already know. Be ruthless about brevity.
+```
+
+A IA ajudará você a identificar o que é essencial versus o que pode ser removido.
+
+---
+
+## Os Novos Comandos
+
+A disponibilidade de comandos depende do perfil:
+
+**Padrão (perfil `core`):**
+
+| Comando | Finalidade |
+|---------|---------|
+| `/opsx:propose` | Criar uma mudança e gerar artefatos de planejamento em um único passo |
+| `/opsx:explore` | Explorar ideias sem estrutura |
+| `/opsx:apply` | Implementar tarefas do tasks.md |
+| `/opsx:archive` | Finalizar e arquivar a mudança |
+
+**Fluxo de trabalho expandido (seleção personalizada):**
+
+| Comando | Finalidade |
+|---------|---------|
+| `/opsx:new` | Iniciar uma estrutura inicial para uma nova mudança |
+| `/opsx:continue` | Criar o próximo artefato (um de cada vez) |
+| `/opsx:ff` | Fast-forward—criar artefatos de planejamento de uma vez |
+| `/opsx:verify` | Validar se a implementação corresponde às specs |
+| `/opsx:sync` | Visualizar/mesclar specs sem arquivar |
+| `/opsx:bulk-archive` | Arquivar múltiplas mudanças de uma vez |
+| `/opsx:onboard` | Fluxo de trabalho de integração guiado de ponta a ponta |
+
+Habilite os comandos expandidos com `openspec config profile`, depois execute `openspec update`.
+
+### Mapeamento de Comandos do Legado
+
+| Legado | Equivalente OPSX |
+|--------|-----------------|
+| `/openspec:proposal` | `/opsx:propose` (padrão) ou `/opsx:new` seguido de `/opsx:ff` (expandido) |
+| `/openspec:apply` | `/opsx:apply` |
+| `/openspec:archive` | `/opsx:archive` |
+
+### Novas Capacidades
+
+Estas capacidades fazem parte do conjunto de comandos de fluxo de trabalho expandido.
+
+**Criação granular de artefatos:**
+```
+/opsx:continue
+```
+Cria um artefato de cada vez com base nas dependências. Use isso quando quiser revisar cada passo.
+
+**Modo de exploração:**
+```
+/opsx:explore
+```
+Explore ideias com um parceiro antes de se comprometer com uma mudança.
+
+---
+
+## Entendendo a Nova Arquitetura
+
+### De Fases Bloqueadas para Fluido
+
+O fluxo de trabalho legado forçava uma progressão linear:
+
+```
+┌──────────────┐ ┌──────────────┐ ┌──────────────┐
+│ PLANNING │ ───► │ IMPLEMENTING │ ───► │ ARCHIVING │
+│ PHASE │ │ PHASE │ │ PHASE │
+└──────────────┘ └──────────────┘ └──────────────┘
+
+If you're in implementation and realize the design is wrong?
+Too bad. Phase gates don't let you go back easily.
+```
+
+O OPSX usa ações, não fases:
+
+```
+ ┌───────────────────────────────────────────────┐
+ │ ACTIONS (not phases) │
+ │ │
+ │ new ◄──► continue ◄──► apply ◄──► archive │
+ │ │ │ │ │ │
+ │ └──────────┴───────────┴─────────────┘ │
+ │ any order │
+ └───────────────────────────────────────────────┘
+```
+
+### Grafo de Dependências
+
+Os artefatos formam um grafo dirigido. As dependências são habilitadores, não bloqueadores:
+
+```
+ proposal
+ (root node)
+ │
+ ┌─────────────┴─────────────┐
+ │ │
+ ▼ ▼
+ specs design
+ (requires: (requires:
+ proposal) proposal)
+ │ │
+ └─────────────┬─────────────┘
+ │
+ ▼
+ tasks
+ (requires:
+ specs, design)
+```
+
+Quando você executa `/opsx:continue`, ele verifica o que está pronto e oferece o próximo artefato. Você também pode criar múltiplos artefatos prontos em qualquer ordem.
+
+### Skills vs Comandos
+
+O sistema legado usava arquivos de comandos específicos por ferramenta:
+
+```
+.claude/commands/openspec/
+├── proposal.md
+├── apply.md
+└── archive.md
+```
+
+O OPSX usa o padrão emergente de **skills**:
+
+```
+.claude/skills/
+├── openspec-explore/SKILL.md
+├── openspec-new-change/SKILL.md
+├── openspec-continue-change/SKILL.md
+├── openspec-apply-change/SKILL.md
+└── ...
+```
+
+As skills são reconhecidas em múltiplas ferramentas de codificação com IA e fornecem metadados mais ricos.
+
+---
+
+## Continuando Mudanças Existentes
+
+Suas mudanças em andamento funcionam perfeitamente com os comandos OPSX.
+
+**Tem uma mudança ativa do fluxo de trabalho legado?**
+
+```
+/opsx:apply add-my-feature
+```
+
+O OPSX lê os artefatos existentes e continua de onde você parou.
+
+**Quer adicionar mais artefatos a uma mudança existente?**
+
+```
+/opsx:continue add-my-feature
+```
+
+Mostra o que está pronto para criar com base no que já existe.
+
+**Precisa ver o status?**
+
+```bash
+openspec status --change add-my-feature
+```
+
+---
+
+## O Novo Sistema de Configuração
+
+### Estrutura do config.yaml
+
+```yaml
+# Required: Default schema for new changes
+schema: spec-driven
+
+# Optional: Project context (max 50KB)
+# Injected into ALL artifact instructions
+context: |
+ Your project background, tech stack,
+ conventions, and constraints.
+
+# Optional: Per-artifact rules
+# Only injected into matching artifacts
+rules:
+ proposal:
+ - Include rollback plan
+ specs:
+ - Use Given/When/Then format
+ design:
+ - Document fallback strategies
+ tasks:
+ - Break into 2-hour maximum chunks
+```
+
+### Resolução de Schema
+
+Ao determinar qual schema usar, o OPSX verifica na seguinte ordem:
+
+1. **Flag CLI**: `--schema ` (maior prioridade)
+2. **Metadados da mudança**: `.openspec.yaml` no diretório da mudança
+3. **Configuração do projeto**: `openspec/config.yaml`
+4. **Padrão**: `spec-driven`
+
+### Schemas Disponíveis
+
+| Schema | Artefatos | Melhor Para |
+|--------|-----------|----------|
+| `spec-driven` | proposal → specs → design → tasks | A maioria dos projetos |
+
+Listar todos os schemas disponíveis:
+
+```bash
+openspec schemas
+```
+
+### Schemas Personalizados
+
+Crie seu próprio fluxo de trabalho:
+
+```bash
+openspec schema init my-workflow
+```
+
+Ou faça um fork de um existente:
+
+```bash
+openspec schema fork spec-driven my-workflow
+```
+
+Consulte [Customização](customization.md) para detalhes.
+
+---
+
+## Solução de Problemas
+
+### "Legacy files detected in non-interactive mode"
+
+Você está executando em um ambiente CI ou não interativo. Use:
+
+```bash
+openspec init --force
+```
+
+### Comandos não aparecem após a migração
+
+Reinicie sua IDE. As skills são detectadas na inicialização.
+
+### "Unknown artifact ID in rules"
+
+Verifique se as chaves de `rules:` correspondem aos IDs de artefatos do seu schema:
+
+- **spec-driven**: `proposal`, `specs`, `design`, `tasks`
+
+Execute isso para ver os IDs de artefatos válidos:
+
+```bash
+openspec schemas --json
+```
+
+### Configuração não está sendo aplicada
+
+1. Certifique-se de que o arquivo está em `openspec/config.yaml` (não `.yml`)
+2. Valide a sintaxe YAML
+3. As alterações de configuração entram em vigor imediatamente—sem necessidade de reiniciar
+
+### project.md não migrado
+
+O sistema preserva intencionalmente o `project.md` porque pode conter seu conteúdo personalizado. Revise-o manualmente, mova as partes úteis para `config.yaml` e depois exclua-o.
+
+### Quer ver o que seria limpo?
+
+Execute o init e recuse o prompt de limpeza—você verá o resumo completo de detecção sem que nenhuma alteração seja feita.
+
+---
+
+## Referência Rápida
+
+### Arquivos Após a Migração
+
+```
+project/
+├── openspec/
+│ ├── specs/ # Inalterado
+│ ├── changes/ # Inalterado
+│ │ └── archive/ # Inalterado
+│ └── config.yaml # NOVO: Configuração do projeto
+├── .claude/
+│ └── skills/ # NOVO: Skills OPSX
+│ ├── openspec-propose/ # perfil core padrão
+│ ├── openspec-explore/
+│ ├── openspec-apply-change/
+│ └── ... # perfil expandido adiciona new/continue/ff/etc.
+├── CLAUDE.md # Marcadores do BR-OpenSpec removidos, seu conteúdo preservado
+└── AGENTS.md # Marcadores do BR-OpenSpec removidos, seu conteúdo preservado
+```
+
+### O Que Foi Removido
+
+- `.claude/commands/openspec/` — substituído por `.claude/skills/`
+- `openspec/AGENTS.md` — obsoleto
+- `openspec/project.md` — migre para `config.yaml`, depois exclua
+- Blocos de marcadores do BR-OpenSpec em `CLAUDE.md`, `AGENTS.md`, etc.
+
+### Guia Rápido de Comandos
+
+```text
+/opsx:propose Iniciar rapidamente (perfil core padrão)
+/opsx:apply Implementar tarefas
+/opsx:archive Finalizar e arquivar
+
+# Fluxo de trabalho expandido (se habilitado):
+/opsx:new Criar estrutura inicial para uma mudança
+/opsx:continue Criar próximo artefato
+/opsx:ff Criar artefatos de planejamento
+```
+
+---
+
+## Obtendo Ajuda
+
+- **GitHub Issues**: [github.com/fkmatsuda/BR-OpenSpec/issues](https://github.com/fkmatsuda/BR-OpenSpec/issues)
+- **Documentação**: [docs/opsx.md](opsx.md) para a referência completa do OPSX
diff --git a/docs/pt-BR/multi-language.md b/docs/pt-BR/multi-language.md
new file mode 100644
index 0000000000..ba3cbefde6
--- /dev/null
+++ b/docs/pt-BR/multi-language.md
@@ -0,0 +1,115 @@
+# Guia Multi-Idioma
+
+Configure o BR-OpenSpec para gerar artefatos em idiomas diferentes do inglês.
+
+## Configuração Rápida
+
+Adicione uma instrução de idioma ao seu `openspec/config.yaml`:
+
+```yaml
+schema: spec-driven
+
+context: |
+ Language: Portuguese (pt-BR)
+ All artifacts must be written in Brazilian Portuguese.
+
+ # Seu outro contexto de projeto abaixo...
+ Tech stack: TypeScript, React, Node.js
+```
+
+Pronto. Todos os artefatos gerados agora estarão em português.
+
+## Exemplos de Idiomas
+
+### Português (Brasil)
+
+```yaml
+context: |
+ Language: Portuguese (pt-BR)
+ All artifacts must be written in Brazilian Portuguese.
+```
+
+### Espanhol
+
+```yaml
+context: |
+ Idioma: Español
+ Todos los artefactos deben escribirse en español.
+```
+
+### Chinês (Simplificado)
+
+```yaml
+context: |
+ 语言:中文(简体)
+ 所有产出物必须用简体中文撰写。
+```
+
+### Japonês
+
+```yaml
+context: |
+ 言語:日本語
+ すべての成果物は日本語で作成してください。
+```
+
+### Francês
+
+```yaml
+context: |
+ Langue : Français
+ Tous les artefacts doivent être rédigés en français.
+```
+
+### Alemão
+
+```yaml
+context: |
+ Sprache: Deutsch
+ Alle Artefakte müssen auf Deutsch verfasst werden.
+```
+
+## Dicas
+
+### Lidar com Termos Técnicos
+
+Decida como tratar a terminologia técnica:
+
+```yaml
+context: |
+ Language: Japanese
+ Write in Japanese, but:
+ - Keep technical terms like "API", "REST", "GraphQL" in English
+ - Code examples and file paths remain in English
+```
+
+### Combinar com Outro Contexto
+
+As configurações de idioma funcionam junto com o restante do contexto do seu projeto:
+
+```yaml
+schema: spec-driven
+
+context: |
+ Language: Portuguese (pt-BR)
+ All artifacts must be written in Brazilian Portuguese.
+
+ Tech stack: TypeScript, React 18, Node.js 20
+ Database: PostgreSQL with Prisma ORM
+```
+
+## Verificação
+
+Para verificar se a configuração de idioma está funcionando:
+
+```bash
+# Verifique as instruções - deve exibir o contexto de idioma
+openspec instructions proposal --change my-change
+
+# A saída incluirá o contexto de idioma
+```
+
+## Documentação Relacionada
+
+- [Guia de Personalização](../customization.md) - Opções de configuração do projeto
+- [Guia de Fluxos de Trabalho](../workflows.md) - Documentação completa de fluxos de trabalho
diff --git a/docs/pt-BR/opsx.md b/docs/pt-BR/opsx.md
new file mode 100644
index 0000000000..bc1e17b51c
--- /dev/null
+++ b/docs/pt-BR/opsx.md
@@ -0,0 +1,657 @@
+# Fluxo de Trabalho OPSX
+
+## O Que É?
+
+O OPSX é agora o fluxo de trabalho padrão do BR-OpenSpec.
+
+É um **fluxo de trabalho fluido e iterativo** para mudanças no BR-OpenSpec. Sem mais fases rígidas — apenas ações que você pode executar a qualquer momento.
+
+## Por Que Existe
+
+O fluxo de trabalho legado do BR-OpenSpec funciona, mas é **engessado**:
+
+- **Instruções estão hardcoded** — enterradas no TypeScript, você não pode alterá-las
+- **Tudo ou nada** — um grande comando cria tudo, não dá para testar partes individuais
+- **Estrutura fixa** — mesmo fluxo de trabalho para todos, sem personalização
+- **Caixa preta** — quando a saída da IA é ruim, você não pode ajustar os prompts
+
+**O OPSX abre isso.** Agora qualquer pessoa pode:
+
+1. **Experimentar com instruções** — editar um template, ver se a IA melhora
+2. **Testar de forma granular** — validar as instruções de cada artefato de forma independente
+3. **Personalizar fluxos de trabalho** — definir seus próprios artefatos e dependências
+4. **Iterar rapidamente** — mudar um template, testar imediatamente, sem rebuild
+
+```
+Legacy workflow: OPSX:
+┌────────────────────────┐ ┌────────────────────────┐
+│ Hardcoded in package │ │ schema.yaml │◄── You edit this
+│ (can't change) │ │ templates/*.md │◄── Or this
+│ ↓ │ │ ↓ │
+│ Wait for new release │ │ Instant effect │
+│ ↓ │ │ ↓ │
+│ Hope it's better │ │ Test it yourself │
+└────────────────────────┘ └────────────────────────┘
+```
+
+**Isso é para todos:**
+- **Equipes** — crie fluxos de trabalho que correspondam à forma como você realmente trabalha
+- **Usuários avançados** — ajuste prompts para obter melhores saídas da IA para sua base de código
+- **Contribuidores do BR-OpenSpec** — experimente novas abordagens sem precisar de releases
+
+Ainda estamos aprendendo o que funciona melhor. O OPSX nos permite aprender juntos.
+
+## A Experiência do Usuário
+
+**O problema com fluxos de trabalho lineares:**
+Você está "na fase de planejamento", depois "na fase de implementação", depois "pronto". Mas o trabalho real não funciona assim. Você implementa algo, percebe que seu design estava errado, precisa atualizar as specs, continua implementando. Fases lineares lutam contra como o trabalho realmente acontece.
+
+**Abordagem do OPSX:**
+- **Ações, não fases** — criar, implementar, atualizar, arquivar — faça qualquer uma delas a qualquer momento
+- **Dependências são facilitadores** — elas mostram o que é possível, não o que é obrigatório a seguir
+
+```
+ proposal ──→ specs ──→ design ──→ tasks ──→ implement
+```
+
+## Configuração
+
+```bash
+# Make sure you have openspec installed — skills are automatically generated
+openspec init
+```
+
+Isso cria skills em `.claude/skills/` (ou equivalente) que assistentes de codificação com IA detectam automaticamente.
+
+Por padrão, o BR-OpenSpec usa o perfil de fluxo de trabalho `core` (`propose`, `explore`, `apply`, `archive`). Se você quiser os comandos de fluxo de trabalho expandido (`new`, `continue`, `ff`, `verify`, `sync`, `bulk-archive`, `onboard`), configure-os com `openspec config profile` e aplique com `openspec update`.
+
+Durante a configuração, você será solicitado a criar uma **configuração de projeto** (`openspec/config.yaml`). Isso é opcional, mas recomendado.
+
+## Configuração do Projeto
+
+A configuração do projeto permite definir padrões e injetar contexto específico do projeto em todos os artefatos.
+
+### Criando a Configuração
+
+A configuração é criada durante `openspec init`, ou manualmente:
+
+```yaml
+# openspec/config.yaml
+schema: spec-driven
+
+context: |
+ Tech stack: TypeScript, React, Node.js
+ API conventions: RESTful, JSON responses
+ Testing: Vitest for unit tests, Playwright for e2e
+ Style: ESLint with Prettier, strict TypeScript
+
+rules:
+ proposal:
+ - Include rollback plan
+ - Identify affected teams
+ specs:
+ - Use Given/When/Then format for scenarios
+ design:
+ - Include sequence diagrams for complex flows
+```
+
+### Campos de Configuração
+
+| Campo | Tipo | Descrição |
+|-------|------|-----------|
+| `schema` | string | Schema padrão para novas mudanças (ex.: `spec-driven`) |
+| `context` | string | Contexto do projeto injetado em todas as instruções de artefatos |
+| `rules` | object | Regras por artefato, indexadas pelo ID do artefato |
+
+### Como Funciona
+
+**Precedência do schema** (maior para menor):
+1. Flag CLI (`--schema `)
+2. Metadados da mudança (`.openspec.yaml` no diretório da mudança)
+3. Configuração do projeto (`openspec/config.yaml`)
+4. Padrão (`spec-driven`)
+
+**Injeção de contexto:**
+- O contexto é adicionado ao início das instruções de cada artefato
+- Envolvido em tags `... `
+- Ajuda a IA a entender as convenções do seu projeto
+
+**Injeção de regras:**
+- As regras são injetadas apenas para os artefatos correspondentes
+- Envolvidas em tags `... `
+- Aparecem após o contexto, antes do template
+
+### IDs de Artefatos por Schema
+
+**spec-driven** (padrão):
+- `proposal` — Proposta de mudança
+- `specs` — Especificações
+- `design` — Design técnico
+- `tasks` — Tarefas de implementação
+
+### Validação da Configuração
+
+- IDs de artefatos desconhecidos em `rules` geram avisos
+- Nomes de schemas são validados contra os schemas disponíveis
+- O contexto tem um limite de tamanho de 50KB
+- YAML inválido é reportado com números de linha
+
+### Resolução de Problemas
+
+**"Unknown artifact ID in rules: X"**
+- Verifique se os IDs dos artefatos correspondem ao seu schema (veja a lista acima)
+- Execute `openspec schemas --json` para ver os IDs dos artefatos de cada schema
+
+**Configuração não está sendo aplicada:**
+- Certifique-se de que o arquivo está em `openspec/config.yaml` (não `.yml`)
+- Verifique a sintaxe YAML com um validador
+- As alterações na configuração têm efeito imediato (sem necessidade de reiniciar)
+
+**Contexto muito grande:**
+- O contexto é limitado a 50KB
+- Resuma ou faça referência a documentos externos
+
+## Comandos
+
+| Comando | O que faz |
+|---------|-----------|
+| `/opsx:propose` | Cria uma mudança e gera artefatos de planejamento em uma etapa (caminho rápido padrão) |
+| `/opsx:explore` | Pensa em ideias, investiga problemas, esclarece requisitos |
+| `/opsx:new` | Inicia um novo scaffold de mudança (fluxo de trabalho expandido) |
+| `/opsx:continue` | Cria o próximo artefato (fluxo de trabalho expandido) |
+| `/opsx:ff` | Avança rapidamente os artefatos de planejamento (fluxo de trabalho expandido) |
+| `/opsx:apply` | Implementa tarefas, atualizando artefatos conforme necessário |
+| `/opsx:verify` | Valida a implementação contra os artefatos (fluxo de trabalho expandido) |
+| `/opsx:sync` | Sincroniza specs delta com a principal (fluxo de trabalho expandido, opcional) |
+| `/opsx:archive` | Arquiva quando concluído |
+| `/opsx:bulk-archive` | Arquiva múltiplas mudanças concluídas (fluxo de trabalho expandido) |
+| `/opsx:onboard` | Guia passo a passo por uma mudança completa (fluxo de trabalho expandido) |
+
+## Uso
+
+### Explorar uma ideia
+```
+/opsx:explore
+```
+Pense em ideias, investigue problemas, compare opções. Nenhuma estrutura necessária — apenas um parceiro de raciocínio. Quando os insights se cristalizarem, faça a transição para `/opsx:propose` (padrão) ou `/opsx:new`/`/opsx:ff` (expandido).
+
+### Iniciar uma nova mudança
+```
+/opsx:propose
+```
+Cria a mudança e gera os artefatos de planejamento necessários antes da implementação.
+
+Se você habilitou fluxos de trabalho expandidos, pode usar alternativamente:
+
+```text
+/opsx:new # scaffold only
+/opsx:continue # create one artifact at a time
+/opsx:ff # create all planning artifacts at once
+```
+
+### Criar artefatos
+```
+/opsx:continue
+```
+Mostra o que está pronto para criar com base nas dependências, depois cria um artefato. Use repetidamente para construir sua mudança de forma incremental.
+
+```
+/opsx:ff add-dark-mode
+```
+Cria todos os artefatos de planejamento de uma vez. Use quando você tem uma visão clara do que está construindo.
+
+### Implementar (a parte fluida)
+```
+/opsx:apply
+```
+Percorre as tarefas, marcando-as conforme avança. Se você está gerenciando múltiplas mudanças, pode executar `/opsx:apply `; caso contrário, ele deve inferir pela conversa e solicitar que você escolha se não conseguir determinar.
+
+### Finalizar
+```
+/opsx:archive # Move to archive when done (prompts to sync specs if needed)
+```
+
+## Quando Atualizar vs. Começar do Zero
+
+Você sempre pode editar sua proposta ou specs antes da implementação. Mas quando o refinamento se torna "este é um trabalho diferente"?
+
+### O Que uma Proposta Captura
+
+Uma proposta define três coisas:
+1. **Intenção** — Qual problema você está resolvendo?
+2. **Escopo** — O que está dentro/fora dos limites?
+3. **Abordagem** — Como você vai resolver?
+
+A questão é: o que mudou, e em que medida?
+
+### Atualize a Mudança Existente Quando:
+
+**Mesma intenção, execução refinada**
+- Você descobre casos extremos que não considerou
+- A abordagem precisa de ajustes, mas o objetivo não mudou
+- A implementação revela que o design estava ligeiramente errado
+
+**O escopo diminui**
+- Você percebe que o escopo completo é muito grande, quer entregar o MVP primeiro
+- "Adicionar modo escuro" → "Adicionar alternância de modo escuro (preferência do sistema na v2)"
+
+**Correções baseadas em aprendizado**
+- A base de código não está estruturada como você pensava
+- Uma dependência não funciona como esperado
+- "Usar variáveis CSS" → "Usar o prefixo dark: do Tailwind"
+
+### Inicie uma Nova Mudança Quando:
+
+**A intenção mudou fundamentalmente**
+- O problema em si é diferente agora
+- "Adicionar modo escuro" → "Adicionar sistema de temas abrangente com cores, fontes e espaçamento personalizados"
+
+**O escopo explodiu**
+- A mudança cresceu tanto que é essencialmente um trabalho diferente
+- A proposta original ficaria irreconhecível após as atualizações
+- "Corrigir bug de login" → "Reescrever sistema de autenticação"
+
+**A original pode ser concluída**
+- A mudança original pode ser marcada como "feita"
+- O novo trabalho existe por conta própria, não é um refinamento
+- Conclua "Adicionar MVP de modo escuro" → Arquivar → Nova mudança "Aprimorar modo escuro"
+
+### As Heurísticas
+
+```
+ ┌─────────────────────────────────────┐
+ │ Is this the same work? │
+ └──────────────┬──────────────────────┘
+ │
+ ┌──────────────────┼──────────────────┐
+ │ │ │
+ ▼ ▼ ▼
+ Same intent? >50% overlap? Can original
+ Same problem? Same scope? be "done" without
+ │ │ these changes?
+ │ │ │
+ ┌────────┴────────┐ ┌──────┴──────┐ ┌───────┴───────┐
+ │ │ │ │ │ │
+ YES NO YES NO NO YES
+ │ │ │ │ │ │
+ ▼ ▼ ▼ ▼ ▼ ▼
+ UPDATE NEW UPDATE NEW UPDATE NEW
+```
+
+| Teste | Atualizar | Nova Mudança |
+|-------|-----------|--------------|
+| **Identidade** | "Mesma coisa, refinada" | "Trabalho diferente" |
+| **Sobreposição de escopo** | >50% sobrepõe | <50% sobrepõe |
+| **Conclusão** | Não pode ser "feita" sem as mudanças | Pode terminar a original, novo trabalho existe por conta própria |
+| **Narrativa** | A cadeia de atualizações conta uma história coerente | Correções confundiriam mais do que esclareceriam |
+
+### O Princípio
+
+> **Atualizar preserva o contexto. Nova mudança proporciona clareza.**
+>
+> Escolha atualizar quando o histórico do seu raciocínio é valioso.
+> Escolha novo quando começar do zero seria mais claro do que corrigir.
+
+Pense como branches do git:
+- Continue fazendo commits enquanto trabalha na mesma funcionalidade
+- Inicie um novo branch quando for genuinamente um trabalho novo
+- Às vezes faça merge de uma funcionalidade parcial e comece do zero para a fase 2
+
+## O Que é Diferente?
+
+| | Legado (`/openspec:proposal`) | OPSX (`/opsx:*`) |
+|---|---|---|
+| **Estrutura** | Um grande documento de proposta | Artefatos discretos com dependências |
+| **Fluxo de trabalho** | Fases lineares: planejar → implementar → arquivar | Ações fluidas — faça qualquer coisa a qualquer momento |
+| **Iteração** | Difícil voltar atrás | Atualizar artefatos conforme aprende |
+| **Personalização** | Estrutura fixa | Baseado em schema (defina seus próprios artefatos) |
+
+**O insight principal:** o trabalho não é linear. O OPSX para de fingir que é.
+
+## Visão Detalhada da Arquitetura
+
+Esta seção explica como o OPSX funciona internamente e como se compara ao fluxo de trabalho legado.
+Os exemplos nesta seção usam o conjunto de comandos expandido (`new`, `continue`, etc.); usuários do `core` padrão podem mapear o mesmo fluxo para `propose → apply → archive`.
+
+### Filosofia: Fases vs. Ações
+
+```
+┌─────────────────────────────────────────────────────────────────────────────┐
+│ LEGACY WORKFLOW │
+│ (Phase-Locked, All-or-Nothing) │
+├─────────────────────────────────────────────────────────────────────────────┤
+│ │
+│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
+│ │ PLANNING │ ───► │ IMPLEMENTING │ ───► │ ARCHIVING │ │
+│ │ PHASE │ │ PHASE │ │ PHASE │ │
+│ └──────────────┘ └──────────────┘ └──────────────┘ │
+│ │ │ │ │
+│ ▼ ▼ ▼ │
+│ /openspec:proposal /openspec:apply /openspec:archive │
+│ │
+│ • Creates ALL artifacts at once │
+│ • Can't go back to update specs during implementation │
+│ • Phase gates enforce linear progression │
+│ │
+└─────────────────────────────────────────────────────────────────────────────┘
+
+
+┌─────────────────────────────────────────────────────────────────────────────┐
+│ OPSX WORKFLOW │
+│ (Fluid Actions, Iterative) │
+├─────────────────────────────────────────────────────────────────────────────┤
+│ │
+│ ┌────────────────────────────────────────────┐ │
+│ │ ACTIONS (not phases) │ │
+│ │ │ │
+│ │ new ◄──► continue ◄──► apply ◄──► archive │ │
+│ │ │ │ │ │ │ │
+│ │ └──────────┴───────────┴───────────┘ │ │
+│ │ any order │ │
+│ └────────────────────────────────────────────┘ │
+│ │
+│ • Create artifacts one at a time OR fast-forward │
+│ • Update specs/design/tasks during implementation │
+│ • Dependencies enable progress, phases don't exist │
+│ │
+└─────────────────────────────────────────────────────────────────────────────┘
+```
+
+### Arquitetura de Componentes
+
+**Fluxo de trabalho legado** usa templates hardcoded em TypeScript:
+
+```
+┌─────────────────────────────────────────────────────────────────────────────┐
+│ LEGACY WORKFLOW COMPONENTS │
+├─────────────────────────────────────────────────────────────────────────────┤
+│ │
+│ Hardcoded Templates (TypeScript strings) │
+│ │ │
+│ ▼ │
+│ Tool-specific configurators/adapters │
+│ │ │
+│ ▼ │
+│ Generated Command Files (.claude/commands/openspec/*.md) │
+│ │
+│ • Fixed structure, no artifact awareness │
+│ • Change requires code modification + rebuild │
+│ │
+└─────────────────────────────────────────────────────────────────────────────┘
+```
+
+**OPSX** usa schemas externos e um motor de grafo de dependências:
+
+```
+┌─────────────────────────────────────────────────────────────────────────────┐
+│ OPSX COMPONENTS │
+├─────────────────────────────────────────────────────────────────────────────┤
+│ │
+│ Schema Definitions (YAML) │
+│ ┌─────────────────────────────────────────────────────────────────────┐ │
+│ │ name: spec-driven │ │
+│ │ artifacts: │ │
+│ │ - id: proposal │ │
+│ │ generates: proposal.md │ │
+│ │ requires: [] ◄── Dependencies │ │
+│ │ - id: specs │ │
+│ │ generates: specs/**/*.md ◄── Glob patterns │ │
+│ │ requires: [proposal] ◄── Enables after proposal │ │
+│ └─────────────────────────────────────────────────────────────────────┘ │
+│ │ │
+│ ▼ │
+│ Artifact Graph Engine │
+│ ┌─────────────────────────────────────────────────────────────────────┐ │
+│ │ • Topological sort (dependency ordering) │ │
+│ │ • State detection (filesystem existence) │ │
+│ │ • Rich instruction generation (templates + context) │ │
+│ └─────────────────────────────────────────────────────────────────────┘ │
+│ │ │
+│ ▼ │
+│ Skill Files (.claude/skills/openspec-*/SKILL.md) │
+│ │
+│ • Cross-editor compatible (Claude Code, Cursor, Windsurf) │
+│ • Skills query CLI for structured data │
+│ • Fully customizable via schema files │
+│ │
+└─────────────────────────────────────────────────────────────────────────────┘
+```
+
+### Modelo de Grafo de Dependências
+
+Os artefatos formam um grafo acíclico dirigido (DAG). Dependências são **facilitadores**, não portões:
+
+```
+ proposal
+ (root node)
+ │
+ ┌─────────────┴─────────────┐
+ │ │
+ ▼ ▼
+ specs design
+ (requires: (requires:
+ proposal) proposal)
+ │ │
+ └─────────────┬─────────────┘
+ │
+ ▼
+ tasks
+ (requires:
+ specs, design)
+ │
+ ▼
+ ┌──────────────┐
+ │ APPLY PHASE │
+ │ (requires: │
+ │ tasks) │
+ └──────────────┘
+```
+
+**Transições de estado:**
+
+```
+ BLOCKED ────────────────► READY ────────────────► DONE
+ │ │ │
+ Missing All deps File exists
+ dependencies are DONE on filesystem
+```
+
+### Fluxo de Informações
+
+**Fluxo de trabalho legado** — o agente recebe instruções estáticas:
+
+```
+ User: "/openspec:proposal"
+ │
+ ▼
+ ┌─────────────────────────────────────────┐
+ │ Static instructions: │
+ │ • Create proposal.md │
+ │ • Create tasks.md │
+ │ • Create design.md │
+ │ • Create specs//spec.md │
+ │ │
+ │ No awareness of what exists or │
+ │ dependencies between artifacts │
+ └─────────────────────────────────────────┘
+ │
+ ▼
+ Agent creates ALL artifacts in one go
+```
+
+**OPSX** — o agente consulta por contexto rico:
+
+```
+ User: "/opsx:continue"
+ │
+ ▼
+ ┌──────────────────────────────────────────────────────────────────────────┐
+ │ Step 1: Query current state │
+ │ ┌────────────────────────────────────────────────────────────────────┐ │
+ │ │ $ openspec status --change "add-auth" --json │ │
+ │ │ │ │
+ │ │ { │ │
+ │ │ "artifacts": [ │ │
+ │ │ {"id": "proposal", "status": "done"}, │ │
+ │ │ {"id": "specs", "status": "ready"}, ◄── First ready │ │
+ │ │ {"id": "design", "status": "ready"}, │ │
+ │ │ {"id": "tasks", "status": "blocked", "missingDeps": ["specs"]}│ │
+ │ │ ] │ │
+ │ │ } │ │
+ │ └────────────────────────────────────────────────────────────────────┘ │
+ │ │
+ │ Step 2: Get rich instructions for ready artifact │
+ │ ┌────────────────────────────────────────────────────────────────────┐ │
+ │ │ $ openspec instructions specs --change "add-auth" --json │ │
+ │ │ │ │
+ │ │ { │ │
+ │ │ "template": "# Specification\n\n## ADDED Requirements...", │ │
+ │ │ "dependencies": [{"id": "proposal", "path": "...", "done": true}│ │
+ │ │ "unlocks": ["tasks"] │ │
+ │ │ } │ │
+ │ └────────────────────────────────────────────────────────────────────┘ │
+ │ │
+ │ Step 3: Read dependencies → Create ONE artifact → Show what's unlocked │
+ └──────────────────────────────────────────────────────────────────────────┘
+```
+
+### Modelo de Iteração
+
+**Fluxo de trabalho legado** — difícil de iterar:
+
+```
+ ┌─────────┐ ┌─────────┐ ┌─────────┐
+ │/proposal│ ──► │ /apply │ ──► │/archive │
+ └─────────┘ └─────────┘ └─────────┘
+ │ │
+ │ ├── "Wait, the design is wrong"
+ │ │
+ │ ├── Options:
+ │ │ • Edit files manually (breaks context)
+ │ │ • Abandon and start over
+ │ │ • Push through and fix later
+ │ │
+ │ └── No official "go back" mechanism
+ │
+ └── Creates ALL artifacts at once
+```
+
+**OPSX** — iteração natural:
+
+```
+ /opsx:new ───► /opsx:continue ───► /opsx:apply ───► /opsx:archive
+ │ │ │
+ │ │ ├── "The design is wrong"
+ │ │ │
+ │ │ ▼
+ │ │ Just edit design.md
+ │ │ and continue!
+ │ │ │
+ │ │ ▼
+ │ │ /opsx:apply picks up
+ │ │ where you left off
+ │ │
+ │ └── Creates ONE artifact, shows what's unlocked
+ │
+ └── Scaffolds change, waits for direction
+```
+
+### Schemas Personalizados
+
+Crie fluxos de trabalho personalizados usando os comandos de gerenciamento de schema:
+
+```bash
+# Create a new schema from scratch (interactive)
+openspec schema init my-workflow
+
+# Or fork an existing schema as a starting point
+openspec schema fork spec-driven my-workflow
+
+# Validate your schema structure
+openspec schema validate my-workflow
+
+# See where a schema resolves from (useful for debugging)
+openspec schema which my-workflow
+```
+
+Schemas são armazenados em `openspec/schemas/` (local do projeto, versionado) ou `~/.local/share/openspec/schemas/` (global do usuário).
+
+**Estrutura do schema:**
+```
+openspec/schemas/research-first/
+├── schema.yaml
+└── templates/
+ ├── research.md
+ ├── proposal.md
+ └── tasks.md
+```
+
+**Exemplo de schema.yaml:**
+```yaml
+name: research-first
+artifacts:
+ - id: research # Added before proposal
+ generates: research.md
+ requires: []
+
+ - id: proposal
+ generates: proposal.md
+ requires: [research] # Now depends on research
+
+ - id: tasks
+ generates: tasks.md
+ requires: [proposal]
+```
+
+**Grafo de Dependências:**
+```
+ research ──► proposal ──► tasks
+```
+
+### Resumo
+
+| Aspecto | Legado | OPSX |
+|---------|--------|------|
+| **Templates** | TypeScript hardcoded | YAML + Markdown externos |
+| **Dependências** | Nenhuma (tudo de uma vez) | DAG com ordenação topológica |
+| **Estado** | Modelo mental baseado em fases | Existência no sistema de arquivos |
+| **Personalização** | Editar código-fonte, rebuild | Criar schema.yaml |
+| **Iteração** | Bloqueada por fases | Fluida, edite qualquer coisa |
+| **Suporte a Editores** | Configurador/adaptadores específicos por ferramenta | Diretório único de skills |
+
+## Schemas
+
+Schemas definem quais artefatos existem e suas dependências. Atualmente disponíveis:
+
+- **spec-driven** (padrão): proposal → specs → design → tasks
+
+```bash
+# List available schemas
+openspec schemas
+
+# See all schemas with their resolution sources
+openspec schema which --all
+
+# Create a new schema interactively
+openspec schema init my-workflow
+
+# Fork an existing schema for customization
+openspec schema fork spec-driven my-workflow
+
+# Validate schema structure before use
+openspec schema validate my-workflow
+```
+
+## Dicas
+
+- Use `/opsx:explore` para pensar em uma ideia antes de se comprometer com uma mudança
+- `/opsx:ff` quando você sabe o que quer, `/opsx:continue` quando está explorando
+- Durante `/opsx:apply`, se algo estiver errado — corrija o artefato, depois continue
+- As tarefas rastreiam o progresso via checkboxes em `tasks.md`
+- Verifique o status a qualquer momento: `openspec status --change "name"`
+
+## Feedback
+
+Isso ainda está em desenvolvimento. Isso é intencional — estamos aprendendo o que funciona.
+
+Encontrou um bug? Tem ideias? Abra uma issue no [GitHub](https://github.com/fkmatsuda/BR-OpenSpec/issues).
diff --git a/docs/pt-BR/supported-tools.md b/docs/pt-BR/supported-tools.md
new file mode 100644
index 0000000000..c53d159811
--- /dev/null
+++ b/docs/pt-BR/supported-tools.md
@@ -0,0 +1,109 @@
+# Ferramentas Suportadas
+
+O BR-OpenSpec funciona com muitos assistentes de codificação com IA. Quando você executa `openspec init`, o BR-OpenSpec configura as ferramentas selecionadas usando o perfil/seleção de fluxo de trabalho ativo e o modo de entrega.
+
+## Como Funciona
+
+Para cada ferramenta selecionada, o BR-OpenSpec pode instalar:
+
+1. **Skills** (se a entrega incluir skills): `.../skills/openspec-*/SKILL.md`
+2. **Comandos** (se a entrega incluir comandos): arquivos de comando `opsx-*` específicos da ferramenta
+
+Por padrão, o BR-OpenSpec usa o perfil `core`, que inclui:
+- `propose`
+- `explore`
+- `apply`
+- `archive`
+
+Você pode habilitar fluxos de trabalho expandidos (`new`, `continue`, `ff`, `verify`, `sync`, `bulk-archive`, `onboard`) via `openspec config profile` e depois executar `openspec update`.
+
+## Referência de Diretórios das Ferramentas
+
+| Ferramenta (ID) | Padrão de caminho de skills | Padrão de caminho de comandos |
+|-----------------|------------------------------|-------------------------------|
+| Amazon Q Developer (`amazon-q`) | `.amazonq/skills/openspec-*/SKILL.md` | `.amazonq/prompts/opsx-.md` |
+| Antigravity (`antigravity`) | `.agent/skills/openspec-*/SKILL.md` | `.agent/workflows/opsx-.md` |
+| Auggie (`auggie`) | `.augment/skills/openspec-*/SKILL.md` | `.augment/commands/opsx-.md` |
+| IBM Bob Shell (`bob`) | `.bob/skills/openspec-*/SKILL.md` | `.bob/commands/opsx-.md` |
+| Claude Code (`claude`) | `.claude/skills/openspec-*/SKILL.md` | `.claude/commands/opsx/.md` |
+| Cline (`cline`) | `.cline/skills/openspec-*/SKILL.md` | `.clinerules/workflows/opsx-.md` |
+| CodeBuddy (`codebuddy`) | `.codebuddy/skills/openspec-*/SKILL.md` | `.codebuddy/commands/opsx/.md` |
+| Codex (`codex`) | `.codex/skills/openspec-*/SKILL.md` | `$CODEX_HOME/prompts/opsx-.md`\* |
+| ForgeCode (`forgecode`) | `.forge/skills/openspec-*/SKILL.md` | Não gerado (sem adaptador de comando; use invocações `/openspec-*` baseadas em skill) |
+| Continue (`continue`) | `.continue/skills/openspec-*/SKILL.md` | `.continue/prompts/opsx-.prompt` |
+| CoStrict (`costrict`) | `.cospec/skills/openspec-*/SKILL.md` | `.cospec/openspec/commands/opsx-.md` |
+| Crush (`crush`) | `.crush/skills/openspec-*/SKILL.md` | `.crush/commands/opsx/.md` |
+| Cursor (`cursor`) | `.cursor/skills/openspec-*/SKILL.md` | `.cursor/commands/opsx-.md` |
+| Factory Droid (`factory`) | `.factory/skills/openspec-*/SKILL.md` | `.factory/commands/opsx-.md` |
+| Gemini CLI (`gemini`) | `.gemini/skills/openspec-*/SKILL.md` | `.gemini/commands/opsx/.toml` |
+| GitHub Copilot (`github-copilot`) | `.github/skills/openspec-*/SKILL.md` | `.github/prompts/opsx-.prompt.md`\*\* |
+| iFlow (`iflow`) | `.iflow/skills/openspec-*/SKILL.md` | `.iflow/commands/opsx-.md` |
+| Junie (`junie`) | `.junie/skills/openspec-*/SKILL.md` | `.junie/commands/opsx-.md` |
+| Kilo Code (`kilocode`) | `.kilocode/skills/openspec-*/SKILL.md` | `.kilocode/workflows/opsx-.md` |
+| Kimi Code CLI (`kimi`) | `.kimi/skills/openspec-*/SKILL.md` | Não gerado (use invocações `/skill:openspec-*` ou `/flow:openspec-*` baseadas em skill) |
+| Kiro (`kiro`) | `.kiro/skills/openspec-*/SKILL.md` | `.kiro/prompts/opsx-.prompt.md` |
+| OpenCode (`opencode`) | `.opencode/skills/openspec-*/SKILL.md` | `.opencode/commands/opsx-.md` |
+| Pi (`pi`) | `.pi/skills/openspec-*/SKILL.md` | `.pi/prompts/opsx-.md` |
+| Qoder (`qoder`) | `.qoder/skills/openspec-*/SKILL.md` | `.qoder/commands/opsx/.md` |
+| Qwen Code (`qwen`) | `.qwen/skills/openspec-*/SKILL.md` | `.qwen/commands/opsx-.toml` |
+| RooCode (`roocode`) | `.roo/skills/openspec-*/SKILL.md` | `.roo/commands/opsx-.md` |
+| Trae (`trae`) | `.trae/skills/openspec-*/SKILL.md` | Não gerado (sem adaptador de comando; use invocações `/openspec-*` baseadas em skill) |
+| Windsurf (`windsurf`) | `.windsurf/skills/openspec-*/SKILL.md` | `.windsurf/workflows/opsx-.md` |
+
+\* Os comandos do Codex são instalados no diretório global do Codex (`$CODEX_HOME/prompts/` se definido, caso contrário `~/.codex/prompts/`), não no diretório do seu projeto.
+
+\*\* Os arquivos de prompt do GitHub Copilot são reconhecidos como slash commands personalizados nas extensões de IDE (VS Code, JetBrains, Visual Studio). O Copilot CLI atualmente não consome arquivos `.github/prompts/*.prompt.md` diretamente.
+
+## Configuração Não Interativa
+
+Para CI/CD ou configuração via script, use `--tools` (e opcionalmente `--profile`):
+
+```bash
+# Configurar ferramentas específicas
+openspec init --tools claude,cursor
+
+# Configurar todas as ferramentas suportadas
+openspec init --tools all
+
+# Ignorar configuração de ferramentas
+openspec init --tools none
+
+# Substituir perfil para esta execução de init
+openspec init --profile core
+```
+
+**IDs de ferramentas disponíveis (`--tools`):** `amazon-q`, `antigravity`, `auggie`, `bob`, `claude`, `cline`, `codex`, `codebuddy`, `continue`, `costrict`, `crush`, `cursor`, `factory`, `forgecode`, `gemini`, `github-copilot`, `iflow`, `junie`, `kilocode`, `kimi`, `kiro`, `opencode`, `pi`, `qoder`, `qwen`, `roocode`, `trae`, `windsurf`
+
+## Instalação Dependente de Fluxo de Trabalho
+
+O BR-OpenSpec instala artefatos de fluxo de trabalho com base nos fluxos selecionados:
+
+- **Perfil core (padrão):** `propose`, `explore`, `apply`, `archive`
+- **Seleção personalizada:** qualquer subconjunto de todos os IDs de fluxo de trabalho:
+ `propose`, `explore`, `new`, `continue`, `apply`, `ff`, `sync`, `archive`, `bulk-archive`, `verify`, `onboard`
+
+Em outras palavras, a quantidade de skills/comandos depende do perfil e do modo de entrega, não é fixa.
+
+## Nomes de Skills Geradas
+
+Quando selecionadas pela configuração de perfil/fluxo de trabalho, o BR-OpenSpec gera estas skills:
+
+- `openspec-propose`
+- `openspec-explore`
+- `openspec-new-change`
+- `openspec-continue-change`
+- `openspec-apply-change`
+- `openspec-ff-change`
+- `openspec-sync-specs`
+- `openspec-archive-change`
+- `openspec-bulk-archive-change`
+- `openspec-verify-change`
+- `openspec-onboard`
+
+Veja [Comandos](../commands.md) para o comportamento dos comandos e [CLI](../cli.md) para as opções de `init`/`update`.
+
+## Relacionados
+
+- [Referência da CLI](../cli.md) — Comandos do terminal
+- [Comandos](../commands.md) — Slash commands e skills
+- [Primeiros Passos](../getting-started.md) — Configuração inicial
diff --git a/docs/pt-BR/workflows.md b/docs/pt-BR/workflows.md
new file mode 100644
index 0000000000..de51d357e0
--- /dev/null
+++ b/docs/pt-BR/workflows.md
@@ -0,0 +1,451 @@
+# Fluxos de Trabalho
+
+Este guia aborda os padrões de workflow mais comuns do BR-OpenSpec e quando usar cada um. Para configuração básica, consulte [Primeiros Passos](getting-started.md). Para referência de comandos, consulte [Comandos](commands.md).
+
+## Filosofia: Ações, Não Fases
+
+Workflows tradicionais forçam você a percorrer fases: planejamento, depois implementação, depois conclusão. Mas o trabalho real não se encaixa perfeitamente em caixas.
+
+O OPSX adota uma abordagem diferente:
+
+```text
+Tradicional (fases fixas):
+
+ PLANEJAMENTO ────────► IMPLEMENTAÇÃO ────────► CONCLUÍDO
+ │ │
+ │ "Não dá pra voltar" │
+ └───────────────────────┘
+
+OPSX (ações fluidas):
+
+ proposta ──► specs ──► design ──► tarefas ──► implementação
+```
+
+**Princípios fundamentais:**
+
+- **Ações, não fases** — Os comandos são coisas que você pode fazer, não etapas em que você fica preso
+- **Dependências são habilitadoras** — Elas mostram o que é possível, não o que é obrigatório em seguida
+
+> **Personalização:** Os workflows do OPSX são orientados por schemas que definem sequências de artefatos. Consulte [Personalização](customization.md) para detalhes sobre como criar schemas personalizados.
+
+## Dois Modos
+
+### Caminho Rápido Padrão (perfil `core`)
+
+Novas instalações usam `core` por padrão, que fornece:
+- `/opsx:propose`
+- `/opsx:explore`
+- `/opsx:apply`
+- `/opsx:archive`
+
+Fluxo típico:
+
+```text
+/opsx:propose ──► /opsx:apply ──► /opsx:archive
+```
+
+### Workflow Expandido/Completo (seleção personalizada)
+
+Se você quiser comandos explícitos de scaffold e construção (`/opsx:new`, `/opsx:continue`, `/opsx:ff`, `/opsx:verify`, `/opsx:sync`, `/opsx:bulk-archive`, `/opsx:onboard`), habilite-os com:
+
+```bash
+openspec config profile
+openspec update
+```
+
+## Padrões de Workflow (Modo Expandido)
+
+### Recurso Rápido
+
+Quando você sabe o que quer construir e só precisa executar:
+
+```text
+/opsx:new ──► /opsx:ff ──► /opsx:apply ──► /opsx:verify ──► /opsx:archive
+```
+
+**Exemplo de conversa:**
+
+```text
+Você: /opsx:new add-logout-button
+
+IA: Criado openspec/changes/add-logout-button/
+ Pronto para criar: proposta
+
+Você: /opsx:ff
+
+IA: Criando todos os artefatos de planejamento...
+ ✓ proposal.md
+ ✓ specs/
+ ✓ design.md
+ ✓ tasks.md
+ Pronto para implementação!
+
+Você: /opsx:apply
+
+IA: Executando as tarefas...
+ ✓ Botão de logout adicionado ao cabeçalho
+ ✓ Limpeza de sessão implementada
+ ✓ Diálogo de confirmação adicionado
+ Todas as tarefas concluídas!
+
+Você: /opsx:archive
+
+IA: ✓ Specs mescladas
+ ✓ Mudança arquivada
+```
+
+**Ideal para:** Recursos pequenos a médios, correções de bugs, mudanças diretas.
+
+### Exploratório
+
+Quando os requisitos não estão claros ou você precisa investigar primeiro:
+
+```text
+/opsx:explore ──► /opsx:new ──► /opsx:continue ──► ... ──► /opsx:apply
+```
+
+**Exemplo de conversa:**
+
+```text
+Você: /opsx:explore
+
+IA: O que você gostaria de explorar?
+
+Você: Quero melhorar o desempenho de carregamento das páginas, mas não tenho
+ certeza de onde estão os gargalos.
+
+IA: Deixe-me ajudar a investigar...
+ [Analisa tamanhos de bundles, identifica consultas lentas, revisa
+ padrões de renderização de componentes]
+
+ Encontrei três gargalos principais:
+ 1. Imagens grandes não otimizadas
+ 2. Busca de dados síncrona no ProductList
+ 3. Re-renderizações causadas por mudanças de contexto
+
+ Qual você gostaria de resolver primeiro?
+
+Você: Vamos atacar o problema de busca de dados.
+
+Você: /opsx:new optimize-product-list-fetching
+
+IA: Mudança criada. Pronto para criar: proposta
+
+Você: /opsx:continue
+
+IA: Criando proposta com base na nossa exploração...
+ [Escreve a proposta incorporando os insights da investigação]
+
+ Pronto para criar: specs, design
+ Qual você gostaria a seguir?
+
+Você: /opsx:continue
+
+IA: Criando specs...
+```
+
+**Ideal para:** Otimização de desempenho, depuração, decisões arquiteturais, requisitos pouco claros.
+
+### Mudanças Paralelas
+
+Trabalhe em múltiplas mudanças ao mesmo tempo:
+
+```text
+Mudança A: /opsx:new ──► /opsx:ff ──► /opsx:apply (em andamento)
+ │
+ troca de contexto
+ │
+Mudança B: /opsx:new ──► /opsx:ff ──────► /opsx:apply
+```
+
+**Exemplo de conversa:**
+
+```text
+Você: Estou trabalhando no add-dark-mode, mas fui chamado para corrigir um bug
+
+Você: /opsx:new fix-login-redirect
+
+IA: Criado openspec/changes/fix-login-redirect/
+
+Você: /opsx:ff
+
+IA: ✓ Artefatos de planejamento criados
+
+Você: /opsx:apply
+
+IA: Trabalhando no fix-login-redirect...
+ [Implementa a correção]
+ Todas as tarefas concluídas!
+
+Você: /opsx:archive
+
+IA: ✓ fix-login-redirect arquivado
+
+Você: Vamos voltar ao modo escuro
+
+Você: /opsx:apply add-dark-mode
+
+IA: Retomando add-dark-mode...
+ Continuando na tarefa 2.3: Atualizar o Header...
+```
+
+**Ideal para:** Fluxos de trabalho paralelos, interrupções urgentes, colaboração em equipe.
+
+Quando você tiver múltiplas mudanças concluídas, use `/opsx:bulk-archive`:
+
+```text
+Você: /opsx:bulk-archive
+
+IA: Encontradas 3 mudanças concluídas:
+ - add-dark-mode (todas as tarefas feitas)
+ - fix-login-redirect (todas as tarefas feitas)
+ - update-footer (todas as tarefas feitas)
+
+ Verificando conflitos de specs...
+ ⚠ add-dark-mode e update-footer tocam em specs/ui/
+
+ Inspecionando a base de código para resolver...
+ Ambas as mudanças estão implementadas. Serão aplicadas em ordem cronológica.
+
+ Arquivar as 3 mudanças?
+
+Você: Sim
+
+IA: ✓ add-dark-mode arquivado
+ ✓ fix-login-redirect arquivado
+ ✓ update-footer arquivado
+ Specs mescladas na ordem: add-dark-mode → update-footer
+```
+
+O bulk archive detecta quando múltiplas mudanças tocam nas mesmas specs e resolve conflitos verificando o que está realmente implementado.
+
+### Concluindo uma Mudança
+
+O fluxo de conclusão recomendado:
+
+```text
+/opsx:apply ──► /opsx:verify ──► /opsx:archive
+ │ │
+ valida a solicita sync
+ implementação se necessário
+```
+
+#### Verify: Verifique seu Trabalho
+
+`/opsx:verify` valida a implementação em relação aos seus artefatos em três dimensões:
+
+```text
+Você: /opsx:verify
+
+IA: Verificando add-auth...
+
+ COMPLETUDE
+ ✓ Todas as 12 tarefas em tasks.md estão marcadas
+ ✓ Todos os requisitos nas specs têm código correspondente
+ ⚠ Cenário "Session timeout after inactivity" não está testado
+
+ CORREÇÃO
+ ✓ A implementação corresponde à intenção da spec
+ ✓ Casos extremos dos cenários são tratados
+ ✓ Estados de erro correspondem às definições da spec
+
+ COERÊNCIA
+ ✓ Decisões de design refletidas na estrutura do código
+ ✓ Convenções de nomenclatura consistentes com design.md
+ ⚠ O design menciona "orientado a eventos", mas a implementação usa polling
+
+ RESUMO
+ ─────────────────────────────
+ Problemas críticos: 0
+ Avisos: 2
+ Pronto para arquivar: Sim (com avisos)
+
+ Recomendações:
+ 1. Adicionar teste para o cenário de timeout de sessão
+ 2. Considerar refatorar para orientado a eventos conforme projetado, ou atualizar design.md
+```
+
+**O que o verify verifica:**
+
+| Dimensão | O que valida |
+|----------|--------------|
+| Completude | Todas as tarefas feitas, todos os requisitos implementados, cenários cobertos |
+| Correção | A implementação corresponde à intenção da spec, casos extremos tratados |
+| Coerência | Decisões de design refletidas no código, padrões consistentes |
+
+O verify não bloqueia o archive, mas evidencia problemas que você pode querer resolver antes.
+
+#### Archive: Finalizar a Mudança
+
+`/opsx:archive` conclui a mudança e a move para o histórico:
+
+```text
+Você: /opsx:archive
+
+IA: Arquivando add-auth...
+
+ Status dos artefatos:
+ ✓ proposal.md existe
+ ✓ specs/ existe
+ ✓ design.md existe
+ ✓ tasks.md existe (12/12 tarefas concluídas)
+
+ Delta specs: Ainda não sincronizadas com o principal
+ → Você gostaria de sincronizar agora?
+
+Você: Sim
+
+IA: ✓ Specs sincronizadas com openspec/specs/auth/spec.md
+ ✓ Movido para openspec/changes/archive/2025-01-24-add-auth/
+
+ Mudança arquivada com sucesso.
+```
+
+O archive solicitará que as specs sejam sincronizadas caso ainda não estejam. Ele não bloqueia em tarefas incompletas, mas irá alertá-lo.
+
+## Quando Usar o Quê
+
+### `/opsx:ff` vs `/opsx:continue`
+
+| Situação | Use |
+|----------|-----|
+| Requisitos claros, pronto para construir | `/opsx:ff` |
+| Explorando, quer revisar cada etapa | `/opsx:continue` |
+| Quer iterar na proposta antes das specs | `/opsx:continue` |
+| Pressão de tempo, precisa avançar rápido | `/opsx:ff` |
+| Mudança complexa, quer controle | `/opsx:continue` |
+
+**Regra geral:** Se você consegue descrever o escopo completo antecipadamente, use `/opsx:ff`. Se está descobrindo à medida que avança, use `/opsx:continue`.
+
+### Quando Atualizar vs Começar do Zero
+
+Uma pergunta comum: quando é adequado atualizar uma mudança existente e quando você deve iniciar uma nova?
+
+**Atualize a mudança existente quando:**
+
+- Mesma intenção, execução refinada
+- Escopo reduzido (MVP primeiro, o resto depois)
+- Correções orientadas pelo aprendizado (a base de código não era o que você esperava)
+- Ajustes de design baseados em descobertas da implementação
+
+**Inicie uma nova mudança quando:**
+
+- A intenção mudou fundamentalmente
+- O escopo explodiu para um trabalho completamente diferente
+- A mudança original pode ser marcada como "concluída" de forma independente
+- As correções confundiriam mais do que esclareceriam
+
+```text
+ ┌─────────────────────────────────────┐
+ │ É o mesmo trabalho? │
+ └──────────────┬──────────────────────┘
+ │
+ ┌──────────────────┼──────────────────┐
+ │ │ │
+ ▼ ▼ ▼
+ Mesma intenção? >50% de sobreposição? O original pode
+ Mesmo problema? Mesmo escopo? ser "concluído" sem
+ │ │ essas mudanças?
+ │ │ │
+ ┌────────┴────────┐ ┌──────┴──────┐ ┌───────┴───────┐
+ │ │ │ │ │ │
+ SIM NÃO SIM NÃO NÃO SIM
+ │ │ │ │ │ │
+ ▼ ▼ ▼ ▼ ▼ ▼
+ ATUALIZAR NOVA ATUALIZAR NOVA ATUALIZAR NOVA
+```
+
+**Exemplo: "Adicionar modo escuro"**
+
+- "Preciso também suportar temas personalizados" → Nova mudança (escopo explodiu)
+- "Detectar preferência do sistema é mais difícil do que esperado" → Atualizar (mesma intenção)
+- "Vamos lançar o toggle primeiro, adicionar preferências depois" → Atualizar e arquivar, depois nova mudança
+
+## Boas Práticas
+
+### Mantenha as Mudanças Focadas
+
+Uma unidade lógica de trabalho por mudança. Se você está fazendo "adicionar recurso X e também refatorar Y", considere duas mudanças separadas.
+
+**Por que isso importa:**
+- Mais fácil de revisar e entender
+- Histórico de arquivo mais limpo
+- Pode ser entregue de forma independente
+- Rollback mais simples se necessário
+
+### Use `/opsx:explore` para Requisitos Pouco Claros
+
+Antes de se comprometer com uma mudança, explore o espaço do problema:
+
+```text
+Você: /opsx:explore
+
+IA: O que você gostaria de explorar?
+
+Você: Como devemos lidar com rate limiting para nossa API?
+
+IA: Deixe-me investigar sua configuração atual e as opções...
+ [Pesquisa a base de código, considera padrões]
+
+ Vejo três abordagens que poderíamos adotar:
+ 1. Baseada em middleware (simples, por endpoint)
+ 2. Apoiada por Redis (escalável, estado compartilhado)
+ 3. Token bucket por usuário (justa, complexa)
+
+ Sua stack atual sugere #1 ou #2. Qual é a sua escala?
+```
+
+A exploração clarifica o pensamento antes de você criar os artefatos.
+
+### Verifique Antes de Arquivar
+
+Use `/opsx:verify` para checar se a implementação corresponde aos artefatos:
+
+```text
+Você: /opsx:verify
+
+IA: Verificando add-dark-mode...
+
+ ✓ Todas as tarefas em tasks.md estão marcadas
+ ✓ Os requisitos nas specs têm código correspondente
+ ✓ As decisões de design estão refletidas na implementação
+
+ Pronto para arquivar!
+```
+
+Detecta inconsistências antes de você fechar a mudança.
+
+### Nomeie as Mudanças de Forma Clara
+
+Bons nomes tornam o `openspec list` útil:
+
+```text
+Bom: Evite:
+add-dark-mode feature-1
+fix-login-redirect update
+optimize-product-query changes
+implement-2fa wip
+```
+
+## Referência Rápida de Comandos
+
+Para detalhes completos e opções dos comandos, consulte [Comandos](commands.md).
+
+| Comando | Propósito | Quando Usar |
+|---------|-----------|-------------|
+| `/opsx:propose` | Criar mudança + artefatos de planejamento | Caminho rápido padrão (perfil `core`) |
+| `/opsx:explore` | Pensar sobre ideias | Requisitos pouco claros, investigação |
+| `/opsx:new` | Iniciar um scaffold de mudança | Modo expandido, controle explícito de artefatos |
+| `/opsx:continue` | Criar o próximo artefato | Modo expandido, criação de artefatos passo a passo |
+| `/opsx:ff` | Criar todos os artefatos de planejamento | Modo expandido, escopo claro |
+| `/opsx:apply` | Implementar tarefas | Pronto para escrever código |
+| `/opsx:verify` | Validar a implementação | Modo expandido, antes de arquivar |
+| `/opsx:sync` | Mesclar delta specs | Modo expandido, opcional |
+| `/opsx:archive` | Concluir a mudança | Todo o trabalho finalizado |
+| `/opsx:bulk-archive` | Arquivar múltiplas mudanças | Modo expandido, trabalho paralelo |
+
+## Próximos Passos
+
+- [Comandos](commands.md) — Referência completa de comandos com opções
+- [Conceitos](concepts.md) — Aprofundamento em specs, artefatos e schemas
+- [Personalização](customization.md) — Crie workflows personalizados
diff --git a/docs/supported-tools.md b/docs/supported-tools.md
index dc55009204..1f4c64f8ec 100644
--- a/docs/supported-tools.md
+++ b/docs/supported-tools.md
@@ -1,15 +1,15 @@
# Supported Tools
-OpenSpec works with many AI coding assistants. When you run `openspec init`, OpenSpec configures selected tools using your active profile/workflow selection and delivery mode.
+BR-OpenSpec works with many AI coding assistants. When you run `openspec init`, BR-OpenSpec configures selected tools using your active profile/workflow selection and delivery mode.
## How It Works
-For each selected tool, OpenSpec can install:
+For each selected tool, BR-OpenSpec can install:
1. **Skills** (if delivery includes skills): `.../skills/openspec-*/SKILL.md`
2. **Commands** (if delivery includes commands): tool-specific `opsx-*` command files
-By default, OpenSpec uses the `core` profile, which includes:
+By default, BR-OpenSpec uses the `core` profile, which includes:
- `propose`
- `explore`
- `apply`
@@ -40,6 +40,7 @@ You can enable expanded workflows (`new`, `continue`, `ff`, `verify`, `sync`, `b
| iFlow (`iflow`) | `.iflow/skills/openspec-*/SKILL.md` | `.iflow/commands/opsx-.md` |
| Junie (`junie`) | `.junie/skills/openspec-*/SKILL.md` | `.junie/commands/opsx-.md` |
| Kilo Code (`kilocode`) | `.kilocode/skills/openspec-*/SKILL.md` | `.kilocode/workflows/opsx-.md` |
+| Kimi Code CLI (`kimi`) | `.kimi/skills/openspec-*/SKILL.md` | Not generated (use skill-based `/skill:openspec-*` or `/flow:openspec-*` invocations) |
| Kiro (`kiro`) | `.kiro/skills/openspec-*/SKILL.md` | `.kiro/prompts/opsx-.prompt.md` |
| OpenCode (`opencode`) | `.opencode/skills/openspec-*/SKILL.md` | `.opencode/commands/opsx-.md` |
| Pi (`pi`) | `.pi/skills/openspec-*/SKILL.md` | `.pi/prompts/opsx-.md` |
@@ -71,11 +72,11 @@ openspec init --tools none
openspec init --profile core
```
-**Available tool IDs (`--tools`):** `amazon-q`, `antigravity`, `auggie`, `bob`, `claude`, `cline`, `codex`, `codebuddy`, `continue`, `costrict`, `crush`, `cursor`, `factory`, `forgecode`, `gemini`, `github-copilot`, `iflow`, `junie`, `kilocode`, `kiro`, `opencode`, `pi`, `qoder`, `qwen`, `roocode`, `trae`, `windsurf`
+**Available tool IDs (`--tools`):** `amazon-q`, `antigravity`, `auggie`, `bob`, `claude`, `cline`, `codex`, `codebuddy`, `continue`, `costrict`, `crush`, `cursor`, `factory`, `forgecode`, `gemini`, `github-copilot`, `iflow`, `junie`, `kilocode`, `kimi`, `kiro`, `lingma`, `opencode`, `pi`, `qoder`, `qwen`, `roocode`, `trae`, `windsurf`
## Workflow-Dependent Installation
-OpenSpec installs workflow artifacts based on selected workflows:
+BR-OpenSpec installs workflow artifacts based on selected workflows:
- **Core profile (default):** `propose`, `explore`, `apply`, `archive`
- **Custom selection:** any subset of all workflow IDs:
@@ -85,7 +86,7 @@ In other words, skill/command counts are profile-dependent and delivery-dependen
## Generated Skill Names
-When selected by profile/workflow config, OpenSpec generates these skills:
+When selected by profile/workflow config, BR-OpenSpec generates these skills:
- `openspec-propose`
- `openspec-explore`
diff --git a/docs/workflows.md b/docs/workflows.md
index 6cfd7e063b..1fcef7b22f 100644
--- a/docs/workflows.md
+++ b/docs/workflows.md
@@ -1,6 +1,6 @@
# Workflows
-This guide covers common workflow patterns for OpenSpec and when to use each one. For basic setup, see [Getting Started](getting-started.md). For command reference, see [Commands](commands.md).
+This guide covers common workflow patterns for BR-OpenSpec and when to use each one. For basic setup, see [Getting Started](getting-started.md). For command reference, see [Commands](commands.md).
## Philosophy: Actions, Not Phases
diff --git a/flake.nix b/flake.nix
index 90ba68aef9..95f10d779b 100644
--- a/flake.nix
+++ b/flake.nix
@@ -1,5 +1,5 @@
{
- description = "OpenSpec - AI-native system for spec-driven development";
+ description = "BR-OpenSpec - AI-native system for spec-driven development";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
@@ -51,7 +51,7 @@
inherit (finalAttrs) pname version src;
pnpm = pkgs.pnpm_9;
fetcherVersion = 3;
- hash = "sha256-9s2kdvd7svK4hofnD66HkDc86WTQeayfF5y7L2dmjNg=";
+ hash = "sha256-JMQMQBriv89MLw+SE5qfO/oNjJEI44g/Y9dpyRz1hro=";
};
nativeBuildInputs = with pkgs; [
@@ -72,8 +72,8 @@
dontNpmPrune = true;
meta = with pkgs.lib; {
- description = "AI-native system for spec-driven development";
- homepage = "https://github.com/Fission-AI/OpenSpec";
+ description = "BR-OpenSpec - AI-native system for spec-driven development";
+ homepage = "https://github.com/fkmatsuda/BR-OpenSpec";
license = licenses.mit;
maintainers = [ ];
mainProgram = "openspec";
@@ -102,7 +102,7 @@
];
shellHook = ''
- echo "OpenSpec development environment"
+ echo "BR-OpenSpec development environment"
echo "Node version: $(node --version)"
echo "pnpm version: $(pnpm --version)"
echo "Run 'pnpm install' to install dependencies"
diff --git a/package-lock.json b/package-lock.json
deleted file mode 100644
index 03dad207d4..0000000000
--- a/package-lock.json
+++ /dev/null
@@ -1,4978 +0,0 @@
-{
- "name": "@fission-ai/openspec",
- "version": "1.2.0",
- "lockfileVersion": 3,
- "requires": true,
- "packages": {
- "": {
- "name": "@fission-ai/openspec",
- "version": "1.2.0",
- "hasInstallScript": true,
- "license": "MIT",
- "dependencies": {
- "@inquirer/core": "^10.2.2",
- "@inquirer/prompts": "^7.8.0",
- "chalk": "^5.5.0",
- "commander": "^14.0.0",
- "fast-glob": "^3.3.3",
- "ora": "^8.2.0",
- "posthog-node": "^5.20.0",
- "yaml": "^2.8.2",
- "zod": "^4.0.17"
- },
- "bin": {
- "openspec": "bin/openspec.js"
- },
- "devDependencies": {
- "@changesets/changelog-github": "^0.5.2",
- "@changesets/cli": "^2.27.7",
- "@types/node": "^24.2.0",
- "@vitest/ui": "^3.2.4",
- "eslint": "^9.39.2",
- "typescript": "^5.9.3",
- "typescript-eslint": "^8.50.1",
- "vitest": "^3.2.4"
- },
- "engines": {
- "node": ">=20.19.0"
- }
- },
- "node_modules/@babel/runtime": {
- "version": "7.28.6",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz",
- "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@changesets/apply-release-plan": {
- "version": "7.0.14",
- "resolved": "https://registry.npmjs.org/@changesets/apply-release-plan/-/apply-release-plan-7.0.14.tgz",
- "integrity": "sha512-ddBvf9PHdy2YY0OUiEl3TV78mH9sckndJR14QAt87KLEbIov81XO0q0QAmvooBxXlqRRP8I9B7XOzZwQG7JkWA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@changesets/config": "^3.1.2",
- "@changesets/get-version-range-type": "^0.4.0",
- "@changesets/git": "^3.0.4",
- "@changesets/should-skip-package": "^0.1.2",
- "@changesets/types": "^6.1.0",
- "@manypkg/get-packages": "^1.1.3",
- "detect-indent": "^6.0.0",
- "fs-extra": "^7.0.1",
- "lodash.startcase": "^4.4.0",
- "outdent": "^0.5.0",
- "prettier": "^2.7.1",
- "resolve-from": "^5.0.0",
- "semver": "^7.5.3"
- }
- },
- "node_modules/@changesets/assemble-release-plan": {
- "version": "6.0.9",
- "resolved": "https://registry.npmjs.org/@changesets/assemble-release-plan/-/assemble-release-plan-6.0.9.tgz",
- "integrity": "sha512-tPgeeqCHIwNo8sypKlS3gOPmsS3wP0zHt67JDuL20P4QcXiw/O4Hl7oXiuLnP9yg+rXLQ2sScdV1Kkzde61iSQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@changesets/errors": "^0.2.0",
- "@changesets/get-dependents-graph": "^2.1.3",
- "@changesets/should-skip-package": "^0.1.2",
- "@changesets/types": "^6.1.0",
- "@manypkg/get-packages": "^1.1.3",
- "semver": "^7.5.3"
- }
- },
- "node_modules/@changesets/changelog-git": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/@changesets/changelog-git/-/changelog-git-0.2.1.tgz",
- "integrity": "sha512-x/xEleCFLH28c3bQeQIyeZf8lFXyDFVn1SgcBiR2Tw/r4IAWlk1fzxCEZ6NxQAjF2Nwtczoen3OA2qR+UawQ8Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@changesets/types": "^6.1.0"
- }
- },
- "node_modules/@changesets/changelog-github": {
- "version": "0.5.2",
- "resolved": "https://registry.npmjs.org/@changesets/changelog-github/-/changelog-github-0.5.2.tgz",
- "integrity": "sha512-HeGeDl8HaIGj9fQHo/tv5XKQ2SNEi9+9yl1Bss1jttPqeiASRXhfi0A2wv8yFKCp07kR1gpOI5ge6+CWNm1jPw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@changesets/get-github-info": "^0.7.0",
- "@changesets/types": "^6.1.0",
- "dotenv": "^8.1.0"
- }
- },
- "node_modules/@changesets/cli": {
- "version": "2.29.8",
- "resolved": "https://registry.npmjs.org/@changesets/cli/-/cli-2.29.8.tgz",
- "integrity": "sha512-1weuGZpP63YWUYjay/E84qqwcnt5yJMM0tep10Up7Q5cS/DGe2IZ0Uj3HNMxGhCINZuR7aO9WBMdKnPit5ZDPA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@changesets/apply-release-plan": "^7.0.14",
- "@changesets/assemble-release-plan": "^6.0.9",
- "@changesets/changelog-git": "^0.2.1",
- "@changesets/config": "^3.1.2",
- "@changesets/errors": "^0.2.0",
- "@changesets/get-dependents-graph": "^2.1.3",
- "@changesets/get-release-plan": "^4.0.14",
- "@changesets/git": "^3.0.4",
- "@changesets/logger": "^0.1.1",
- "@changesets/pre": "^2.0.2",
- "@changesets/read": "^0.6.6",
- "@changesets/should-skip-package": "^0.1.2",
- "@changesets/types": "^6.1.0",
- "@changesets/write": "^0.4.0",
- "@inquirer/external-editor": "^1.0.2",
- "@manypkg/get-packages": "^1.1.3",
- "ansi-colors": "^4.1.3",
- "ci-info": "^3.7.0",
- "enquirer": "^2.4.1",
- "fs-extra": "^7.0.1",
- "mri": "^1.2.0",
- "p-limit": "^2.2.0",
- "package-manager-detector": "^0.2.0",
- "picocolors": "^1.1.0",
- "resolve-from": "^5.0.0",
- "semver": "^7.5.3",
- "spawndamnit": "^3.0.1",
- "term-size": "^2.1.0"
- },
- "bin": {
- "changeset": "bin.js"
- }
- },
- "node_modules/@changesets/config": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/@changesets/config/-/config-3.1.2.tgz",
- "integrity": "sha512-CYiRhA4bWKemdYi/uwImjPxqWNpqGPNbEBdX1BdONALFIDK7MCUj6FPkzD+z9gJcvDFUQJn9aDVf4UG7OT6Kog==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@changesets/errors": "^0.2.0",
- "@changesets/get-dependents-graph": "^2.1.3",
- "@changesets/logger": "^0.1.1",
- "@changesets/types": "^6.1.0",
- "@manypkg/get-packages": "^1.1.3",
- "fs-extra": "^7.0.1",
- "micromatch": "^4.0.8"
- }
- },
- "node_modules/@changesets/errors": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/@changesets/errors/-/errors-0.2.0.tgz",
- "integrity": "sha512-6BLOQUscTpZeGljvyQXlWOItQyU71kCdGz7Pi8H8zdw6BI0g3m43iL4xKUVPWtG+qrrL9DTjpdn8eYuCQSRpow==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "extendable-error": "^0.1.5"
- }
- },
- "node_modules/@changesets/get-dependents-graph": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/@changesets/get-dependents-graph/-/get-dependents-graph-2.1.3.tgz",
- "integrity": "sha512-gphr+v0mv2I3Oxt19VdWRRUxq3sseyUpX9DaHpTUmLj92Y10AGy+XOtV+kbM6L/fDcpx7/ISDFK6T8A/P3lOdQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@changesets/types": "^6.1.0",
- "@manypkg/get-packages": "^1.1.3",
- "picocolors": "^1.1.0",
- "semver": "^7.5.3"
- }
- },
- "node_modules/@changesets/get-github-info": {
- "version": "0.7.0",
- "resolved": "https://registry.npmjs.org/@changesets/get-github-info/-/get-github-info-0.7.0.tgz",
- "integrity": "sha512-+i67Bmhfj9V4KfDeS1+Tz3iF32btKZB2AAx+cYMqDSRFP7r3/ZdGbjCo+c6qkyViN9ygDuBjzageuPGJtKGe5A==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "dataloader": "^1.4.0",
- "node-fetch": "^2.5.0"
- }
- },
- "node_modules/@changesets/get-release-plan": {
- "version": "4.0.14",
- "resolved": "https://registry.npmjs.org/@changesets/get-release-plan/-/get-release-plan-4.0.14.tgz",
- "integrity": "sha512-yjZMHpUHgl4Xl5gRlolVuxDkm4HgSJqT93Ri1Uz8kGrQb+5iJ8dkXJ20M2j/Y4iV5QzS2c5SeTxVSKX+2eMI0g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@changesets/assemble-release-plan": "^6.0.9",
- "@changesets/config": "^3.1.2",
- "@changesets/pre": "^2.0.2",
- "@changesets/read": "^0.6.6",
- "@changesets/types": "^6.1.0",
- "@manypkg/get-packages": "^1.1.3"
- }
- },
- "node_modules/@changesets/get-version-range-type": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/@changesets/get-version-range-type/-/get-version-range-type-0.4.0.tgz",
- "integrity": "sha512-hwawtob9DryoGTpixy1D3ZXbGgJu1Rhr+ySH2PvTLHvkZuQ7sRT4oQwMh0hbqZH1weAooedEjRsbrWcGLCeyVQ==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@changesets/git": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/@changesets/git/-/git-3.0.4.tgz",
- "integrity": "sha512-BXANzRFkX+XcC1q/d27NKvlJ1yf7PSAgi8JG6dt8EfbHFHi4neau7mufcSca5zRhwOL8j9s6EqsxmT+s+/E6Sw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@changesets/errors": "^0.2.0",
- "@manypkg/get-packages": "^1.1.3",
- "is-subdir": "^1.1.1",
- "micromatch": "^4.0.8",
- "spawndamnit": "^3.0.1"
- }
- },
- "node_modules/@changesets/logger": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/@changesets/logger/-/logger-0.1.1.tgz",
- "integrity": "sha512-OQtR36ZlnuTxKqoW4Sv6x5YIhOmClRd5pWsjZsddYxpWs517R0HkyiefQPIytCVh4ZcC5x9XaG8KTdd5iRQUfg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "picocolors": "^1.1.0"
- }
- },
- "node_modules/@changesets/parse": {
- "version": "0.4.2",
- "resolved": "https://registry.npmjs.org/@changesets/parse/-/parse-0.4.2.tgz",
- "integrity": "sha512-Uo5MC5mfg4OM0jU3up66fmSn6/NE9INK+8/Vn/7sMVcdWg46zfbvvUSjD9EMonVqPi9fbrJH9SXHn48Tr1f2yA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@changesets/types": "^6.1.0",
- "js-yaml": "^4.1.1"
- }
- },
- "node_modules/@changesets/pre": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/@changesets/pre/-/pre-2.0.2.tgz",
- "integrity": "sha512-HaL/gEyFVvkf9KFg6484wR9s0qjAXlZ8qWPDkTyKF6+zqjBe/I2mygg3MbpZ++hdi0ToqNUF8cjj7fBy0dg8Ug==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@changesets/errors": "^0.2.0",
- "@changesets/types": "^6.1.0",
- "@manypkg/get-packages": "^1.1.3",
- "fs-extra": "^7.0.1"
- }
- },
- "node_modules/@changesets/read": {
- "version": "0.6.6",
- "resolved": "https://registry.npmjs.org/@changesets/read/-/read-0.6.6.tgz",
- "integrity": "sha512-P5QaN9hJSQQKJShzzpBT13FzOSPyHbqdoIBUd2DJdgvnECCyO6LmAOWSV+O8se2TaZJVwSXjL+v9yhb+a9JeJg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@changesets/git": "^3.0.4",
- "@changesets/logger": "^0.1.1",
- "@changesets/parse": "^0.4.2",
- "@changesets/types": "^6.1.0",
- "fs-extra": "^7.0.1",
- "p-filter": "^2.1.0",
- "picocolors": "^1.1.0"
- }
- },
- "node_modules/@changesets/should-skip-package": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/@changesets/should-skip-package/-/should-skip-package-0.1.2.tgz",
- "integrity": "sha512-qAK/WrqWLNCP22UDdBTMPH5f41elVDlsNyat180A33dWxuUDyNpg6fPi/FyTZwRriVjg0L8gnjJn2F9XAoF0qw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@changesets/types": "^6.1.0",
- "@manypkg/get-packages": "^1.1.3"
- }
- },
- "node_modules/@changesets/types": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/@changesets/types/-/types-6.1.0.tgz",
- "integrity": "sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@changesets/write": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/@changesets/write/-/write-0.4.0.tgz",
- "integrity": "sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@changesets/types": "^6.1.0",
- "fs-extra": "^7.0.1",
- "human-id": "^4.1.1",
- "prettier": "^2.7.1"
- }
- },
- "node_modules/@esbuild/aix-ppc64": {
- "version": "0.27.3",
- "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz",
- "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==",
- "cpu": [
- "ppc64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "aix"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/android-arm": {
- "version": "0.27.3",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz",
- "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/android-arm64": {
- "version": "0.27.3",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz",
- "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/android-x64": {
- "version": "0.27.3",
- "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz",
- "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/darwin-arm64": {
- "version": "0.27.3",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz",
- "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/darwin-x64": {
- "version": "0.27.3",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz",
- "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/freebsd-arm64": {
- "version": "0.27.3",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz",
- "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "freebsd"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/freebsd-x64": {
- "version": "0.27.3",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz",
- "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "freebsd"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/linux-arm": {
- "version": "0.27.3",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz",
- "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/linux-arm64": {
- "version": "0.27.3",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz",
- "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/linux-ia32": {
- "version": "0.27.3",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz",
- "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==",
- "cpu": [
- "ia32"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/linux-loong64": {
- "version": "0.27.3",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz",
- "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==",
- "cpu": [
- "loong64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/linux-mips64el": {
- "version": "0.27.3",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz",
- "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==",
- "cpu": [
- "mips64el"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/linux-ppc64": {
- "version": "0.27.3",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz",
- "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==",
- "cpu": [
- "ppc64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/linux-riscv64": {
- "version": "0.27.3",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz",
- "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==",
- "cpu": [
- "riscv64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/linux-s390x": {
- "version": "0.27.3",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz",
- "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==",
- "cpu": [
- "s390x"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/linux-x64": {
- "version": "0.27.3",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz",
- "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/netbsd-arm64": {
- "version": "0.27.3",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz",
- "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "netbsd"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/netbsd-x64": {
- "version": "0.27.3",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz",
- "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "netbsd"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/openbsd-arm64": {
- "version": "0.27.3",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz",
- "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "openbsd"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/openbsd-x64": {
- "version": "0.27.3",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz",
- "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "openbsd"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/openharmony-arm64": {
- "version": "0.27.3",
- "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz",
- "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "openharmony"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/sunos-x64": {
- "version": "0.27.3",
- "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz",
- "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "sunos"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/win32-arm64": {
- "version": "0.27.3",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz",
- "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/win32-ia32": {
- "version": "0.27.3",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz",
- "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==",
- "cpu": [
- "ia32"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/win32-x64": {
- "version": "0.27.3",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz",
- "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@eslint-community/eslint-utils": {
- "version": "4.9.1",
- "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz",
- "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "eslint-visitor-keys": "^3.4.3"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- },
- "peerDependencies": {
- "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
- }
- },
- "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": {
- "version": "3.4.3",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
- "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
- "dev": true,
- "license": "Apache-2.0",
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/@eslint-community/regexpp": {
- "version": "4.12.2",
- "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz",
- "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
- }
- },
- "node_modules/@eslint/config-array": {
- "version": "0.21.1",
- "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz",
- "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==",
- "dev": true,
- "license": "Apache-2.0",
- "dependencies": {
- "@eslint/object-schema": "^2.1.7",
- "debug": "^4.3.1",
- "minimatch": "^3.1.2"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- }
- },
- "node_modules/@eslint/config-helpers": {
- "version": "0.4.2",
- "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz",
- "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==",
- "dev": true,
- "license": "Apache-2.0",
- "dependencies": {
- "@eslint/core": "^0.17.0"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- }
- },
- "node_modules/@eslint/core": {
- "version": "0.17.0",
- "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz",
- "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==",
- "dev": true,
- "license": "Apache-2.0",
- "dependencies": {
- "@types/json-schema": "^7.0.15"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- }
- },
- "node_modules/@eslint/eslintrc": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz",
- "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "ajv": "^6.12.4",
- "debug": "^4.3.2",
- "espree": "^10.0.1",
- "globals": "^14.0.0",
- "ignore": "^5.2.0",
- "import-fresh": "^3.2.1",
- "js-yaml": "^4.1.1",
- "minimatch": "^3.1.2",
- "strip-json-comments": "^3.1.1"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/@eslint/js": {
- "version": "9.39.3",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.3.tgz",
- "integrity": "sha512-1B1VkCq6FuUNlQvlBYb+1jDu/gV297TIs/OeiaSR9l1H27SVW55ONE1e1Vp16NqP683+xEGzxYtv4XCiDPaQiw==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "url": "https://eslint.org/donate"
- }
- },
- "node_modules/@eslint/object-schema": {
- "version": "2.1.7",
- "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz",
- "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==",
- "dev": true,
- "license": "Apache-2.0",
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- }
- },
- "node_modules/@eslint/plugin-kit": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz",
- "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==",
- "dev": true,
- "license": "Apache-2.0",
- "dependencies": {
- "@eslint/core": "^0.17.0",
- "levn": "^0.4.1"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- }
- },
- "node_modules/@humanfs/core": {
- "version": "0.19.1",
- "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
- "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==",
- "dev": true,
- "license": "Apache-2.0",
- "engines": {
- "node": ">=18.18.0"
- }
- },
- "node_modules/@humanfs/node": {
- "version": "0.16.7",
- "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz",
- "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==",
- "dev": true,
- "license": "Apache-2.0",
- "dependencies": {
- "@humanfs/core": "^0.19.1",
- "@humanwhocodes/retry": "^0.4.0"
- },
- "engines": {
- "node": ">=18.18.0"
- }
- },
- "node_modules/@humanwhocodes/module-importer": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
- "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
- "dev": true,
- "license": "Apache-2.0",
- "engines": {
- "node": ">=12.22"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/nzakas"
- }
- },
- "node_modules/@humanwhocodes/retry": {
- "version": "0.4.3",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz",
- "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==",
- "dev": true,
- "license": "Apache-2.0",
- "engines": {
- "node": ">=18.18"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/nzakas"
- }
- },
- "node_modules/@inquirer/ansi": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.2.tgz",
- "integrity": "sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==",
- "license": "MIT",
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@inquirer/checkbox": {
- "version": "4.3.2",
- "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.3.2.tgz",
- "integrity": "sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==",
- "license": "MIT",
- "dependencies": {
- "@inquirer/ansi": "^1.0.2",
- "@inquirer/core": "^10.3.2",
- "@inquirer/figures": "^1.0.15",
- "@inquirer/type": "^3.0.10",
- "yoctocolors-cjs": "^2.1.3"
- },
- "engines": {
- "node": ">=18"
- },
- "peerDependencies": {
- "@types/node": ">=18"
- },
- "peerDependenciesMeta": {
- "@types/node": {
- "optional": true
- }
- }
- },
- "node_modules/@inquirer/confirm": {
- "version": "5.1.21",
- "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.21.tgz",
- "integrity": "sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==",
- "license": "MIT",
- "dependencies": {
- "@inquirer/core": "^10.3.2",
- "@inquirer/type": "^3.0.10"
- },
- "engines": {
- "node": ">=18"
- },
- "peerDependencies": {
- "@types/node": ">=18"
- },
- "peerDependenciesMeta": {
- "@types/node": {
- "optional": true
- }
- }
- },
- "node_modules/@inquirer/core": {
- "version": "10.3.2",
- "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.2.tgz",
- "integrity": "sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==",
- "license": "MIT",
- "dependencies": {
- "@inquirer/ansi": "^1.0.2",
- "@inquirer/figures": "^1.0.15",
- "@inquirer/type": "^3.0.10",
- "cli-width": "^4.1.0",
- "mute-stream": "^2.0.0",
- "signal-exit": "^4.1.0",
- "wrap-ansi": "^6.2.0",
- "yoctocolors-cjs": "^2.1.3"
- },
- "engines": {
- "node": ">=18"
- },
- "peerDependencies": {
- "@types/node": ">=18"
- },
- "peerDependenciesMeta": {
- "@types/node": {
- "optional": true
- }
- }
- },
- "node_modules/@inquirer/editor": {
- "version": "4.2.23",
- "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.23.tgz",
- "integrity": "sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==",
- "license": "MIT",
- "dependencies": {
- "@inquirer/core": "^10.3.2",
- "@inquirer/external-editor": "^1.0.3",
- "@inquirer/type": "^3.0.10"
- },
- "engines": {
- "node": ">=18"
- },
- "peerDependencies": {
- "@types/node": ">=18"
- },
- "peerDependenciesMeta": {
- "@types/node": {
- "optional": true
- }
- }
- },
- "node_modules/@inquirer/expand": {
- "version": "4.0.23",
- "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.23.tgz",
- "integrity": "sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==",
- "license": "MIT",
- "dependencies": {
- "@inquirer/core": "^10.3.2",
- "@inquirer/type": "^3.0.10",
- "yoctocolors-cjs": "^2.1.3"
- },
- "engines": {
- "node": ">=18"
- },
- "peerDependencies": {
- "@types/node": ">=18"
- },
- "peerDependenciesMeta": {
- "@types/node": {
- "optional": true
- }
- }
- },
- "node_modules/@inquirer/external-editor": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz",
- "integrity": "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==",
- "license": "MIT",
- "dependencies": {
- "chardet": "^2.1.1",
- "iconv-lite": "^0.7.0"
- },
- "engines": {
- "node": ">=18"
- },
- "peerDependencies": {
- "@types/node": ">=18"
- },
- "peerDependenciesMeta": {
- "@types/node": {
- "optional": true
- }
- }
- },
- "node_modules/@inquirer/figures": {
- "version": "1.0.15",
- "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.15.tgz",
- "integrity": "sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==",
- "license": "MIT",
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@inquirer/input": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.3.1.tgz",
- "integrity": "sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==",
- "license": "MIT",
- "dependencies": {
- "@inquirer/core": "^10.3.2",
- "@inquirer/type": "^3.0.10"
- },
- "engines": {
- "node": ">=18"
- },
- "peerDependencies": {
- "@types/node": ">=18"
- },
- "peerDependenciesMeta": {
- "@types/node": {
- "optional": true
- }
- }
- },
- "node_modules/@inquirer/number": {
- "version": "3.0.23",
- "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.23.tgz",
- "integrity": "sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==",
- "license": "MIT",
- "dependencies": {
- "@inquirer/core": "^10.3.2",
- "@inquirer/type": "^3.0.10"
- },
- "engines": {
- "node": ">=18"
- },
- "peerDependencies": {
- "@types/node": ">=18"
- },
- "peerDependenciesMeta": {
- "@types/node": {
- "optional": true
- }
- }
- },
- "node_modules/@inquirer/password": {
- "version": "4.0.23",
- "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.23.tgz",
- "integrity": "sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==",
- "license": "MIT",
- "dependencies": {
- "@inquirer/ansi": "^1.0.2",
- "@inquirer/core": "^10.3.2",
- "@inquirer/type": "^3.0.10"
- },
- "engines": {
- "node": ">=18"
- },
- "peerDependencies": {
- "@types/node": ">=18"
- },
- "peerDependenciesMeta": {
- "@types/node": {
- "optional": true
- }
- }
- },
- "node_modules/@inquirer/prompts": {
- "version": "7.10.1",
- "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.10.1.tgz",
- "integrity": "sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==",
- "license": "MIT",
- "dependencies": {
- "@inquirer/checkbox": "^4.3.2",
- "@inquirer/confirm": "^5.1.21",
- "@inquirer/editor": "^4.2.23",
- "@inquirer/expand": "^4.0.23",
- "@inquirer/input": "^4.3.1",
- "@inquirer/number": "^3.0.23",
- "@inquirer/password": "^4.0.23",
- "@inquirer/rawlist": "^4.1.11",
- "@inquirer/search": "^3.2.2",
- "@inquirer/select": "^4.4.2"
- },
- "engines": {
- "node": ">=18"
- },
- "peerDependencies": {
- "@types/node": ">=18"
- },
- "peerDependenciesMeta": {
- "@types/node": {
- "optional": true
- }
- }
- },
- "node_modules/@inquirer/rawlist": {
- "version": "4.1.11",
- "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.11.tgz",
- "integrity": "sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==",
- "license": "MIT",
- "dependencies": {
- "@inquirer/core": "^10.3.2",
- "@inquirer/type": "^3.0.10",
- "yoctocolors-cjs": "^2.1.3"
- },
- "engines": {
- "node": ">=18"
- },
- "peerDependencies": {
- "@types/node": ">=18"
- },
- "peerDependenciesMeta": {
- "@types/node": {
- "optional": true
- }
- }
- },
- "node_modules/@inquirer/search": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.2.2.tgz",
- "integrity": "sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==",
- "license": "MIT",
- "dependencies": {
- "@inquirer/core": "^10.3.2",
- "@inquirer/figures": "^1.0.15",
- "@inquirer/type": "^3.0.10",
- "yoctocolors-cjs": "^2.1.3"
- },
- "engines": {
- "node": ">=18"
- },
- "peerDependencies": {
- "@types/node": ">=18"
- },
- "peerDependenciesMeta": {
- "@types/node": {
- "optional": true
- }
- }
- },
- "node_modules/@inquirer/select": {
- "version": "4.4.2",
- "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.4.2.tgz",
- "integrity": "sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==",
- "license": "MIT",
- "dependencies": {
- "@inquirer/ansi": "^1.0.2",
- "@inquirer/core": "^10.3.2",
- "@inquirer/figures": "^1.0.15",
- "@inquirer/type": "^3.0.10",
- "yoctocolors-cjs": "^2.1.3"
- },
- "engines": {
- "node": ">=18"
- },
- "peerDependencies": {
- "@types/node": ">=18"
- },
- "peerDependenciesMeta": {
- "@types/node": {
- "optional": true
- }
- }
- },
- "node_modules/@inquirer/type": {
- "version": "3.0.10",
- "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.10.tgz",
- "integrity": "sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==",
- "license": "MIT",
- "engines": {
- "node": ">=18"
- },
- "peerDependencies": {
- "@types/node": ">=18"
- },
- "peerDependenciesMeta": {
- "@types/node": {
- "optional": true
- }
- }
- },
- "node_modules/@jridgewell/sourcemap-codec": {
- "version": "1.5.5",
- "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
- "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@manypkg/find-root": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@manypkg/find-root/-/find-root-1.1.0.tgz",
- "integrity": "sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/runtime": "^7.5.5",
- "@types/node": "^12.7.1",
- "find-up": "^4.1.0",
- "fs-extra": "^8.1.0"
- }
- },
- "node_modules/@manypkg/find-root/node_modules/@types/node": {
- "version": "12.20.55",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz",
- "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@manypkg/find-root/node_modules/fs-extra": {
- "version": "8.1.0",
- "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
- "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "graceful-fs": "^4.2.0",
- "jsonfile": "^4.0.0",
- "universalify": "^0.1.0"
- },
- "engines": {
- "node": ">=6 <7 || >=8"
- }
- },
- "node_modules/@manypkg/get-packages": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/@manypkg/get-packages/-/get-packages-1.1.3.tgz",
- "integrity": "sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/runtime": "^7.5.5",
- "@changesets/types": "^4.0.1",
- "@manypkg/find-root": "^1.1.0",
- "fs-extra": "^8.1.0",
- "globby": "^11.0.0",
- "read-yaml-file": "^1.1.0"
- }
- },
- "node_modules/@manypkg/get-packages/node_modules/@changesets/types": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/@changesets/types/-/types-4.1.0.tgz",
- "integrity": "sha512-LDQvVDv5Kb50ny2s25Fhm3d9QSZimsoUGBsUioj6MC3qbMUCuC8GPIvk/M6IvXx3lYhAs0lwWUQLb+VIEUCECw==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@manypkg/get-packages/node_modules/fs-extra": {
- "version": "8.1.0",
- "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
- "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "graceful-fs": "^4.2.0",
- "jsonfile": "^4.0.0",
- "universalify": "^0.1.0"
- },
- "engines": {
- "node": ">=6 <7 || >=8"
- }
- },
- "node_modules/@nodelib/fs.scandir": {
- "version": "2.1.5",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
- "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
- "license": "MIT",
- "dependencies": {
- "@nodelib/fs.stat": "2.0.5",
- "run-parallel": "^1.1.9"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/@nodelib/fs.stat": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
- "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
- "license": "MIT",
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/@nodelib/fs.walk": {
- "version": "1.2.8",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
- "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
- "license": "MIT",
- "dependencies": {
- "@nodelib/fs.scandir": "2.1.5",
- "fastq": "^1.6.0"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/@polka/url": {
- "version": "1.0.0-next.29",
- "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz",
- "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@posthog/core": {
- "version": "1.23.1",
- "resolved": "https://registry.npmjs.org/@posthog/core/-/core-1.23.1.tgz",
- "integrity": "sha512-GViD5mOv/mcbZcyzz3z9CS0R79JzxVaqEz4sP5Dsea178M/j3ZWe6gaHDZB9yuyGfcmIMQ/8K14yv+7QrK4sQQ==",
- "license": "MIT",
- "dependencies": {
- "cross-spawn": "^7.0.6"
- }
- },
- "node_modules/@rollup/rollup-android-arm-eabi": {
- "version": "4.58.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.58.0.tgz",
- "integrity": "sha512-mr0tmS/4FoVk1cnaeN244A/wjvGDNItZKR8hRhnmCzygyRXYtKF5jVDSIILR1U97CTzAYmbgIj/Dukg62ggG5w==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "android"
- ]
- },
- "node_modules/@rollup/rollup-android-arm64": {
- "version": "4.58.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.58.0.tgz",
- "integrity": "sha512-+s++dbp+/RTte62mQD9wLSbiMTV+xr/PeRJEc/sFZFSBRlHPNPVaf5FXlzAL77Mr8FtSfQqCN+I598M8U41ccQ==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "android"
- ]
- },
- "node_modules/@rollup/rollup-darwin-arm64": {
- "version": "4.58.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.58.0.tgz",
- "integrity": "sha512-MFWBwTcYs0jZbINQBXHfSrpSQJq3IUOakcKPzfeSznONop14Pxuqa0Kg19GD0rNBMPQI2tFtu3UzapZpH0Uc1Q==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "darwin"
- ]
- },
- "node_modules/@rollup/rollup-darwin-x64": {
- "version": "4.58.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.58.0.tgz",
- "integrity": "sha512-yiKJY7pj9c9JwzuKYLFaDZw5gma3fI9bkPEIyofvVfsPqjCWPglSHdpdwXpKGvDeYDms3Qal8qGMEHZ1M/4Udg==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "darwin"
- ]
- },
- "node_modules/@rollup/rollup-freebsd-arm64": {
- "version": "4.58.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.58.0.tgz",
- "integrity": "sha512-x97kCoBh5MOevpn/CNK9W1x8BEzO238541BGWBc315uOlN0AD/ifZ1msg+ZQB05Ux+VF6EcYqpiagfLJ8U3LvQ==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "freebsd"
- ]
- },
- "node_modules/@rollup/rollup-freebsd-x64": {
- "version": "4.58.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.58.0.tgz",
- "integrity": "sha512-Aa8jPoZ6IQAG2eIrcXPpjRcMjROMFxCt1UYPZZtCxRV68WkuSigYtQ/7Zwrcr2IvtNJo7T2JfDXyMLxq5L4Jlg==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "freebsd"
- ]
- },
- "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
- "version": "4.58.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.58.0.tgz",
- "integrity": "sha512-Ob8YgT5kD/lSIYW2Rcngs5kNB/44Q2RzBSPz9brf2WEtcGR7/f/E9HeHn1wYaAwKBni+bdXEwgHvUd0x12lQSA==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@rollup/rollup-linux-arm-musleabihf": {
- "version": "4.58.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.58.0.tgz",
- "integrity": "sha512-K+RI5oP1ceqoadvNt1FecL17Qtw/n9BgRSzxif3rTL2QlIu88ccvY+Y9nnHe/cmT5zbH9+bpiJuG1mGHRVwF4Q==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@rollup/rollup-linux-arm64-gnu": {
- "version": "4.58.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.58.0.tgz",
- "integrity": "sha512-T+17JAsCKUjmbopcKepJjHWHXSjeW7O5PL7lEFaeQmiVyw4kkc5/lyYKzrv6ElWRX/MrEWfPiJWqbTvfIvjM1Q==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@rollup/rollup-linux-arm64-musl": {
- "version": "4.58.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.58.0.tgz",
- "integrity": "sha512-cCePktb9+6R9itIJdeCFF9txPU7pQeEHB5AbHu/MKsfH/k70ZtOeq1k4YAtBv9Z7mmKI5/wOLYjQ+B9QdxR6LA==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@rollup/rollup-linux-loong64-gnu": {
- "version": "4.58.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.58.0.tgz",
- "integrity": "sha512-iekUaLkfliAsDl4/xSdoCJ1gnnIXvoNz85C8U8+ZxknM5pBStfZjeXgB8lXobDQvvPRCN8FPmmuTtH+z95HTmg==",
- "cpu": [
- "loong64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@rollup/rollup-linux-loong64-musl": {
- "version": "4.58.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.58.0.tgz",
- "integrity": "sha512-68ofRgJNl/jYJbxFjCKE7IwhbfxOl1muPN4KbIqAIe32lm22KmU7E8OPvyy68HTNkI2iV/c8y2kSPSm2mW/Q9Q==",
- "cpu": [
- "loong64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@rollup/rollup-linux-ppc64-gnu": {
- "version": "4.58.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.58.0.tgz",
- "integrity": "sha512-dpz8vT0i+JqUKuSNPCP5SYyIV2Lh0sNL1+FhM7eLC457d5B9/BC3kDPp5BBftMmTNsBarcPcoz5UGSsnCiw4XQ==",
- "cpu": [
- "ppc64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@rollup/rollup-linux-ppc64-musl": {
- "version": "4.58.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.58.0.tgz",
- "integrity": "sha512-4gdkkf9UJ7tafnweBCR/mk4jf3Jfl0cKX9Np80t5i78kjIH0ZdezUv/JDI2VtruE5lunfACqftJ8dIMGN4oHew==",
- "cpu": [
- "ppc64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@rollup/rollup-linux-riscv64-gnu": {
- "version": "4.58.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.58.0.tgz",
- "integrity": "sha512-YFS4vPnOkDTD/JriUeeZurFYoJhPf9GQQEF/v4lltp3mVcBmnsAdjEWhr2cjUCZzZNzxCG0HZOvJU44UGHSdzw==",
- "cpu": [
- "riscv64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@rollup/rollup-linux-riscv64-musl": {
- "version": "4.58.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.58.0.tgz",
- "integrity": "sha512-x2xgZlFne+QVNKV8b4wwaCS8pwq3y14zedZ5DqLzjdRITvreBk//4Knbcvm7+lWmms9V9qFp60MtUd0/t/PXPw==",
- "cpu": [
- "riscv64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@rollup/rollup-linux-s390x-gnu": {
- "version": "4.58.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.58.0.tgz",
- "integrity": "sha512-jIhrujyn4UnWF8S+DHSkAkDEO3hLX0cjzxJZPLF80xFyzyUIYgSMRcYQ3+uqEoyDD2beGq7Dj7edi8OnJcS/hg==",
- "cpu": [
- "s390x"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@rollup/rollup-linux-x64-gnu": {
- "version": "4.58.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.58.0.tgz",
- "integrity": "sha512-+410Srdoh78MKSJxTQ+hZ/Mx+ajd6RjjPwBPNd0R3J9FtL6ZA0GqiiyNjCO9In0IzZkCNrpGymSfn+kgyPQocg==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@rollup/rollup-linux-x64-musl": {
- "version": "4.58.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.58.0.tgz",
- "integrity": "sha512-ZjMyby5SICi227y1MTR3VYBpFTdZs823Rs/hpakufleBoufoOIB6jtm9FEoxn/cgO7l6PM2rCEl5Kre5vX0QrQ==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@rollup/rollup-openbsd-x64": {
- "version": "4.58.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.58.0.tgz",
- "integrity": "sha512-ds4iwfYkSQ0k1nb8LTcyXw//ToHOnNTJtceySpL3fa7tc/AsE+UpUFphW126A6fKBGJD5dhRvg8zw1rvoGFxmw==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "openbsd"
- ]
- },
- "node_modules/@rollup/rollup-openharmony-arm64": {
- "version": "4.58.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.58.0.tgz",
- "integrity": "sha512-fd/zpJniln4ICdPkjWFhZYeY/bpnaN9pGa6ko+5WD38I0tTqk9lXMgXZg09MNdhpARngmxiCg0B0XUamNw/5BQ==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "openharmony"
- ]
- },
- "node_modules/@rollup/rollup-win32-arm64-msvc": {
- "version": "4.58.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.58.0.tgz",
- "integrity": "sha512-YpG8dUOip7DCz3nr/JUfPbIUo+2d/dy++5bFzgi4ugOGBIox+qMbbqt/JoORwvI/C9Kn2tz6+Bieoqd5+B1CjA==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "win32"
- ]
- },
- "node_modules/@rollup/rollup-win32-ia32-msvc": {
- "version": "4.58.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.58.0.tgz",
- "integrity": "sha512-b9DI8jpFQVh4hIXFr0/+N/TzLdpBIoPzjt0Rt4xJbW3mzguV3mduR9cNgiuFcuL/TeORejJhCWiAXe3E/6PxWA==",
- "cpu": [
- "ia32"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "win32"
- ]
- },
- "node_modules/@rollup/rollup-win32-x64-gnu": {
- "version": "4.58.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.58.0.tgz",
- "integrity": "sha512-CSrVpmoRJFN06LL9xhkitkwUcTZtIotYAF5p6XOR2zW0Zz5mzb3IPpcoPhB02frzMHFNo1reQ9xSF5fFm3hUsQ==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "win32"
- ]
- },
- "node_modules/@rollup/rollup-win32-x64-msvc": {
- "version": "4.58.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.58.0.tgz",
- "integrity": "sha512-QFsBgQNTnh5K0t/sBsjJLq24YVqEIVkGpfN2VHsnN90soZyhaiA9UUHufcctVNL4ypJY0wrwad0wslx2KJQ1/w==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "win32"
- ]
- },
- "node_modules/@types/chai": {
- "version": "5.2.3",
- "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz",
- "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/deep-eql": "*",
- "assertion-error": "^2.0.1"
- }
- },
- "node_modules/@types/deep-eql": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz",
- "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@types/estree": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
- "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@types/json-schema": {
- "version": "7.0.15",
- "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
- "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@types/node": {
- "version": "24.10.13",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.13.tgz",
- "integrity": "sha512-oH72nZRfDv9lADUBSo104Aq7gPHpQZc4BTx38r9xf9pg5LfP6EzSyH2n7qFmmxRQXh7YlUXODcYsg6PuTDSxGg==",
- "devOptional": true,
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "undici-types": "~7.16.0"
- }
- },
- "node_modules/@typescript-eslint/eslint-plugin": {
- "version": "8.56.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.56.0.tgz",
- "integrity": "sha512-lRyPDLzNCuae71A3t9NEINBiTn7swyOhvUj3MyUOxb8x6g6vPEFoOU+ZRmGMusNC3X3YMhqMIX7i8ShqhT74Pw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@eslint-community/regexpp": "^4.12.2",
- "@typescript-eslint/scope-manager": "8.56.0",
- "@typescript-eslint/type-utils": "8.56.0",
- "@typescript-eslint/utils": "8.56.0",
- "@typescript-eslint/visitor-keys": "8.56.0",
- "ignore": "^7.0.5",
- "natural-compare": "^1.4.0",
- "ts-api-utils": "^2.4.0"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "@typescript-eslint/parser": "^8.56.0",
- "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
- "typescript": ">=4.8.4 <6.0.0"
- }
- },
- "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": {
- "version": "7.0.5",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz",
- "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 4"
- }
- },
- "node_modules/@typescript-eslint/parser": {
- "version": "8.56.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.56.0.tgz",
- "integrity": "sha512-IgSWvLobTDOjnaxAfDTIHaECbkNlAlKv2j5SjpB2v7QHKv1FIfjwMy8FsDbVfDX/KjmCmYICcw7uGaXLhtsLNg==",
- "dev": true,
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@typescript-eslint/scope-manager": "8.56.0",
- "@typescript-eslint/types": "8.56.0",
- "@typescript-eslint/typescript-estree": "8.56.0",
- "@typescript-eslint/visitor-keys": "8.56.0",
- "debug": "^4.4.3"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
- "typescript": ">=4.8.4 <6.0.0"
- }
- },
- "node_modules/@typescript-eslint/project-service": {
- "version": "8.56.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.0.tgz",
- "integrity": "sha512-M3rnyL1vIQOMeWxTWIW096/TtVP+8W3p/XnaFflhmcFp+U4zlxUxWj4XwNs6HbDeTtN4yun0GNTTDBw/SvufKg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@typescript-eslint/tsconfig-utils": "^8.56.0",
- "@typescript-eslint/types": "^8.56.0",
- "debug": "^4.4.3"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "typescript": ">=4.8.4 <6.0.0"
- }
- },
- "node_modules/@typescript-eslint/scope-manager": {
- "version": "8.56.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.56.0.tgz",
- "integrity": "sha512-7UiO/XwMHquH+ZzfVCfUNkIXlp/yQjjnlYUyYz7pfvlK3/EyyN6BK+emDmGNyQLBtLGaYrTAI6KOw8tFucWL2w==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@typescript-eslint/types": "8.56.0",
- "@typescript-eslint/visitor-keys": "8.56.0"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/@typescript-eslint/tsconfig-utils": {
- "version": "8.56.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.0.tgz",
- "integrity": "sha512-bSJoIIt4o3lKXD3xmDh9chZcjCz5Lk8xS7Rxn+6l5/pKrDpkCwtQNQQwZ2qRPk7TkUYhrq3WPIHXOXlbXP0itg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "typescript": ">=4.8.4 <6.0.0"
- }
- },
- "node_modules/@typescript-eslint/type-utils": {
- "version": "8.56.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.56.0.tgz",
- "integrity": "sha512-qX2L3HWOU2nuDs6GzglBeuFXviDODreS58tLY/BALPC7iu3Fa+J7EOTwnX9PdNBxUI7Uh0ntP0YWGnxCkXzmfA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@typescript-eslint/types": "8.56.0",
- "@typescript-eslint/typescript-estree": "8.56.0",
- "@typescript-eslint/utils": "8.56.0",
- "debug": "^4.4.3",
- "ts-api-utils": "^2.4.0"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
- "typescript": ">=4.8.4 <6.0.0"
- }
- },
- "node_modules/@typescript-eslint/types": {
- "version": "8.56.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.0.tgz",
- "integrity": "sha512-DBsLPs3GsWhX5HylbP9HNG15U0bnwut55Lx12bHB9MpXxQ+R5GC8MwQe+N1UFXxAeQDvEsEDY6ZYwX03K7Z6HQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/@typescript-eslint/typescript-estree": {
- "version": "8.56.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.0.tgz",
- "integrity": "sha512-ex1nTUMWrseMltXUHmR2GAQ4d+WjkZCT4f+4bVsps8QEdh0vlBsaCokKTPlnqBFqqGaxilDNJG7b8dolW2m43Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@typescript-eslint/project-service": "8.56.0",
- "@typescript-eslint/tsconfig-utils": "8.56.0",
- "@typescript-eslint/types": "8.56.0",
- "@typescript-eslint/visitor-keys": "8.56.0",
- "debug": "^4.4.3",
- "minimatch": "^9.0.5",
- "semver": "^7.7.3",
- "tinyglobby": "^0.2.15",
- "ts-api-utils": "^2.4.0"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "typescript": ">=4.8.4 <6.0.0"
- }
- },
- "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
- "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "balanced-match": "^1.0.0"
- }
- },
- "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
- "version": "9.0.5",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
- "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "brace-expansion": "^2.0.1"
- },
- "engines": {
- "node": ">=16 || 14 >=14.17"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/@typescript-eslint/utils": {
- "version": "8.56.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.56.0.tgz",
- "integrity": "sha512-RZ3Qsmi2nFGsS+n+kjLAYDPVlrzf7UhTffrDIKr+h2yzAlYP/y5ZulU0yeDEPItos2Ph46JAL5P/On3pe7kDIQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@eslint-community/eslint-utils": "^4.9.1",
- "@typescript-eslint/scope-manager": "8.56.0",
- "@typescript-eslint/types": "8.56.0",
- "@typescript-eslint/typescript-estree": "8.56.0"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
- "typescript": ">=4.8.4 <6.0.0"
- }
- },
- "node_modules/@typescript-eslint/visitor-keys": {
- "version": "8.56.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.0.tgz",
- "integrity": "sha512-q+SL+b+05Ud6LbEE35qe4A99P+htKTKVbyiNEe45eCbJFyh/HVK9QXwlrbz+Q4L8SOW4roxSVwXYj4DMBT7Ieg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@typescript-eslint/types": "8.56.0",
- "eslint-visitor-keys": "^5.0.0"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz",
- "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==",
- "dev": true,
- "license": "Apache-2.0",
- "engines": {
- "node": "^20.19.0 || ^22.13.0 || >=24"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/@vitest/expect": {
- "version": "3.2.4",
- "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz",
- "integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/chai": "^5.2.2",
- "@vitest/spy": "3.2.4",
- "@vitest/utils": "3.2.4",
- "chai": "^5.2.0",
- "tinyrainbow": "^2.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/vitest"
- }
- },
- "node_modules/@vitest/mocker": {
- "version": "3.2.4",
- "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.4.tgz",
- "integrity": "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@vitest/spy": "3.2.4",
- "estree-walker": "^3.0.3",
- "magic-string": "^0.30.17"
- },
- "funding": {
- "url": "https://opencollective.com/vitest"
- },
- "peerDependencies": {
- "msw": "^2.4.9",
- "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0"
- },
- "peerDependenciesMeta": {
- "msw": {
- "optional": true
- },
- "vite": {
- "optional": true
- }
- }
- },
- "node_modules/@vitest/pretty-format": {
- "version": "3.2.4",
- "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz",
- "integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "tinyrainbow": "^2.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/vitest"
- }
- },
- "node_modules/@vitest/runner": {
- "version": "3.2.4",
- "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.4.tgz",
- "integrity": "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@vitest/utils": "3.2.4",
- "pathe": "^2.0.3",
- "strip-literal": "^3.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/vitest"
- }
- },
- "node_modules/@vitest/snapshot": {
- "version": "3.2.4",
- "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.4.tgz",
- "integrity": "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@vitest/pretty-format": "3.2.4",
- "magic-string": "^0.30.17",
- "pathe": "^2.0.3"
- },
- "funding": {
- "url": "https://opencollective.com/vitest"
- }
- },
- "node_modules/@vitest/spy": {
- "version": "3.2.4",
- "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz",
- "integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "tinyspy": "^4.0.3"
- },
- "funding": {
- "url": "https://opencollective.com/vitest"
- }
- },
- "node_modules/@vitest/ui": {
- "version": "3.2.4",
- "resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-3.2.4.tgz",
- "integrity": "sha512-hGISOaP18plkzbWEcP/QvtRW1xDXF2+96HbEX6byqQhAUbiS5oH6/9JwW+QsQCIYON2bI6QZBF+2PvOmrRZ9wA==",
- "dev": true,
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@vitest/utils": "3.2.4",
- "fflate": "^0.8.2",
- "flatted": "^3.3.3",
- "pathe": "^2.0.3",
- "sirv": "^3.0.1",
- "tinyglobby": "^0.2.14",
- "tinyrainbow": "^2.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/vitest"
- },
- "peerDependencies": {
- "vitest": "3.2.4"
- }
- },
- "node_modules/@vitest/utils": {
- "version": "3.2.4",
- "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz",
- "integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@vitest/pretty-format": "3.2.4",
- "loupe": "^3.1.4",
- "tinyrainbow": "^2.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/vitest"
- }
- },
- "node_modules/acorn": {
- "version": "8.16.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
- "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
- "dev": true,
- "license": "MIT",
- "peer": true,
- "bin": {
- "acorn": "bin/acorn"
- },
- "engines": {
- "node": ">=0.4.0"
- }
- },
- "node_modules/acorn-jsx": {
- "version": "5.3.2",
- "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
- "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
- "dev": true,
- "license": "MIT",
- "peerDependencies": {
- "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
- }
- },
- "node_modules/ajv": {
- "version": "6.14.0",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz",
- "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "fast-deep-equal": "^3.1.1",
- "fast-json-stable-stringify": "^2.0.0",
- "json-schema-traverse": "^0.4.1",
- "uri-js": "^4.2.2"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/epoberezkin"
- }
- },
- "node_modules/ansi-colors": {
- "version": "4.1.3",
- "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
- "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "license": "MIT",
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/argparse": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
- "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
- "dev": true,
- "license": "Python-2.0"
- },
- "node_modules/array-union": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
- "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/assertion-error": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz",
- "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/balanced-match": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
- "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/better-path-resolve": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/better-path-resolve/-/better-path-resolve-1.0.0.tgz",
- "integrity": "sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "is-windows": "^1.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/brace-expansion": {
- "version": "1.1.12",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
- "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
- }
- },
- "node_modules/braces": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
- "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
- "license": "MIT",
- "dependencies": {
- "fill-range": "^7.1.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/cac": {
- "version": "6.7.14",
- "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
- "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/callsites": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
- "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/chai": {
- "version": "5.3.3",
- "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz",
- "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "assertion-error": "^2.0.1",
- "check-error": "^2.1.1",
- "deep-eql": "^5.0.1",
- "loupe": "^3.1.0",
- "pathval": "^2.0.0"
- },
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/chalk": {
- "version": "5.6.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz",
- "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==",
- "license": "MIT",
- "engines": {
- "node": "^12.17.0 || ^14.13 || >=16.0.0"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/chardet": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.1.tgz",
- "integrity": "sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==",
- "license": "MIT"
- },
- "node_modules/check-error": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz",
- "integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 16"
- }
- },
- "node_modules/ci-info": {
- "version": "3.9.0",
- "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz",
- "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/sibiraj-s"
- }
- ],
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/cli-cursor": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz",
- "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==",
- "license": "MIT",
- "dependencies": {
- "restore-cursor": "^5.0.0"
- },
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/cli-spinners": {
- "version": "2.9.2",
- "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz",
- "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==",
- "license": "MIT",
- "engines": {
- "node": ">=6"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/cli-width": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz",
- "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==",
- "license": "ISC",
- "engines": {
- "node": ">= 12"
- }
- },
- "node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "license": "MIT",
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "license": "MIT"
- },
- "node_modules/commander": {
- "version": "14.0.3",
- "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz",
- "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==",
- "license": "MIT",
- "engines": {
- "node": ">=20"
- }
- },
- "node_modules/concat-map": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/cross-spawn": {
- "version": "7.0.6",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
- "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
- "license": "MIT",
- "dependencies": {
- "path-key": "^3.1.0",
- "shebang-command": "^2.0.0",
- "which": "^2.0.1"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/dataloader": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/dataloader/-/dataloader-1.4.0.tgz",
- "integrity": "sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==",
- "dev": true,
- "license": "BSD-3-Clause"
- },
- "node_modules/debug": {
- "version": "4.4.3",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
- "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "ms": "^2.1.3"
- },
- "engines": {
- "node": ">=6.0"
- },
- "peerDependenciesMeta": {
- "supports-color": {
- "optional": true
- }
- }
- },
- "node_modules/deep-eql": {
- "version": "5.0.2",
- "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz",
- "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/deep-is": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
- "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/detect-indent": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz",
- "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/dir-glob": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
- "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "path-type": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/dotenv": {
- "version": "8.6.0",
- "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz",
- "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==",
- "dev": true,
- "license": "BSD-2-Clause",
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/emoji-regex": {
- "version": "10.6.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz",
- "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==",
- "license": "MIT"
- },
- "node_modules/enquirer": {
- "version": "2.4.1",
- "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz",
- "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "ansi-colors": "^4.1.1",
- "strip-ansi": "^6.0.1"
- },
- "engines": {
- "node": ">=8.6"
- }
- },
- "node_modules/es-module-lexer": {
- "version": "1.7.0",
- "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz",
- "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/esbuild": {
- "version": "0.27.3",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz",
- "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==",
- "dev": true,
- "hasInstallScript": true,
- "license": "MIT",
- "bin": {
- "esbuild": "bin/esbuild"
- },
- "engines": {
- "node": ">=18"
- },
- "optionalDependencies": {
- "@esbuild/aix-ppc64": "0.27.3",
- "@esbuild/android-arm": "0.27.3",
- "@esbuild/android-arm64": "0.27.3",
- "@esbuild/android-x64": "0.27.3",
- "@esbuild/darwin-arm64": "0.27.3",
- "@esbuild/darwin-x64": "0.27.3",
- "@esbuild/freebsd-arm64": "0.27.3",
- "@esbuild/freebsd-x64": "0.27.3",
- "@esbuild/linux-arm": "0.27.3",
- "@esbuild/linux-arm64": "0.27.3",
- "@esbuild/linux-ia32": "0.27.3",
- "@esbuild/linux-loong64": "0.27.3",
- "@esbuild/linux-mips64el": "0.27.3",
- "@esbuild/linux-ppc64": "0.27.3",
- "@esbuild/linux-riscv64": "0.27.3",
- "@esbuild/linux-s390x": "0.27.3",
- "@esbuild/linux-x64": "0.27.3",
- "@esbuild/netbsd-arm64": "0.27.3",
- "@esbuild/netbsd-x64": "0.27.3",
- "@esbuild/openbsd-arm64": "0.27.3",
- "@esbuild/openbsd-x64": "0.27.3",
- "@esbuild/openharmony-arm64": "0.27.3",
- "@esbuild/sunos-x64": "0.27.3",
- "@esbuild/win32-arm64": "0.27.3",
- "@esbuild/win32-ia32": "0.27.3",
- "@esbuild/win32-x64": "0.27.3"
- }
- },
- "node_modules/escape-string-regexp": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
- "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/eslint": {
- "version": "9.39.3",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.3.tgz",
- "integrity": "sha512-VmQ+sifHUbI/IcSopBCF/HO3YiHQx/AVd3UVyYL6weuwW+HvON9VYn5l6Zl1WZzPWXPNZrSQpxwkkZ/VuvJZzg==",
- "dev": true,
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@eslint-community/eslint-utils": "^4.8.0",
- "@eslint-community/regexpp": "^4.12.1",
- "@eslint/config-array": "^0.21.1",
- "@eslint/config-helpers": "^0.4.2",
- "@eslint/core": "^0.17.0",
- "@eslint/eslintrc": "^3.3.1",
- "@eslint/js": "9.39.3",
- "@eslint/plugin-kit": "^0.4.1",
- "@humanfs/node": "^0.16.6",
- "@humanwhocodes/module-importer": "^1.0.1",
- "@humanwhocodes/retry": "^0.4.2",
- "@types/estree": "^1.0.6",
- "ajv": "^6.12.4",
- "chalk": "^4.0.0",
- "cross-spawn": "^7.0.6",
- "debug": "^4.3.2",
- "escape-string-regexp": "^4.0.0",
- "eslint-scope": "^8.4.0",
- "eslint-visitor-keys": "^4.2.1",
- "espree": "^10.4.0",
- "esquery": "^1.5.0",
- "esutils": "^2.0.2",
- "fast-deep-equal": "^3.1.3",
- "file-entry-cache": "^8.0.0",
- "find-up": "^5.0.0",
- "glob-parent": "^6.0.2",
- "ignore": "^5.2.0",
- "imurmurhash": "^0.1.4",
- "is-glob": "^4.0.0",
- "json-stable-stringify-without-jsonify": "^1.0.1",
- "lodash.merge": "^4.6.2",
- "minimatch": "^3.1.2",
- "natural-compare": "^1.4.0",
- "optionator": "^0.9.3"
- },
- "bin": {
- "eslint": "bin/eslint.js"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "url": "https://eslint.org/donate"
- },
- "peerDependencies": {
- "jiti": "*"
- },
- "peerDependenciesMeta": {
- "jiti": {
- "optional": true
- }
- }
- },
- "node_modules/eslint-scope": {
- "version": "8.4.0",
- "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz",
- "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==",
- "dev": true,
- "license": "BSD-2-Clause",
- "dependencies": {
- "esrecurse": "^4.3.0",
- "estraverse": "^5.2.0"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/eslint-visitor-keys": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
- "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
- "dev": true,
- "license": "Apache-2.0",
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/eslint/node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/eslint/node_modules/find-up": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
- "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "locate-path": "^6.0.0",
- "path-exists": "^4.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/eslint/node_modules/locate-path": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
- "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "p-locate": "^5.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/eslint/node_modules/p-limit": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
- "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "yocto-queue": "^0.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/eslint/node_modules/p-locate": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
- "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "p-limit": "^3.0.2"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/espree": {
- "version": "10.4.0",
- "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
- "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
- "dev": true,
- "license": "BSD-2-Clause",
- "dependencies": {
- "acorn": "^8.15.0",
- "acorn-jsx": "^5.3.2",
- "eslint-visitor-keys": "^4.2.1"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/esprima": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
- "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
- "dev": true,
- "license": "BSD-2-Clause",
- "bin": {
- "esparse": "bin/esparse.js",
- "esvalidate": "bin/esvalidate.js"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/esquery": {
- "version": "1.7.0",
- "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz",
- "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==",
- "dev": true,
- "license": "BSD-3-Clause",
- "dependencies": {
- "estraverse": "^5.1.0"
- },
- "engines": {
- "node": ">=0.10"
- }
- },
- "node_modules/esrecurse": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
- "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
- "dev": true,
- "license": "BSD-2-Clause",
- "dependencies": {
- "estraverse": "^5.2.0"
- },
- "engines": {
- "node": ">=4.0"
- }
- },
- "node_modules/estraverse": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
- "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
- "dev": true,
- "license": "BSD-2-Clause",
- "engines": {
- "node": ">=4.0"
- }
- },
- "node_modules/estree-walker": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
- "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/estree": "^1.0.0"
- }
- },
- "node_modules/esutils": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
- "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
- "dev": true,
- "license": "BSD-2-Clause",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/expect-type": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz",
- "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==",
- "dev": true,
- "license": "Apache-2.0",
- "engines": {
- "node": ">=12.0.0"
- }
- },
- "node_modules/extendable-error": {
- "version": "0.1.7",
- "resolved": "https://registry.npmjs.org/extendable-error/-/extendable-error-0.1.7.tgz",
- "integrity": "sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/fast-deep-equal": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
- "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/fast-glob": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
- "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
- "license": "MIT",
- "dependencies": {
- "@nodelib/fs.stat": "^2.0.2",
- "@nodelib/fs.walk": "^1.2.3",
- "glob-parent": "^5.1.2",
- "merge2": "^1.3.0",
- "micromatch": "^4.0.8"
- },
- "engines": {
- "node": ">=8.6.0"
- }
- },
- "node_modules/fast-glob/node_modules/glob-parent": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
- "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
- "license": "ISC",
- "dependencies": {
- "is-glob": "^4.0.1"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/fast-json-stable-stringify": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
- "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/fast-levenshtein": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
- "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/fastq": {
- "version": "1.20.1",
- "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz",
- "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==",
- "license": "ISC",
- "dependencies": {
- "reusify": "^1.0.4"
- }
- },
- "node_modules/fflate": {
- "version": "0.8.2",
- "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz",
- "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/file-entry-cache": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
- "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "flat-cache": "^4.0.0"
- },
- "engines": {
- "node": ">=16.0.0"
- }
- },
- "node_modules/fill-range": {
- "version": "7.1.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
- "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
- "license": "MIT",
- "dependencies": {
- "to-regex-range": "^5.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/find-up": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
- "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "locate-path": "^5.0.0",
- "path-exists": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/flat-cache": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
- "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "flatted": "^3.2.9",
- "keyv": "^4.5.4"
- },
- "engines": {
- "node": ">=16"
- }
- },
- "node_modules/flatted": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
- "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
- "dev": true,
- "license": "ISC"
- },
- "node_modules/fs-extra": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz",
- "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "graceful-fs": "^4.1.2",
- "jsonfile": "^4.0.0",
- "universalify": "^0.1.0"
- },
- "engines": {
- "node": ">=6 <7 || >=8"
- }
- },
- "node_modules/fsevents": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
- "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
- "dev": true,
- "hasInstallScript": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
- }
- },
- "node_modules/get-east-asian-width": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.5.0.tgz",
- "integrity": "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==",
- "license": "MIT",
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/glob-parent": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
- "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "is-glob": "^4.0.3"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/globals": {
- "version": "14.0.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
- "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/globby": {
- "version": "11.1.0",
- "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
- "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "array-union": "^2.1.0",
- "dir-glob": "^3.0.1",
- "fast-glob": "^3.2.9",
- "ignore": "^5.2.0",
- "merge2": "^1.4.1",
- "slash": "^3.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/graceful-fs": {
- "version": "4.2.11",
- "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
- "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
- "dev": true,
- "license": "ISC"
- },
- "node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/human-id": {
- "version": "4.1.3",
- "resolved": "https://registry.npmjs.org/human-id/-/human-id-4.1.3.tgz",
- "integrity": "sha512-tsYlhAYpjCKa//8rXZ9DqKEawhPoSytweBC2eNvcaDK+57RZLHGqNs3PZTQO6yekLFSuvA6AlnAfrw1uBvtb+Q==",
- "dev": true,
- "license": "MIT",
- "bin": {
- "human-id": "dist/cli.js"
- }
- },
- "node_modules/iconv-lite": {
- "version": "0.7.2",
- "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz",
- "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==",
- "license": "MIT",
- "dependencies": {
- "safer-buffer": ">= 2.1.2 < 3.0.0"
- },
- "engines": {
- "node": ">=0.10.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/express"
- }
- },
- "node_modules/ignore": {
- "version": "5.3.2",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
- "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 4"
- }
- },
- "node_modules/import-fresh": {
- "version": "3.3.1",
- "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
- "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "parent-module": "^1.0.0",
- "resolve-from": "^4.0.0"
- },
- "engines": {
- "node": ">=6"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/import-fresh/node_modules/resolve-from": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
- "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/imurmurhash": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
- "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.8.19"
- }
- },
- "node_modules/is-extglob": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
- "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/is-fullwidth-code-point": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/is-glob": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
- "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
- "license": "MIT",
- "dependencies": {
- "is-extglob": "^2.1.1"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/is-interactive": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz",
- "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==",
- "license": "MIT",
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/is-number": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
- "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
- "license": "MIT",
- "engines": {
- "node": ">=0.12.0"
- }
- },
- "node_modules/is-subdir": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/is-subdir/-/is-subdir-1.2.0.tgz",
- "integrity": "sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "better-path-resolve": "1.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/is-unicode-supported": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz",
- "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==",
- "license": "MIT",
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/is-windows": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
- "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/isexe": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
- "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
- "license": "ISC"
- },
- "node_modules/js-tokens": {
- "version": "9.0.1",
- "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz",
- "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/js-yaml": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
- "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "argparse": "^2.0.1"
- },
- "bin": {
- "js-yaml": "bin/js-yaml.js"
- }
- },
- "node_modules/json-buffer": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
- "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/json-schema-traverse": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
- "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/json-stable-stringify-without-jsonify": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
- "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/jsonfile": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
- "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==",
- "dev": true,
- "license": "MIT",
- "optionalDependencies": {
- "graceful-fs": "^4.1.6"
- }
- },
- "node_modules/keyv": {
- "version": "4.5.4",
- "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
- "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "json-buffer": "3.0.1"
- }
- },
- "node_modules/levn": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
- "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "prelude-ls": "^1.2.1",
- "type-check": "~0.4.0"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/locate-path": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
- "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "p-locate": "^4.1.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/lodash.merge": {
- "version": "4.6.2",
- "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
- "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/lodash.startcase": {
- "version": "4.4.0",
- "resolved": "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz",
- "integrity": "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/log-symbols": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz",
- "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==",
- "license": "MIT",
- "dependencies": {
- "chalk": "^5.3.0",
- "is-unicode-supported": "^1.3.0"
- },
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/log-symbols/node_modules/is-unicode-supported": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz",
- "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==",
- "license": "MIT",
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/loupe": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz",
- "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/magic-string": {
- "version": "0.30.21",
- "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
- "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@jridgewell/sourcemap-codec": "^1.5.5"
- }
- },
- "node_modules/merge2": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
- "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
- "license": "MIT",
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/micromatch": {
- "version": "4.0.8",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
- "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
- "license": "MIT",
- "dependencies": {
- "braces": "^3.0.3",
- "picomatch": "^2.3.1"
- },
- "engines": {
- "node": ">=8.6"
- }
- },
- "node_modules/mimic-function": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz",
- "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==",
- "license": "MIT",
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "brace-expansion": "^1.1.7"
- },
- "engines": {
- "node": "*"
- }
- },
- "node_modules/mri": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
- "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/mrmime": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz",
- "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/ms": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
- "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/mute-stream": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz",
- "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==",
- "license": "ISC",
- "engines": {
- "node": "^18.17.0 || >=20.5.0"
- }
- },
- "node_modules/nanoid": {
- "version": "3.3.11",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
- "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/ai"
- }
- ],
- "license": "MIT",
- "bin": {
- "nanoid": "bin/nanoid.cjs"
- },
- "engines": {
- "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
- }
- },
- "node_modules/natural-compare": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
- "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/node-fetch": {
- "version": "2.7.0",
- "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
- "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "whatwg-url": "^5.0.0"
- },
- "engines": {
- "node": "4.x || >=6.0.0"
- },
- "peerDependencies": {
- "encoding": "^0.1.0"
- },
- "peerDependenciesMeta": {
- "encoding": {
- "optional": true
- }
- }
- },
- "node_modules/onetime": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz",
- "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==",
- "license": "MIT",
- "dependencies": {
- "mimic-function": "^5.0.0"
- },
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/optionator": {
- "version": "0.9.4",
- "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
- "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "deep-is": "^0.1.3",
- "fast-levenshtein": "^2.0.6",
- "levn": "^0.4.1",
- "prelude-ls": "^1.2.1",
- "type-check": "^0.4.0",
- "word-wrap": "^1.2.5"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/ora": {
- "version": "8.2.0",
- "resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz",
- "integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==",
- "license": "MIT",
- "dependencies": {
- "chalk": "^5.3.0",
- "cli-cursor": "^5.0.0",
- "cli-spinners": "^2.9.2",
- "is-interactive": "^2.0.0",
- "is-unicode-supported": "^2.0.0",
- "log-symbols": "^6.0.0",
- "stdin-discarder": "^0.2.2",
- "string-width": "^7.2.0",
- "strip-ansi": "^7.1.0"
- },
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/ora/node_modules/ansi-regex": {
- "version": "6.2.2",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
- "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
- "license": "MIT",
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-regex?sponsor=1"
- }
- },
- "node_modules/ora/node_modules/strip-ansi": {
- "version": "7.1.2",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz",
- "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==",
- "license": "MIT",
- "dependencies": {
- "ansi-regex": "^6.0.1"
- },
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/chalk/strip-ansi?sponsor=1"
- }
- },
- "node_modules/outdent": {
- "version": "0.5.0",
- "resolved": "https://registry.npmjs.org/outdent/-/outdent-0.5.0.tgz",
- "integrity": "sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/p-filter": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/p-filter/-/p-filter-2.1.0.tgz",
- "integrity": "sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "p-map": "^2.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/p-limit": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
- "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "p-try": "^2.0.0"
- },
- "engines": {
- "node": ">=6"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/p-locate": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
- "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "p-limit": "^2.2.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/p-map": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz",
- "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/p-try": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
- "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/package-manager-detector": {
- "version": "0.2.11",
- "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-0.2.11.tgz",
- "integrity": "sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "quansync": "^0.2.7"
- }
- },
- "node_modules/parent-module": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
- "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "callsites": "^3.0.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/path-exists": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
- "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/path-key": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
- "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/path-type": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
- "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/pathe": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
- "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/pathval": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz",
- "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 14.16"
- }
- },
- "node_modules/picocolors": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
- "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
- "dev": true,
- "license": "ISC"
- },
- "node_modules/picomatch": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
- "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
- "license": "MIT",
- "engines": {
- "node": ">=8.6"
- },
- "funding": {
- "url": "https://github.com/sponsors/jonschlinkert"
- }
- },
- "node_modules/pify": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
- "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/postcss": {
- "version": "8.5.6",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
- "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
- "dev": true,
- "funding": [
- {
- "type": "opencollective",
- "url": "https://opencollective.com/postcss/"
- },
- {
- "type": "tidelift",
- "url": "https://tidelift.com/funding/github/npm/postcss"
- },
- {
- "type": "github",
- "url": "https://github.com/sponsors/ai"
- }
- ],
- "license": "MIT",
- "dependencies": {
- "nanoid": "^3.3.11",
- "picocolors": "^1.1.1",
- "source-map-js": "^1.2.1"
- },
- "engines": {
- "node": "^10 || ^12 || >=14"
- }
- },
- "node_modules/posthog-node": {
- "version": "5.24.17",
- "resolved": "https://registry.npmjs.org/posthog-node/-/posthog-node-5.24.17.tgz",
- "integrity": "sha512-mdb8TKt+YCRbGQdYar3AKNUPCyEiqcprScF4unYpGALF6HlBaEuO6wPuIqXXpCWkw4VclJYCKbb6lq6pH6bJeA==",
- "license": "MIT",
- "dependencies": {
- "@posthog/core": "1.23.1"
- },
- "engines": {
- "node": "^20.20.0 || >=22.22.0"
- }
- },
- "node_modules/prelude-ls": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
- "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/prettier": {
- "version": "2.8.8",
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
- "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
- "dev": true,
- "license": "MIT",
- "bin": {
- "prettier": "bin-prettier.js"
- },
- "engines": {
- "node": ">=10.13.0"
- },
- "funding": {
- "url": "https://github.com/prettier/prettier?sponsor=1"
- }
- },
- "node_modules/punycode": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
- "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/quansync": {
- "version": "0.2.11",
- "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz",
- "integrity": "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==",
- "dev": true,
- "funding": [
- {
- "type": "individual",
- "url": "https://github.com/sponsors/antfu"
- },
- {
- "type": "individual",
- "url": "https://github.com/sponsors/sxzz"
- }
- ],
- "license": "MIT"
- },
- "node_modules/queue-microtask": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
- "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "license": "MIT"
- },
- "node_modules/read-yaml-file": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/read-yaml-file/-/read-yaml-file-1.1.0.tgz",
- "integrity": "sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "graceful-fs": "^4.1.5",
- "js-yaml": "^3.6.1",
- "pify": "^4.0.1",
- "strip-bom": "^3.0.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/read-yaml-file/node_modules/argparse": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
- "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "sprintf-js": "~1.0.2"
- }
- },
- "node_modules/read-yaml-file/node_modules/js-yaml": {
- "version": "3.14.2",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz",
- "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "argparse": "^1.0.7",
- "esprima": "^4.0.0"
- },
- "bin": {
- "js-yaml": "bin/js-yaml.js"
- }
- },
- "node_modules/resolve-from": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
- "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/restore-cursor": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz",
- "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==",
- "license": "MIT",
- "dependencies": {
- "onetime": "^7.0.0",
- "signal-exit": "^4.1.0"
- },
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/reusify": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
- "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
- "license": "MIT",
- "engines": {
- "iojs": ">=1.0.0",
- "node": ">=0.10.0"
- }
- },
- "node_modules/rollup": {
- "version": "4.58.0",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.58.0.tgz",
- "integrity": "sha512-wbT0mBmWbIvvq8NeEYWWvevvxnOyhKChir47S66WCxw1SXqhw7ssIYejnQEVt7XYQpsj2y8F9PM+Cr3SNEa0gw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/estree": "1.0.8"
- },
- "bin": {
- "rollup": "dist/bin/rollup"
- },
- "engines": {
- "node": ">=18.0.0",
- "npm": ">=8.0.0"
- },
- "optionalDependencies": {
- "@rollup/rollup-android-arm-eabi": "4.58.0",
- "@rollup/rollup-android-arm64": "4.58.0",
- "@rollup/rollup-darwin-arm64": "4.58.0",
- "@rollup/rollup-darwin-x64": "4.58.0",
- "@rollup/rollup-freebsd-arm64": "4.58.0",
- "@rollup/rollup-freebsd-x64": "4.58.0",
- "@rollup/rollup-linux-arm-gnueabihf": "4.58.0",
- "@rollup/rollup-linux-arm-musleabihf": "4.58.0",
- "@rollup/rollup-linux-arm64-gnu": "4.58.0",
- "@rollup/rollup-linux-arm64-musl": "4.58.0",
- "@rollup/rollup-linux-loong64-gnu": "4.58.0",
- "@rollup/rollup-linux-loong64-musl": "4.58.0",
- "@rollup/rollup-linux-ppc64-gnu": "4.58.0",
- "@rollup/rollup-linux-ppc64-musl": "4.58.0",
- "@rollup/rollup-linux-riscv64-gnu": "4.58.0",
- "@rollup/rollup-linux-riscv64-musl": "4.58.0",
- "@rollup/rollup-linux-s390x-gnu": "4.58.0",
- "@rollup/rollup-linux-x64-gnu": "4.58.0",
- "@rollup/rollup-linux-x64-musl": "4.58.0",
- "@rollup/rollup-openbsd-x64": "4.58.0",
- "@rollup/rollup-openharmony-arm64": "4.58.0",
- "@rollup/rollup-win32-arm64-msvc": "4.58.0",
- "@rollup/rollup-win32-ia32-msvc": "4.58.0",
- "@rollup/rollup-win32-x64-gnu": "4.58.0",
- "@rollup/rollup-win32-x64-msvc": "4.58.0",
- "fsevents": "~2.3.2"
- }
- },
- "node_modules/run-parallel": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
- "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "license": "MIT",
- "dependencies": {
- "queue-microtask": "^1.2.2"
- }
- },
- "node_modules/safer-buffer": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
- "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
- "license": "MIT"
- },
- "node_modules/semver": {
- "version": "7.7.4",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
- "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
- "dev": true,
- "license": "ISC",
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/shebang-command": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
- "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
- "license": "MIT",
- "dependencies": {
- "shebang-regex": "^3.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/shebang-regex": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
- "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/siginfo": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz",
- "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==",
- "dev": true,
- "license": "ISC"
- },
- "node_modules/signal-exit": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
- "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
- "license": "ISC",
- "engines": {
- "node": ">=14"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/sirv": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz",
- "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@polka/url": "^1.0.0-next.24",
- "mrmime": "^2.0.0",
- "totalist": "^3.0.0"
- },
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/slash": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
- "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/source-map-js": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
- "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
- "dev": true,
- "license": "BSD-3-Clause",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/spawndamnit": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/spawndamnit/-/spawndamnit-3.0.1.tgz",
- "integrity": "sha512-MmnduQUuHCoFckZoWnXsTg7JaiLBJrKFj9UI2MbRPGaJeVpsLcVBu6P/IGZovziM/YBsellCmsprgNA+w0CzVg==",
- "dev": true,
- "license": "SEE LICENSE IN LICENSE",
- "dependencies": {
- "cross-spawn": "^7.0.5",
- "signal-exit": "^4.0.1"
- }
- },
- "node_modules/sprintf-js": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
- "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
- "dev": true,
- "license": "BSD-3-Clause"
- },
- "node_modules/stackback": {
- "version": "0.0.2",
- "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz",
- "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/std-env": {
- "version": "3.10.0",
- "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz",
- "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/stdin-discarder": {
- "version": "0.2.2",
- "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz",
- "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==",
- "license": "MIT",
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/string-width": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
- "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==",
- "license": "MIT",
- "dependencies": {
- "emoji-regex": "^10.3.0",
- "get-east-asian-width": "^1.0.0",
- "strip-ansi": "^7.1.0"
- },
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/string-width/node_modules/ansi-regex": {
- "version": "6.2.2",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
- "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
- "license": "MIT",
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-regex?sponsor=1"
- }
- },
- "node_modules/string-width/node_modules/strip-ansi": {
- "version": "7.1.2",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz",
- "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==",
- "license": "MIT",
- "dependencies": {
- "ansi-regex": "^6.0.1"
- },
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/chalk/strip-ansi?sponsor=1"
- }
- },
- "node_modules/strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "license": "MIT",
- "dependencies": {
- "ansi-regex": "^5.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/strip-bom": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
- "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/strip-json-comments": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
- "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/strip-literal": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.1.0.tgz",
- "integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "js-tokens": "^9.0.1"
- },
- "funding": {
- "url": "https://github.com/sponsors/antfu"
- }
- },
- "node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/term-size": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz",
- "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/tinybench": {
- "version": "2.9.0",
- "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz",
- "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/tinyexec": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz",
- "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/tinyglobby": {
- "version": "0.2.15",
- "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
- "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "fdir": "^6.5.0",
- "picomatch": "^4.0.3"
- },
- "engines": {
- "node": ">=12.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/SuperchupuDev"
- }
- },
- "node_modules/tinyglobby/node_modules/fdir": {
- "version": "6.5.0",
- "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
- "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=12.0.0"
- },
- "peerDependencies": {
- "picomatch": "^3 || ^4"
- },
- "peerDependenciesMeta": {
- "picomatch": {
- "optional": true
- }
- }
- },
- "node_modules/tinyglobby/node_modules/picomatch": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
- "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
- "dev": true,
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/jonschlinkert"
- }
- },
- "node_modules/tinypool": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz",
- "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": "^18.0.0 || >=20.0.0"
- }
- },
- "node_modules/tinyrainbow": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz",
- "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=14.0.0"
- }
- },
- "node_modules/tinyspy": {
- "version": "4.0.4",
- "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.4.tgz",
- "integrity": "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=14.0.0"
- }
- },
- "node_modules/to-regex-range": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
- "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
- "license": "MIT",
- "dependencies": {
- "is-number": "^7.0.0"
- },
- "engines": {
- "node": ">=8.0"
- }
- },
- "node_modules/totalist": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz",
- "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/tr46": {
- "version": "0.0.3",
- "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
- "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/ts-api-utils": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz",
- "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=18.12"
- },
- "peerDependencies": {
- "typescript": ">=4.8.4"
- }
- },
- "node_modules/type-check": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
- "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "prelude-ls": "^1.2.1"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/typescript": {
- "version": "5.9.3",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
- "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
- "dev": true,
- "license": "Apache-2.0",
- "peer": true,
- "bin": {
- "tsc": "bin/tsc",
- "tsserver": "bin/tsserver"
- },
- "engines": {
- "node": ">=14.17"
- }
- },
- "node_modules/typescript-eslint": {
- "version": "8.56.0",
- "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.56.0.tgz",
- "integrity": "sha512-c7toRLrotJ9oixgdW7liukZpsnq5CZ7PuKztubGYlNppuTqhIoWfhgHo/7EU0v06gS2l/x0i2NEFK1qMIf0rIg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@typescript-eslint/eslint-plugin": "8.56.0",
- "@typescript-eslint/parser": "8.56.0",
- "@typescript-eslint/typescript-estree": "8.56.0",
- "@typescript-eslint/utils": "8.56.0"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
- "typescript": ">=4.8.4 <6.0.0"
- }
- },
- "node_modules/undici-types": {
- "version": "7.16.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
- "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
- "devOptional": true,
- "license": "MIT"
- },
- "node_modules/universalify": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
- "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 4.0.0"
- }
- },
- "node_modules/uri-js": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
- "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
- "dev": true,
- "license": "BSD-2-Clause",
- "dependencies": {
- "punycode": "^2.1.0"
- }
- },
- "node_modules/vite": {
- "version": "7.3.1",
- "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz",
- "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==",
- "dev": true,
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "esbuild": "^0.27.0",
- "fdir": "^6.5.0",
- "picomatch": "^4.0.3",
- "postcss": "^8.5.6",
- "rollup": "^4.43.0",
- "tinyglobby": "^0.2.15"
- },
- "bin": {
- "vite": "bin/vite.js"
- },
- "engines": {
- "node": "^20.19.0 || >=22.12.0"
- },
- "funding": {
- "url": "https://github.com/vitejs/vite?sponsor=1"
- },
- "optionalDependencies": {
- "fsevents": "~2.3.3"
- },
- "peerDependencies": {
- "@types/node": "^20.19.0 || >=22.12.0",
- "jiti": ">=1.21.0",
- "less": "^4.0.0",
- "lightningcss": "^1.21.0",
- "sass": "^1.70.0",
- "sass-embedded": "^1.70.0",
- "stylus": ">=0.54.8",
- "sugarss": "^5.0.0",
- "terser": "^5.16.0",
- "tsx": "^4.8.1",
- "yaml": "^2.4.2"
- },
- "peerDependenciesMeta": {
- "@types/node": {
- "optional": true
- },
- "jiti": {
- "optional": true
- },
- "less": {
- "optional": true
- },
- "lightningcss": {
- "optional": true
- },
- "sass": {
- "optional": true
- },
- "sass-embedded": {
- "optional": true
- },
- "stylus": {
- "optional": true
- },
- "sugarss": {
- "optional": true
- },
- "terser": {
- "optional": true
- },
- "tsx": {
- "optional": true
- },
- "yaml": {
- "optional": true
- }
- }
- },
- "node_modules/vite-node": {
- "version": "3.2.4",
- "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz",
- "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "cac": "^6.7.14",
- "debug": "^4.4.1",
- "es-module-lexer": "^1.7.0",
- "pathe": "^2.0.3",
- "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0"
- },
- "bin": {
- "vite-node": "vite-node.mjs"
- },
- "engines": {
- "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/vitest"
- }
- },
- "node_modules/vite/node_modules/fdir": {
- "version": "6.5.0",
- "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
- "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=12.0.0"
- },
- "peerDependencies": {
- "picomatch": "^3 || ^4"
- },
- "peerDependenciesMeta": {
- "picomatch": {
- "optional": true
- }
- }
- },
- "node_modules/vite/node_modules/picomatch": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
- "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
- "dev": true,
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/jonschlinkert"
- }
- },
- "node_modules/vitest": {
- "version": "3.2.4",
- "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.4.tgz",
- "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==",
- "dev": true,
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@types/chai": "^5.2.2",
- "@vitest/expect": "3.2.4",
- "@vitest/mocker": "3.2.4",
- "@vitest/pretty-format": "^3.2.4",
- "@vitest/runner": "3.2.4",
- "@vitest/snapshot": "3.2.4",
- "@vitest/spy": "3.2.4",
- "@vitest/utils": "3.2.4",
- "chai": "^5.2.0",
- "debug": "^4.4.1",
- "expect-type": "^1.2.1",
- "magic-string": "^0.30.17",
- "pathe": "^2.0.3",
- "picomatch": "^4.0.2",
- "std-env": "^3.9.0",
- "tinybench": "^2.9.0",
- "tinyexec": "^0.3.2",
- "tinyglobby": "^0.2.14",
- "tinypool": "^1.1.1",
- "tinyrainbow": "^2.0.0",
- "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0",
- "vite-node": "3.2.4",
- "why-is-node-running": "^2.3.0"
- },
- "bin": {
- "vitest": "vitest.mjs"
- },
- "engines": {
- "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/vitest"
- },
- "peerDependencies": {
- "@edge-runtime/vm": "*",
- "@types/debug": "^4.1.12",
- "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
- "@vitest/browser": "3.2.4",
- "@vitest/ui": "3.2.4",
- "happy-dom": "*",
- "jsdom": "*"
- },
- "peerDependenciesMeta": {
- "@edge-runtime/vm": {
- "optional": true
- },
- "@types/debug": {
- "optional": true
- },
- "@types/node": {
- "optional": true
- },
- "@vitest/browser": {
- "optional": true
- },
- "@vitest/ui": {
- "optional": true
- },
- "happy-dom": {
- "optional": true
- },
- "jsdom": {
- "optional": true
- }
- }
- },
- "node_modules/vitest/node_modules/picomatch": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
- "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/jonschlinkert"
- }
- },
- "node_modules/webidl-conversions": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
- "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
- "dev": true,
- "license": "BSD-2-Clause"
- },
- "node_modules/whatwg-url": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
- "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "tr46": "~0.0.3",
- "webidl-conversions": "^3.0.0"
- }
- },
- "node_modules/which": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
- "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
- "license": "ISC",
- "dependencies": {
- "isexe": "^2.0.0"
- },
- "bin": {
- "node-which": "bin/node-which"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/why-is-node-running": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz",
- "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "siginfo": "^2.0.0",
- "stackback": "0.0.2"
- },
- "bin": {
- "why-is-node-running": "cli.js"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/word-wrap": {
- "version": "1.2.5",
- "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
- "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/wrap-ansi": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
- "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
- "license": "MIT",
- "dependencies": {
- "ansi-styles": "^4.0.0",
- "string-width": "^4.1.0",
- "strip-ansi": "^6.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/wrap-ansi/node_modules/emoji-regex": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "license": "MIT"
- },
- "node_modules/wrap-ansi/node_modules/string-width": {
- "version": "4.2.3",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
- "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "license": "MIT",
- "dependencies": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/yaml": {
- "version": "2.8.2",
- "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz",
- "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==",
- "license": "ISC",
- "peer": true,
- "bin": {
- "yaml": "bin.mjs"
- },
- "engines": {
- "node": ">= 14.6"
- },
- "funding": {
- "url": "https://github.com/sponsors/eemeli"
- }
- },
- "node_modules/yocto-queue": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
- "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/yoctocolors-cjs": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz",
- "integrity": "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==",
- "license": "MIT",
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/zod": {
- "version": "4.3.6",
- "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz",
- "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==",
- "license": "MIT",
- "funding": {
- "url": "https://github.com/sponsors/colinhacks"
- }
- }
- }
-}
diff --git a/package.json b/package.json
index 7e0159fe73..b31dc3f95c 100644
--- a/package.json
+++ b/package.json
@@ -1,5 +1,5 @@
{
- "name": "@fission-ai/openspec",
+ "name": "@fkmatsuda/br-openspec",
"version": "1.3.1",
"description": "AI-native system for spec-driven development",
"keywords": [
@@ -9,13 +9,13 @@
"ai",
"development"
],
- "homepage": "https://github.com/Fission-AI/OpenSpec",
+ "homepage": "https://github.com/fkmatsuda/BR-OpenSpec",
"repository": {
"type": "git",
- "url": "https://github.com/Fission-AI/OpenSpec"
+ "url": "https://github.com/fkmatsuda/BR-OpenSpec"
},
"license": "MIT",
- "author": "OpenSpec Contributors",
+ "author": "BR-OpenSpec Contributors",
"type": "module",
"publishConfig": {
"access": "public"
@@ -63,6 +63,7 @@
"@changesets/changelog-github": "^0.5.2",
"@changesets/cli": "^2.27.7",
"@types/node": "^24.2.0",
+ "@vitest/coverage-v8": "^3.2.4",
"@vitest/ui": "^3.2.4",
"eslint": "^9.39.2",
"typescript": "^5.9.3",
@@ -77,7 +78,7 @@
"fast-glob": "^3.3.3",
"ora": "^8.2.0",
"posthog-node": "^5.20.0",
- "yaml": "^2.8.2",
+ "yaml": "^2.8.3",
"zod": "^4.0.17"
}
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index a632f81133..4a2d76f917 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -30,8 +30,8 @@ importers:
specifier: ^5.20.0
version: 5.20.0
yaml:
- specifier: ^2.8.2
- version: 2.8.2
+ specifier: ^2.8.3
+ version: 2.8.3
zod:
specifier: ^4.0.17
version: 4.0.17
@@ -45,6 +45,9 @@ importers:
'@types/node':
specifier: ^24.2.0
version: 24.2.0
+ '@vitest/coverage-v8':
+ specifier: ^3.2.4
+ version: 3.2.4(vitest@3.2.4)
'@vitest/ui':
specifier: ^3.2.4
version: 3.2.4(vitest@3.2.4)
@@ -59,14 +62,39 @@ importers:
version: 8.50.1(eslint@9.39.2)(typescript@5.9.3)
vitest:
specifier: ^3.2.4
- version: 3.2.4(@types/node@24.2.0)(@vitest/ui@3.2.4)(yaml@2.8.2)
+ version: 3.2.4(@types/node@24.2.0)(@vitest/ui@3.2.4)(yaml@2.8.3)
packages:
+ '@ampproject/remapping@2.3.0':
+ resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
+ engines: {node: '>=6.0.0'}
+
+ '@babel/helper-string-parser@7.27.1':
+ resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-validator-identifier@7.28.5':
+ resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/parser@7.29.2':
+ resolution: {integrity: sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==}
+ engines: {node: '>=6.0.0'}
+ hasBin: true
+
'@babel/runtime@7.28.4':
resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==}
engines: {node: '>=6.9.0'}
+ '@babel/types@7.29.0':
+ resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==}
+ engines: {node: '>=6.9.0'}
+
+ '@bcoe/v8-coverage@1.0.2':
+ resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==}
+ engines: {node: '>=18'}
+
'@changesets/apply-release-plan@7.0.12':
resolution: {integrity: sha512-EaET7As5CeuhTzvXTQCRZeBUcisoYPDDcXvgTE/2jmmypKp0RC7LxKj/yzqeh/1qFTZI7oDGFcL1PHRuQuketQ==}
@@ -472,9 +500,27 @@ packages:
'@types/node':
optional: true
+ '@isaacs/cliui@8.0.2':
+ resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
+ engines: {node: '>=12'}
+
+ '@istanbuljs/schema@0.1.6':
+ resolution: {integrity: sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==}
+ engines: {node: '>=8'}
+
+ '@jridgewell/gen-mapping@0.3.13':
+ resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
+
+ '@jridgewell/resolve-uri@3.1.2':
+ resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
+ engines: {node: '>=6.0.0'}
+
'@jridgewell/sourcemap-codec@1.5.4':
resolution: {integrity: sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==}
+ '@jridgewell/trace-mapping@0.3.31':
+ resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
+
'@manypkg/find-root@1.1.0':
resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==}
@@ -493,6 +539,10 @@ packages:
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
engines: {node: '>= 8'}
+ '@pkgjs/parseargs@0.11.0':
+ resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
+ engines: {node: '>=14'}
+
'@polka/url@1.0.0-next.29':
resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==}
@@ -533,56 +583,67 @@ packages:
resolution: {integrity: sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA==}
cpu: [arm]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-arm-musleabihf@4.46.2':
resolution: {integrity: sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ==}
cpu: [arm]
os: [linux]
+ libc: [musl]
'@rollup/rollup-linux-arm64-gnu@4.46.2':
resolution: {integrity: sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng==}
cpu: [arm64]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-arm64-musl@4.46.2':
resolution: {integrity: sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg==}
cpu: [arm64]
os: [linux]
+ libc: [musl]
'@rollup/rollup-linux-loongarch64-gnu@4.46.2':
resolution: {integrity: sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA==}
cpu: [loong64]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-ppc64-gnu@4.46.2':
resolution: {integrity: sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw==}
cpu: [ppc64]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-riscv64-gnu@4.46.2':
resolution: {integrity: sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ==}
cpu: [riscv64]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-riscv64-musl@4.46.2':
resolution: {integrity: sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw==}
cpu: [riscv64]
os: [linux]
+ libc: [musl]
'@rollup/rollup-linux-s390x-gnu@4.46.2':
resolution: {integrity: sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA==}
cpu: [s390x]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-x64-gnu@4.46.2':
resolution: {integrity: sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA==}
cpu: [x64]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-x64-musl@4.46.2':
resolution: {integrity: sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA==}
cpu: [x64]
os: [linux]
+ libc: [musl]
'@rollup/rollup-win32-arm64-msvc@4.46.2':
resolution: {integrity: sha512-wiJWMIpeaak/jsbaq2HMh/rzZxHVW1rU6coyeNNpMwk5isiPjSTx0a4YLSlYDwBH/WBvLz+EtsNqQScZTLJy3g==}
@@ -676,6 +737,15 @@ packages:
resolution: {integrity: sha512-IrDKrw7pCRUR94zeuCSUWQ+w8JEf5ZX5jl/e6AHGSLi1/zIr0lgutfn/7JpfCey+urpgQEdrZVYzCaVVKiTwhQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ '@vitest/coverage-v8@3.2.4':
+ resolution: {integrity: sha512-EyF9SXU6kS5Ku/U82E259WSnvg6c8KTjppUncuNdm5QHpe17mwREHnjDzozC8x9MZ0xfBUFSaLkRv4TMA75ALQ==}
+ peerDependencies:
+ '@vitest/browser': 3.2.4
+ vitest: 3.2.4
+ peerDependenciesMeta:
+ '@vitest/browser':
+ optional: true
+
'@vitest/expect@3.2.4':
resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==}
@@ -743,6 +813,10 @@ packages:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
engines: {node: '>=8'}
+ ansi-styles@6.2.3:
+ resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==}
+ engines: {node: '>=12'}
+
argparse@1.0.10:
resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
@@ -757,9 +831,16 @@ packages:
resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
engines: {node: '>=12'}
+ ast-v8-to-istanbul@0.3.12:
+ resolution: {integrity: sha512-BRRC8VRZY2R4Z4lFIL35MwNXmwVqBityvOIwETtsCSwvjl0IdgFsy9NhdaA6j74nUdtJJlIypeRhpDam19Wq3g==}
+
balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
+ balanced-match@4.0.4:
+ resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==}
+ engines: {node: 18 || 20 || >=22}
+
better-path-resolve@1.0.0:
resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==}
engines: {node: '>=4'}
@@ -770,6 +851,10 @@ packages:
brace-expansion@2.0.2:
resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==}
+ brace-expansion@5.0.5:
+ resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==}
+ engines: {node: 18 || 20 || >=22}
+
braces@3.0.3:
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
engines: {node: '>=8'}
@@ -869,12 +954,18 @@ packages:
resolution: {integrity: sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==}
engines: {node: '>=10'}
+ eastasianwidth@0.2.0:
+ resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
+
emoji-regex@10.4.0:
resolution: {integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==}
emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
+ emoji-regex@9.2.2:
+ resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
+
enquirer@2.4.1:
resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==}
engines: {node: '>=8.6'}
@@ -1011,6 +1102,10 @@ packages:
flatted@3.3.3:
resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==}
+ foreground-child@3.3.1:
+ resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
+ engines: {node: '>=14'}
+
fs-extra@7.0.1:
resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==}
engines: {node: '>=6 <7 || >=8'}
@@ -1036,6 +1131,11 @@ packages:
resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
engines: {node: '>=10.13.0'}
+ glob@10.5.0:
+ resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==}
+ deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
+ hasBin: true
+
globals@14.0.0:
resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==}
engines: {node: '>=18'}
@@ -1051,6 +1151,9 @@ packages:
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
engines: {node: '>=8'}
+ html-escaper@2.0.2:
+ resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
+
human-id@4.1.1:
resolution: {integrity: sha512-3gKm/gCSUipeLsRYZbbdA1BD83lBoWUkZ7G9VFrhWPAU76KwYo5KR8V28bpoPm/ygy0x5/GCbpRQdY7VLYCoIg==}
hasBin: true
@@ -1118,6 +1221,28 @@ packages:
isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
+ istanbul-lib-coverage@3.2.2:
+ resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==}
+ engines: {node: '>=8'}
+
+ istanbul-lib-report@3.0.1:
+ resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==}
+ engines: {node: '>=10'}
+
+ istanbul-lib-source-maps@5.0.6:
+ resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==}
+ engines: {node: '>=10'}
+
+ istanbul-reports@3.2.0:
+ resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==}
+ engines: {node: '>=8'}
+
+ jackspeak@3.4.3:
+ resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==}
+
+ js-tokens@10.0.0:
+ resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==}
+
js-tokens@9.0.1:
resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==}
@@ -1169,9 +1294,19 @@ packages:
loupe@3.2.0:
resolution: {integrity: sha512-2NCfZcT5VGVNX9mSZIxLRkEAegDGBpuQZBy13desuHeVORmBDyAET4TkJr4SjqQy3A8JDofMN6LpkK8Xcm/dlw==}
+ lru-cache@10.4.3:
+ resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
+
magic-string@0.30.17:
resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
+ magicast@0.3.5:
+ resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==}
+
+ make-dir@4.0.0:
+ resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}
+ engines: {node: '>=10'}
+
merge2@1.4.1:
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
engines: {node: '>= 8'}
@@ -1184,6 +1319,10 @@ packages:
resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==}
engines: {node: '>=18'}
+ minimatch@10.2.5:
+ resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==}
+ engines: {node: 18 || 20 || >=22}
+
minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
@@ -1191,6 +1330,10 @@ packages:
resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
engines: {node: '>=16 || 14 >=14.17'}
+ minipass@7.1.3:
+ resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==}
+ engines: {node: '>=16 || 14 >=14.17'}
+
mri@1.2.0:
resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
engines: {node: '>=4'}
@@ -1270,6 +1413,9 @@ packages:
resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
engines: {node: '>=6'}
+ package-json-from-dist@1.0.1:
+ resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==}
+
package-manager-detector@0.2.11:
resolution: {integrity: sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ==}
@@ -1285,6 +1431,10 @@ packages:
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
engines: {node: '>=8'}
+ path-scurry@1.11.1:
+ resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
+ engines: {node: '>=16 || 14 >=14.18'}
+
path-type@4.0.0:
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
engines: {node: '>=8'}
@@ -1421,6 +1571,10 @@ packages:
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
engines: {node: '>=8'}
+ string-width@5.1.2:
+ resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
+ engines: {node: '>=12'}
+
string-width@7.2.0:
resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==}
engines: {node: '>=18'}
@@ -1452,6 +1606,10 @@ packages:
resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==}
engines: {node: '>=8'}
+ test-exclude@7.0.2:
+ resolution: {integrity: sha512-u9E6A+ZDYdp7a4WnarkXPZOx8Ilz46+kby6p1yZ8zsGTz9gYa6FIS7lj2oezzNKmtdyyJNNmmXDppga5GB7kSw==}
+ engines: {node: '>=18'}
+
tinybench@2.9.0:
resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
@@ -1626,8 +1784,16 @@ packages:
resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}
engines: {node: '>=8'}
- yaml@2.8.2:
- resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==}
+ wrap-ansi@7.0.0:
+ resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
+ engines: {node: '>=10'}
+
+ wrap-ansi@8.1.0:
+ resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
+ engines: {node: '>=12'}
+
+ yaml@2.8.3:
+ resolution: {integrity: sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==}
engines: {node: '>= 14.6'}
hasBin: true
@@ -1644,8 +1810,28 @@ packages:
snapshots:
+ '@ampproject/remapping@2.3.0':
+ dependencies:
+ '@jridgewell/gen-mapping': 0.3.13
+ '@jridgewell/trace-mapping': 0.3.31
+
+ '@babel/helper-string-parser@7.27.1': {}
+
+ '@babel/helper-validator-identifier@7.28.5': {}
+
+ '@babel/parser@7.29.2':
+ dependencies:
+ '@babel/types': 7.29.0
+
'@babel/runtime@7.28.4': {}
+ '@babel/types@7.29.0':
+ dependencies:
+ '@babel/helper-string-parser': 7.27.1
+ '@babel/helper-validator-identifier': 7.28.5
+
+ '@bcoe/v8-coverage@1.0.2': {}
+
'@changesets/apply-release-plan@7.0.12':
dependencies:
'@changesets/config': 3.1.1
@@ -2065,8 +2251,31 @@ snapshots:
optionalDependencies:
'@types/node': 24.2.0
+ '@isaacs/cliui@8.0.2':
+ dependencies:
+ string-width: 5.1.2
+ string-width-cjs: string-width@4.2.3
+ strip-ansi: 7.1.0
+ strip-ansi-cjs: strip-ansi@6.0.1
+ wrap-ansi: 8.1.0
+ wrap-ansi-cjs: wrap-ansi@7.0.0
+
+ '@istanbuljs/schema@0.1.6': {}
+
+ '@jridgewell/gen-mapping@0.3.13':
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.5.4
+ '@jridgewell/trace-mapping': 0.3.31
+
+ '@jridgewell/resolve-uri@3.1.2': {}
+
'@jridgewell/sourcemap-codec@1.5.4': {}
+ '@jridgewell/trace-mapping@0.3.31':
+ dependencies:
+ '@jridgewell/resolve-uri': 3.1.2
+ '@jridgewell/sourcemap-codec': 1.5.4
+
'@manypkg/find-root@1.1.0':
dependencies:
'@babel/runtime': 7.28.4
@@ -2095,6 +2304,9 @@ snapshots:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.19.1
+ '@pkgjs/parseargs@0.11.0':
+ optional: true
+
'@polka/url@1.0.0-next.29': {}
'@posthog/core@1.9.1':
@@ -2268,6 +2480,25 @@ snapshots:
'@typescript-eslint/types': 8.50.1
eslint-visitor-keys: 4.2.1
+ '@vitest/coverage-v8@3.2.4(vitest@3.2.4)':
+ dependencies:
+ '@ampproject/remapping': 2.3.0
+ '@bcoe/v8-coverage': 1.0.2
+ ast-v8-to-istanbul: 0.3.12
+ debug: 4.4.1
+ istanbul-lib-coverage: 3.2.2
+ istanbul-lib-report: 3.0.1
+ istanbul-lib-source-maps: 5.0.6
+ istanbul-reports: 3.2.0
+ magic-string: 0.30.17
+ magicast: 0.3.5
+ std-env: 3.9.0
+ test-exclude: 7.0.2
+ tinyrainbow: 2.0.0
+ vitest: 3.2.4(@types/node@24.2.0)(@vitest/ui@3.2.4)(yaml@2.8.3)
+ transitivePeerDependencies:
+ - supports-color
+
'@vitest/expect@3.2.4':
dependencies:
'@types/chai': 5.2.2
@@ -2276,13 +2507,13 @@ snapshots:
chai: 5.2.1
tinyrainbow: 2.0.0
- '@vitest/mocker@3.2.4(vite@7.0.6(@types/node@24.2.0)(yaml@2.8.2))':
+ '@vitest/mocker@3.2.4(vite@7.0.6(@types/node@24.2.0)(yaml@2.8.3))':
dependencies:
'@vitest/spy': 3.2.4
estree-walker: 3.0.3
magic-string: 0.30.17
optionalDependencies:
- vite: 7.0.6(@types/node@24.2.0)(yaml@2.8.2)
+ vite: 7.0.6(@types/node@24.2.0)(yaml@2.8.3)
'@vitest/pretty-format@3.2.4':
dependencies:
@@ -2313,7 +2544,7 @@ snapshots:
sirv: 3.0.1
tinyglobby: 0.2.14
tinyrainbow: 2.0.0
- vitest: 3.2.4(@types/node@24.2.0)(@vitest/ui@3.2.4)(yaml@2.8.2)
+ vitest: 3.2.4(@types/node@24.2.0)(@vitest/ui@3.2.4)(yaml@2.8.3)
'@vitest/utils@3.2.4':
dependencies:
@@ -2348,6 +2579,8 @@ snapshots:
dependencies:
color-convert: 2.0.1
+ ansi-styles@6.2.3: {}
+
argparse@1.0.10:
dependencies:
sprintf-js: 1.0.3
@@ -2358,8 +2591,16 @@ snapshots:
assertion-error@2.0.1: {}
+ ast-v8-to-istanbul@0.3.12:
+ dependencies:
+ '@jridgewell/trace-mapping': 0.3.31
+ estree-walker: 3.0.3
+ js-tokens: 10.0.0
+
balanced-match@1.0.2: {}
+ balanced-match@4.0.4: {}
+
better-path-resolve@1.0.0:
dependencies:
is-windows: 1.0.2
@@ -2373,6 +2614,10 @@ snapshots:
dependencies:
balanced-match: 1.0.2
+ brace-expansion@5.0.5:
+ dependencies:
+ balanced-match: 4.0.4
+
braces@3.0.3:
dependencies:
fill-range: 7.1.1
@@ -2446,10 +2691,14 @@ snapshots:
dotenv@8.6.0: {}
+ eastasianwidth@0.2.0: {}
+
emoji-regex@10.4.0: {}
emoji-regex@8.0.0: {}
+ emoji-regex@9.2.2: {}
+
enquirer@2.4.1:
dependencies:
ansi-colors: 4.1.3
@@ -2623,6 +2872,11 @@ snapshots:
flatted@3.3.3: {}
+ foreground-child@3.3.1:
+ dependencies:
+ cross-spawn: 7.0.6
+ signal-exit: 4.1.0
+
fs-extra@7.0.1:
dependencies:
graceful-fs: 4.2.11
@@ -2648,6 +2902,15 @@ snapshots:
dependencies:
is-glob: 4.0.3
+ glob@10.5.0:
+ dependencies:
+ foreground-child: 3.3.1
+ jackspeak: 3.4.3
+ minimatch: 9.0.5
+ minipass: 7.1.3
+ package-json-from-dist: 1.0.1
+ path-scurry: 1.11.1
+
globals@14.0.0: {}
globby@11.1.0:
@@ -2663,6 +2926,8 @@ snapshots:
has-flag@4.0.0: {}
+ html-escaper@2.0.2: {}
+
human-id@4.1.1: {}
iconv-lite@0.4.24:
@@ -2708,6 +2973,35 @@ snapshots:
isexe@2.0.0: {}
+ istanbul-lib-coverage@3.2.2: {}
+
+ istanbul-lib-report@3.0.1:
+ dependencies:
+ istanbul-lib-coverage: 3.2.2
+ make-dir: 4.0.0
+ supports-color: 7.2.0
+
+ istanbul-lib-source-maps@5.0.6:
+ dependencies:
+ '@jridgewell/trace-mapping': 0.3.31
+ debug: 4.4.1
+ istanbul-lib-coverage: 3.2.2
+ transitivePeerDependencies:
+ - supports-color
+
+ istanbul-reports@3.2.0:
+ dependencies:
+ html-escaper: 2.0.2
+ istanbul-lib-report: 3.0.1
+
+ jackspeak@3.4.3:
+ dependencies:
+ '@isaacs/cliui': 8.0.2
+ optionalDependencies:
+ '@pkgjs/parseargs': 0.11.0
+
+ js-tokens@10.0.0: {}
+
js-tokens@9.0.1: {}
js-yaml@3.14.1:
@@ -2757,10 +3051,22 @@ snapshots:
loupe@3.2.0: {}
+ lru-cache@10.4.3: {}
+
magic-string@0.30.17:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.4
+ magicast@0.3.5:
+ dependencies:
+ '@babel/parser': 7.29.2
+ '@babel/types': 7.29.0
+ source-map-js: 1.2.1
+
+ make-dir@4.0.0:
+ dependencies:
+ semver: 7.7.2
+
merge2@1.4.1: {}
micromatch@4.0.8:
@@ -2770,6 +3076,10 @@ snapshots:
mimic-function@5.0.1: {}
+ minimatch@10.2.5:
+ dependencies:
+ brace-expansion: 5.0.5
+
minimatch@3.1.2:
dependencies:
brace-expansion: 1.1.12
@@ -2778,6 +3088,8 @@ snapshots:
dependencies:
brace-expansion: 2.0.2
+ minipass@7.1.3: {}
+
mri@1.2.0: {}
mrmime@2.0.1: {}
@@ -2847,6 +3159,8 @@ snapshots:
p-try@2.2.0: {}
+ package-json-from-dist@1.0.1: {}
+
package-manager-detector@0.2.11:
dependencies:
quansync: 0.2.11
@@ -2859,6 +3173,11 @@ snapshots:
path-key@3.1.1: {}
+ path-scurry@1.11.1:
+ dependencies:
+ lru-cache: 10.4.3
+ minipass: 7.1.3
+
path-type@4.0.0: {}
pathe@2.0.3: {}
@@ -2984,6 +3303,12 @@ snapshots:
is-fullwidth-code-point: 3.0.0
strip-ansi: 6.0.1
+ string-width@5.1.2:
+ dependencies:
+ eastasianwidth: 0.2.0
+ emoji-regex: 9.2.2
+ strip-ansi: 7.1.0
+
string-width@7.2.0:
dependencies:
emoji-regex: 10.4.0
@@ -3012,6 +3337,12 @@ snapshots:
term-size@2.2.1: {}
+ test-exclude@7.0.2:
+ dependencies:
+ '@istanbuljs/schema': 0.1.6
+ glob: 10.5.0
+ minimatch: 10.2.5
+
tinybench@2.9.0: {}
tinyexec@0.3.2: {}
@@ -3075,13 +3406,13 @@ snapshots:
dependencies:
punycode: 2.3.1
- vite-node@3.2.4(@types/node@24.2.0)(yaml@2.8.2):
+ vite-node@3.2.4(@types/node@24.2.0)(yaml@2.8.3):
dependencies:
cac: 6.7.14
debug: 4.4.1
es-module-lexer: 1.7.0
pathe: 2.0.3
- vite: 7.0.6(@types/node@24.2.0)(yaml@2.8.2)
+ vite: 7.0.6(@types/node@24.2.0)(yaml@2.8.3)
transitivePeerDependencies:
- '@types/node'
- jiti
@@ -3096,7 +3427,7 @@ snapshots:
- tsx
- yaml
- vite@7.0.6(@types/node@24.2.0)(yaml@2.8.2):
+ vite@7.0.6(@types/node@24.2.0)(yaml@2.8.3):
dependencies:
esbuild: 0.25.8
fdir: 6.4.6(picomatch@4.0.3)
@@ -3107,13 +3438,13 @@ snapshots:
optionalDependencies:
'@types/node': 24.2.0
fsevents: 2.3.3
- yaml: 2.8.2
+ yaml: 2.8.3
- vitest@3.2.4(@types/node@24.2.0)(@vitest/ui@3.2.4)(yaml@2.8.2):
+ vitest@3.2.4(@types/node@24.2.0)(@vitest/ui@3.2.4)(yaml@2.8.3):
dependencies:
'@types/chai': 5.2.2
'@vitest/expect': 3.2.4
- '@vitest/mocker': 3.2.4(vite@7.0.6(@types/node@24.2.0)(yaml@2.8.2))
+ '@vitest/mocker': 3.2.4(vite@7.0.6(@types/node@24.2.0)(yaml@2.8.3))
'@vitest/pretty-format': 3.2.4
'@vitest/runner': 3.2.4
'@vitest/snapshot': 3.2.4
@@ -3131,8 +3462,8 @@ snapshots:
tinyglobby: 0.2.14
tinypool: 1.1.1
tinyrainbow: 2.0.0
- vite: 7.0.6(@types/node@24.2.0)(yaml@2.8.2)
- vite-node: 3.2.4(@types/node@24.2.0)(yaml@2.8.2)
+ vite: 7.0.6(@types/node@24.2.0)(yaml@2.8.3)
+ vite-node: 3.2.4(@types/node@24.2.0)(yaml@2.8.3)
why-is-node-running: 2.3.0
optionalDependencies:
'@types/node': 24.2.0
@@ -3175,7 +3506,19 @@ snapshots:
string-width: 4.2.3
strip-ansi: 6.0.1
- yaml@2.8.2: {}
+ wrap-ansi@7.0.0:
+ dependencies:
+ ansi-styles: 4.3.0
+ string-width: 4.2.3
+ strip-ansi: 6.0.1
+
+ wrap-ansi@8.1.0:
+ dependencies:
+ ansi-styles: 6.2.3
+ string-width: 5.1.2
+ strip-ansi: 7.1.0
+
+ yaml@2.8.3: {}
yocto-queue@0.1.0: {}
diff --git a/schemas/spec-driven/schema.yaml b/schemas/spec-driven/schema.yaml
index 45f61e222b..6464ddb206 100644
--- a/schemas/spec-driven/schema.yaml
+++ b/schemas/spec-driven/schema.yaml
@@ -1,6 +1,6 @@
name: spec-driven
version: 1
-description: Default OpenSpec workflow - proposal → specs → design → tasks
+description: Default BR-OpenSpec workflow - proposal → specs → design → tasks
artifacts:
- id: proposal
generates: proposal.md
diff --git a/scripts/README.md b/scripts/README.md
index dcdc6e744a..7605515370 100644
--- a/scripts/README.md
+++ b/scripts/README.md
@@ -1,6 +1,6 @@
-# OpenSpec Scripts
+# BR-OpenSpec Scripts
-Utility scripts for OpenSpec maintenance and development.
+Utility scripts for BR-OpenSpec maintenance and development.
## update-flake.sh
diff --git a/scripts/pack-version-check.mjs b/scripts/pack-version-check.mjs
index 43cf8050eb..71131f3833 100644
--- a/scripts/pack-version-check.mjs
+++ b/scripts/pack-version-check.mjs
@@ -53,7 +53,7 @@ function main() {
let tgzPath;
try {
- log(`Packing @fission-ai/openspec@${expected}...`);
+ log(`Packing @fkmatsuda/br-openspec@${expected}...`);
const filename = npmPack();
tgzPath = path.resolve(filename);
log(`Created: ${tgzPath}`);
diff --git a/src/cli/index.ts b/src/cli/index.ts
index 8947736f7c..c948af8dd3 100644
--- a/src/cli/index.ts
+++ b/src/cli/index.ts
@@ -4,6 +4,7 @@ import ora from 'ora';
import path from 'path';
import { promises as fs } from 'fs';
import { AI_TOOLS } from '../core/config.js';
+import { CLI_DESCRIPTIONS, CLI_MESSAGES, CONFIG_MESSAGES } from '../messages/index.js';
import { UpdateCommand } from '../core/update.js';
import { ListCommand } from '../core/list.js';
import { ArchiveCommand } from '../core/archive.js';
@@ -16,6 +17,7 @@ import { CompletionCommand } from '../commands/completion.js';
import { FeedbackCommand } from '../commands/feedback.js';
import { registerConfigCommand } from '../commands/config.js';
import { registerSchemaCommand } from '../commands/schema.js';
+import { registerToolsCommand } from '../commands/tools.js';
import {
statusCommand,
instructionsCommand,
@@ -58,11 +60,11 @@ function getCommandPath(command: Command): string {
program
.name('openspec')
- .description('AI-native system for spec-driven development')
+ .description(CLI_DESCRIPTIONS.root)
.version(version);
// Global options
-program.option('--no-color', 'Disable color output');
+program.option('--no-color', CLI_DESCRIPTIONS.noColor);
// Apply global flags and telemetry before any command runs
// Note: preAction receives (thisCommand, actionCommand) where:
@@ -88,14 +90,14 @@ program.hook('postAction', async () => {
});
const availableToolIds = AI_TOOLS.filter((tool) => tool.skillsDir).map((tool) => tool.value);
-const toolsOptionDescription = `Configure AI tools non-interactively. Use "all", "none", or a comma-separated list of: ${availableToolIds.join(', ')}`;
+const toolsOptionDescription = `Configura ferramentas de IA não interativamente. Use "all", "none" ou uma lista separada por vírgula: ${availableToolIds.join(', ')}`;
program
.command('init [path]')
- .description('Initialize OpenSpec in your project')
+ .description(CLI_DESCRIPTIONS.init)
.option('--tools ', toolsOptionDescription)
- .option('--force', 'Auto-cleanup legacy files without prompting')
- .option('--profile ', 'Override global config profile (core or custom)')
+ .option('--force', CLI_DESCRIPTIONS.force)
+ .option('--profile ', CLI_DESCRIPTIONS.profile)
.action(async (targetPath = '.', options?: { tools?: string; force?: boolean; profile?: string }) => {
try {
// Validate that the path is a valid directory
@@ -104,16 +106,16 @@ program
try {
const stats = await fs.stat(resolvedPath);
if (!stats.isDirectory()) {
- throw new Error(`Path "${targetPath}" is not a directory`);
+ throw new Error(CLI_MESSAGES.notADirectory(targetPath));
}
} catch (error: any) {
if (error.code === 'ENOENT') {
// Directory doesn't exist, but we can create it
- console.log(`Directory "${targetPath}" doesn't exist, it will be created.`);
+ console.log(CLI_MESSAGES.directoryWillBeCreated(targetPath));
} else if (error.message && error.message.includes('not a directory')) {
throw error;
} else {
- throw new Error(`Cannot access path "${targetPath}": ${error.message}`);
+ throw new Error(CLI_MESSAGES.cannotAccessPath(targetPath, error.message));
}
}
@@ -126,7 +128,7 @@ program
await initCommand.execute(targetPath);
} catch (error) {
console.log(); // Empty line for spacing
- ora().fail(`Error: ${(error as Error).message}`);
+ ora().fail(CLI_MESSAGES.error((error as Error).message));
process.exit(1);
}
});
@@ -134,12 +136,12 @@ program
// Hidden alias: 'experimental' -> 'init' for backwards compatibility
program
.command('experimental', { hidden: true })
- .description('Alias for init (deprecated)')
+ .description(CLI_DESCRIPTIONS.experimental)
.option('--tool ', 'Target AI tool (maps to --tools)')
- .option('--no-interactive', 'Disable interactive prompts')
+ .option('--no-interactive', 'Desativa prompts interativos')
.action(async (options?: { tool?: string; noInteractive?: boolean }) => {
try {
- console.log('Note: "openspec experimental" is deprecated. Use "openspec init" instead.');
+ console.log(CLI_MESSAGES.experimentalDeprecated);
const { InitCommand } = await import('../core/init.js');
const initCommand = new InitCommand({
tools: options?.tool,
@@ -148,15 +150,15 @@ program
await initCommand.execute('.');
} catch (error) {
console.log();
- ora().fail(`Error: ${(error as Error).message}`);
+ ora().fail(CLI_MESSAGES.error((error as Error).message));
process.exit(1);
}
});
program
.command('update [path]')
- .description('Update OpenSpec instruction files')
- .option('--force', 'Force update even when tools are up to date')
+ .description(CLI_DESCRIPTIONS.update)
+ .option('--force', 'Força atualização mesmo quando as ferramentas estão atualizadas')
.action(async (targetPath = '.', options?: { force?: boolean }) => {
try {
const resolvedPath = path.resolve(targetPath);
@@ -164,18 +166,18 @@ program
await updateCommand.execute(resolvedPath);
} catch (error) {
console.log(); // Empty line for spacing
- ora().fail(`Error: ${(error as Error).message}`);
+ ora().fail(CLI_MESSAGES.error((error as Error).message));
process.exit(1);
}
});
program
.command('list')
- .description('List items (changes by default). Use --specs to list specs.')
- .option('--specs', 'List specs instead of changes')
- .option('--changes', 'List changes explicitly (default)')
- .option('--sort ', 'Sort order: "recent" (default) or "name"', 'recent')
- .option('--json', 'Output as JSON (for programmatic use)')
+ .description(CLI_DESCRIPTIONS.list)
+ .option('--specs', 'Lista especificações em vez de alterações')
+ .option('--changes', 'Lista alterações explicitamente (padrão)')
+ .option('--sort ', 'Ordem de classificação: "recent" (padrão) ou "name"', 'recent')
+ .option('--json', 'Saída como JSON (para uso programático)')
.action(async (options?: { specs?: boolean; changes?: boolean; sort?: string; json?: boolean }) => {
try {
const listCommand = new ListCommand();
@@ -184,21 +186,21 @@ program
await listCommand.execute('.', mode, { sort, json: options?.json });
} catch (error) {
console.log(); // Empty line for spacing
- ora().fail(`Error: ${(error as Error).message}`);
+ ora().fail(CLI_MESSAGES.error((error as Error).message));
process.exit(1);
}
});
program
.command('view')
- .description('Display an interactive dashboard of specs and changes')
+ .description(CLI_DESCRIPTIONS.view)
.action(async () => {
try {
const viewCommand = new ViewCommand();
await viewCommand.execute('.');
} catch (error) {
console.log(); // Empty line for spacing
- ora().fail(`Error: ${(error as Error).message}`);
+ ora().fail(CLI_MESSAGES.error((error as Error).message));
process.exit(1);
}
});
@@ -206,51 +208,51 @@ program
// Change command with subcommands
const changeCmd = program
.command('change')
- .description('Manage OpenSpec change proposals');
+ .description(CLI_DESCRIPTIONS.change);
// Deprecation notice for noun-based commands
changeCmd.hook('preAction', () => {
- console.error('Warning: The "openspec change ..." commands are deprecated. Prefer verb-first commands (e.g., "openspec list", "openspec validate --changes").');
+ console.error(CLI_MESSAGES.changeCommandsDeprecated);
});
changeCmd
.command('show [change-name]')
- .description('Show a change proposal in JSON or markdown format')
- .option('--json', 'Output as JSON')
- .option('--deltas-only', 'Show only deltas (JSON only)')
- .option('--requirements-only', 'Alias for --deltas-only (deprecated)')
+ .description(CLI_DESCRIPTIONS.changeShow)
+ .option('--json', 'Saída como JSON')
+ .option('--deltas-only', 'Exibe apenas deltas (somente JSON)')
+ .option('--requirements-only', 'Alias para --deltas-only (descontinuado)')
.option('--no-interactive', 'Disable interactive prompts')
.action(async (changeName?: string, options?: { json?: boolean; requirementsOnly?: boolean; deltasOnly?: boolean; noInteractive?: boolean }) => {
try {
const changeCommand = new ChangeCommand();
await changeCommand.show(changeName, options);
} catch (error) {
- console.error(`Error: ${(error as Error).message}`);
+ console.error(CLI_MESSAGES.error((error as Error).message));
process.exitCode = 1;
}
});
changeCmd
.command('list')
- .description('List all active changes (DEPRECATED: use "openspec list" instead)')
- .option('--json', 'Output as JSON')
+ .description(CLI_DESCRIPTIONS.changeList)
+ .option('--json', 'Saída como JSON')
.option('--long', 'Show id and title with counts')
.action(async (options?: { json?: boolean; long?: boolean }) => {
try {
- console.error('Warning: "openspec change list" is deprecated. Use "openspec list".');
+ console.error(CLI_MESSAGES.changeListDeprecated);
const changeCommand = new ChangeCommand();
await changeCommand.list(options);
} catch (error) {
- console.error(`Error: ${(error as Error).message}`);
+ console.error(CLI_MESSAGES.error((error as Error).message));
process.exitCode = 1;
}
});
changeCmd
.command('validate [change-name]')
- .description('Validate a change proposal')
- .option('--strict', 'Enable strict validation mode')
- .option('--json', 'Output validation report as JSON')
+ .description(CLI_DESCRIPTIONS.changeValidate)
+ .option('--strict', 'Ativa modo de validação estrita')
+ .option('--json', 'Saída do relatório de validação como JSON')
.option('--no-interactive', 'Disable interactive prompts')
.action(async (changeName?: string, options?: { strict?: boolean; json?: boolean; noInteractive?: boolean }) => {
try {
@@ -260,24 +262,24 @@ changeCmd
process.exit(process.exitCode);
}
} catch (error) {
- console.error(`Error: ${(error as Error).message}`);
+ console.error(CLI_MESSAGES.error((error as Error).message));
process.exitCode = 1;
}
});
program
.command('archive [change-name]')
- .description('Archive a completed change and update main specs')
- .option('-y, --yes', 'Skip confirmation prompts')
- .option('--skip-specs', 'Skip spec update operations (useful for infrastructure, tooling, or doc-only changes)')
- .option('--no-validate', 'Skip validation (not recommended, requires confirmation)')
+ .description(CLI_DESCRIPTIONS.archive)
+ .option('-y, --yes', 'Pula confirmações interativas')
+ .option('--skip-specs', 'Ignora operações de atualização de especificação (útil para alterações de infraestrutura, ferramentas ou apenas documentação)')
+ .option('--no-validate', 'Ignora validação (não recomendado, requer confirmação)')
.action(async (changeName?: string, options?: { yes?: boolean; skipSpecs?: boolean; noValidate?: boolean; validate?: boolean }) => {
try {
const archiveCommand = new ArchiveCommand();
await archiveCommand.execute(changeName, options);
} catch (error) {
console.log(); // Empty line for spacing
- ora().fail(`Error: ${(error as Error).message}`);
+ ora().fail(CLI_MESSAGES.error((error as Error).message));
process.exit(1);
}
});
@@ -285,18 +287,19 @@ program
registerSpecCommand(program);
registerConfigCommand(program);
registerSchemaCommand(program);
+registerToolsCommand(program);
// Top-level validate command
program
.command('validate [item-name]')
- .description('Validate changes and specs')
- .option('--all', 'Validate all changes and specs')
- .option('--changes', 'Validate all changes')
- .option('--specs', 'Validate all specs')
- .option('--type ', 'Specify item type when ambiguous: change|spec')
- .option('--strict', 'Enable strict validation mode')
- .option('--json', 'Output validation results as JSON')
- .option('--concurrency ', 'Max concurrent validations (defaults to env OPENSPEC_CONCURRENCY or 6)')
+ .description(CLI_DESCRIPTIONS.validate)
+ .option('--all', 'Valida todas as alterações e especificações')
+ .option('--changes', 'Valida todas as alterações')
+ .option('--specs', 'Valida todas as especificações')
+ .option('--type ', 'Especifica o tipo do item quando ambíguo: change|spec')
+ .option('--strict', 'Ativa modo de validação estrita')
+ .option('--json', 'Saída dos resultados de validação como JSON')
+ .option('--concurrency ', 'Máximo de validações concorrentes (padrão: env OPENSPEC_CONCURRENCY ou 6)')
.option('--no-interactive', 'Disable interactive prompts')
.action(async (itemName?: string, options?: { all?: boolean; changes?: boolean; specs?: boolean; type?: string; strict?: boolean; json?: boolean; noInteractive?: boolean; concurrency?: string }) => {
try {
@@ -304,7 +307,7 @@ program
await validateCommand.execute(itemName, options);
} catch (error) {
console.log();
- ora().fail(`Error: ${(error as Error).message}`);
+ ora().fail(CLI_MESSAGES.error((error as Error).message));
process.exit(1);
}
});
@@ -312,17 +315,17 @@ program
// Top-level show command
program
.command('show [item-name]')
- .description('Show a change or spec')
- .option('--json', 'Output as JSON')
- .option('--type ', 'Specify item type when ambiguous: change|spec')
+ .description(CLI_DESCRIPTIONS.show)
+ .option('--json', 'Saída como JSON')
+ .option('--type ', 'Especifica o tipo do item quando ambíguo: change|spec')
.option('--no-interactive', 'Disable interactive prompts')
// change-only flags
- .option('--deltas-only', 'Show only deltas (JSON only, change)')
- .option('--requirements-only', 'Alias for --deltas-only (deprecated, change)')
+ .option('--deltas-only', 'Exibe apenas deltas (somente JSON, alteração)')
+ .option('--requirements-only', 'Alias para --deltas-only (descontinuado, alteração)')
// spec-only flags
- .option('--requirements', 'JSON only: Show only requirements (exclude scenarios)')
- .option('--no-scenarios', 'JSON only: Exclude scenario content')
- .option('-r, --requirement ', 'JSON only: Show specific requirement by ID (1-based)')
+ .option('--requirements', 'Somente JSON: Exibe apenas requisitos (exclui cenários)')
+ .option('--no-scenarios', 'Somente JSON: Exclui conteúdo de cenários')
+ .option('-r, --requirement ', 'Somente JSON: Exibe requisito específico pelo ID (base 1)')
// allow unknown options to pass-through to underlying command implementation
.allowUnknownOption(true)
.action(async (itemName?: string, options?: { json?: boolean; type?: string; noInteractive?: boolean; [k: string]: any }) => {
@@ -331,7 +334,7 @@ program
await showCommand.execute(itemName, options ?? {});
} catch (error) {
console.log();
- ora().fail(`Error: ${(error as Error).message}`);
+ ora().fail(CLI_MESSAGES.error((error as Error).message));
process.exit(1);
}
});
@@ -339,15 +342,15 @@ program
// Feedback command
program
.command('feedback ')
- .description('Submit feedback about OpenSpec')
- .option('--body ', 'Detailed description for the feedback')
+ .description(CLI_DESCRIPTIONS.feedback)
+ .option('--body ', 'Descrição detalhada do feedback')
.action(async (message: string, options?: { body?: string }) => {
try {
const feedbackCommand = new FeedbackCommand();
await feedbackCommand.execute(message, options);
} catch (error) {
console.log();
- ora().fail(`Error: ${(error as Error).message}`);
+ ora().fail(CLI_MESSAGES.error((error as Error).message));
process.exit(1);
}
});
@@ -355,48 +358,48 @@ program
// Completion command with subcommands
const completionCmd = program
.command('completion')
- .description('Manage shell completions for OpenSpec CLI');
+ .description(CLI_DESCRIPTIONS.completion);
completionCmd
.command('generate [shell]')
- .description('Generate completion script for a shell (outputs to stdout)')
+ .description(CLI_DESCRIPTIONS.completionGenerate)
.action(async (shell?: string) => {
try {
const completionCommand = new CompletionCommand();
await completionCommand.generate({ shell });
} catch (error) {
console.log();
- ora().fail(`Error: ${(error as Error).message}`);
+ ora().fail(CLI_MESSAGES.error((error as Error).message));
process.exit(1);
}
});
completionCmd
.command('install [shell]')
- .description('Install completion script for a shell')
- .option('--verbose', 'Show detailed installation output')
+ .description(CLI_DESCRIPTIONS.completionInstall)
+ .option('--verbose', 'Mostra saída detalhada da instalação')
.action(async (shell?: string, options?: { verbose?: boolean }) => {
try {
const completionCommand = new CompletionCommand();
await completionCommand.install({ shell, verbose: options?.verbose });
} catch (error) {
console.log();
- ora().fail(`Error: ${(error as Error).message}`);
+ ora().fail(CLI_MESSAGES.error((error as Error).message));
process.exit(1);
}
});
completionCmd
.command('uninstall [shell]')
- .description('Uninstall completion script for a shell')
- .option('-y, --yes', 'Skip confirmation prompts')
+ .description(CLI_DESCRIPTIONS.completionUninstall)
+ .option('-y, --yes', CONFIG_MESSAGES.skipConfirmationOption)
.action(async (shell?: string, options?: { yes?: boolean }) => {
try {
const completionCommand = new CompletionCommand();
await completionCommand.uninstall({ shell, yes: options?.yes });
} catch (error) {
console.log();
- ora().fail(`Error: ${(error as Error).message}`);
+ ora().fail(CLI_MESSAGES.error((error as Error).message));
process.exit(1);
}
});
@@ -404,7 +407,7 @@ completionCmd
// Hidden command for machine-readable completion data
program
.command('__complete ', { hidden: true })
- .description('Output completion data in machine-readable format (internal use)')
+ .description(CLI_DESCRIPTIONS.__complete)
.action(async (type: string) => {
try {
const completionCommand = new CompletionCommand();
@@ -422,16 +425,16 @@ program
// Status command
program
.command('status')
- .description('Display artifact completion status for a change')
- .option('--change ', 'Change name to show status for')
- .option('--schema ', 'Schema override (auto-detected from config.yaml)')
+ .description(CLI_DESCRIPTIONS.status)
+ .option('--change ', 'Nome da alteração para exibir o status')
+ .option('--schema ', 'Sobrescreve o esquema (auto-detectado do config.yaml)')
.option('--json', 'Output as JSON')
.action(async (options: StatusOptions) => {
try {
await statusCommand(options);
} catch (error) {
console.log();
- ora().fail(`Error: ${(error as Error).message}`);
+ ora().fail(CLI_MESSAGES.error((error as Error).message));
process.exit(1);
}
});
@@ -439,9 +442,9 @@ program
// Instructions command
program
.command('instructions [artifact]')
- .description('Output enriched instructions for creating an artifact or applying tasks')
- .option('--change ', 'Change name')
- .option('--schema ', 'Schema override (auto-detected from config.yaml)')
+ .description(CLI_DESCRIPTIONS.instructions)
+ .option('--change ', 'Nome da alteração')
+ .option('--schema ', 'Sobrescreve o esquema (auto-detectado do config.yaml)')
.option('--json', 'Output as JSON')
.action(async (artifactId: string | undefined, options: InstructionsOptions) => {
try {
@@ -453,7 +456,7 @@ program
}
} catch (error) {
console.log();
- ora().fail(`Error: ${(error as Error).message}`);
+ ora().fail(CLI_MESSAGES.error((error as Error).message));
process.exit(1);
}
});
@@ -461,15 +464,15 @@ program
// Templates command
program
.command('templates')
- .description('Show resolved template paths for all artifacts in a schema')
- .option('--schema ', `Schema to use (default: ${DEFAULT_SCHEMA})`)
- .option('--json', 'Output as JSON mapping artifact IDs to template paths')
+ .description(CLI_DESCRIPTIONS.templates)
+ .option('--schema ', `Esquema a usar (padrão: ${DEFAULT_SCHEMA})`)
+ .option('--json', 'Saída como JSON mapeando IDs de artefatos para caminhos de templates')
.action(async (options: TemplatesOptions) => {
try {
await templatesCommand(options);
} catch (error) {
console.log();
- ora().fail(`Error: ${(error as Error).message}`);
+ ora().fail(CLI_MESSAGES.error((error as Error).message));
process.exit(1);
}
});
@@ -477,32 +480,32 @@ program
// Schemas command
program
.command('schemas')
- .description('List available workflow schemas with descriptions')
- .option('--json', 'Output as JSON (for agent use)')
+ .description(CLI_DESCRIPTIONS.schemas)
+ .option('--json', 'Saída como JSON (para uso por agentes)')
.action(async (options: SchemasOptions) => {
try {
await schemasCommand(options);
} catch (error) {
console.log();
- ora().fail(`Error: ${(error as Error).message}`);
+ ora().fail(CLI_MESSAGES.error((error as Error).message));
process.exit(1);
}
});
// New command group with change subcommand
-const newCmd = program.command('new').description('Create new items');
+const newCmd = program.command('new').description(CLI_DESCRIPTIONS.new);
newCmd
.command('change ')
- .description('Create a new change directory')
- .option('--description ', 'Description to add to README.md')
- .option('--schema ', `Workflow schema to use (default: ${DEFAULT_SCHEMA})`)
+ .description(CLI_DESCRIPTIONS.newChange)
+ .option('--description ', 'Descrição a adicionar ao README.md')
+ .option('--schema ', `Esquema de fluxo de trabalho a usar (padrão: ${DEFAULT_SCHEMA})`)
.action(async (name: string, options: NewChangeOptions) => {
try {
await newChangeCommand(name, options);
} catch (error) {
console.log();
- ora().fail(`Error: ${(error as Error).message}`);
+ ora().fail(CLI_MESSAGES.error((error as Error).message));
process.exit(1);
}
});
diff --git a/src/commands/change.ts b/src/commands/change.ts
index 051b4697c6..26b545b10d 100644
--- a/src/commands/change.ts
+++ b/src/commands/change.ts
@@ -6,6 +6,7 @@ import { ChangeParser } from '../core/parsers/change-parser.js';
import { Change } from '../core/schemas/index.js';
import { isInteractive } from '../utils/interactive.js';
import { getActiveChangeIds } from '../utils/item-discovery.js';
+import { CHANGE_MESSAGES, UTILS_MESSAGES } from '../messages/index.js';
// Constants for better maintainability
const ARCHIVE_DIR = 'archive';
@@ -34,17 +35,17 @@ export class ChangeCommand {
if (canPrompt && changes.length > 0) {
const { select } = await import('@inquirer/prompts');
const selected = await select({
- message: 'Select a change to show',
+ message: CHANGE_MESSAGES.selectChangeToShow,
choices: changes.map(id => ({ name: id, value: id })),
});
changeName = selected;
} else {
if (changes.length === 0) {
- console.error('No change specified. No active changes found.');
+ console.error(CHANGE_MESSAGES.noChangeSpecifiedNoActive);
} else {
- console.error(`No change specified. Available IDs: ${changes.join(', ')}`);
+ console.error(CHANGE_MESSAGES.noChangeSpecifiedAvailable(changes.join(', ')));
}
- console.error('Hint: use "openspec change list" to view available changes.');
+ console.error(CHANGE_MESSAGES.hintViewChanges);
process.exitCode = 1;
return;
}
@@ -55,14 +56,14 @@ export class ChangeCommand {
try {
await fs.access(proposalPath);
} catch {
- throw new Error(`Change "${changeName}" not found at ${proposalPath}`);
+ throw new Error(CHANGE_MESSAGES.changeNotFound(changeName, proposalPath));
}
if (options?.json) {
const jsonOutput = await this.converter.convertChangeToJson(proposalPath);
if (options.requirementsOnly) {
- console.error('Flag --requirements-only is deprecated; use --deltas-only instead.');
+ console.error(CHANGE_MESSAGES.requirementsOnlyDeprecated);
}
const parsed: Change = JSON.parse(jsonOutput);
@@ -118,7 +119,7 @@ export class ChangeCommand {
} catch (error) {
// Tasks file may not exist, which is okay
if (process.env.DEBUG) {
- console.error(`Failed to read tasks file at ${tasksPath}:`, error);
+ console.error(UTILS_MESSAGES.failedToReadTasks(tasksPath, error));
}
}
@@ -143,7 +144,7 @@ export class ChangeCommand {
console.log(JSON.stringify(sorted, null, 2));
} else {
if (changes.length === 0) {
- console.log('No items found');
+ console.log(CHANGE_MESSAGES.noItemsFound);
return;
}
const sorted = [...changes].sort();
@@ -167,16 +168,16 @@ export class ChangeCommand {
taskStatusText = ` [tasks ${completed}/${total}]`;
} catch (error) {
if (process.env.DEBUG) {
- console.error(`Failed to read tasks file at ${tasksPath}:`, error);
+ console.error(UTILS_MESSAGES.failedToReadTasks(tasksPath, error));
}
}
const changeDir = path.join(changesPath, changeName);
const parser = new ChangeParser(await fs.readFile(proposalPath, 'utf-8'), changeDir);
const change = await parser.parseChangeWithDeltas(changeName);
- const deltaCountText = ` [deltas ${change.deltas.length}]`;
+ const deltaCountText = CHANGE_MESSAGES.deltas(change.deltas.length);
console.log(`${changeName}: ${title}${deltaCountText}${taskStatusText}`);
} catch {
- console.log(`${changeName}: (unable to read)`);
+ console.log(`${changeName}: ${CHANGE_MESSAGES.unableToRead}`);
}
}
}
@@ -191,17 +192,17 @@ export class ChangeCommand {
if (canPrompt && changes.length > 0) {
const { select } = await import('@inquirer/prompts');
const selected = await select({
- message: 'Select a change to validate',
+ message: CHANGE_MESSAGES.selectChangeToValidate,
choices: changes.map(id => ({ name: id, value: id })),
});
changeName = selected;
} else {
if (changes.length === 0) {
- console.error('No change specified. No active changes found.');
+ console.error(CHANGE_MESSAGES.noChangeSpecifiedNoActive);
} else {
- console.error(`No change specified. Available IDs: ${changes.join(', ')}`);
+ console.error(CHANGE_MESSAGES.noChangeSpecifiedAvailable(changes.join(', ')));
}
- console.error('Hint: use "openspec change list" to view available changes.');
+ console.error(CHANGE_MESSAGES.hintViewChanges);
process.exitCode = 1;
return;
}
@@ -212,7 +213,7 @@ export class ChangeCommand {
try {
await fs.access(changeDir);
} catch {
- throw new Error(`Change "${changeName}" not found at ${changeDir}`);
+ throw new Error(CHANGE_MESSAGES.changeNotFound(changeName, changeDir));
}
const validator = new Validator(options?.strict || false);
@@ -222,9 +223,9 @@ export class ChangeCommand {
console.log(JSON.stringify(report, null, 2));
} else {
if (report.valid) {
- console.log(`Change "${changeName}" is valid`);
+ console.log(CHANGE_MESSAGES.changeIsValid(changeName));
} else {
- console.error(`Change "${changeName}" has issues`);
+ console.error(CHANGE_MESSAGES.changeHasIssues(changeName));
report.issues.forEach(issue => {
const label = issue.level === 'ERROR' ? 'ERROR' : 'WARNING';
const prefix = issue.level === 'ERROR' ? '✗' : '⚠';
@@ -283,10 +284,10 @@ export class ChangeCommand {
private printNextSteps(): void {
const bullets: string[] = [];
- bullets.push('- Ensure change has deltas in specs/: use headers ## ADDED/MODIFIED/REMOVED/RENAMED Requirements');
- bullets.push('- Each requirement MUST include at least one #### Scenario: block');
- bullets.push('- Debug parsed deltas: openspec change show --json --deltas-only');
- console.error('Next steps:');
+ bullets.push(CHANGE_MESSAGES.ensureDeltasInSpecs);
+ bullets.push(CHANGE_MESSAGES.eachRequirementNeedsScenario);
+ bullets.push(CHANGE_MESSAGES.debugParsedDeltas);
+ console.error(CHANGE_MESSAGES.nextSteps);
bullets.forEach(b => console.error(` ${b}`));
}
}
diff --git a/src/commands/completion.ts b/src/commands/completion.ts
index bbdee7d92a..42a018d2f6 100644
--- a/src/commands/completion.ts
+++ b/src/commands/completion.ts
@@ -4,6 +4,7 @@ import { COMMAND_REGISTRY } from '../core/completions/command-registry.js';
import { detectShell, SupportedShell } from '../utils/shell-detection.js';
import { CompletionProvider } from '../core/completions/completion-provider.js';
import { getArchivedChangeIds } from '../utils/item-discovery.js';
+import { COMPLETION_MESSAGES, CLI_MESSAGES } from '../messages/index.js';
interface GenerateOptions {
shell?: string;
@@ -24,7 +25,7 @@ interface CompleteOptions {
}
/**
- * Command for managing shell completions for OpenSpec CLI
+ * Command for managing shell completions for BR-OpenSpec CLI
*/
export class CompletionCommand {
private completionProvider: CompletionProvider;
@@ -51,21 +52,21 @@ export class CompletionCommand {
// Shell was detected but not supported
if (detectionResult.detected && !detectionResult.shell) {
- console.error(`Error: Shell '${detectionResult.detected}' is not supported yet. Currently supported: ${CompletionFactory.getSupportedShells().join(', ')}`);
+ console.error(COMPLETION_MESSAGES.shellNotSupported(detectionResult.detected, CompletionFactory.getSupportedShells().join(', ')));
process.exitCode = 1;
return null;
}
// No shell specified and cannot auto-detect
- console.error('Error: Could not auto-detect shell. Please specify shell explicitly.');
- console.error(`Usage: openspec completion ${operationName} [shell]`);
- console.error(`Currently supported: ${CompletionFactory.getSupportedShells().join(', ')}`);
+ console.error(COMPLETION_MESSAGES.couldNotDetectShell);
+ console.error(COMPLETION_MESSAGES.usageCompletion(operationName));
+ console.error(COMPLETION_MESSAGES.currentlySupported(CompletionFactory.getSupportedShells().join(', ')));
process.exitCode = 1;
return null;
}
if (!CompletionFactory.isSupported(normalizedShell)) {
- console.error(`Error: Shell '${normalizedShell}' is not supported yet. Currently supported: ${CompletionFactory.getSupportedShells().join(', ')}`);
+ console.error(COMPLETION_MESSAGES.shellNotSupported(normalizedShell, CompletionFactory.getSupportedShells().join(', ')));
process.exitCode = 1;
return null;
}
@@ -125,7 +126,7 @@ export class CompletionCommand {
const generator = CompletionFactory.createGenerator(shell);
const installer = CompletionFactory.createInstaller(shell);
- const spinner = ora(`Installing ${shell} completion script...`).start();
+ const spinner = ora(COMPLETION_MESSAGES.installingCompletion(shell)).start();
try {
// Generate the completion script
@@ -137,12 +138,12 @@ export class CompletionCommand {
spinner.stop();
if (result.success) {
- console.log(`✓ ${result.message}`);
+ console.log(COMPLETION_MESSAGES.installSuccess(result.message));
if (verbose && result.installedPath) {
- console.log(` Installed to: ${result.installedPath}`);
+ console.log(COMPLETION_MESSAGES.installedTo(result.installedPath));
if (result.backupPath) {
- console.log(` Backup created: ${result.backupPath}`);
+ console.log(COMPLETION_MESSAGES.backupCreated(result.backupPath));
}
// Check if any shell config was updated
@@ -156,7 +157,7 @@ export class CompletionCommand {
powershell: '$PROFILE',
};
const configPath = configPaths[shell] || 'config file';
- console.log(` ${configPath} configured automatically`);
+ console.log(COMPLETION_MESSAGES.configFileConfigured(configPath));
}
}
@@ -190,16 +191,16 @@ export class CompletionCommand {
};
const reloadCmd = reloadCommands[shell] || `restart your ${shell} shell`;
- console.log(`Restart your shell or run: ${reloadCmd}`);
+ console.log(COMPLETION_MESSAGES.restartShell(reloadCmd));
}
}
} else {
- console.error(`✗ ${result.message}`);
+ console.error(COMPLETION_MESSAGES.installFailed(result.message));
process.exitCode = 1;
}
} catch (error) {
spinner.stop();
- console.error(`✗ Failed to install completion script: ${error instanceof Error ? error.message : String(error)}`);
+ console.error(COMPLETION_MESSAGES.failedToInstall(error instanceof Error ? error.message : String(error)));
process.exitCode = 1;
}
}
@@ -224,17 +225,17 @@ export class CompletionCommand {
const configPath = configPaths[shell] || `${shell} configuration`;
const confirmed = await confirm({
- message: `Remove OpenSpec configuration from ${configPath}?`,
+ message: COMPLETION_MESSAGES.removeConfigConfirm(configPath),
default: false,
});
if (!confirmed) {
- console.log('Uninstall cancelled.');
+ console.log(COMPLETION_MESSAGES.uninstallCancelled);
return;
}
}
- const spinner = ora(`Uninstalling ${shell} completion script...`).start();
+ const spinner = ora(COMPLETION_MESSAGES.uninstallingCompletion(shell)).start();
try {
const result = await installer.uninstall();
@@ -242,14 +243,14 @@ export class CompletionCommand {
spinner.stop();
if (result.success) {
- console.log(`✓ ${result.message}`);
+ console.log(COMPLETION_MESSAGES.uninstallSuccess(result.message));
} else {
- console.error(`✗ ${result.message}`);
+ console.error(COMPLETION_MESSAGES.uninstallFailed(result.message));
process.exitCode = 1;
}
} catch (error) {
spinner.stop();
- console.error(`✗ Failed to uninstall completion script: ${error instanceof Error ? error.message : String(error)}`);
+ console.error(COMPLETION_MESSAGES.failedToUninstall(error instanceof Error ? error.message : String(error)));
process.exitCode = 1;
}
}
@@ -268,21 +269,21 @@ export class CompletionCommand {
case 'changes': {
const changeIds = await this.completionProvider.getChangeIds();
for (const id of changeIds) {
- console.log(`${id}\tactive change`);
+ console.log(`${id}\t${COMPLETION_MESSAGES.activeChange}`);
}
break;
}
case 'specs': {
const specIds = await this.completionProvider.getSpecIds();
for (const id of specIds) {
- console.log(`${id}\tspecification`);
+ console.log(`${id}\t${COMPLETION_MESSAGES.specification}`);
}
break;
}
case 'archived-changes': {
const archivedIds = await getArchivedChangeIds();
for (const id of archivedIds) {
- console.log(`${id}\tarchived change`);
+ console.log(`${id}\t${COMPLETION_MESSAGES.archivedChange}`);
}
break;
}
diff --git a/src/commands/config.ts b/src/commands/config.ts
index 42c736d147..b03c4293ba 100644
--- a/src/commands/config.ts
+++ b/src/commands/config.ts
@@ -22,6 +22,7 @@ import {
import { CORE_WORKFLOWS, ALL_WORKFLOWS, getProfileWorkflows } from '../core/profiles.js';
import { OPENSPEC_DIR_NAME } from '../core/config.js';
import { hasProjectConfigDrift } from '../core/profile-sync-drift.js';
+import { CONFIG_MESSAGES, CLI_MESSAGES } from '../messages/index.js';
type ProfileAction = 'both' | 'delivery' | 'workflows' | 'keep';
@@ -43,48 +44,48 @@ interface WorkflowPromptMeta {
const WORKFLOW_PROMPT_META: Record = {
propose: {
- name: 'Propose change',
- description: 'Create proposal, design, and tasks from a request',
+ name: CONFIG_MESSAGES.workflowProposeName,
+ description: CONFIG_MESSAGES.workflowProposeDesc,
},
explore: {
- name: 'Explore ideas',
- description: 'Investigate a problem before implementation',
+ name: CONFIG_MESSAGES.workflowExploreName,
+ description: CONFIG_MESSAGES.workflowExploreDesc,
},
new: {
- name: 'New change',
- description: 'Create a new change scaffold quickly',
+ name: CONFIG_MESSAGES.workflowNewName,
+ description: CONFIG_MESSAGES.workflowNewDesc,
},
continue: {
- name: 'Continue change',
- description: 'Resume work on an existing change',
+ name: CONFIG_MESSAGES.workflowContinueName,
+ description: CONFIG_MESSAGES.workflowContinueDesc,
},
apply: {
- name: 'Apply tasks',
- description: 'Implement tasks from the current change',
+ name: CONFIG_MESSAGES.workflowApplyName,
+ description: CONFIG_MESSAGES.workflowApplyDesc,
},
ff: {
- name: 'Fast-forward',
- description: 'Run a faster implementation workflow',
+ name: CONFIG_MESSAGES.workflowFastForwardName,
+ description: CONFIG_MESSAGES.workflowFastForwardDesc,
},
sync: {
- name: 'Sync specs',
- description: 'Sync change artifacts with specs',
+ name: CONFIG_MESSAGES.workflowSyncName,
+ description: CONFIG_MESSAGES.workflowSyncDesc,
},
archive: {
- name: 'Archive change',
- description: 'Finalize and archive a completed change',
+ name: CONFIG_MESSAGES.workflowArchiveName,
+ description: CONFIG_MESSAGES.workflowArchiveDesc,
},
'bulk-archive': {
- name: 'Bulk archive',
- description: 'Archive multiple completed changes together',
+ name: CONFIG_MESSAGES.workflowBulkArchiveName,
+ description: CONFIG_MESSAGES.workflowBulkArchiveDesc,
},
verify: {
- name: 'Verify change',
- description: 'Run verification checks against a change',
+ name: CONFIG_MESSAGES.workflowVerifyName,
+ description: CONFIG_MESSAGES.workflowVerifyDesc,
},
onboard: {
- name: 'Onboard',
- description: 'Guided onboarding flow for OpenSpec',
+ name: CONFIG_MESSAGES.workflowOnboardName,
+ description: CONFIG_MESSAGES.workflowOnboardDesc,
},
};
@@ -198,7 +199,7 @@ function maybeWarnConfigDrift(
if (!hasProjectConfigDrift(projectDir, state.workflows, state.delivery)) {
return;
}
- console.log(colorize('Warning: Global config is not applied to this project. Run `openspec update` to sync.'));
+ console.log(colorize(CONFIG_MESSAGES.warningGlobalConfigNotApplied));
}
/**
@@ -209,12 +210,12 @@ function maybeWarnConfigDrift(
export function registerConfigCommand(program: Command): void {
const configCmd = program
.command('config')
- .description('View and modify global OpenSpec configuration')
- .option('--scope ', 'Config scope (only "global" supported currently)')
+ .description(CONFIG_MESSAGES.viewAndModify)
+ .option('--scope ', CONFIG_MESSAGES.configScopeOption)
.hook('preAction', (thisCommand) => {
const opts = thisCommand.opts();
if (opts.scope && opts.scope !== 'global') {
- console.error('Error: Project-local config is not yet implemented');
+ console.error(CLI_MESSAGES.projectLocalNotImplemented);
process.exit(1);
}
});
@@ -222,7 +223,7 @@ export function registerConfigCommand(program: Command): void {
// config path
configCmd
.command('path')
- .description('Show config file location')
+ .description(CONFIG_MESSAGES.showLocation)
.action(() => {
console.log(getGlobalConfigPath());
});
@@ -230,8 +231,8 @@ export function registerConfigCommand(program: Command): void {
// config list
configCmd
.command('list')
- .description('Show all current settings')
- .option('--json', 'Output as JSON')
+ .description(CONFIG_MESSAGES.showAllSettings)
+ .option('--json', CONFIG_MESSAGES.outputAsJson)
.action((options: { json?: boolean }) => {
const config = getGlobalConfig();
@@ -254,15 +255,15 @@ export function registerConfigCommand(program: Command): void {
// Annotate profile settings
const profileSource = rawConfig.profile !== undefined ? '(explicit)' : '(default)';
const deliverySource = rawConfig.delivery !== undefined ? '(explicit)' : '(default)';
- console.log(`\nProfile settings:`);
- console.log(` profile: ${config.profile} ${profileSource}`);
- console.log(` delivery: ${config.delivery} ${deliverySource}`);
+ console.log(`\n${CONFIG_MESSAGES.profileSettings}`);
+ console.log(CONFIG_MESSAGES.profileLabel(config.profile, profileSource));
+ console.log(CONFIG_MESSAGES.deliveryLabel(config.delivery, deliverySource));
if (config.profile === 'core') {
- console.log(` workflows: ${CORE_WORKFLOWS.join(', ')} (from core profile)`);
+ console.log(CONFIG_MESSAGES.coreWorkflowsNote(CORE_WORKFLOWS.join(', ')));
} else if (config.workflows && config.workflows.length > 0) {
- console.log(` workflows: ${config.workflows.join(', ')} (explicit)`);
+ console.log(CONFIG_MESSAGES.explicitWorkflowsNote(config.workflows.join(', ')));
} else {
- console.log(` workflows: (none)`);
+ console.log(CONFIG_MESSAGES.noWorkflowsNote);
}
}
});
@@ -270,7 +271,7 @@ export function registerConfigCommand(program: Command): void {
// config get
configCmd
.command('get ')
- .description('Get a specific value (raw, scriptable)')
+ .description(CONFIG_MESSAGES.getValue)
.action((key: string) => {
const config = getGlobalConfig();
const value = getNestedValue(config as Record, key);
@@ -290,17 +291,17 @@ export function registerConfigCommand(program: Command): void {
// config set
configCmd
.command('set ')
- .description('Set a value (auto-coerce types)')
- .option('--string', 'Force value to be stored as string')
- .option('--allow-unknown', 'Allow setting unknown keys')
+ .description(CONFIG_MESSAGES.setValue)
+ .option('--string', CONFIG_MESSAGES.forceStringOption)
+ .option('--allow-unknown', CONFIG_MESSAGES.allowUnknownOption)
.action((key: string, value: string, options: { string?: boolean; allowUnknown?: boolean }) => {
const allowUnknown = Boolean(options.allowUnknown);
const keyValidation = validateConfigKeyPath(key);
if (!keyValidation.valid && !allowUnknown) {
const reason = keyValidation.reason ? ` ${keyValidation.reason}.` : '';
- console.error(`Error: Invalid configuration key "${key}".${reason}`);
- console.error('Use "openspec config list" to see available keys.');
- console.error('Pass --allow-unknown to bypass this check.');
+ console.error(CONFIG_MESSAGES.invalidConfigKey(key, reason));
+ console.error(CONFIG_MESSAGES.useConfigList);
+ console.error(CONFIG_MESSAGES.passAllowUnknown);
process.exitCode = 1;
return;
}
@@ -315,7 +316,7 @@ export function registerConfigCommand(program: Command): void {
// Validate the new config
const validation = validateConfig(newConfig);
if (!validation.success) {
- console.error(`Error: Invalid configuration - ${validation.error}`);
+ console.error(CONFIG_MESSAGES.invalidConfiguration(validation.error!));
process.exitCode = 1;
return;
}
@@ -326,35 +327,35 @@ export function registerConfigCommand(program: Command): void {
const displayValue =
typeof coercedValue === 'string' ? `"${coercedValue}"` : String(coercedValue);
- console.log(`Set ${key} = ${displayValue}`);
+ console.log(CONFIG_MESSAGES.setKeyValue(key, displayValue));
});
// config unset
configCmd
.command('unset ')
- .description('Remove a key (revert to default)')
+ .description(CONFIG_MESSAGES.removeKey)
.action((key: string) => {
const config = getGlobalConfig() as Record;
const existed = deleteNestedValue(config, key);
if (existed) {
saveGlobalConfig(config as GlobalConfig);
- console.log(`Unset ${key} (reverted to default)`);
+ console.log(CONFIG_MESSAGES.unsetKey(key));
} else {
- console.log(`Key "${key}" was not set`);
+ console.log(CONFIG_MESSAGES.keyNotSet(key));
}
});
// config reset
configCmd
.command('reset')
- .description('Reset configuration to defaults')
- .option('--all', 'Reset all configuration (required)')
- .option('-y, --yes', 'Skip confirmation prompts')
+ .description(CONFIG_MESSAGES.resetConfig)
+ .option('--all', CONFIG_MESSAGES.resetAllOption)
+ .option('-y, --yes', CONFIG_MESSAGES.skipConfirmationOption)
.action(async (options: { all?: boolean; yes?: boolean }) => {
if (!options.all) {
- console.error('Error: --all flag is required for reset');
- console.error('Usage: openspec config reset --all [-y]');
+ console.error(CONFIG_MESSAGES.resetAllRequired);
+ console.error(CONFIG_MESSAGES.resetUsage);
process.exitCode = 1;
return;
}
@@ -364,12 +365,12 @@ export function registerConfigCommand(program: Command): void {
let confirmed: boolean;
try {
confirmed = await confirm({
- message: 'Reset all configuration to defaults?',
+ message: CONFIG_MESSAGES.resetConfirm,
default: false,
});
} catch (error) {
if (isPromptCancellationError(error)) {
- console.log('Reset cancelled.');
+ console.log(CONFIG_MESSAGES.resetCancelled);
process.exitCode = 130;
return;
}
@@ -377,26 +378,26 @@ export function registerConfigCommand(program: Command): void {
}
if (!confirmed) {
- console.log('Reset cancelled.');
+ console.log(CONFIG_MESSAGES.resetCancelled);
return;
}
}
saveGlobalConfig({ ...DEFAULT_CONFIG });
- console.log('Configuration reset to defaults');
+ console.log(CONFIG_MESSAGES.configurationReset);
});
// config edit
configCmd
.command('edit')
- .description('Open config in $EDITOR')
+ .description(CONFIG_MESSAGES.openInEditor)
.action(async () => {
const editor = process.env.EDITOR || process.env.VISUAL;
if (!editor) {
- console.error('Error: No editor configured');
- console.error('Set the EDITOR or VISUAL environment variable to your preferred editor');
- console.error('Example: export EDITOR=vim');
+ console.error(CONFIG_MESSAGES.noEditorConfigured);
+ console.error(CONFIG_MESSAGES.setEditorEnv);
+ console.error(CONFIG_MESSAGES.editorExample);
process.exitCode = 1;
return;
}
@@ -433,17 +434,17 @@ export function registerConfigCommand(program: Command): void {
const validation = validateConfig(parsedConfig);
if (!validation.success) {
- console.error(`Error: Invalid configuration - ${validation.error}`);
+ console.error(CONFIG_MESSAGES.invalidConfiguration(validation.error!));
process.exitCode = 1;
}
} catch (error) {
if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
- console.error(`Error: Config file not found at ${configPath}`);
+ console.error(CONFIG_MESSAGES.configFileNotFound(configPath));
} else if (error instanceof SyntaxError) {
- console.error(`Error: Invalid JSON in ${configPath}`);
+ console.error(CONFIG_MESSAGES.invalidJson(configPath));
console.error(error.message);
} else {
- console.error(`Error: Unable to validate configuration - ${error instanceof Error ? error.message : String(error)}`);
+ console.error(CONFIG_MESSAGES.unableToValidateConfig(error instanceof Error ? error.message : String(error)));
}
process.exitCode = 1;
}
@@ -452,7 +453,7 @@ export function registerConfigCommand(program: Command): void {
// config profile [preset]
configCmd
.command('profile [preset]')
- .description('Configure workflow profile (interactive picker or preset shortcut)')
+ .description(CONFIG_MESSAGES.configureProfile)
.action(async (preset?: string) => {
// Preset shortcut: `openspec config profile core`
if (preset === 'core') {
@@ -461,19 +462,19 @@ export function registerConfigCommand(program: Command): void {
config.workflows = [...CORE_WORKFLOWS];
// Preserve delivery setting
saveGlobalConfig(config);
- console.log('Config updated. Run `openspec update` in your projects to apply.');
+ console.log(CONFIG_MESSAGES.configUpdated);
return;
}
if (preset) {
- console.error(`Error: Unknown profile preset "${preset}". Available presets: core`);
+ console.error(CONFIG_MESSAGES.unknownProfilePreset(preset));
process.exitCode = 1;
return;
}
// Non-interactive check
if (!process.stdout.isTTY) {
- console.error('Interactive mode required. Use `openspec config profile core` or set config via environment/flags.');
+ console.error(CONFIG_MESSAGES.interactiveModeRequired);
process.exitCode = 1;
return;
}
@@ -486,41 +487,41 @@ export function registerConfigCommand(program: Command): void {
const config = getGlobalConfig();
const currentState = resolveCurrentProfileState(config);
- console.log(chalk.bold('\nCurrent profile settings'));
- console.log(` Delivery: ${currentState.delivery}`);
- console.log(` Workflows: ${formatWorkflowSummary(currentState.workflows, currentState.profile)}`);
- console.log(chalk.dim(' Delivery = where workflows are installed (skills, commands, or both)'));
- console.log(chalk.dim(' Workflows = which actions are available (propose, explore, apply, etc.)'));
+ console.log(chalk.bold('\n' + CONFIG_MESSAGES.currentProfileSettings));
+ console.log(CONFIG_MESSAGES.deliveryLabel(currentState.delivery));
+ console.log(CONFIG_MESSAGES.workflowsLabel(formatWorkflowSummary(currentState.workflows, currentState.profile)));
+ console.log(chalk.dim(CONFIG_MESSAGES.deliveryHelp));
+ console.log(chalk.dim(CONFIG_MESSAGES.workflowsHelp));
console.log();
const action = await select({
- message: 'What do you want to configure?',
+ message: CONFIG_MESSAGES.whatToConfigure,
choices: [
{
value: 'both',
- name: 'Delivery and workflows',
- description: 'Update install mode and available actions together',
+ name: CONFIG_MESSAGES.deliveryAndWorkflows,
+ description: CONFIG_MESSAGES.deliveryAndWorkflowsDesc,
},
{
value: 'delivery',
- name: 'Delivery only',
- description: 'Change where workflows are installed',
+ name: CONFIG_MESSAGES.deliveryOnly,
+ description: CONFIG_MESSAGES.deliveryOnlyDesc,
},
{
value: 'workflows',
- name: 'Workflows only',
- description: 'Change which workflow actions are available',
+ name: CONFIG_MESSAGES.workflowsOnly,
+ description: CONFIG_MESSAGES.workflowsOnlyDesc,
},
{
value: 'keep',
- name: 'Keep current settings (exit)',
- description: 'Leave configuration unchanged and exit',
+ name: CONFIG_MESSAGES.keepCurrentSettings,
+ description: CONFIG_MESSAGES.keepCurrentSettingsDesc,
},
],
});
if (action === 'keep') {
- console.log('No config changes.');
+ console.log(CONFIG_MESSAGES.noConfigChanges);
maybeWarnConfigDrift(process.cwd(), currentState, chalk.yellow);
return;
}
@@ -535,28 +536,28 @@ export function registerConfigCommand(program: Command): void {
const deliveryChoices: { value: Delivery; name: string; description: string }[] = [
{
value: 'both' as Delivery,
- name: 'Both (skills + commands)',
- description: 'Install workflows as both skills and slash commands',
+ name: CONFIG_MESSAGES.bothSkillsAndCommands,
+ description: CONFIG_MESSAGES.bothSkillsAndCommandsDesc,
},
{
value: 'skills' as Delivery,
- name: 'Skills only',
- description: 'Install workflows only as skills',
+ name: CONFIG_MESSAGES.skillsOnly,
+ description: CONFIG_MESSAGES.skillsOnlyDesc,
},
{
value: 'commands' as Delivery,
- name: 'Commands only',
- description: 'Install workflows only as slash commands',
+ name: CONFIG_MESSAGES.commandsOnly,
+ description: CONFIG_MESSAGES.commandsOnlyDesc,
},
];
for (const choice of deliveryChoices) {
if (choice.value === currentState.delivery) {
- choice.name += ' [current]';
+ choice.name += CONFIG_MESSAGES.currentSuffix;
}
}
nextState.delivery = await select({
- message: 'Delivery mode (how workflows are installed):',
+ message: CONFIG_MESSAGES.deliveryMode,
choices: deliveryChoices,
default: currentState.delivery,
});
@@ -578,8 +579,8 @@ export function registerConfigCommand(program: Command): void {
};
const selectedWorkflows = await checkbox({
- message: 'Select workflows to make available:',
- instructions: 'Space to toggle, Enter to confirm',
+ message: CONFIG_MESSAGES.selectWorkflows,
+ instructions: CONFIG_MESSAGES.spaceToToggle,
pageSize: ALL_WORKFLOWS.length,
theme: {
icon: {
@@ -595,12 +596,12 @@ export function registerConfigCommand(program: Command): void {
const diff = diffProfileState(currentState, nextState);
if (!diff.hasChanges) {
- console.log('No config changes.');
+ console.log(CONFIG_MESSAGES.noConfigChanges);
maybeWarnConfigDrift(process.cwd(), nextState, chalk.yellow);
return;
}
- console.log(chalk.bold('\nConfig changes:'));
+ console.log(chalk.bold('\n' + CONFIG_MESSAGES.configChanges));
for (const line of diff.lines) {
console.log(` ${line}`);
}
@@ -616,26 +617,26 @@ export function registerConfigCommand(program: Command): void {
const openspecDir = path.join(projectDir, OPENSPEC_DIR_NAME);
if (fs.existsSync(openspecDir)) {
const applyNow = await confirm({
- message: 'Apply changes to this project now?',
+ message: CONFIG_MESSAGES.applyChangesNow,
default: true,
});
if (applyNow) {
try {
execSync('npx openspec update', { stdio: 'inherit', cwd: projectDir });
- console.log('Run `openspec update` in your other projects to apply.');
+ console.log(CONFIG_MESSAGES.configUpdated);
} catch {
- console.error('`openspec update` failed. Please run it manually to apply the profile changes.');
+ console.error(CONFIG_MESSAGES.updateFailed);
process.exitCode = 1;
}
return;
}
}
- console.log('Config updated. Run `openspec update` in your projects to apply.');
+ console.log(CONFIG_MESSAGES.configUpdated);
} catch (error) {
if (isPromptCancellationError(error)) {
- console.log('Config profile cancelled.');
+ console.log(CONFIG_MESSAGES.configProfileCancelled);
process.exitCode = 130;
return;
}
diff --git a/src/commands/feedback.ts b/src/commands/feedback.ts
index e157d11e18..a8af0b7147 100644
--- a/src/commands/feedback.ts
+++ b/src/commands/feedback.ts
@@ -1,6 +1,7 @@
import { execSync, execFileSync } from 'child_process';
import { createRequire } from 'module';
import os from 'os';
+import { FEEDBACK_MESSAGES } from '../messages/index.js';
const require = createRequire(import.meta.url);
@@ -31,7 +32,7 @@ function isGhAuthenticated(): boolean {
}
/**
- * Get OpenSpec version from package.json
+ * Get BR-OpenSpec version from package.json
*/
function getVersion(): string {
try {
@@ -65,17 +66,17 @@ function generateMetadata(): string {
const timestamp = getTimestamp();
return `---
-Submitted via OpenSpec CLI
-- Version: ${version}
-- Platform: ${platform}
-- Timestamp: ${timestamp}`;
+${FEEDBACK_MESSAGES.submittedVia}
+${FEEDBACK_MESSAGES.versionLabel(version)}
+${FEEDBACK_MESSAGES.platformLabel(platform)}
+${FEEDBACK_MESSAGES.timestampLabel(timestamp)}`;
}
/**
* Format the feedback title
*/
function formatTitle(message: string): string {
- return `Feedback: ${message}`;
+ return FEEDBACK_MESSAGES.feedbackTitle(message);
}
/**
@@ -98,7 +99,7 @@ function formatBody(bodyText?: string): string {
* Generate a pre-filled GitHub issue URL for manual submission
*/
function generateManualSubmissionUrl(title: string, body: string): string {
- const repo = 'Fission-AI/OpenSpec';
+ const repo = 'fkmatsuda/BR-OpenSpec';
const encodedTitle = encodeURIComponent(title);
const encodedBody = encodeURIComponent(body);
const encodedLabels = encodeURIComponent('feedback');
@@ -110,12 +111,12 @@ function generateManualSubmissionUrl(title: string, body: string): string {
* Display formatted feedback content for manual submission
*/
function displayFormattedFeedback(title: string, body: string): void {
- console.log('\n--- FORMATTED FEEDBACK ---');
- console.log(`Title: ${title}`);
- console.log(`Labels: feedback`);
- console.log('\nBody:');
+ console.log(FEEDBACK_MESSAGES.formattedFeedbackHeader);
+ console.log(FEEDBACK_MESSAGES.titleLabel(title));
+ console.log(FEEDBACK_MESSAGES.labelsFeedback);
+ console.log(FEEDBACK_MESSAGES.bodyLabel);
console.log(body);
- console.log('--- END FEEDBACK ---\n');
+ console.log(FEEDBACK_MESSAGES.endFeedback);
}
/**
@@ -130,7 +131,7 @@ function submitViaGhCli(title: string, body: string): void {
'issue',
'create',
'--repo',
- 'Fission-AI/OpenSpec',
+ 'fkmatsuda/BR-OpenSpec',
'--title',
title,
'--body',
@@ -142,8 +143,8 @@ function submitViaGhCli(title: string, body: string): void {
);
const issueUrl = result.trim();
- console.log(`\n✓ Feedback submitted successfully!`);
- console.log(`Issue URL: ${issueUrl}\n`);
+ console.log(FEEDBACK_MESSAGES.feedbackSubmitted);
+ console.log(FEEDBACK_MESSAGES.issueUrl(issueUrl));
} catch (error: any) {
// Display the error output from gh CLI
if (error.stderr) {
@@ -162,19 +163,19 @@ function submitViaGhCli(title: string, body: string): void {
*/
function handleFallback(title: string, body: string, reason: 'missing' | 'unauthenticated'): void {
if (reason === 'missing') {
- console.log('⚠️ GitHub CLI not found. Manual submission required.');
+ console.log(FEEDBACK_MESSAGES.githubCliNotFound);
} else {
- console.log('⚠️ GitHub authentication required. Manual submission required.');
+ console.log(FEEDBACK_MESSAGES.githubAuthRequired);
}
displayFormattedFeedback(title, body);
const manualUrl = generateManualSubmissionUrl(title, body);
- console.log('Please submit your feedback manually:');
+ console.log(FEEDBACK_MESSAGES.submitManually);
console.log(manualUrl);
if (reason === 'unauthenticated') {
- console.log('\nTo auto-submit in the future: gh auth login');
+ console.log(FEEDBACK_MESSAGES.autoSubmitHint);
}
// Exit with success code (fallback is successful)
diff --git a/src/commands/schema.ts b/src/commands/schema.ts
index 7f8d0b7888..b20aa395b7 100644
--- a/src/commands/schema.ts
+++ b/src/commands/schema.ts
@@ -12,6 +12,7 @@ import {
} from '../core/artifact-graph/resolver.js';
import { parseSchema, SchemaValidationError } from '../core/artifact-graph/schema.js';
import type { SchemaYaml, Artifact } from '../core/artifact-graph/types.js';
+import { SCHEMA_MESSAGES, CLI_MESSAGES, CONFIG_MESSAGES } from '../messages/index.js';
/**
* Schema source location type
@@ -144,20 +145,20 @@ function validateSchema(
// Check schema.yaml exists
if (verbose) {
- console.log(' Checking schema.yaml exists...');
+ console.log(SCHEMA_MESSAGES.checkingSchemaExists);
}
if (!fs.existsSync(schemaPath)) {
issues.push({
level: 'error',
path: 'schema.yaml',
- message: 'schema.yaml not found',
+ message: SCHEMA_MESSAGES.schemaNotFound,
});
return { valid: false, issues };
}
// Parse YAML
if (verbose) {
- console.log(' Parsing YAML...');
+ console.log(SCHEMA_MESSAGES.parsingYaml);
}
let content: string;
try {
@@ -166,14 +167,14 @@ function validateSchema(
issues.push({
level: 'error',
path: 'schema.yaml',
- message: `Failed to read file: ${(err as Error).message}`,
+ message: SCHEMA_MESSAGES.failedToReadFile((err as Error).message),
});
return { valid: false, issues };
}
// Validate against Zod schema
if (verbose) {
- console.log(' Validating schema structure...');
+ console.log(SCHEMA_MESSAGES.validatingSchemaStructure);
}
let schema: SchemaYaml;
try {
@@ -189,7 +190,7 @@ function validateSchema(
issues.push({
level: 'error',
path: 'schema.yaml',
- message: `Parse error: ${(err as Error).message}`,
+ message: SCHEMA_MESSAGES.parseError((err as Error).message),
});
}
return { valid: false, issues };
@@ -198,7 +199,7 @@ function validateSchema(
// Check template files exist
// Templates can be in schemaDir directly or in a templates/ subdirectory
if (verbose) {
- console.log(' Checking template files...');
+ console.log(SCHEMA_MESSAGES.checkingTemplateFiles);
}
for (const artifact of schema.artifacts) {
// Try templates subdirectory first (standard location), then root
@@ -209,7 +210,7 @@ function validateSchema(
issues.push({
level: 'error',
path: `artifacts.${artifact.id}.template`,
- message: `Template file '${artifact.template}' not found for artifact '${artifact.id}'`,
+ message: SCHEMA_MESSAGES.templateNotFound(artifact.template, artifact.id),
});
}
}
@@ -217,7 +218,7 @@ function validateSchema(
// Dependency graph validation is already done by parseSchema
// (it throws on cycles and invalid references)
if (verbose) {
- console.log(' Dependency graph validation passed (via parseSchema)');
+ console.log(SCHEMA_MESSAGES.dependencyGraphPassed);
}
return { valid: issues.length === 0, issues };
@@ -290,19 +291,19 @@ const DEFAULT_ARTIFACTS: Array<{
export function registerSchemaCommand(program: Command): void {
const schemaCmd = program
.command('schema')
- .description('Manage workflow schemas [experimental]');
+ .description(SCHEMA_MESSAGES.manageWorkflows);
// Experimental warning
schemaCmd.hook('preAction', () => {
- console.error('Note: Schema commands are experimental and may change.');
+ console.error(SCHEMA_MESSAGES.experimentalWarning);
});
// schema which
schemaCmd
.command('which [name]')
- .description('Show where a schema resolves from')
- .option('--json', 'Output as JSON')
- .option('--all', 'List all schemas with their resolution sources')
+ .description(SCHEMA_MESSAGES.showResolve)
+ .option('--json', SCHEMA_MESSAGES.outputAsJson)
+ .option('--all', SCHEMA_MESSAGES.listAllSchemasOption)
.action(async (name?: string, options?: { json?: boolean; all?: boolean }) => {
try {
const projectRoot = process.cwd();
@@ -315,7 +316,7 @@ export function registerSchemaCommand(program: Command): void {
console.log(JSON.stringify(schemas, null, 2));
} else {
if (schemas.length === 0) {
- console.log('No schemas found.');
+ console.log(SCHEMA_MESSAGES.noSchemasFound);
return;
}
@@ -327,27 +328,27 @@ export function registerSchemaCommand(program: Command): void {
};
if (bySource.project.length > 0) {
- console.log('\nProject schemas:');
+ console.log('\n' + SCHEMA_MESSAGES.projectSchemasHeader);
for (const schema of bySource.project) {
const shadowInfo = schema.shadows.length > 0
- ? ` (shadows: ${schema.shadows.map((s) => s.source).join(', ')})`
+ ? SCHEMA_MESSAGES.shadowsLabel(schema.shadows.map((s) => s.source).join(', '))
: '';
console.log(` ${schema.name}${shadowInfo}`);
}
}
if (bySource.user.length > 0) {
- console.log('\nUser schemas:');
+ console.log('\n' + SCHEMA_MESSAGES.userSchemasHeader);
for (const schema of bySource.user) {
const shadowInfo = schema.shadows.length > 0
- ? ` (shadows: ${schema.shadows.map((s) => s.source).join(', ')})`
+ ? SCHEMA_MESSAGES.shadowsLabel(schema.shadows.map((s) => s.source).join(', '))
: '';
console.log(` ${schema.name}${shadowInfo}`);
}
}
if (bySource.package.length > 0) {
- console.log('\nPackage schemas:');
+ console.log('\n' + SCHEMA_MESSAGES.packageSchemasHeader);
for (const schema of bySource.package) {
console.log(` ${schema.name}`);
}
@@ -357,7 +358,7 @@ export function registerSchemaCommand(program: Command): void {
}
if (!name) {
- console.error('Error: Schema name is required (or use --all to list all schemas)');
+ console.error(SCHEMA_MESSAGES.schemaNameRequired);
process.exitCode = 1;
return;
}
@@ -368,12 +369,12 @@ export function registerSchemaCommand(program: Command): void {
const available = listSchemas(projectRoot);
if (options?.json) {
console.log(JSON.stringify({
- error: `Schema '${name}' not found`,
+ error: SCHEMA_MESSAGES.schemaNotFoundError(name),
available,
}, null, 2));
} else {
- console.error(`Error: Schema '${name}' not found`);
- console.error(`Available schemas: ${available.join(', ')}`);
+ console.error(SCHEMA_MESSAGES.schemaNotFoundError(name));
+ console.error(SCHEMA_MESSAGES.availableSchemas(available.join(', ')));
}
process.exitCode = 1;
return;
@@ -382,19 +383,19 @@ export function registerSchemaCommand(program: Command): void {
if (options?.json) {
console.log(JSON.stringify(resolution, null, 2));
} else {
- console.log(`Schema: ${resolution.name}`);
- console.log(`Source: ${resolution.source}`);
- console.log(`Path: ${resolution.path}`);
+ console.log(SCHEMA_MESSAGES.schemaLabel(resolution.name));
+ console.log(SCHEMA_MESSAGES.sourceLabel(resolution.source));
+ console.log(SCHEMA_MESSAGES.pathLabel(resolution.path));
if (resolution.shadows.length > 0) {
- console.log('\nShadows:');
+ console.log('\n' + SCHEMA_MESSAGES.shadowsHeader);
for (const shadow of resolution.shadows) {
- console.log(` ${shadow.source}: ${shadow.path}`);
+ console.log(SCHEMA_MESSAGES.shadowEntry(shadow.source, shadow.path));
}
}
}
} catch (error) {
- console.error(`Error: ${(error as Error).message}`);
+ console.error(CLI_MESSAGES.error((error as Error).message));
process.exitCode = 1;
}
});
@@ -402,9 +403,9 @@ export function registerSchemaCommand(program: Command): void {
// schema validate
schemaCmd
.command('validate [name]')
- .description('Validate a schema structure and templates')
- .option('--json', 'Output as JSON')
- .option('--verbose', 'Show detailed validation steps')
+ .description(SCHEMA_MESSAGES.validateStructure)
+ .option('--json', SCHEMA_MESSAGES.outputAsJson)
+ .option('--verbose', SCHEMA_MESSAGES.verboseOption)
.action(async (name?: string, options?: { json?: boolean; verbose?: boolean }) => {
try {
const projectRoot = process.cwd();
@@ -417,11 +418,11 @@ export function registerSchemaCommand(program: Command): void {
if (options?.json) {
console.log(JSON.stringify({
valid: true,
- message: 'No project schemas directory found',
+ message: SCHEMA_MESSAGES.noProjectSchemasDir,
schemas: [],
}, null, 2));
} else {
- console.log('No project schemas directory found.');
+ console.log(SCHEMA_MESSAGES.noProjectSchemasDir + '.');
}
return;
}
@@ -445,7 +446,7 @@ export function registerSchemaCommand(program: Command): void {
if (!fs.existsSync(schemaPath)) continue;
if (options?.verbose && !options?.json) {
- console.log(`\nValidating ${entry.name}...`);
+ console.log('\n' + SCHEMA_MESSAGES.validatingEntry(entry.name));
}
const result = validateSchema(schemaDir, options?.verbose && !options?.json);
@@ -468,16 +469,15 @@ export function registerSchemaCommand(program: Command): void {
}, null, 2));
} else {
if (schemaResults.length === 0) {
- console.log('No schemas found in project.');
+ console.log(SCHEMA_MESSAGES.noSchemasInProject);
return;
}
- console.log('\nValidation Results:');
+ console.log('\n' + SCHEMA_MESSAGES.validationResultsHeader);
for (const result of schemaResults) {
- const status = result.valid ? '✓' : '✗';
- console.log(` ${status} ${result.name}`);
+ console.log(SCHEMA_MESSAGES.validationStatus(result.valid, result.name));
for (const issue of result.issues) {
- console.log(` ${issue.level}: ${issue.message}`);
+ console.log(SCHEMA_MESSAGES.issueLine(issue.level, issue.message));
}
}
@@ -496,19 +496,19 @@ export function registerSchemaCommand(program: Command): void {
if (options?.json) {
console.log(JSON.stringify({
valid: false,
- error: `Schema '${name}' not found`,
+ error: SCHEMA_MESSAGES.schemaNotFoundError(name),
available,
}, null, 2));
} else {
- console.error(`Error: Schema '${name}' not found`);
- console.error(`Available schemas: ${available.join(', ')}`);
+ console.error(SCHEMA_MESSAGES.schemaNotFoundError(name));
+ console.error(SCHEMA_MESSAGES.availableSchemas(available.join(', ')));
}
process.exitCode = 1;
return;
}
if (options?.verbose && !options?.json) {
- console.log(`Validating ${name}...`);
+ console.log(SCHEMA_MESSAGES.validatingEntry(name));
}
const result = validateSchema(schemaDir, options?.verbose && !options?.json);
@@ -522,11 +522,11 @@ export function registerSchemaCommand(program: Command): void {
}, null, 2));
} else {
if (result.valid) {
- console.log(`✓ Schema '${name}' is valid`);
+ console.log(SCHEMA_MESSAGES.schemaIsValid(name));
} else {
- console.log(`✗ Schema '${name}' has errors:`);
+ console.log(SCHEMA_MESSAGES.schemaHasErrors(name));
for (const issue of result.issues) {
- console.log(` ${issue.level}: ${issue.message}`);
+ console.log(SCHEMA_MESSAGES.issueLine(issue.level, issue.message));
}
process.exitCode = 1;
}
@@ -538,7 +538,7 @@ export function registerSchemaCommand(program: Command): void {
error: (error as Error).message,
}, null, 2));
} else {
- console.error(`Error: ${(error as Error).message}`);
+ console.error(CLI_MESSAGES.error((error as Error).message));
}
process.exitCode = 1;
}
@@ -547,9 +547,9 @@ export function registerSchemaCommand(program: Command): void {
// schema fork
schemaCmd
.command('fork [name]')
- .description('Copy an existing schema to project for customization')
- .option('--json', 'Output as JSON')
- .option('--force', 'Overwrite existing destination')
+ .description(SCHEMA_MESSAGES.copySchema)
+ .option('--json', SCHEMA_MESSAGES.outputAsJson)
+ .option('--force', SCHEMA_MESSAGES.forceOption)
.action(async (source: string, name?: string, options?: { json?: boolean; force?: boolean }) => {
const spinner = options?.json ? null : ora();
@@ -562,11 +562,11 @@ export function registerSchemaCommand(program: Command): void {
if (options?.json) {
console.log(JSON.stringify({
forked: false,
- error: `Invalid schema name '${destinationName}'. Use kebab-case (e.g., my-workflow)`,
+ error: SCHEMA_MESSAGES.invalidSchemaName(destinationName),
}, null, 2));
} else {
- console.error(`Error: Invalid schema name '${destinationName}'`);
- console.error('Schema names must be kebab-case (e.g., my-workflow)');
+ console.error(SCHEMA_MESSAGES.invalidSchemaName(destinationName).replace(/^Nome/, 'Erro: Nome'));
+ console.error(SCHEMA_MESSAGES.schemaNamesKebabCase);
}
process.exitCode = 1;
return;
@@ -579,12 +579,12 @@ export function registerSchemaCommand(program: Command): void {
if (options?.json) {
console.log(JSON.stringify({
forked: false,
- error: `Schema '${source}' not found`,
+ error: SCHEMA_MESSAGES.schemaSourceNotFound(source),
available,
}, null, 2));
} else {
- console.error(`Error: Schema '${source}' not found`);
- console.error(`Available schemas: ${available.join(', ')}`);
+ console.error(SCHEMA_MESSAGES.schemaNotFoundError(source).replace(/^Esquema/, 'Erro: Esquema'));
+ console.error(SCHEMA_MESSAGES.availableSchemas(available.join(', ')));
}
process.exitCode = 1;
return;
@@ -602,24 +602,24 @@ export function registerSchemaCommand(program: Command): void {
if (options?.json) {
console.log(JSON.stringify({
forked: false,
- error: `Schema '${destinationName}' already exists`,
- suggestion: 'Use --force to overwrite',
+ error: SCHEMA_MESSAGES.schemaAlreadyExists(destinationName),
+ suggestion: SCHEMA_MESSAGES.suggestionForceOverwrite,
}, null, 2));
} else {
- console.error(`Error: Schema '${destinationName}' already exists at ${destinationDir}`);
- console.error('Use --force to overwrite');
+ console.error(SCHEMA_MESSAGES.schemaAlreadyExistsAt(destinationName, destinationDir));
+ console.error(SCHEMA_MESSAGES.suggestionForceOverwrite);
}
process.exitCode = 1;
return;
}
// Remove existing
- if (spinner) spinner.start(`Removing existing schema '${destinationName}'...`);
+ if (spinner) spinner.start(SCHEMA_MESSAGES.removingExistingSchema(destinationName));
fs.rmSync(destinationDir, { recursive: true });
}
// Copy schema
- if (spinner) spinner.start(`Forking '${source}' to '${destinationName}'...`);
+ if (spinner) spinner.start(SCHEMA_MESSAGES.forkingSchema(source, destinationName));
copyDirRecursive(sourceDir, destinationDir);
// Update name in schema.yaml
@@ -630,7 +630,7 @@ export function registerSchemaCommand(program: Command): void {
fs.writeFileSync(destSchemaPath, stringifyYaml(schema));
- if (spinner) spinner.succeed(`Forked '${source}' to '${destinationName}'`);
+ if (spinner) spinner.succeed(SCHEMA_MESSAGES.forkedSchema(source, destinationName));
if (options?.json) {
console.log(JSON.stringify({
@@ -642,20 +642,20 @@ export function registerSchemaCommand(program: Command): void {
destinationPath: destinationDir,
}, null, 2));
} else {
- console.log(`\nSource: ${sourceDir} (${sourceLocation})`);
- console.log(`Destination: ${destinationDir}`);
- console.log(`\nYou can now customize the schema at:`);
+ console.log('\n' + SCHEMA_MESSAGES.sourceLabel2(sourceDir, sourceLocation));
+ console.log(SCHEMA_MESSAGES.destinationLabel(destinationDir));
+ console.log('\n' + SCHEMA_MESSAGES.customizeSchemaAt);
console.log(` ${destinationDir}/schema.yaml`);
}
} catch (error) {
- if (spinner) spinner.fail(`Fork failed`);
+ if (spinner) spinner.fail(SCHEMA_MESSAGES.forkFailed);
if (options?.json) {
console.log(JSON.stringify({
forked: false,
error: (error as Error).message,
}, null, 2));
} else {
- console.error(`Error: ${(error as Error).message}`);
+ console.error(CLI_MESSAGES.error((error as Error).message));
}
process.exitCode = 1;
}
@@ -664,13 +664,13 @@ export function registerSchemaCommand(program: Command): void {
// schema init
schemaCmd
.command('init ')
- .description('Create a new project-local schema')
- .option('--json', 'Output as JSON')
- .option('--description ', 'Schema description')
+ .description(SCHEMA_MESSAGES.createSchema)
+ .option('--json', SCHEMA_MESSAGES.outputAsJson)
+ .option('--description ', SCHEMA_MESSAGES.descriptionOption)
.option('--artifacts ', 'Comma-separated artifact IDs (proposal,specs,design,tasks)')
- .option('--default', 'Set as project default schema')
- .option('--no-default', 'Do not prompt to set as default')
- .option('--force', 'Overwrite existing schema')
+ .option('--default', SCHEMA_MESSAGES.defaultOption)
+ .option('--no-default', SCHEMA_MESSAGES.noDefaultOption)
+ .option('--force', SCHEMA_MESSAGES.forceOption2)
.action(async (
name: string,
options?: {
@@ -691,11 +691,11 @@ export function registerSchemaCommand(program: Command): void {
if (options?.json) {
console.log(JSON.stringify({
created: false,
- error: `Invalid schema name '${name}'. Use kebab-case (e.g., my-workflow)`,
+ error: SCHEMA_MESSAGES.invalidSchemaName(name),
}, null, 2));
} else {
- console.error(`Error: Invalid schema name '${name}'`);
- console.error('Schema names must be kebab-case (e.g., my-workflow)');
+ console.error(SCHEMA_MESSAGES.invalidSchemaName(name).replace(/^Nome/, 'Erro: Nome'));
+ console.error(SCHEMA_MESSAGES.schemaNamesKebabCase);
}
process.exitCode = 1;
return;
@@ -709,18 +709,18 @@ export function registerSchemaCommand(program: Command): void {
if (options?.json) {
console.log(JSON.stringify({
created: false,
- error: `Schema '${name}' already exists`,
- suggestion: 'Use --force to overwrite or "openspec schema fork" to copy',
+ error: SCHEMA_MESSAGES.schemaAlreadyExists(name),
+ suggestion: SCHEMA_MESSAGES.suggestionForkOrForce,
}, null, 2));
} else {
- console.error(`Error: Schema '${name}' already exists at ${schemaDir}`);
- console.error('Use --force to overwrite or "openspec schema fork" to copy');
+ console.error(SCHEMA_MESSAGES.schemaAlreadyExistsAt(name, schemaDir));
+ console.error(SCHEMA_MESSAGES.suggestionForkOrForce);
}
process.exitCode = 1;
return;
}
- if (spinner) spinner.start(`Removing existing schema '${name}'...`);
+ if (spinner) spinner.start(SCHEMA_MESSAGES.removingExistingSchema(name));
fs.rmSync(schemaDir, { recursive: true });
}
@@ -737,7 +737,7 @@ export function registerSchemaCommand(program: Command): void {
const { input, checkbox, confirm } = await import('@inquirer/prompts');
description = await input({
- message: 'Schema description:',
+ message: CONFIG_MESSAGES.schemaDescription,
default: `Custom workflow schema for ${name}`,
});
@@ -748,12 +748,12 @@ export function registerSchemaCommand(program: Command): void {
}));
selectedArtifactIds = await checkbox({
- message: 'Select artifacts to include:',
+ message: CONFIG_MESSAGES.selectArtifacts,
choices: artifactChoices,
});
if (selectedArtifactIds.length === 0) {
- console.error('Error: At least one artifact must be selected');
+ console.error(SCHEMA_MESSAGES.atLeastOneArtifact);
process.exitCode = 1;
return;
}
@@ -761,7 +761,7 @@ export function registerSchemaCommand(program: Command): void {
// Ask about setting as default (unless --no-default was passed)
if (options?.default === undefined) {
const setAsDefault = await confirm({
- message: 'Set as project default schema?',
+ message: CONFIG_MESSAGES.setAsDefaultSchema,
default: false,
});
@@ -783,12 +783,12 @@ export function registerSchemaCommand(program: Command): void {
if (options?.json) {
console.log(JSON.stringify({
created: false,
- error: `Unknown artifact '${id}'`,
+ error: SCHEMA_MESSAGES.unknownArtifact(id),
valid: validIds,
}, null, 2));
} else {
- console.error(`Error: Unknown artifact '${id}'`);
- console.error(`Valid artifacts: ${validIds.join(', ')}`);
+ console.error(SCHEMA_MESSAGES.unknownArtifact(id).replace(/^Artefato/, 'Erro: Artefato'));
+ console.error(SCHEMA_MESSAGES.validArtifacts(validIds.join(', ')));
}
process.exitCode = 1;
return;
@@ -801,7 +801,7 @@ export function registerSchemaCommand(program: Command): void {
}
// Create schema directory
- if (spinner) spinner.start(`Creating schema '${name}'...`);
+ if (spinner) spinner.start(SCHEMA_MESSAGES.creatingSchema(name));
fs.mkdirSync(schemaDir, { recursive: true });
// Build artifacts array with proper dependencies
@@ -886,7 +886,7 @@ export function registerSchemaCommand(program: Command): void {
}
}
- if (spinner) spinner.succeed(`Created schema '${name}'`);
+ if (spinner) spinner.succeed(SCHEMA_MESSAGES.schemaCreated(name));
if (options?.json) {
console.log(JSON.stringify({
@@ -897,25 +897,25 @@ export function registerSchemaCommand(program: Command): void {
setAsDefault: options?.default || false,
}, null, 2));
} else {
- console.log(`\nSchema created at: ${schemaDir}`);
- console.log(`\nArtifacts: ${selectedArtifactIds.join(', ')}`);
+ console.log('\n' + SCHEMA_MESSAGES.schemaCreatedAt(schemaDir));
+ console.log('\n' + SCHEMA_MESSAGES.artifactsLabel(selectedArtifactIds.join(', ')));
if (options?.default) {
- console.log(`\nSet as project default schema.`);
+ console.log('\n' + SCHEMA_MESSAGES.setAsDefaultSchemaLabel);
}
- console.log(`\nNext steps:`);
- console.log(` 1. Edit ${schemaDir}/schema.yaml to customize artifacts`);
- console.log(` 2. Modify templates in the schema directory`);
- console.log(` 3. Use with: openspec new --schema ${name}`);
+ console.log('\n' + SCHEMA_MESSAGES.nextStepsHeader);
+ console.log(SCHEMA_MESSAGES.editSchemaYaml(schemaDir));
+ console.log(SCHEMA_MESSAGES.modifyTemplates);
+ console.log(SCHEMA_MESSAGES.useWithSchema(name));
}
} catch (error) {
- if (spinner) spinner.fail(`Creation failed`);
+ if (spinner) spinner.fail(SCHEMA_MESSAGES.creationFailed);
if (options?.json) {
console.log(JSON.stringify({
created: false,
error: (error as Error).message,
}, null, 2));
} else {
- console.error(`Error: ${(error as Error).message}`);
+ console.error(CLI_MESSAGES.error((error as Error).message));
}
process.exitCode = 1;
}
diff --git a/src/commands/show.ts b/src/commands/show.ts
index 6413b5951c..3c6a0ebf95 100644
--- a/src/commands/show.ts
+++ b/src/commands/show.ts
@@ -4,6 +4,7 @@ import { getActiveChangeIds, getSpecIds } from '../utils/item-discovery.js';
import { ChangeCommand } from './change.js';
import { SpecCommand } from './spec.js';
import { nearestMatches } from '../utils/match.js';
+import { SHOW_MESSAGES } from '../messages/index.js';
type ItemType = 'change' | 'spec';
@@ -19,10 +20,10 @@ export class ShowCommand {
if (interactive) {
const { select } = await import('@inquirer/prompts');
const type = await select({
- message: 'What would you like to show?',
+ message: SHOW_MESSAGES.whatToShow,
choices: [
- { name: 'Change', value: 'change' as const },
- { name: 'Spec', value: 'spec' as const },
+ { name: SHOW_MESSAGES.optionChange, value: 'change' as const },
+ { name: SHOW_MESSAGES.optionSpec, value: 'spec' as const },
],
});
await this.runInteractiveByType(type, options);
@@ -48,11 +49,11 @@ export class ShowCommand {
if (type === 'change') {
const changes = await getActiveChangeIds();
if (changes.length === 0) {
- console.error('No changes found.');
+ console.error(SHOW_MESSAGES.noChangesFound);
process.exitCode = 1;
return;
}
- const picked = await select({ message: 'Pick a change', choices: changes.map(id => ({ name: id, value: id })) });
+ const picked = await select({ message: SHOW_MESSAGES.pickChange, choices: changes.map(id => ({ name: id, value: id })) });
const cmd = new ChangeCommand();
await cmd.show(picked, options as any);
return;
@@ -60,11 +61,11 @@ export class ShowCommand {
const specs = await getSpecIds();
if (specs.length === 0) {
- console.error('No specs found.');
+ console.error(SHOW_MESSAGES.noSpecsFound);
process.exitCode = 1;
return;
}
- const picked = await select({ message: 'Pick a spec', choices: specs.map(id => ({ name: id, value: id })) });
+ const picked = await select({ message: SHOW_MESSAGES.pickSpec, choices: specs.map(id => ({ name: id, value: id })) });
const cmd = new SpecCommand();
await cmd.show(picked, options as any);
}
@@ -90,16 +91,16 @@ export class ShowCommand {
const resolvedType = params.typeOverride ?? (isChange ? 'change' : isSpec ? 'spec' : undefined);
if (!resolvedType) {
- console.error(`Unknown item '${itemName}'`);
+ console.error(SHOW_MESSAGES.unknownItem(itemName));
const suggestions = nearestMatches(itemName, [...changes, ...specs]);
- if (suggestions.length) console.error(`Did you mean: ${suggestions.join(', ')}?`);
+ if (suggestions.length) console.error(SHOW_MESSAGES.didYouMean(suggestions.join(', ')));
process.exitCode = 1;
return;
}
if (!params.typeOverride && isChange && isSpec) {
- console.error(`Ambiguous item '${itemName}' matches both a change and a spec.`);
- console.error('Pass --type change|spec, or use: openspec change show / openspec spec show');
+ console.error(SHOW_MESSAGES.ambiguousItem(itemName));
+ console.error(SHOW_MESSAGES.passTypeHint);
process.exitCode = 1;
return;
}
@@ -115,11 +116,11 @@ export class ShowCommand {
}
private printNonInteractiveHint(): void {
- console.error('Nothing to show. Try one of:');
- console.error(' openspec show - ');
- console.error(' openspec change show');
- console.error(' openspec spec show');
- console.error('Or run in an interactive terminal.');
+ console.error(SHOW_MESSAGES.nothingToShow);
+ console.error(SHOW_MESSAGES.showItemHint);
+ console.error(SHOW_MESSAGES.showChangeHint);
+ console.error(SHOW_MESSAGES.showSpecHint);
+ console.error(SHOW_MESSAGES.runInteractiveHint);
}
private warnIrrelevantFlags(type: ItemType, options: { [k: string]: any }): boolean {
@@ -130,7 +131,7 @@ export class ShowCommand {
for (const k of CHANGE_FLAG_KEYS) if (k in options) irrelevant.push(k);
}
if (irrelevant.length > 0) {
- console.error(`Warning: Ignoring flags not applicable to ${type}: ${irrelevant.join(', ')}`);
+ console.error(SHOW_MESSAGES.ignoringFlags(type, irrelevant.join(', ')));
return true;
}
return false;
diff --git a/src/commands/spec.ts b/src/commands/spec.ts
index d28052f140..6bb78f3392 100644
--- a/src/commands/spec.ts
+++ b/src/commands/spec.ts
@@ -6,6 +6,7 @@ import { Validator } from '../core/validation/validator.js';
import type { Spec } from '../core/schemas/index.js';
import { isInteractive } from '../utils/interactive.js';
import { getSpecIds } from '../utils/item-discovery.js';
+import { CLI_DESCRIPTIONS, CLI_MESSAGES, SPEC_MESSAGES } from '../messages/index.js';
const SPECS_DIR = 'openspec/specs';
@@ -74,22 +75,22 @@ export class SpecCommand {
if (canPrompt && specIds.length > 0) {
const { select } = await import('@inquirer/prompts');
specId = await select({
- message: 'Select a spec to show',
+ message: SPEC_MESSAGES.selectSpecToShow,
choices: specIds.map(id => ({ name: id, value: id })),
});
} else {
- throw new Error('Missing required argument
');
+ throw new Error(SPEC_MESSAGES.missingSpecId);
}
}
const specPath = join(this.SPECS_DIR, specId, 'spec.md');
if (!existsSync(specPath)) {
- throw new Error(`Spec '${specId}' not found at openspec/specs/${specId}/spec.md`);
+ throw new Error(SPEC_MESSAGES.specNotFound(specId));
}
if (options.json) {
if (options.requirements && options.requirement) {
- throw new Error('Options --requirements and --requirement cannot be used together');
+ throw new Error(SPEC_MESSAGES.requirementsAndRequirementConflict);
}
const parsed = parseSpecFromFile(specPath, specId);
const filtered = filterSpec(parsed, options);
@@ -111,40 +112,40 @@ export class SpecCommand {
export function registerSpecCommand(rootProgram: typeof program) {
const specCommand = rootProgram
.command('spec')
- .description('Manage and view OpenSpec specifications');
+ .description(CLI_DESCRIPTIONS.spec);
// Deprecation notice for noun-based commands
specCommand.hook('preAction', () => {
- console.error('Warning: The "openspec spec ..." commands are deprecated. Prefer verb-first commands (e.g., "openspec show", "openspec validate --specs").');
+ console.error(CLI_MESSAGES.specCommandsDeprecated);
});
specCommand
.command('show [spec-id]')
- .description('Display a specific specification')
- .option('--json', 'Output as JSON')
- .option('--requirements', 'JSON only: Show only requirements (exclude scenarios)')
- .option('--no-scenarios', 'JSON only: Exclude scenario content')
- .option('-r, --requirement ', 'JSON only: Show specific requirement by ID (1-based)')
- .option('--no-interactive', 'Disable interactive prompts')
+ .description(CLI_DESCRIPTIONS.specShow)
+ .option('--json', 'Saída como JSON')
+ .option('--requirements', 'Somente JSON: Exibe apenas requisitos (exclui cenários)')
+ .option('--no-scenarios', 'Somente JSON: Exclui conteúdo de cenários')
+ .option('-r, --requirement ', 'Somente JSON: Exibe requisito específico pelo ID (base 1)')
+ .option('--no-interactive', 'Desativa prompts interativos')
.action(async (specId: string | undefined, options: ShowOptions & { noInteractive?: boolean }) => {
try {
const cmd = new SpecCommand();
await cmd.show(specId, options as any);
} catch (error) {
- console.error(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
+ console.error(CLI_MESSAGES.error(error instanceof Error ? error.message : CLI_MESSAGES.unknownError));
process.exitCode = 1;
}
});
specCommand
.command('list')
- .description('List all available specifications')
- .option('--json', 'Output as JSON')
- .option('--long', 'Show id and title with counts')
+ .description(CLI_DESCRIPTIONS.specList)
+ .option('--json', 'Saída como JSON')
+ .option('--long', 'Exibe id e título com contagens')
.action((options: { json?: boolean; long?: boolean }) => {
try {
if (!existsSync(SPECS_DIR)) {
- console.log('No items found');
+ console.log(SPEC_MESSAGES.noItemsFound);
return;
}
@@ -178,7 +179,7 @@ export function registerSpecCommand(rootProgram: typeof program) {
console.log(JSON.stringify(specs, null, 2));
} else {
if (specs.length === 0) {
- console.log('No items found');
+ console.log(SPEC_MESSAGES.noItemsFound);
return;
}
if (!options.long) {
@@ -186,21 +187,21 @@ export function registerSpecCommand(rootProgram: typeof program) {
return;
}
specs.forEach(spec => {
- console.log(`${spec.id}: ${spec.title} [requirements ${spec.requirementCount}]`);
+ console.log(`${spec.id}: ${spec.title} ${SPEC_MESSAGES.requirementCount(spec.requirementCount)}`);
});
}
} catch (error) {
- console.error(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
+ console.error(CLI_MESSAGES.error(error instanceof Error ? error.message : CLI_MESSAGES.unknownError));
process.exitCode = 1;
}
});
specCommand
.command('validate [spec-id]')
- .description('Validate a specification structure')
- .option('--strict', 'Enable strict validation mode')
- .option('--json', 'Output validation report as JSON')
- .option('--no-interactive', 'Disable interactive prompts')
+ .description(CLI_DESCRIPTIONS.specValidate)
+ .option('--strict', 'Ativa modo de validação estrita')
+ .option('--json', 'Saída do relatório de validação como JSON')
+ .option('--no-interactive', 'Desativa prompts interativos')
.action(async (specId: string | undefined, options: { strict?: boolean; json?: boolean; noInteractive?: boolean }) => {
try {
if (!specId) {
@@ -209,18 +210,18 @@ export function registerSpecCommand(rootProgram: typeof program) {
if (canPrompt && specIds.length > 0) {
const { select } = await import('@inquirer/prompts');
specId = await select({
- message: 'Select a spec to validate',
+ message: SPEC_MESSAGES.selectSpecToValidate,
choices: specIds.map(id => ({ name: id, value: id })),
});
} else {
- throw new Error('Missing required argument ');
+ throw new Error(SPEC_MESSAGES.missingSpecId);
}
}
const specPath = join(SPECS_DIR, specId, 'spec.md');
if (!existsSync(specPath)) {
- throw new Error(`Spec '${specId}' not found at openspec/specs/${specId}/spec.md`);
+ throw new Error(SPEC_MESSAGES.specNotFound(specId));
}
const validator = new Validator(options.strict);
@@ -230,9 +231,9 @@ export function registerSpecCommand(rootProgram: typeof program) {
console.log(JSON.stringify(report, null, 2));
} else {
if (report.valid) {
- console.log(`Specification '${specId}' is valid`);
+ console.log(SPEC_MESSAGES.specIsValid(specId));
} else {
- console.error(`Specification '${specId}' has issues`);
+ console.error(SPEC_MESSAGES.specHasIssues(specId));
report.issues.forEach(issue => {
const label = issue.level === 'ERROR' ? 'ERROR' : issue.level;
const prefix = issue.level === 'ERROR' ? '✗' : issue.level === 'WARNING' ? '⚠' : 'ℹ';
@@ -242,7 +243,7 @@ export function registerSpecCommand(rootProgram: typeof program) {
}
process.exitCode = report.valid ? 0 : 1;
} catch (error) {
- console.error(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
+ console.error(CLI_MESSAGES.error(error instanceof Error ? error.message : CLI_MESSAGES.unknownError));
process.exitCode = 1;
}
});
diff --git a/src/commands/tools.ts b/src/commands/tools.ts
new file mode 100644
index 0000000000..84522166f5
--- /dev/null
+++ b/src/commands/tools.ts
@@ -0,0 +1,305 @@
+/**
+ * Tools Command
+ *
+ * `openspec tools [path]`
+ *
+ * Add or remove IDE/Code Agent BR-OpenSpec configuration files interactively.
+ * Requires the project to already be initialized with `openspec init`.
+ */
+
+import { Command } from 'commander';
+import path from 'path';
+import chalk from 'chalk';
+import ora from 'ora';
+import { isProjectInitialized } from '../core/is-project-initialized.js';
+import {
+ addTool,
+ removeTool,
+ getCurrentToolIds,
+ getEligibleTools,
+ resolveToolsArg,
+} from '../core/tools-manager.js';
+import { AI_TOOLS } from '../core/config.js';
+import { getToolStates } from '../core/shared/index.js';
+import { isInteractive } from '../utils/interactive.js';
+import { TOOLS_MESSAGES, CLI_MESSAGES } from '../messages/index.js';
+
+// ─────────────────────────────────────────────────────────────────────────────
+// Helpers
+// ─────────────────────────────────────────────────────────────────────────────
+
+function requireInitialized(projectPath: string): void {
+ if (!isProjectInitialized(projectPath)) {
+ ora().fail(TOOLS_MESSAGES.notInitialized);
+ process.exit(1);
+ }
+}
+
+// ─────────────────────────────────────────────────────────────────────────────
+// Non-interactive add
+// ─────────────────────────────────────────────────────────────────────────────
+
+async function runAdd(projectPath: string, toolsArg: string): Promise {
+ const toolIds = resolveToolsArg(toolsArg);
+ if (toolIds.length === 0) {
+ console.log(chalk.dim(TOOLS_MESSAGES.noToolsToAdd));
+ return;
+ }
+
+ const added: string[] = [];
+ const failed: Array<{ name: string; error: Error }> = [];
+
+ for (const toolId of toolIds) {
+ const tool = AI_TOOLS.find((t) => t.value === toolId);
+ if (!tool) continue;
+ const spinner = ora(TOOLS_MESSAGES.adding(tool.name)).start();
+ try {
+ await addTool(projectPath, tool);
+ spinner.succeed(TOOLS_MESSAGES.added(tool.name));
+ added.push(tool.name);
+ } catch (err) {
+ spinner.fail(TOOLS_MESSAGES.failedToAdd(tool.name));
+ failed.push({ name: tool.name, error: err as Error });
+ }
+ }
+
+ console.log();
+ if (added.length > 0) {
+ console.log(TOOLS_MESSAGES.addedList(added.join(', ')));
+ }
+ if (failed.length > 0) {
+ console.log(
+ chalk.red(
+ TOOLS_MESSAGES.failedList(failed.map((f) => `${f.name} (${f.error.message})`).join(', '))
+ )
+ );
+ }
+ if (added.length > 0) {
+ console.log();
+ console.log(chalk.white(TOOLS_MESSAGES.restartIDE));
+ }
+}
+
+// ─────────────────────────────────────────────────────────────────────────────
+// Non-interactive remove
+// ─────────────────────────────────────────────────────────────────────────────
+
+async function runRemove(projectPath: string, toolsArg: string): Promise {
+ const toolIds = resolveToolsArg(toolsArg);
+ if (toolIds.length === 0) {
+ console.log(chalk.dim(TOOLS_MESSAGES.noToolsToRemove));
+ return;
+ }
+
+ const removed: string[] = [];
+ const failed: Array<{ name: string; error: Error }> = [];
+
+ for (const toolId of toolIds) {
+ const tool = AI_TOOLS.find((t) => t.value === toolId);
+ if (!tool) continue;
+ const spinner = ora(TOOLS_MESSAGES.removing(tool.name)).start();
+ try {
+ const counts = await removeTool(projectPath, tool);
+ spinner.succeed(TOOLS_MESSAGES.removed(tool.name));
+ removed.push(tool.name);
+ if (counts.removedSkillCount > 0 || counts.removedCommandCount > 0) {
+ console.log(
+ chalk.dim(
+ TOOLS_MESSAGES.removedCounts(counts.removedSkillCount, counts.removedCommandCount)
+ )
+ );
+ }
+ } catch (err) {
+ spinner.fail(TOOLS_MESSAGES.failedToRemove(tool.name));
+ failed.push({ name: tool.name, error: err as Error });
+ }
+ }
+
+ console.log();
+ if (removed.length > 0) {
+ console.log(TOOLS_MESSAGES.removedList(removed.join(', ')));
+ }
+ if (failed.length > 0) {
+ console.log(
+ chalk.red(
+ TOOLS_MESSAGES.failedList(failed.map((f) => `${f.name} (${f.error.message})`).join(', '))
+ )
+ );
+ }
+}
+
+// ─────────────────────────────────────────────────────────────────────────────
+// Interactive mode
+// ─────────────────────────────────────────────────────────────────────────────
+
+async function runInteractive(projectPath: string): Promise {
+ const eligibleTools = getEligibleTools();
+ const toolStates = getToolStates(projectPath);
+ const currentlyConfigured = getCurrentToolIds(projectPath);
+
+ // Build choices for the multi-select, sorted: configured first, then the rest
+ const choices = eligibleTools
+ .map((tool) => {
+ const status = toolStates.get(tool.value);
+ const configured = status?.configured ?? false;
+ return {
+ name: tool.name,
+ value: tool.value,
+ configured,
+ preSelected: configured,
+ };
+ })
+ .sort((a, b) => {
+ if (a.configured && !b.configured) return -1;
+ if (!a.configured && b.configured) return 1;
+ return 0;
+ });
+
+ if (currentlyConfigured.size > 0) {
+ const names = [...currentlyConfigured]
+ .map((id) => AI_TOOLS.find((t) => t.value === id)?.name ?? id)
+ .join(', ');
+ console.log(TOOLS_MESSAGES.currentlyConfigured(names));
+ } else {
+ console.log(chalk.dim(TOOLS_MESSAGES.noToolsConfigured));
+ }
+ console.log();
+
+ const { searchableMultiSelect } = await import('../prompts/searchable-multi-select.js');
+
+ const newSelection: string[] = await searchableMultiSelect({
+ message: TOOLS_MESSAGES.selectToolsToConfigure(eligibleTools.length),
+ pageSize: 15,
+ choices,
+ });
+
+ const newSet = new Set(newSelection);
+
+ // Compute diffs
+ const toAdd = newSelection.filter((id) => !currentlyConfigured.has(id));
+ const toRemove = [...currentlyConfigured].filter((id) => !newSet.has(id));
+
+ if (toAdd.length === 0 && toRemove.length === 0) {
+ console.log(chalk.dim('\n' + TOOLS_MESSAGES.noChanges));
+ return;
+ }
+
+ console.log();
+
+ const addedNames: string[] = [];
+ const removedNames: string[] = [];
+ const failed: Array<{ name: string; error: Error }> = [];
+
+ for (const toolId of toAdd) {
+ const tool = AI_TOOLS.find((t) => t.value === toolId);
+ if (!tool) continue;
+ const spinner = ora(TOOLS_MESSAGES.adding(tool.name)).start();
+ try {
+ await addTool(projectPath, tool);
+ spinner.succeed(TOOLS_MESSAGES.added(tool.name));
+ addedNames.push(tool.name);
+ } catch (err) {
+ spinner.fail(TOOLS_MESSAGES.failedToAdd(tool.name));
+ failed.push({ name: tool.name, error: err as Error });
+ }
+ }
+
+ for (const toolId of toRemove) {
+ const tool = AI_TOOLS.find((t) => t.value === toolId);
+ if (!tool) continue;
+ const spinner = ora(TOOLS_MESSAGES.removing(tool.name)).start();
+ try {
+ await removeTool(projectPath, tool);
+ spinner.succeed(TOOLS_MESSAGES.removed(tool.name));
+ removedNames.push(tool.name);
+ } catch (err) {
+ spinner.fail(TOOLS_MESSAGES.failedToRemove(tool.name));
+ failed.push({ name: tool.name, error: err as Error });
+ }
+ }
+
+ console.log();
+ if (addedNames.length > 0) {
+ console.log(TOOLS_MESSAGES.addedList(addedNames.join(', ')));
+ }
+ if (removedNames.length > 0) {
+ console.log(TOOLS_MESSAGES.removedList(removedNames.join(', ')));
+ }
+ if (failed.length > 0) {
+ console.log(
+ chalk.red(
+ TOOLS_MESSAGES.failedList(failed.map((f) => `${f.name} (${f.error.message})`).join(', '))
+ )
+ );
+ }
+ if (addedNames.length > 0) {
+ console.log();
+ console.log(chalk.white(TOOLS_MESSAGES.restartIDE));
+ }
+}
+
+// ─────────────────────────────────────────────────────────────────────────────
+// Command registration
+// ─────────────────────────────────────────────────────────────────────────────
+
+export function registerToolsCommand(program: Command): void {
+ program
+ .command('tools [path]')
+ .description(TOOLS_MESSAGES.description)
+ .option('--add ', TOOLS_MESSAGES.addOption)
+ .option('--remove ', TOOLS_MESSAGES.removeOption)
+ .action(
+ async (
+ targetPath = '.',
+ options?: { add?: string; remove?: string }
+ ) => {
+ try {
+ const projectPath = path.resolve(targetPath);
+
+ requireInitialized(projectPath);
+
+ const hasAdd = typeof options?.add === 'string';
+ const hasRemove = typeof options?.remove === 'string';
+
+ if (hasAdd && hasRemove) {
+ // Check for overlap
+ const addIds = resolveToolsArg(options!.add!);
+ const removeIds = resolveToolsArg(options!.remove!);
+ const overlap = addIds.filter((id) => removeIds.includes(id));
+ if (overlap.length > 0) {
+ throw new Error(
+ TOOLS_MESSAGES.cannotAddAndRemoveSame(overlap.join(', '))
+ );
+ }
+ // Run both sequentially
+ if (addIds.length > 0) await runAdd(projectPath, options!.add!);
+ if (removeIds.length > 0) await runRemove(projectPath, options!.remove!);
+ return;
+ }
+
+ if (hasAdd) {
+ await runAdd(projectPath, options!.add!);
+ return;
+ }
+
+ if (hasRemove) {
+ await runRemove(projectPath, options!.remove!);
+ return;
+ }
+
+ // Interactive mode
+ if (!isInteractive()) {
+ throw new Error(
+ TOOLS_MESSAGES.noFlagNonInteractive
+ );
+ }
+
+ await runInteractive(projectPath);
+ } catch (error) {
+ console.log();
+ ora().fail(CLI_MESSAGES.error((error as Error).message));
+ process.exit(1);
+ }
+ }
+ );
+}
diff --git a/src/commands/validate.ts b/src/commands/validate.ts
index 9e59a4d48d..87e37b5482 100644
--- a/src/commands/validate.ts
+++ b/src/commands/validate.ts
@@ -4,6 +4,7 @@ import { Validator } from '../core/validation/validator.js';
import { isInteractive, resolveNoInteractive } from '../utils/interactive.js';
import { getActiveChangeIds, getSpecIds } from '../utils/item-discovery.js';
import { nearestMatches } from '../utils/match.js';
+import { VALIDATE_MESSAGES } from '../messages/index.js';
type ItemType = 'change' | 'spec';
@@ -66,9 +67,12 @@ export class ValidateCommand {
private async runInteractiveSelector(opts: { strict: boolean; json: boolean; concurrency?: string }): Promise {
const { select } = await import('@inquirer/prompts');
const choice = await select({
- message: 'What would you like to validate?',
+ message: VALIDATE_MESSAGES.whatToValidate,
choices: [
- { name: 'All (changes + specs)', value: 'all' },
+ { name: VALIDATE_MESSAGES.optionAll, value: 'all' },
+ { name: VALIDATE_MESSAGES.optionAllChanges, value: 'changes' },
+ { name: VALIDATE_MESSAGES.optionAllSpecs, value: 'specs' },
+ { name: VALIDATE_MESSAGES.optionPickOne, value: 'one' },
{ name: 'All changes', value: 'changes' },
{ name: 'All specs', value: 'specs' },
{ name: 'Pick a specific change or spec', value: 'one' },
@@ -85,21 +89,21 @@ export class ValidateCommand {
items.push(...changes.map(id => ({ name: `change/${id}`, value: { type: 'change' as const, id } })));
items.push(...specs.map(id => ({ name: `spec/${id}`, value: { type: 'spec' as const, id } })));
if (items.length === 0) {
- console.error('No items found to validate.');
+ console.error(VALIDATE_MESSAGES.noItemsToValidate);
process.exitCode = 1;
return;
}
- const picked = await select<{ type: ItemType; id: string }>({ message: 'Pick an item', choices: items });
+ const picked = await select<{ type: ItemType; id: string }>({ message: VALIDATE_MESSAGES.pickAnItem, choices: items });
await this.validateByType(picked.type, picked.id, opts);
}
private printNonInteractiveHint(): void {
- console.error('Nothing to validate. Try one of:');
- console.error(' openspec validate --all');
- console.error(' openspec validate --changes');
- console.error(' openspec validate --specs');
- console.error(' openspec validate ');
- console.error('Or run in an interactive terminal.');
+ console.error(VALIDATE_MESSAGES.nothingToValidate);
+ console.error(VALIDATE_MESSAGES.validateAllHint);
+ console.error(VALIDATE_MESSAGES.validateChangesHint);
+ console.error(VALIDATE_MESSAGES.validateSpecsHint);
+ console.error(VALIDATE_MESSAGES.validateItemHint);
+ console.error(VALIDATE_MESSAGES.runInteractiveHint);
}
private async validateDirectItem(itemName: string, opts: { typeOverride?: ItemType; strict: boolean; json: boolean }): Promise {
@@ -110,16 +114,16 @@ export class ValidateCommand {
const type = opts.typeOverride ?? (isChange ? 'change' : isSpec ? 'spec' : undefined);
if (!type) {
- console.error(`Unknown item '${itemName}'`);
+ console.error(VALIDATE_MESSAGES.unknownItem(itemName));
const suggestions = nearestMatches(itemName, [...changes, ...specs]);
- if (suggestions.length) console.error(`Did you mean: ${suggestions.join(', ')}?`);
+ if (suggestions.length) console.error(VALIDATE_MESSAGES.didYouMean(suggestions.join(', ')));
process.exitCode = 1;
return;
}
if (!opts.typeOverride && isChange && isSpec) {
- console.error(`Ambiguous item '${itemName}' matches both a change and a spec.`);
- console.error('Pass --type change|spec, or use: openspec change validate / openspec spec validate');
+ console.error(VALIDATE_MESSAGES.ambiguousItem(itemName));
+ console.error(VALIDATE_MESSAGES.passTypeHint);
process.exitCode = 1;
return;
}
@@ -154,9 +158,9 @@ export class ValidateCommand {
return;
}
if (report.valid) {
- console.log(`${type === 'change' ? 'Change' : 'Specification'} '${id}' is valid`);
+ console.log(type === 'change' ? VALIDATE_MESSAGES.changeIsValid(id) : VALIDATE_MESSAGES.specIsValid(id));
} else {
- console.error(`${type === 'change' ? 'Change' : 'Specification'} '${id}' has issues`);
+ console.error(type === 'change' ? VALIDATE_MESSAGES.changeHasIssues(id) : VALIDATE_MESSAGES.specHasIssues(id));
for (const issue of report.issues) {
const label = issue.level === 'ERROR' ? 'ERROR' : issue.level;
const prefix = issue.level === 'ERROR' ? '✗' : issue.level === 'WARNING' ? '⚠' : 'ℹ';
@@ -169,20 +173,20 @@ export class ValidateCommand {
private printNextSteps(type: ItemType): void {
const bullets: string[] = [];
if (type === 'change') {
- bullets.push('- Ensure change has deltas in specs/: use headers ## ADDED/MODIFIED/REMOVED/RENAMED Requirements');
- bullets.push('- Each requirement MUST include at least one #### Scenario: block');
- bullets.push('- Debug parsed deltas: openspec change show --json --deltas-only');
+ bullets.push(VALIDATE_MESSAGES.ensureDeltasInSpecs);
+ bullets.push(VALIDATE_MESSAGES.eachRequirementNeedsScenario);
+ bullets.push(VALIDATE_MESSAGES.debugParsedDeltas);
} else {
- bullets.push('- Ensure spec includes ## Purpose and ## Requirements sections');
- bullets.push('- Each requirement MUST include at least one #### Scenario: block');
- bullets.push('- Re-run with --json to see structured report');
+ bullets.push(VALIDATE_MESSAGES.ensurePurposeAndRequirements);
+ bullets.push(VALIDATE_MESSAGES.requirementScenarioBullet);
+ bullets.push(VALIDATE_MESSAGES.rerunWithJson);
}
- console.error('Next steps:');
+ console.error(type === 'change' ? VALIDATE_MESSAGES.nextStepsChange : VALIDATE_MESSAGES.nextStepsSpec);
bullets.forEach(b => console.error(` ${b}`));
}
private async runBulkValidation(scope: { changes: boolean; specs: boolean }, opts: { strict: boolean; json: boolean; concurrency?: string; noInteractive?: boolean }): Promise {
- const spinner = !opts.json && !opts.noInteractive ? ora('Validating...').start() : undefined;
+ const spinner = !opts.json && !opts.noInteractive ? ora(VALIDATE_MESSAGES.validating).start() : undefined;
const [changeIds, specIds] = await Promise.all([
scope.changes ? getActiveChangeIds() : Promise.resolve([]),
scope.specs ? getSpecIds() : Promise.resolve([]),
@@ -228,7 +232,7 @@ export class ValidateCommand {
const out = { items: [] as BulkItemResult[], summary, version: '1.0' };
console.log(JSON.stringify(out, null, 2));
} else {
- console.log('No items found to validate.');
+ console.log(VALIDATE_MESSAGES.noItemsFoundToValidate);
}
process.exitCode = 0;
@@ -247,7 +251,7 @@ export class ValidateCommand {
const currentIndex = index++;
const task = queue[currentIndex];
running++;
- if (spinner) spinner.text = `Validating (${currentIndex + 1}/${queue.length})...`;
+ if (spinner) spinner.text = VALIDATE_MESSAGES.validatingProgress(currentIndex + 1, queue.length);
task()
.then(res => {
results.push(res);
@@ -288,7 +292,7 @@ export class ValidateCommand {
if (res.valid) console.log(`✓ ${res.type}/${res.id}`);
else console.error(`✗ ${res.type}/${res.id}`);
}
- console.log(`Totals: ${summary.totals.passed} passed, ${summary.totals.failed} failed (${summary.totals.items} items)`);
+ console.log(VALIDATE_MESSAGES.totals(summary.totals.passed, summary.totals.failed, summary.totals.items));
}
process.exitCode = failed > 0 ? 1 : 0;
diff --git a/src/commands/workflow/instructions.ts b/src/commands/workflow/instructions.ts
index 7afba14753..a16c7e51ce 100644
--- a/src/commands/workflow/instructions.ts
+++ b/src/commands/workflow/instructions.ts
@@ -21,6 +21,7 @@ import {
type TaskItem,
type ApplyInstructions,
} from './shared.js';
+import { WORKFLOW_MESSAGES } from '../../messages/index.js';
// -----------------------------------------------------------------------------
// Types
@@ -46,7 +47,7 @@ export async function instructionsCommand(
artifactId: string | undefined,
options: InstructionsOptions
): Promise {
- const spinner = options.json ? undefined : ora('Generating instructions...').start();
+ const spinner = options.json ? undefined : ora(WORKFLOW_MESSAGES.generatingInstructions).start();
try {
const projectRoot = process.cwd();
@@ -64,7 +65,7 @@ export async function instructionsCommand(
spinner?.stop();
const validIds = context.graph.getAllArtifacts().map((a) => a.id);
throw new Error(
- `Missing required argument . Valid artifacts:\n ${validIds.join('\n ')}`
+ WORKFLOW_MESSAGES.missingArtifactArgument(validIds.join('\n '))
);
}
@@ -74,7 +75,7 @@ export async function instructionsCommand(
spinner?.stop();
const validIds = context.graph.getAllArtifacts().map((a) => a.id);
throw new Error(
- `Artifact '${artifactId}' not found in schema '${context.schemaName}'. Valid artifacts:\n ${validIds.join('\n ')}`
+ WORKFLOW_MESSAGES.artifactNotFound(artifactId, context.schemaName, validIds.join('\n '))
);
}
@@ -119,8 +120,8 @@ export function printInstructionsText(instructions: ArtifactInstructions, isBloc
if (isBlocked) {
const missing = dependencies.filter((d) => !d.done).map((d) => d.id);
console.log('');
- console.log('This artifact has unmet dependencies. Complete them first or proceed with caution.');
- console.log(`Missing: ${missing.join(', ')}`);
+ console.log(WORKFLOW_MESSAGES.unmetDependenciesWarning);
+ console.log(WORKFLOW_MESSAGES.missingDependencies(missing.join(', ')));
console.log(' ');
console.log();
}
@@ -155,7 +156,7 @@ export function printInstructionsText(instructions: ArtifactInstructions, isBloc
// Dependencies (files to read for context)
if (dependencies.length > 0) {
console.log('');
- console.log('Read these files for context before creating this artifact:');
+ console.log(WORKFLOW_MESSAGES.readFilesForContext);
console.log();
for (const dep of dependencies) {
const status = dep.done ? 'done' : 'missing';
@@ -199,7 +200,7 @@ export function printInstructionsText(instructions: ArtifactInstructions, isBloc
// Unlocks
if (unlocks.length > 0) {
console.log('');
- console.log(`Completing this artifact enables: ${unlocks.join(', ')}`);
+ console.log(WORKFLOW_MESSAGES.unlocksArtifacts(unlocks.join(', ')));
console.log(' ');
console.log();
}
@@ -303,27 +304,27 @@ export async function generateApplyInstructions(
if (missingArtifacts.length > 0) {
state = 'blocked';
- instruction = `Cannot apply this change yet. Missing artifacts: ${missingArtifacts.join(', ')}.\nUse the openspec-continue-change skill to create the missing artifacts first.`;
+ instruction = WORKFLOW_MESSAGES.cannotApplyMissingArtifacts(missingArtifacts.join(', '));
} else if (tracksFile && !tracksFileExists) {
// Tracking file configured but doesn't exist yet
const tracksFilename = path.basename(tracksFile);
state = 'blocked';
- instruction = `The ${tracksFilename} file is missing and must be created.\nUse openspec-continue-change to generate the tracking file.`;
+ instruction = WORKFLOW_MESSAGES.missingTrackingFile(tracksFilename);
} else if (tracksFile && tracksFileExists && total === 0) {
// Tracking file exists but contains no tasks
const tracksFilename = path.basename(tracksFile);
state = 'blocked';
- instruction = `The ${tracksFilename} file exists but contains no tasks.\nAdd tasks to ${tracksFilename} or regenerate it with openspec-continue-change.`;
+ instruction = WORKFLOW_MESSAGES.trackingFileNoTasks(tracksFilename);
} else if (tracksFile && remaining === 0 && total > 0) {
state = 'all_done';
- instruction = 'All tasks are complete! This change is ready to be archived.\nConsider running tests and reviewing the changes before archiving.';
+ instruction = WORKFLOW_MESSAGES.allTasksComplete;
} else if (!tracksFile) {
// No tracking file configured in schema - ready to apply
state = 'ready';
- instruction = schemaInstruction?.trim() ?? 'All required artifacts complete. Proceed with implementation.';
+ instruction = schemaInstruction?.trim() ?? WORKFLOW_MESSAGES.allArtifactsCompleteProceed;
} else {
state = 'ready';
- instruction = schemaInstruction?.trim() ?? 'Read context files, work through pending tasks, mark complete as you go.\nPause if you hit blockers or need clarification.';
+ instruction = schemaInstruction?.trim() ?? WORKFLOW_MESSAGES.readContextAndWorkTasks;
}
return {
@@ -340,7 +341,7 @@ export async function generateApplyInstructions(
}
export async function applyInstructionsCommand(options: ApplyInstructionsOptions): Promise {
- const spinner = options.json ? undefined : ora('Generating apply instructions...').start();
+ const spinner = options.json ? undefined : ora(WORKFLOW_MESSAGES.generatingApplyInstructions).start();
try {
const projectRoot = process.cwd();
@@ -371,23 +372,23 @@ export async function applyInstructionsCommand(options: ApplyInstructionsOptions
export function printApplyInstructionsText(instructions: ApplyInstructions): void {
const { changeName, schemaName, contextFiles, progress, tasks, state, missingArtifacts, instruction } = instructions;
- console.log(`## Apply: ${changeName}`);
- console.log(`Schema: ${schemaName}`);
+ console.log(WORKFLOW_MESSAGES.applyTitle(changeName));
+ console.log(WORKFLOW_MESSAGES.schemaLabel(schemaName));
console.log();
// Warning for blocked state
if (state === 'blocked' && missingArtifacts) {
- console.log('### ⚠️ Blocked');
+ console.log(WORKFLOW_MESSAGES.blockedTitle);
console.log();
- console.log(`Missing artifacts: ${missingArtifacts.join(', ')}`);
- console.log('Use the openspec-continue-change skill to create these first.');
+ console.log(WORKFLOW_MESSAGES.missingArtifactsLabel(missingArtifacts.join(', ')));
+ console.log(WORKFLOW_MESSAGES.createMissingFirst);
console.log();
}
// Context files (dynamically from schema)
const contextFileEntries = Object.entries(contextFiles);
if (contextFileEntries.length > 0) {
- console.log('### Context Files');
+ console.log(WORKFLOW_MESSAGES.contextFilesTitle);
for (const [artifactId, filePaths] of contextFileEntries) {
for (const filePath of filePaths) {
console.log(`- ${artifactId}: ${filePath}`);
@@ -398,18 +399,18 @@ export function printApplyInstructionsText(instructions: ApplyInstructions): voi
// Progress (only show if we have tracking)
if (progress.total > 0 || tasks.length > 0) {
- console.log('### Progress');
+ console.log(WORKFLOW_MESSAGES.progressTitle);
if (state === 'all_done') {
- console.log(`${progress.complete}/${progress.total} complete ✓`);
+ console.log(WORKFLOW_MESSAGES.progressCompleteWithCheck(progress.complete, progress.total));
} else {
- console.log(`${progress.complete}/${progress.total} complete`);
+ console.log(WORKFLOW_MESSAGES.progressComplete(progress.complete, progress.total));
}
console.log();
}
// Tasks
if (tasks.length > 0) {
- console.log('### Tasks');
+ console.log(WORKFLOW_MESSAGES.tasksTitle);
for (const task of tasks) {
const checkbox = task.done ? '[x]' : '[ ]';
console.log(`- ${checkbox} ${task.description}`);
@@ -418,6 +419,6 @@ export function printApplyInstructionsText(instructions: ApplyInstructions): voi
}
// Instruction
- console.log('### Instruction');
+ console.log(WORKFLOW_MESSAGES.instructionTitle);
console.log(instruction);
}
diff --git a/src/commands/workflow/new-change.ts b/src/commands/workflow/new-change.ts
index 1435e1addb..f947fcba00 100644
--- a/src/commands/workflow/new-change.ts
+++ b/src/commands/workflow/new-change.ts
@@ -8,6 +8,7 @@ import ora from 'ora';
import path from 'path';
import { createChange, validateChangeName } from '../../utils/change-utils.js';
import { validateSchemaExists } from './shared.js';
+import { WORKFLOW_MESSAGES } from '../../messages/index.js';
// -----------------------------------------------------------------------------
// Types
@@ -24,7 +25,7 @@ export interface NewChangeOptions {
export async function newChangeCommand(name: string | undefined, options: NewChangeOptions): Promise {
if (!name) {
- throw new Error('Missing required argument ');
+ throw new Error(WORKFLOW_MESSAGES.missingNameArgument);
}
const validation = validateChangeName(name);
@@ -39,8 +40,8 @@ export async function newChangeCommand(name: string | undefined, options: NewCha
validateSchemaExists(options.schema, projectRoot);
}
- const schemaDisplay = options.schema ? ` with schema '${options.schema}'` : '';
- const spinner = ora(`Creating change '${name}'${schemaDisplay}...`).start();
+ const schemaDisplay = options.schema ? ` com esquema '${options.schema}'` : '';
+ const spinner = ora(WORKFLOW_MESSAGES.creatingChange(name, schemaDisplay)).start();
try {
const result = await createChange(projectRoot, name, { schema: options.schema });
@@ -53,9 +54,9 @@ export async function newChangeCommand(name: string | undefined, options: NewCha
await fs.writeFile(readmePath, `# ${name}\n\n${options.description}\n`, 'utf-8');
}
- spinner.succeed(`Created change '${name}' at openspec/changes/${name}/ (schema: ${result.schema})`);
+ spinner.succeed(WORKFLOW_MESSAGES.createdChange(name, result.schema));
} catch (error) {
- spinner.fail(`Failed to create change '${name}'`);
+ spinner.fail(WORKFLOW_MESSAGES.failedToCreateChange(name));
throw error;
}
}
diff --git a/src/commands/workflow/schemas.ts b/src/commands/workflow/schemas.ts
index b9af74a677..2f591c46d6 100644
--- a/src/commands/workflow/schemas.ts
+++ b/src/commands/workflow/schemas.ts
@@ -6,6 +6,7 @@
import chalk from 'chalk';
import { listSchemasWithInfo } from '../../core/artifact-graph/index.js';
+import { WORKFLOW_MESSAGES } from '../../messages/index.js';
// -----------------------------------------------------------------------------
// Types
@@ -28,19 +29,19 @@ export async function schemasCommand(options: SchemasOptions): Promise {
return;
}
- console.log('Available schemas:');
+ console.log(WORKFLOW_MESSAGES.availableSchemas);
console.log();
for (const schema of schemas) {
let sourceLabel = '';
if (schema.source === 'project') {
- sourceLabel = chalk.cyan(' (project)');
+ sourceLabel = chalk.cyan(WORKFLOW_MESSAGES.projectLabel);
} else if (schema.source === 'user') {
- sourceLabel = chalk.dim(' (user override)');
+ sourceLabel = chalk.dim(WORKFLOW_MESSAGES.userOverrideLabel);
}
console.log(` ${chalk.bold(schema.name)}${sourceLabel}`);
console.log(` ${schema.description}`);
- console.log(` Artifacts: ${schema.artifacts.join(' → ')}`);
+ console.log(` ${WORKFLOW_MESSAGES.artifactsLabel(schema.artifacts.join(' → '))}`);
console.log();
}
}
diff --git a/src/commands/workflow/shared.ts b/src/commands/workflow/shared.ts
index 43c9aa46c9..303ced732c 100644
--- a/src/commands/workflow/shared.ts
+++ b/src/commands/workflow/shared.ts
@@ -10,6 +10,7 @@ import path from 'path';
import * as fs from 'fs';
import { getSchemaDir, listSchemas } from '../../core/artifact-graph/index.js';
import { validateChangeName } from '../../utils/change-utils.js';
+import { WORKFLOW_MESSAGES } from '../../messages/index.js';
// -----------------------------------------------------------------------------
// Types
@@ -114,17 +115,17 @@ export async function validateChangeExists(
if (!changeName) {
const available = await getAvailableChanges(projectRoot);
if (available.length === 0) {
- throw new Error('No changes found. Create one with: openspec new change ');
+ throw new Error(WORKFLOW_MESSAGES.noChangesFound);
}
throw new Error(
- `Missing required option --change. Available changes:\n ${available.join('\n ')}`
+ WORKFLOW_MESSAGES.missingChangeOption(available.join('\n '))
);
}
// Validate change name format to prevent path traversal
const nameValidation = validateChangeName(changeName);
if (!nameValidation.valid) {
- throw new Error(`Invalid change name '${changeName}': ${nameValidation.error}`);
+ throw new Error(WORKFLOW_MESSAGES.invalidChangeName(changeName, nameValidation.error!));
}
// Check directory existence directly
@@ -135,7 +136,7 @@ export async function validateChangeExists(
const available = await getAvailableChanges(projectRoot);
if (available.length === 0) {
throw new Error(
- `Change '${changeName}' not found. No changes exist. Create one with: openspec new change `
+ WORKFLOW_MESSAGES.changeNotFoundNoChanges(changeName)
);
}
throw new Error(
@@ -157,7 +158,7 @@ export function validateSchemaExists(schemaName: string, projectRoot?: string):
if (!schemaDir) {
const availableSchemas = listSchemas(projectRoot);
throw new Error(
- `Schema '${schemaName}' not found. Available schemas:\n ${availableSchemas.join('\n ')}`
+ WORKFLOW_MESSAGES.schemaNotFound(schemaName, availableSchemas.join('\n '))
);
}
return schemaName;
diff --git a/src/commands/workflow/status.ts b/src/commands/workflow/status.ts
index 1109ab1886..94b9ec0029 100644
--- a/src/commands/workflow/status.ts
+++ b/src/commands/workflow/status.ts
@@ -18,6 +18,7 @@ import {
getStatusIndicator,
getStatusColor,
} from './shared.js';
+import { WORKFLOW_MESSAGES } from '../../messages/index.js';
// -----------------------------------------------------------------------------
// Types
@@ -34,7 +35,7 @@ export interface StatusOptions {
// -----------------------------------------------------------------------------
export async function statusCommand(options: StatusOptions): Promise {
- const spinner = options.json ? undefined : ora('Loading change status...').start();
+ const spinner = options.json ? undefined : ora(WORKFLOW_MESSAGES.loadingChangeStatus).start();
try {
const projectRoot = process.cwd();
@@ -46,16 +47,16 @@ export async function statusCommand(options: StatusOptions): Promise {
if (available.length === 0) {
spinner?.stop();
if (options.json) {
- console.log(JSON.stringify({ changes: [], message: 'No active changes.' }, null, 2));
+ console.log(JSON.stringify({ changes: [], message: WORKFLOW_MESSAGES.noActiveChanges }, null, 2));
return;
}
- console.log('No active changes. Create one with: openspec new change ');
+ console.log(WORKFLOW_MESSAGES.noActiveChanges);
return;
}
// Changes exist but --change not provided
spinner?.stop();
throw new Error(
- `Missing required option --change. Available changes:\n ${available.join('\n ')}`
+ WORKFLOW_MESSAGES.missingChangeOption(available.join('\n '))
);
}
@@ -88,9 +89,9 @@ export function printStatusText(status: ChangeStatus): void {
const doneCount = status.artifacts.filter((a) => a.status === 'done').length;
const total = status.artifacts.length;
- console.log(`Change: ${status.changeName}`);
- console.log(`Schema: ${status.schemaName}`);
- console.log(`Progress: ${doneCount}/${total} artifacts complete`);
+ console.log(WORKFLOW_MESSAGES.changeLabel(status.changeName));
+ console.log(WORKFLOW_MESSAGES.schemaLabel2(status.schemaName));
+ console.log(WORKFLOW_MESSAGES.progressArtifacts(doneCount, total));
console.log();
for (const artifact of status.artifacts) {
@@ -99,7 +100,7 @@ export function printStatusText(status: ChangeStatus): void {
let line = `${indicator} ${artifact.id}`;
if (artifact.status === 'blocked' && artifact.missingDeps && artifact.missingDeps.length > 0) {
- line += color(` (blocked by: ${artifact.missingDeps.join(', ')})`);
+ line += color(WORKFLOW_MESSAGES.blockedBy(artifact.missingDeps.join(', ')));
}
console.log(line);
@@ -107,6 +108,6 @@ export function printStatusText(status: ChangeStatus): void {
if (status.isComplete) {
console.log();
- console.log(chalk.green('All artifacts complete!'));
+ console.log(chalk.green(WORKFLOW_MESSAGES.allArtifactsComplete));
}
}
diff --git a/src/commands/workflow/templates.ts b/src/commands/workflow/templates.ts
index fedd323e0d..272fa0529a 100644
--- a/src/commands/workflow/templates.ts
+++ b/src/commands/workflow/templates.ts
@@ -13,6 +13,7 @@ import {
} from '../../core/artifact-graph/index.js';
import { FileSystemUtils } from '../../utils/file-system.js';
import { validateSchemaExists, DEFAULT_SCHEMA } from './shared.js';
+import { WORKFLOW_MESSAGES } from '../../messages/index.js';
// -----------------------------------------------------------------------------
// Types
@@ -34,7 +35,7 @@ export interface TemplateInfo {
// -----------------------------------------------------------------------------
export async function templatesCommand(options: TemplatesOptions): Promise {
- const spinner = options.json ? undefined : ora('Loading templates...').start();
+ const spinner = options.json ? undefined : ora(WORKFLOW_MESSAGES.loadingTemplates).start();
try {
const projectRoot = process.cwd();
@@ -86,8 +87,8 @@ export async function templatesCommand(options: TemplatesOptions): Promise
return;
}
- console.log(`Schema: ${schemaName}`);
- console.log(`Source: ${source}`);
+ console.log(WORKFLOW_MESSAGES.schemaLabel3(schemaName));
+ console.log(WORKFLOW_MESSAGES.sourceLabel(source));
console.log();
for (const t of templates) {
diff --git a/src/core/archive.ts b/src/core/archive.ts
index 5af7181fce..f70e62f275 100644
--- a/src/core/archive.ts
+++ b/src/core/archive.ts
@@ -3,6 +3,7 @@ import path from 'path';
import { getTaskProgressForChange, formatTaskStatus } from '../utils/task-progress.js';
import { Validator } from './validation/validator.js';
import chalk from 'chalk';
+import { ARCHIVE_MESSAGES } from '../messages/index.js';
import {
findSpecUpdates,
buildUpdatedSpec,
@@ -68,7 +69,7 @@ export class ArchiveCommand {
if (!changeName) {
const selectedChange = await this.selectChange(changesDir);
if (!selectedChange) {
- console.log('No change selected. Aborting.');
+ console.log(ARCHIVE_MESSAGES.noChangeSelected);
return;
}
changeName = selectedChange;
@@ -80,10 +81,10 @@ export class ArchiveCommand {
try {
const stat = await fs.stat(changeDir);
if (!stat.isDirectory()) {
- throw new Error(`Change '${changeName}' not found.`);
+ throw new Error(ARCHIVE_MESSAGES.changeNotFound(changeName));
}
} catch {
- throw new Error(`Change '${changeName}' not found.`);
+ throw new Error(ARCHIVE_MESSAGES.changeNotFound(changeName));
}
const skipValidation = options.validate === false || options.noValidate === true;
@@ -100,7 +101,7 @@ export class ArchiveCommand {
const changeReport = await validator.validateChange(changeFile);
// Proposal validation is informative only (do not block archive)
if (!changeReport.valid) {
- console.log(chalk.yellow(`\nProposal warnings in proposal.md (non-blocking):`));
+ console.log(chalk.yellow(`\n${ARCHIVE_MESSAGES.proposalWarnings}`));
for (const issue of changeReport.issues) {
const symbol = issue.level === 'ERROR' ? '⚠' : (issue.level === 'WARNING' ? '⚠' : 'ℹ');
console.log(chalk.yellow(` ${symbol} ${issue.message}`));
@@ -133,7 +134,7 @@ export class ArchiveCommand {
const deltaReport = await validator.validateChangeDeltaSpecs(changeDir);
if (!deltaReport.valid) {
hasValidationErrors = true;
- console.log(chalk.red(`\nValidation errors in change delta specs:`));
+ console.log(chalk.red(`\n${ARCHIVE_MESSAGES.validationErrorsInDeltas}`));
for (const issue of deltaReport.issues) {
if (issue.level === 'ERROR') {
console.log(chalk.red(` ✗ ${issue.message}`));
@@ -145,8 +146,8 @@ export class ArchiveCommand {
}
if (hasValidationErrors) {
- console.log(chalk.red('\nValidation failed. Please fix the errors before archiving.'));
- console.log(chalk.yellow('To skip validation (not recommended), use --no-validate flag.'));
+ console.log(chalk.red(`\n${ARCHIVE_MESSAGES.validationFailed}`));
+ console.log(chalk.yellow(ARCHIVE_MESSAGES.skipValidationHint));
return;
}
} else {
@@ -156,67 +157,67 @@ export class ArchiveCommand {
if (!options.yes) {
const { confirm } = await import('@inquirer/prompts');
const proceed = await confirm({
- message: chalk.yellow('⚠️ WARNING: Skipping validation may archive invalid specs. Continue? (y/N)'),
+ message: chalk.yellow(ARCHIVE_MESSAGES.skipValidationWarning),
default: false
});
if (!proceed) {
- console.log('Archive cancelled.');
+ console.log(ARCHIVE_MESSAGES.archiveCancelled);
return;
}
} else {
- console.log(chalk.yellow(`\n⚠️ WARNING: Skipping validation may archive invalid specs.`));
+ console.log(chalk.yellow(`\n${ARCHIVE_MESSAGES.skipValidationFlagWarning}`));
}
- console.log(chalk.yellow(`[${timestamp}] Validation skipped for change: ${changeName}`));
- console.log(chalk.yellow(`Affected files: ${changeDir}`));
+ console.log(chalk.yellow(ARCHIVE_MESSAGES.skipValidationLog(timestamp, changeName)));
+ console.log(chalk.yellow(ARCHIVE_MESSAGES.affectedFiles(changeDir)));
}
// Show progress and check for incomplete tasks
const progress = await getTaskProgressForChange(changesDir, changeName);
const status = formatTaskStatus(progress);
- console.log(`Task status: ${status}`);
+ console.log(ARCHIVE_MESSAGES.taskStatus(status));
const incompleteTasks = Math.max(progress.total - progress.completed, 0);
if (incompleteTasks > 0) {
if (!options.yes) {
const { confirm } = await import('@inquirer/prompts');
const proceed = await confirm({
- message: `Warning: ${incompleteTasks} incomplete task(s) found. Continue?`,
+ message: ARCHIVE_MESSAGES.incompleteTasksWarning(incompleteTasks),
default: false
});
if (!proceed) {
- console.log('Archive cancelled.');
+ console.log(ARCHIVE_MESSAGES.archiveCancelled);
return;
}
} else {
- console.log(`Warning: ${incompleteTasks} incomplete task(s) found. Continuing due to --yes flag.`);
+ console.log(ARCHIVE_MESSAGES.incompleteTasksContinuing(incompleteTasks));
}
}
// Handle spec updates unless skipSpecs flag is set
if (options.skipSpecs) {
- console.log('Skipping spec updates (--skip-specs flag provided).');
+ console.log(ARCHIVE_MESSAGES.skipSpecUpdates);
} else {
// Find specs to update
const specUpdates = await findSpecUpdates(changeDir, mainSpecsDir);
if (specUpdates.length > 0) {
- console.log('\nSpecs to update:');
+ console.log(`\n${ARCHIVE_MESSAGES.specsToUpdate}`);
for (const update of specUpdates) {
- const status = update.exists ? 'update' : 'create';
+ const status = update.exists ? 'atualizar' : 'criar';
const capability = path.basename(path.dirname(update.target));
- console.log(` ${capability}: ${status}`);
+ console.log(ARCHIVE_MESSAGES.specUpdateStatus(capability, status));
}
let shouldUpdateSpecs = true;
if (!options.yes) {
const { confirm } = await import('@inquirer/prompts');
shouldUpdateSpecs = await confirm({
- message: 'Proceed with spec updates?',
+ message: ARCHIVE_MESSAGES.proceedWithSpecUpdates,
default: true
});
if (!shouldUpdateSpecs) {
- console.log('Skipping spec updates. Proceeding with archive.');
+ console.log(ARCHIVE_MESSAGES.skipSpecUpdatesProceeding);
}
}
@@ -230,7 +231,7 @@ export class ArchiveCommand {
}
} catch (err: any) {
console.log(String(err.message || err));
- console.log('Aborted. No files were changed.');
+ console.log(ARCHIVE_MESSAGES.abortedNoChanges);
return;
}
@@ -241,12 +242,12 @@ export class ArchiveCommand {
if (!skipValidation) {
const report = await new Validator().validateSpecContent(specName, p.rebuilt);
if (!report.valid) {
- console.log(chalk.red(`\nValidation errors in rebuilt spec for ${specName} (will not write changes):`));
+ console.log(chalk.red(`\n${ARCHIVE_MESSAGES.validationErrorsInRebuiltSpec(specName)}`));
for (const issue of report.issues) {
if (issue.level === 'ERROR') console.log(chalk.red(` ✗ ${issue.message}`));
else if (issue.level === 'WARNING') console.log(chalk.yellow(` ⚠ ${issue.message}`));
}
- console.log('Aborted. No files were changed.');
+ console.log(ARCHIVE_MESSAGES.abortedNoChanges);
return;
}
}
@@ -257,9 +258,9 @@ export class ArchiveCommand {
totals.renamed += p.counts.renamed;
}
console.log(
- `Totals: + ${totals.added}, ~ ${totals.modified}, - ${totals.removed}, → ${totals.renamed}`
+ ARCHIVE_MESSAGES.totals(totals.added, totals.modified, totals.removed, totals.renamed)
);
- console.log('Specs updated successfully.');
+ console.log(ARCHIVE_MESSAGES.specsUpdatedSuccessfully);
}
}
}
@@ -271,7 +272,7 @@ export class ArchiveCommand {
// Check if archive already exists
try {
await fs.access(archivePath);
- throw new Error(`Archive '${archiveName}' already exists.`);
+ throw new Error(ARCHIVE_MESSAGES.archiveAlreadyExists(archiveName));
} catch (error: any) {
if (error.code !== 'ENOENT') {
throw error;
@@ -284,7 +285,7 @@ export class ArchiveCommand {
// Move change to archive (uses copy+remove on EPERM/EXDEV, e.g. Windows)
await moveDirectory(changeDir, archivePath);
- console.log(`Change '${changeName}' archived as '${archiveName}'.`);
+ console.log(ARCHIVE_MESSAGES.changeArchived(changeName, archiveName));
}
private async selectChange(changesDir: string): Promise {
@@ -297,7 +298,7 @@ export class ArchiveCommand {
.sort();
if (changeDirs.length === 0) {
- console.log('No active changes found.');
+ console.log(ARCHIVE_MESSAGES.noActiveChanges);
return null;
}
@@ -322,7 +323,7 @@ export class ArchiveCommand {
try {
const answer = await select({
- message: 'Select a change to archive',
+ message: ARCHIVE_MESSAGES.selectChangeToArchive,
choices
});
return answer;
diff --git a/src/core/artifact-graph/instruction-loader.ts b/src/core/artifact-graph/instruction-loader.ts
index b8b2675bb9..477179f593 100644
--- a/src/core/artifact-graph/instruction-loader.ts
+++ b/src/core/artifact-graph/instruction-loader.ts
@@ -4,6 +4,7 @@ import { getSchemaDir, resolveSchema } from './resolver.js';
import { ArtifactGraph } from './graph.js';
import { detectCompleted } from './state.js';
import { resolveSchemaForChange } from '../../utils/change-metadata.js';
+import { WORKFLOW_MESSAGES } from '../../messages/index.js';
import { FileSystemUtils } from '../../utils/file-system.js';
import { readProjectConfig, validateConfigRules } from '../project-config.js';
import type { Artifact, CompletedSet } from './types.js';
@@ -133,7 +134,7 @@ export function loadTemplate(
const schemaDir = getSchemaDir(schemaName, projectRoot);
if (!schemaDir) {
throw new TemplateLoadError(
- `Schema '${schemaName}' not found`,
+ WORKFLOW_MESSAGES.schemaNotFound(schemaName, ''),
templatePath
);
}
diff --git a/src/core/artifact-graph/resolver.ts b/src/core/artifact-graph/resolver.ts
index 9ccd48abaf..2bedfe0b02 100644
--- a/src/core/artifact-graph/resolver.ts
+++ b/src/core/artifact-graph/resolver.ts
@@ -1,6 +1,7 @@
import * as fs from 'node:fs';
import * as path from 'node:path';
import { fileURLToPath } from 'node:url';
+import { WORKFLOW_MESSAGES } from '../../messages/index.js';
import { getGlobalDataDir } from '../global-config.js';
import { parseSchema, SchemaValidationError } from './schema.js';
import type { SchemaYaml } from './types.js';
@@ -114,7 +115,7 @@ export function resolveSchema(name: string, projectRoot?: string): SchemaYaml {
if (!schemaDir) {
const availableSchemas = listSchemas(projectRoot);
throw new Error(
- `Schema '${normalizedName}' not found. Available schemas: ${availableSchemas.join(', ')}`
+ WORKFLOW_MESSAGES.schemaNotFound(normalizedName, availableSchemas.join(', '))
);
}
diff --git a/src/core/completions/command-registry.ts b/src/core/completions/command-registry.ts
index 09c9ecc8db..5ea86d0e3b 100644
--- a/src/core/completions/command-registry.ts
+++ b/src/core/completions/command-registry.ts
@@ -29,13 +29,13 @@ const COMMON_FLAGS = {
} as const;
/**
- * Registry of all OpenSpec CLI commands with their flags and metadata.
+ * Registry of all BR-OpenSpec CLI commands with their flags and metadata.
* This registry is used to generate shell completion scripts.
*/
export const COMMAND_REGISTRY: CommandDefinition[] = [
{
name: 'init',
- description: 'Initialize OpenSpec in your project',
+ description: 'Initialize BR-OpenSpec in your project',
acceptsPositional: true,
positionalType: 'path',
flags: [
@@ -48,7 +48,7 @@ export const COMMAND_REGISTRY: CommandDefinition[] = [
},
{
name: 'update',
- description: 'Update OpenSpec instruction files',
+ description: 'Update BR-OpenSpec instruction files',
acceptsPositional: true,
positionalType: 'path',
flags: [],
@@ -157,7 +157,7 @@ export const COMMAND_REGISTRY: CommandDefinition[] = [
},
{
name: 'feedback',
- description: 'Submit feedback about OpenSpec',
+ description: 'Submit feedback about BR-OpenSpec',
acceptsPositional: true,
flags: [
{
@@ -169,7 +169,7 @@ export const COMMAND_REGISTRY: CommandDefinition[] = [
},
{
name: 'change',
- description: 'Manage OpenSpec change proposals (deprecated)',
+ description: 'Manage BR-OpenSpec change proposals (deprecated)',
flags: [],
subcommands: [
{
@@ -216,7 +216,7 @@ export const COMMAND_REGISTRY: CommandDefinition[] = [
},
{
name: 'spec',
- description: 'Manage OpenSpec specifications',
+ description: 'Manage BR-OpenSpec specifications',
flags: [],
subcommands: [
{
@@ -269,7 +269,7 @@ export const COMMAND_REGISTRY: CommandDefinition[] = [
},
{
name: 'completion',
- description: 'Manage shell completions for OpenSpec CLI',
+ description: 'Manage shell completions for BR-OpenSpec CLI',
flags: [],
subcommands: [
{
@@ -308,7 +308,7 @@ export const COMMAND_REGISTRY: CommandDefinition[] = [
},
{
name: 'config',
- description: 'View and modify global OpenSpec configuration',
+ description: 'View and modify global BR-OpenSpec configuration',
flags: [
{
name: 'scope',
diff --git a/src/core/completions/generators/bash-generator.ts b/src/core/completions/generators/bash-generator.ts
index 73df90c299..cb6fbbb2dc 100644
--- a/src/core/completions/generators/bash-generator.ts
+++ b/src/core/completions/generators/bash-generator.ts
@@ -2,7 +2,7 @@ import { CompletionGenerator, CommandDefinition, FlagDefinition } from '../types
import { BASH_DYNAMIC_HELPERS } from '../templates/bash-templates.js';
/**
- * Generates Bash completion scripts for the OpenSpec CLI.
+ * Generates Bash completion scripts for the BR-OpenSpec CLI.
* Follows Bash completion conventions using complete builtin and COMPREPLY array.
*/
export class BashGenerator implements CompletionGenerator {
@@ -31,7 +31,7 @@ export class BashGenerator implements CompletionGenerator {
const helpers = BASH_DYNAMIC_HELPERS;
// Assemble final script with template literal
- return `# Bash completion script for OpenSpec CLI
+ return `# Bash completion script for BR-OpenSpec CLI
# Auto-generated - do not edit manually
_openspec_completion() {
diff --git a/src/core/completions/generators/fish-generator.ts b/src/core/completions/generators/fish-generator.ts
index 4020fb33db..3692cf63cc 100644
--- a/src/core/completions/generators/fish-generator.ts
+++ b/src/core/completions/generators/fish-generator.ts
@@ -2,7 +2,7 @@ import { CompletionGenerator, CommandDefinition, FlagDefinition } from '../types
import { FISH_STATIC_HELPERS, FISH_DYNAMIC_HELPERS } from '../templates/fish-templates.js';
/**
- * Generates Fish completion scripts for the OpenSpec CLI.
+ * Generates Fish completion scripts for the BR-OpenSpec CLI.
* Follows Fish completion conventions using the complete command.
*/
export class FishGenerator implements CompletionGenerator {
@@ -40,7 +40,7 @@ export class FishGenerator implements CompletionGenerator {
const dynamicHelpers = FISH_DYNAMIC_HELPERS;
// Assemble final script with template literal
- return `# Fish completion script for OpenSpec CLI
+ return `# Fish completion script for BR-OpenSpec CLI
# Auto-generated - do not edit manually
${helperFunctions}
diff --git a/src/core/completions/generators/powershell-generator.ts b/src/core/completions/generators/powershell-generator.ts
index c4be1f9900..e70dd122b1 100644
--- a/src/core/completions/generators/powershell-generator.ts
+++ b/src/core/completions/generators/powershell-generator.ts
@@ -1,8 +1,9 @@
import { CompletionGenerator, CommandDefinition, FlagDefinition } from '../types.js';
import { POWERSHELL_DYNAMIC_HELPERS } from '../templates/powershell-templates.js';
+import { COMPLETION_MESSAGES } from '../../../messages/index.js';
/**
- * Generates PowerShell completion scripts for the OpenSpec CLI.
+ * Generates PowerShell completion scripts for the BR-OpenSpec CLI.
* Uses Register-ArgumentCompleter for command completion.
*/
export class PowerShellGenerator implements CompletionGenerator {
@@ -41,8 +42,8 @@ export class PowerShellGenerator implements CompletionGenerator {
const helpers = POWERSHELL_DYNAMIC_HELPERS;
// Assemble final script with template literal
- return `# PowerShell completion script for OpenSpec CLI
-# Auto-generated - do not edit manually
+ return `${COMPLETION_MESSAGES.powershellCompletionHeader}
+${COMPLETION_MESSAGES.powershellCompletionNote}
${helpers}
$openspecCompleter = {
@@ -182,17 +183,17 @@ Register-ArgumentCompleter -CommandName openspec -ScriptBlock $openspecCompleter
switch (positionalType) {
case 'change-id':
- lines.push(`${indent}Get-OpenSpecChanges | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object {`);
+ lines.push(`${indent}Get-BROpenSpecChanges | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object {`);
lines.push(`${indent} [System.Management.Automation.CompletionResult]::new($_, $_, "ParameterValue", "Change: $_")`);
lines.push(`${indent}}`);
break;
case 'spec-id':
- lines.push(`${indent}Get-OpenSpecSpecs | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object {`);
+ lines.push(`${indent}Get-BROpenSpecSpecs | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object {`);
lines.push(`${indent} [System.Management.Automation.CompletionResult]::new($_, $_, "ParameterValue", "Spec: $_")`);
lines.push(`${indent}}`);
break;
case 'change-or-spec-id':
- lines.push(`${indent}$items = @(Get-OpenSpecChanges) + @(Get-OpenSpecSpecs)`);
+ lines.push(`${indent}$items = @(Get-BROpenSpecChanges) + @(Get-BROpenSpecSpecs)`);
lines.push(`${indent}$items | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object {`);
lines.push(`${indent} [System.Management.Automation.CompletionResult]::new($_, $_, "ParameterValue", $_)`);
lines.push(`${indent}}`);
diff --git a/src/core/completions/generators/zsh-generator.ts b/src/core/completions/generators/zsh-generator.ts
index f9a68c5e5e..abb5f6e4a6 100644
--- a/src/core/completions/generators/zsh-generator.ts
+++ b/src/core/completions/generators/zsh-generator.ts
@@ -2,7 +2,7 @@ import { CompletionGenerator, CommandDefinition, FlagDefinition } from '../types
import { ZSH_DYNAMIC_HELPERS } from '../templates/zsh-templates.js';
/**
- * Generates Zsh completion scripts for the OpenSpec CLI.
+ * Generates Zsh completion scripts for the BR-OpenSpec CLI.
* Follows Zsh completion system conventions using the _openspec function.
*/
export class ZshGenerator implements CompletionGenerator {
@@ -46,7 +46,7 @@ export class ZshGenerator implements CompletionGenerator {
// Assemble final script with template literal
return `#compdef openspec
-# Zsh completion script for OpenSpec CLI
+# Zsh completion script for BR-OpenSpec CLI
# Auto-generated - do not edit manually
_openspec() {
diff --git a/src/core/completions/installers/bash-installer.ts b/src/core/completions/installers/bash-installer.ts
index 8e63cb7e0d..1de642ae76 100644
--- a/src/core/completions/installers/bash-installer.ts
+++ b/src/core/completions/installers/bash-installer.ts
@@ -2,6 +2,7 @@ import { promises as fs } from 'fs';
import path from 'path';
import os from 'os';
import { FileSystemUtils } from '../../../utils/file-system.js';
+import { COMPLETION_MESSAGES } from '../../../messages/index.js';
import { InstallationResult } from '../factory.js';
/**
@@ -101,7 +102,7 @@ export class BashInstaller {
*/
private generateBashrcConfig(completionsDir: string): string {
return [
- '# OpenSpec shell completions configuration',
+ '# BR-OpenSpec shell completions configuration',
`if [ -d "${completionsDir}" ]; then`,
` for f in "${completionsDir}"/*; do`,
' [ -f "$f" ] && . "$f"',
@@ -226,10 +227,10 @@ export class BashInstaller {
return {
success: true,
installedPath: targetPath,
- message: 'Completion script is already installed (up to date)',
+ message: COMPLETION_MESSAGES.bashAlreadyInstalled,
instructions: [
- 'The completion script is already installed and up to date.',
- 'If completions are not working, try: exec bash',
+ COMPLETION_MESSAGES.bashAlreadyInstalledDetail,
+ COMPLETION_MESSAGES.bashAlreadyInstalledHint,
],
};
}
@@ -260,13 +261,13 @@ export class BashInstaller {
const warnings: string[] = [];
if (!hasBashCompletion) {
warnings.push(
- '⚠️ Warning: bash-completion package not detected',
+ COMPLETION_MESSAGES.bashCompletionNotDetected,
'',
- 'The completion script requires bash-completion to function.',
- 'Install it with:',
+ COMPLETION_MESSAGES.bashCompletionRequired,
+ COMPLETION_MESSAGES.installWith,
' brew install bash-completion@2',
'',
- 'Then add to your ~/.bash_profile:',
+ COMPLETION_MESSAGES.addToBashProfile,
' [[ -r "/opt/homebrew/etc/profile.d/bash_completion.sh" ]] && . "/opt/homebrew/etc/profile.d/bash_completion.sh"'
);
}
@@ -275,12 +276,12 @@ export class BashInstaller {
let message: string;
if (isUpdate) {
message = backupPath
- ? 'Completion script updated successfully (previous version backed up)'
- : 'Completion script updated successfully';
+ ? COMPLETION_MESSAGES.bashUpdatedWithBackup
+ : COMPLETION_MESSAGES.bashUpdated;
} else {
message = bashrcConfigured
- ? 'Completion script installed and .bashrc configured successfully'
- : 'Completion script installed successfully for Bash';
+ ? COMPLETION_MESSAGES.bashInstalledWithBashrc
+ : COMPLETION_MESSAGES.bashInstalled;
}
return {
@@ -295,7 +296,7 @@ export class BashInstaller {
} catch (error) {
return {
success: false,
- message: `Failed to install completion script: ${error instanceof Error ? error.message : String(error)}`,
+ message: COMPLETION_MESSAGES.bashFailedToInstall(error instanceof Error ? error.message : String(error)),
};
}
}
@@ -314,7 +315,7 @@ export class BashInstaller {
'',
'To enable completions, add the following to your ~/.bashrc file:',
'',
- ` # Source OpenSpec completions`,
+ ` # Source BR-OpenSpec completions`,
` if [ -d "${completionsDir}" ]; then`,
` for f in "${completionsDir}"/*; do`,
' [ -f "$f" ] && . "$f"',
@@ -342,7 +343,7 @@ export class BashInstaller {
} catch {
return {
success: false,
- message: 'Completion script is not installed',
+ message: COMPLETION_MESSAGES.bashNotInstalled,
};
}
@@ -354,12 +355,12 @@ export class BashInstaller {
return {
success: true,
- message: 'Completion script uninstalled successfully',
+ message: COMPLETION_MESSAGES.bashUninstalled,
};
} catch (error) {
return {
success: false,
- message: `Failed to uninstall completion script: ${error instanceof Error ? error.message : String(error)}`,
+ message: COMPLETION_MESSAGES.bashFailedToUninstall(error instanceof Error ? error.message : String(error)),
};
}
}
diff --git a/src/core/completions/installers/powershell-installer.ts b/src/core/completions/installers/powershell-installer.ts
index 21384fd919..192109a1bd 100644
--- a/src/core/completions/installers/powershell-installer.ts
+++ b/src/core/completions/installers/powershell-installer.ts
@@ -2,6 +2,7 @@ import { promises as fs } from 'fs';
import path from 'path';
import os from 'os';
import { FileSystemUtils } from '../../../utils/file-system.js';
+import { COMPLETION_MESSAGES } from '../../../messages/index.js';
import { InstallationResult } from '../factory.js';
/**
@@ -120,7 +121,7 @@ export class PowerShellInstaller {
getInstallationPath(): string {
const profilePath = this.getProfilePath();
const profileDir = path.dirname(profilePath);
- return path.join(profileDir, 'OpenSpecCompletion.ps1');
+ return path.join(profileDir, 'BROpenSpecCompletion.ps1');
}
/**
@@ -151,7 +152,7 @@ export class PowerShellInstaller {
*/
private generateProfileConfig(scriptPath: string): string {
return [
- '# OpenSpec shell completions configuration',
+ '# BR-OpenSpec shell completions configuration',
`if (Test-Path "${scriptPath}") {`,
` . "${scriptPath}"`,
'}',
@@ -188,7 +189,7 @@ export class PowerShellInstaller {
if (err?.code === 'ENOENT') {
// keep defaults
} else {
- console.warn(`Warning: Skipping ${profilePath}: ${err?.message ?? String(err)}`);
+ console.warn(COMPLETION_MESSAGES.warningSkippingProfile(profilePath, err?.message ?? String(err)));
continue;
}
}
@@ -202,7 +203,7 @@ export class PowerShellInstaller {
// Add OpenSpec completion configuration with markers
const openspecBlock = [
'',
- '# OPENSPEC:START - OpenSpec completion (managed block, do not edit manually)',
+ '# OPENSPEC:START - BR-OpenSpec completion (managed block, do not edit manually)',
scriptLine,
'# OPENSPEC:END',
'',
@@ -213,7 +214,7 @@ export class PowerShellInstaller {
anyConfigured = true;
} catch (error) {
// Continue to next profile if this one fails
- console.warn(`Warning: Could not configure ${profilePath}: ${error}`);
+ console.warn(COMPLETION_MESSAGES.warningCouldNotConfigure(profilePath, String(error)));
}
}
@@ -245,7 +246,7 @@ export class PowerShellInstaller {
if (err?.code === 'ENOENT') {
continue; // Profile doesn't exist, nothing to remove
}
- console.warn(`Warning: Could not read ${profilePath}: ${err?.message ?? String(err)}`);
+ console.warn(COMPLETION_MESSAGES.warningCouldNotRead(profilePath, err?.message ?? String(err)));
continue;
}
@@ -260,7 +261,7 @@ export class PowerShellInstaller {
const endIndex = profileContent.indexOf(endMarker, startIndex);
if (endIndex === -1) {
- console.warn(`Warning: Found start marker but no end marker in ${profilePath}`);
+ console.warn(COMPLETION_MESSAGES.warningStartMarkerWithoutEnd(profilePath));
continue;
}
@@ -274,7 +275,7 @@ export class PowerShellInstaller {
await this.writeProfileFile(profilePath, newContent, fileEncoding, fileBom);
anyRemoved = true;
} catch (error) {
- console.warn(`Warning: Could not clean ${profilePath}: ${error}`);
+ console.warn(COMPLETION_MESSAGES.warningCouldNotClean(profilePath, String(error)));
}
}
@@ -318,6 +319,18 @@ export class PowerShellInstaller {
const targetDir = path.dirname(targetPath);
await fs.mkdir(targetDir, { recursive: true });
+ // Remove legacy OpenSpecCompletion.ps1 if it exists (idempotent)
+ const legacyPath = path.join(targetDir, 'OpenSpecCompletion.ps1');
+ try {
+ await fs.unlink(legacyPath);
+ console.debug(`Removed legacy completion file: ${legacyPath}`);
+ } catch (err: any) {
+ if (err?.code !== 'ENOENT') {
+ // Not a "file not found" error — log but continue
+ console.warn(`Warning: could not remove legacy file ${legacyPath}: ${err?.message ?? String(err)}`);
+ }
+ }
+
// Backup existing file if updating
const backupPath = isUpdate ? await this.backupExistingFile(targetPath) : undefined;
@@ -372,7 +385,7 @@ export class PowerShellInstaller {
'',
`To enable completions, add the following to your PowerShell profile (${profilePath}):`,
'',
- ' # Source OpenSpec completions',
+ ' # Source BR-OpenSpec completions',
` if (Test-Path "${installedPath}") {`,
` . "${installedPath}"`,
' }',
diff --git a/src/core/completions/installers/zsh-installer.ts b/src/core/completions/installers/zsh-installer.ts
index 6a4493180f..119ef1c7bc 100644
--- a/src/core/completions/installers/zsh-installer.ts
+++ b/src/core/completions/installers/zsh-installer.ts
@@ -2,6 +2,7 @@ import { promises as fs } from 'fs';
import path from 'path';
import os from 'os';
import { FileSystemUtils } from '../../../utils/file-system.js';
+import { COMPLETION_MESSAGES } from '../../../messages/index.js';
import { InstallationResult } from '../factory.js';
/**
@@ -105,7 +106,7 @@ export class ZshInstaller {
*/
private generateZshrcConfig(completionsDir: string): string {
return [
- '# OpenSpec shell completions configuration',
+ '# BR-OpenSpec shell completions configuration',
`fpath=("${completionsDir}" $fpath)`,
'autoload -Uz compinit',
'compinit',
@@ -435,10 +436,10 @@ export class ZshInstaller {
const messages: string[] = [];
if (scriptRemoved) {
- messages.push(`Completion script removed from ${targetPath}`);
+ messages.push(COMPLETION_MESSAGES.zshScriptRemoved(targetPath));
}
if (zshrcCleaned && !isOhMyZsh) {
- messages.push('Removed OpenSpec configuration from ~/.zshrc');
+ messages.push(COMPLETION_MESSAGES.zshConfigRemoved);
}
return {
@@ -448,7 +449,7 @@ export class ZshInstaller {
} catch (error) {
return {
success: false,
- message: `Failed to uninstall completion script: ${error instanceof Error ? error.message : String(error)}`,
+ message: COMPLETION_MESSAGES.failedToUninstall(error instanceof Error ? error.message : String(error)),
};
}
}
diff --git a/src/core/completions/templates/powershell-templates.ts b/src/core/completions/templates/powershell-templates.ts
index 4f42a89086..c49fa538ad 100644
--- a/src/core/completions/templates/powershell-templates.ts
+++ b/src/core/completions/templates/powershell-templates.ts
@@ -5,7 +5,7 @@
export const POWERSHELL_DYNAMIC_HELPERS = `# Dynamic completion helpers
-function Get-OpenSpecChanges {
+function Get-BROpenSpecChanges {
$output = openspec __complete changes 2>$null
if ($output) {
$output | ForEach-Object {
@@ -14,7 +14,7 @@ function Get-OpenSpecChanges {
}
}
-function Get-OpenSpecSpecs {
+function Get-BROpenSpecSpecs {
$output = openspec __complete specs 2>$null
if ($output) {
$output | ForEach-Object {
diff --git a/src/core/config.ts b/src/core/config.ts
index 4e6bb24b58..1b43acf0c5 100644
--- a/src/core/config.ts
+++ b/src/core/config.ts
@@ -38,6 +38,7 @@ export const AI_TOOLS: AIToolOption[] = [
{ name: 'iFlow', value: 'iflow', available: true, successLabel: 'iFlow', skillsDir: '.iflow' },
{ name: 'Junie', value: 'junie', available: true, successLabel: 'Junie', skillsDir: '.junie' },
{ name: 'Kilo Code', value: 'kilocode', available: true, successLabel: 'Kilo Code', skillsDir: '.kilocode' },
+ { name: 'Kimi Code CLI', value: 'kimi', available: true, successLabel: 'Kimi Code CLI', skillsDir: '.kimi' },
{ name: 'Kiro', value: 'kiro', available: true, successLabel: 'Kiro', skillsDir: '.kiro' },
{ name: 'OpenCode', value: 'opencode', available: true, successLabel: 'OpenCode', skillsDir: '.opencode' },
{ name: 'Pi', value: 'pi', available: true, successLabel: 'Pi', skillsDir: '.pi' },
diff --git a/src/core/init.ts b/src/core/init.ts
index aa38408f22..c4fea87b4b 100644
--- a/src/core/init.ts
+++ b/src/core/init.ts
@@ -19,11 +19,16 @@ import {
} from './config.js';
import { PALETTE } from './styles/palette.js';
import { isInteractive } from '../utils/interactive.js';
+import { INIT_MESSAGES } from '../messages/index.js';
import { serializeConfig } from './config-prompts.js';
import {
generateCommands,
CommandAdapterRegistry,
} from './command-generation/index.js';
+import {
+ removeOpenSpecSkillDirs,
+ removeOpenSpecCommandFiles,
+} from './tools-manager.js';
import {
detectLegacyArtifacts,
cleanupLegacyArtifacts,
@@ -42,7 +47,7 @@ import {
type ToolSkillStatus,
} from './shared/index.js';
import { getGlobalConfig, type Delivery, type Profile } from './global-config.js';
-import { getProfileWorkflows, CORE_WORKFLOWS, ALL_WORKFLOWS } from './profiles.js';
+import { getProfileWorkflows, CORE_WORKFLOWS } from './profiles.js';
import { getAvailableTools } from './available-tools.js';
import { migrateIfNeeded } from './migration.js';
@@ -60,19 +65,6 @@ const PROGRESS_SPINNER = {
frames: ['░░░', '▒░░', '▒▒░', '▒▒▒', '▓▒▒', '▓▓▒', '▓▓▓', '▒▓▓', '░▒▓'],
};
-const WORKFLOW_TO_SKILL_DIR: Record = {
- 'explore': 'openspec-explore',
- 'new': 'openspec-new-change',
- 'continue': 'openspec-continue-change',
- 'apply': 'openspec-apply-change',
- 'ff': 'openspec-ff-change',
- 'sync': 'openspec-sync-specs',
- 'archive': 'openspec-archive-change',
- 'bulk-archive': 'openspec-bulk-archive-change',
- 'verify': 'openspec-verify-change',
- 'onboard': 'openspec-onboard',
- 'propose': 'openspec-propose',
-};
// -----------------------------------------------------------------------------
// Types
@@ -166,7 +158,7 @@ export class InitCommand {
// Check write permissions
if (!(await FileSystemUtils.ensureWritePermissions(projectPath))) {
- throw new Error(`Insufficient permissions to write to ${projectPath}`);
+ throw new Error(INIT_MESSAGES.insufficientPermissions(projectPath));
}
return extendMode;
}
@@ -219,13 +211,13 @@ export class InitCommand {
// Interactive mode: prompt for confirmation
const { confirm } = await import('@inquirer/prompts');
const shouldCleanup = await confirm({
- message: 'Upgrade and clean up legacy files?',
+ message: INIT_MESSAGES.upgradeLegacyPrompt,
default: true,
});
if (!shouldCleanup) {
- console.log(chalk.dim('Initialization cancelled.'));
- console.log(chalk.dim('Run with --force to skip this prompt, or manually remove legacy files.'));
+ console.log(chalk.dim(INIT_MESSAGES.initializationCancelled));
+ console.log(chalk.dim(INIT_MESSAGES.skipPromptHint));
process.exit(0);
}
@@ -233,11 +225,11 @@ export class InitCommand {
}
private async performLegacyCleanup(projectPath: string, detection: LegacyDetectionResult): Promise {
- const spinner = ora('Cleaning up legacy files...').start();
+ const spinner = ora(INIT_MESSAGES.cleaningLegacy).start();
const result = await cleanupLegacyArtifacts(projectPath, detection);
- spinner.succeed('Legacy files cleaned up');
+ spinner.succeed(INIT_MESSAGES.legacyCleaned);
const summary = formatCleanupSummary(result);
if (summary) {
@@ -280,13 +272,13 @@ export class InitCommand {
return [...detectedToolIds];
}
throw new Error(
- `No tools detected and no --tools flag provided. Valid tools:\n ${validTools.join('\n ')}\n\nUse --tools all, --tools none, or --tools claude,cursor,...`
+ INIT_MESSAGES.noToolsDetected(validTools.join('\n '))
);
}
if (validTools.length === 0) {
throw new Error(
- `No tools available for skill generation.`
+ INIT_MESSAGES.noToolsAvailable
);
}
@@ -323,7 +315,7 @@ export class InitCommand {
.map((toolId) => AI_TOOLS.find((t) => t.value === toolId)?.name || toolId);
if (configuredNames.length > 0) {
- console.log(`OpenSpec configured: ${configuredNames.join(', ')} (pre-selected)`);
+ console.log(INIT_MESSAGES.configuredPreselected(configuredNames.join(', ')));
}
const detectedOnlyNames = detectedTools
@@ -332,20 +324,20 @@ export class InitCommand {
if (detectedOnlyNames.length > 0) {
const detectionLabel = shouldPreselectDetected
- ? 'pre-selected for first-time setup'
- : 'not pre-selected';
- console.log(`Detected tool directories: ${detectedOnlyNames.join(', ')} (${detectionLabel})`);
+ ? INIT_MESSAGES.preselectedFirstTime
+ : INIT_MESSAGES.notPreselected;
+ console.log(INIT_MESSAGES.detectedToolsLabel(detectedOnlyNames.join(', '), detectionLabel));
}
const selectedTools = await searchableMultiSelect({
- message: `Select tools to set up (${validTools.length} available)`,
+ message: INIT_MESSAGES.selectToolsPrompt(validTools.length),
pageSize: 15,
choices: sortedChoices,
- validate: (selected: string[]) => selected.length > 0 || 'Select at least one tool',
+ validate: (selected: string[]) => selected.length > 0 || INIT_MESSAGES.selectAtLeastOneTool,
});
if (selectedTools.length === 0) {
- throw new Error('At least one tool must be selected');
+ throw new Error(INIT_MESSAGES.atLeastOneToolRequired);
}
return selectedTools;
@@ -359,7 +351,7 @@ export class InitCommand {
const raw = this.toolsArg.trim();
if (raw.length === 0) {
throw new Error(
- 'The --tools option requires a value. Use "all", "none", or a comma-separated list of tool IDs.'
+ INIT_MESSAGES.toolsOptionRequired
);
}
@@ -383,14 +375,14 @@ export class InitCommand {
if (tokens.length === 0) {
throw new Error(
- 'The --tools option requires at least one tool ID when not using "all" or "none".'
+ INIT_MESSAGES.toolsOptionRequiresToolId
);
}
const normalizedTokens = tokens.map((token) => token.toLowerCase());
if (normalizedTokens.some((token) => token === 'all' || token === 'none')) {
- throw new Error('Cannot combine reserved values "all" or "none" with specific tool IDs.');
+ throw new Error(INIT_MESSAGES.cannotCombineReservedValues);
}
const invalidTokens = tokens.filter(
@@ -399,7 +391,7 @@ export class InitCommand {
if (invalidTokens.length > 0) {
throw new Error(
- `Invalid tool(s): ${invalidTokens.join(', ')}. Available values: ${availableList}`
+ INIT_MESSAGES.invalidTools(invalidTokens.join(', '), availableList)
);
}
@@ -425,14 +417,14 @@ export class InitCommand {
if (!tool) {
const validToolIds = getToolsWithSkillsDir();
throw new Error(
- `Unknown tool '${toolId}'. Valid tools:\n ${validToolIds.join('\n ')}`
+ INIT_MESSAGES.unknownTool(toolId, validToolIds.join('\n '))
);
}
if (!tool.skillsDir) {
const validToolsWithSkills = getToolsWithSkillsDir();
throw new Error(
- `Tool '${toolId}' does not support skill generation.\nTools with skill generation support:\n ${validToolsWithSkills.join('\n ')}`
+ INIT_MESSAGES.toolNoSkillSupport(toolId, validToolsWithSkills.join('\n '))
);
}
@@ -468,7 +460,7 @@ export class InitCommand {
return;
}
- const spinner = this.startSpinner('Creating OpenSpec structure...');
+ const spinner = this.startSpinner(INIT_MESSAGES.creatingStructure);
const directories = [
openspecPath,
@@ -483,7 +475,7 @@ export class InitCommand {
spinner.stopAndPersist({
symbol: PALETTE.white('▌'),
- text: PALETTE.white('OpenSpec structure created'),
+ text: PALETTE.white(INIT_MESSAGES.structureCreated),
});
}
@@ -523,7 +515,7 @@ export class InitCommand {
// Process each tool
for (const tool of tools) {
- const spinner = ora(`Setting up ${tool.name}...`).start();
+ const spinner = ora(INIT_MESSAGES.settingUp(tool.name)).start();
try {
// Generate skill files if delivery includes skills
@@ -568,7 +560,7 @@ export class InitCommand {
removedCommandCount += await this.removeCommandFiles(projectPath, tool.value);
}
- spinner.succeed(`Setup complete for ${tool.name}`);
+ spinner.succeed(INIT_MESSAGES.setupComplete(tool.name));
if (tool.wasConfigured) {
refreshedTools.push(tool);
@@ -576,7 +568,7 @@ export class InitCommand {
createdTools.push(tool);
}
} catch (error) {
- spinner.fail(`Failed for ${tool.name}`);
+ spinner.fail(INIT_MESSAGES.setupFailed(tool.name));
failedTools.push({ name: tool.name, error: error as Error });
}
}
@@ -637,15 +629,15 @@ export class InitCommand {
configStatus: 'created' | 'exists' | 'skipped'
): void {
console.log();
- console.log(chalk.bold('OpenSpec Setup Complete'));
+ console.log(chalk.bold(INIT_MESSAGES.setupCompleteTitle));
console.log();
// Show created vs refreshed tools
if (results.createdTools.length > 0) {
- console.log(`Created: ${results.createdTools.map((t) => t.name).join(', ')}`);
+ console.log(INIT_MESSAGES.created(results.createdTools.map((t) => t.name).join(', ')));
}
if (results.refreshedTools.length > 0) {
- console.log(`Refreshed: ${results.refreshedTools.map((t) => t.name).join(', ')}`);
+ console.log(INIT_MESSAGES.refreshed(results.refreshedTools.map((t) => t.name).join(', ')));
}
// Show counts (respecting profile filter)
@@ -669,31 +661,31 @@ export class InitCommand {
// Show failures
if (results.failedTools.length > 0) {
- console.log(chalk.red(`Failed: ${results.failedTools.map((f) => `${f.name} (${f.error.message})`).join(', ')}`));
+ console.log(chalk.red(INIT_MESSAGES.failed(results.failedTools.map((f) => `${f.name} (${f.error.message})`).join(', '))));
}
// Show skipped commands
if (results.commandsSkipped.length > 0) {
- console.log(chalk.dim(`Commands skipped for: ${results.commandsSkipped.join(', ')} (no adapter)`));
+ console.log(chalk.dim(INIT_MESSAGES.commandsSkipped(results.commandsSkipped.join(', '))));
}
if (results.removedCommandCount > 0) {
- console.log(chalk.dim(`Removed: ${results.removedCommandCount} command files (delivery: skills)`));
+ console.log(chalk.dim(INIT_MESSAGES.removedCommands(results.removedCommandCount)));
}
if (results.removedSkillCount > 0) {
- console.log(chalk.dim(`Removed: ${results.removedSkillCount} skill directories (delivery: commands)`));
+ console.log(chalk.dim(INIT_MESSAGES.removedSkills(results.removedSkillCount)));
}
// Config status
if (configStatus === 'created') {
- console.log(`Config: openspec/config.yaml (schema: ${DEFAULT_SCHEMA})`);
+ console.log(INIT_MESSAGES.configCreated(DEFAULT_SCHEMA));
} else if (configStatus === 'exists') {
// Show actual filename (config.yaml or config.yml)
const configYaml = path.join(projectPath, OPENSPEC_DIR_NAME, 'config.yaml');
const configYml = path.join(projectPath, OPENSPEC_DIR_NAME, 'config.yml');
const configName = fs.existsSync(configYaml) ? 'config.yaml' : fs.existsSync(configYml) ? 'config.yml' : 'config.yaml';
- console.log(`Config: openspec/${configName} (exists)`);
+ console.log(INIT_MESSAGES.configExists(configName));
} else {
- console.log(chalk.dim(`Config: skipped (non-interactive mode)`));
+ console.log(chalk.dim(INIT_MESSAGES.configSkipped));
}
// Getting started (task 7.6: show propose if in profile)
@@ -702,24 +694,24 @@ export class InitCommand {
const activeWorkflows = [...getProfileWorkflows(activeProfile, globalCfg.workflows)];
console.log();
if (activeWorkflows.includes('propose')) {
- console.log(chalk.bold('Getting started:'));
- console.log(' Start your first change: /opsx:propose "your idea"');
+ console.log(chalk.bold(INIT_MESSAGES.gettingStarted));
+ console.log(INIT_MESSAGES.startFirstChangePropose('/opsx:propose "sua ideia"'));
} else if (activeWorkflows.includes('new')) {
- console.log(chalk.bold('Getting started:'));
- console.log(' Start your first change: /opsx:new "your idea"');
+ console.log(chalk.bold(INIT_MESSAGES.gettingStarted));
+ console.log(INIT_MESSAGES.startFirstChangeNew('/opsx:new "sua ideia"'));
} else {
- console.log("Done. Run 'openspec config profile' to configure your workflows.");
+ console.log(INIT_MESSAGES.configureWorkflowsHint);
}
// Links
console.log();
- console.log(`Learn more: ${chalk.cyan('https://github.com/Fission-AI/OpenSpec')}`);
- console.log(`Feedback: ${chalk.cyan('https://github.com/Fission-AI/OpenSpec/issues')}`);
+ console.log(INIT_MESSAGES.learnMore(chalk.cyan('https://github.com/fkmatsuda/BR-OpenSpec')));
+ console.log(INIT_MESSAGES.feedback(chalk.cyan('https://github.com/fkmatsuda/BR-OpenSpec/issues')));
// Restart instruction if any tools were configured
if (results.createdTools.length > 0 || results.refreshedTools.length > 0) {
console.log();
- console.log(chalk.white('Restart your IDE for slash commands to take effect.'));
+ console.log(chalk.white(INIT_MESSAGES.restartIDE));
}
console.log();
@@ -735,45 +727,10 @@ export class InitCommand {
}
private async removeSkillDirs(skillsDir: string): Promise {
- let removed = 0;
-
- for (const workflow of ALL_WORKFLOWS) {
- const dirName = WORKFLOW_TO_SKILL_DIR[workflow];
- if (!dirName) continue;
-
- const skillDir = path.join(skillsDir, dirName);
- try {
- if (fs.existsSync(skillDir)) {
- await fs.promises.rm(skillDir, { recursive: true, force: true });
- removed++;
- }
- } catch {
- // Ignore errors
- }
- }
-
- return removed;
+ return removeOpenSpecSkillDirs(skillsDir);
}
private async removeCommandFiles(projectPath: string, toolId: string): Promise {
- let removed = 0;
- const adapter = CommandAdapterRegistry.get(toolId);
- if (!adapter) return 0;
-
- for (const workflow of ALL_WORKFLOWS) {
- const cmdPath = adapter.getFilePath(workflow);
- const fullPath = path.isAbsolute(cmdPath) ? cmdPath : path.join(projectPath, cmdPath);
-
- try {
- if (fs.existsSync(fullPath)) {
- await fs.promises.unlink(fullPath);
- removed++;
- }
- } catch {
- // Ignore errors
- }
- }
-
- return removed;
+ return removeOpenSpecCommandFiles(projectPath, toolId);
}
}
diff --git a/src/core/is-project-initialized.ts b/src/core/is-project-initialized.ts
new file mode 100644
index 0000000000..da9ede768d
--- /dev/null
+++ b/src/core/is-project-initialized.ts
@@ -0,0 +1,21 @@
+/**
+ * Project Initialization Check
+ *
+ * Utility for checking whether a project has been initialized with OpenSpec.
+ * Used to guard commands that require an already-initialized project.
+ */
+
+import { existsSync } from 'fs';
+import path from 'path';
+
+/**
+ * Returns true if the project at the given path has been initialized with
+ * OpenSpec (i.e., `openspec/config.yaml` or `openspec/config.yml` exists).
+ */
+export function isProjectInitialized(projectPath: string): boolean {
+ const base = path.join(projectPath, 'openspec');
+ return (
+ existsSync(path.join(base, 'config.yaml')) ||
+ existsSync(path.join(base, 'config.yml'))
+ );
+}
diff --git a/src/core/legacy-cleanup.ts b/src/core/legacy-cleanup.ts
index f3cbb560e1..19df132ad6 100644
--- a/src/core/legacy-cleanup.ts
+++ b/src/core/legacy-cleanup.ts
@@ -451,7 +451,7 @@ export function formatCleanupSummary(result: CleanupResult): string {
}
for (const file of result.modifiedFiles) {
- lines.push(` ✓ Removed OpenSpec markers from ${file}`);
+ lines.push(` ✓ Removed BR-OpenSpec markers from ${file}`);
}
}
@@ -521,7 +521,7 @@ function buildUpdatesList(detection: LegacyDetectionResult): Array<{ path: strin
// All config files with markers get updated (markers removed, file preserved)
for (const file of detection.configFilesToUpdate) {
- updates.push({ path: file, explanation: 'removing OpenSpec markers' });
+ updates.push({ path: file, explanation: 'removing BR-OpenSpec markers' });
}
return updates;
@@ -546,9 +546,9 @@ export function formatDetectionSummary(detection: LegacyDetectionResult): string
}
// Header - welcoming upgrade message
- lines.push(chalk.bold('Upgrading to the new OpenSpec'));
+ lines.push(chalk.bold('Upgrading to the new BR-OpenSpec'));
lines.push('');
- lines.push('OpenSpec now uses agent skills, the emerging standard across coding');
+ lines.push('BR-OpenSpec now uses agent skills, the emerging standard across coding');
lines.push('agents. This simplifies your setup while keeping everything working');
lines.push('as before.');
lines.push('');
@@ -566,7 +566,7 @@ export function formatDetectionSummary(detection: LegacyDetectionResult): string
if (updates.length > 0) {
if (removals.length > 0) lines.push('');
lines.push(chalk.bold('Files to update'));
- lines.push(chalk.dim('OpenSpec markers will be removed, your content preserved:'));
+ lines.push(chalk.dim('BR-OpenSpec markers will be removed, your content preserved:'));
for (const { path } of updates) {
lines.push(` • ${path}`);
}
@@ -643,7 +643,7 @@ export function formatProjectMdMigrationHint(): string {
lines.push(chalk.dim(' We won\'t delete this file. It may contain useful project context.'));
lines.push('');
lines.push(chalk.dim(' The new openspec/config.yaml has a "context:" section for planning'));
- lines.push(chalk.dim(' context. This is included in every OpenSpec request and works more'));
+ lines.push(chalk.dim(' context. This is included in every BR-OpenSpec request and works more'));
lines.push(chalk.dim(' reliably than the old project.md approach.'));
lines.push('');
lines.push(chalk.dim(' Review project.md, move any useful content to config.yaml\'s context'));
diff --git a/src/core/list.ts b/src/core/list.ts
index 3f40829a63..72e2523bda 100644
--- a/src/core/list.ts
+++ b/src/core/list.ts
@@ -4,6 +4,7 @@ import { getTaskProgressForChange, formatTaskStatus } from '../utils/task-progre
import { readFileSync } from 'fs';
import { join } from 'path';
import { MarkdownParser } from './parsers/markdown-parser.js';
+import { LIST_MESSAGES } from '../messages/index.js';
interface ChangeInfo {
name: string;
@@ -64,13 +65,13 @@ function formatRelativeTime(date: Date): string {
if (diffDays > 30) {
return date.toLocaleDateString();
} else if (diffDays > 0) {
- return `${diffDays}d ago`;
+ return LIST_MESSAGES.relativeTime.daysAgo(diffDays);
} else if (diffHours > 0) {
- return `${diffHours}h ago`;
+ return LIST_MESSAGES.relativeTime.hoursAgo(diffHours);
} else if (diffMins > 0) {
- return `${diffMins}m ago`;
+ return LIST_MESSAGES.relativeTime.minutesAgo(diffMins);
} else {
- return 'just now';
+ return LIST_MESSAGES.relativeTime.justNow;
}
}
@@ -85,7 +86,7 @@ export class ListCommand {
try {
await fs.access(changesDir);
} catch {
- throw new Error("No OpenSpec changes directory found. Run 'openspec init' first.");
+ throw new Error(LIST_MESSAGES.noChangesDir);
}
// Get all directories in changes (excluding archive)
@@ -98,7 +99,7 @@ export class ListCommand {
if (json) {
console.log(JSON.stringify({ changes: [] }));
} else {
- console.log('No active changes found.');
+ console.log(LIST_MESSAGES.noActiveChanges);
}
return;
}
@@ -139,7 +140,7 @@ export class ListCommand {
}
// Display results
- console.log('Changes:');
+ console.log(LIST_MESSAGES.changesHeader);
const padding = ' ';
const nameWidth = Math.max(...changes.map(c => c.name.length));
for (const change of changes) {
@@ -156,14 +157,14 @@ export class ListCommand {
try {
await fs.access(specsDir);
} catch {
- console.log('No specs found.');
+ console.log(LIST_MESSAGES.noSpecsFound);
return;
}
const entries = await fs.readdir(specsDir, { withFileTypes: true });
const specDirs = entries.filter(e => e.isDirectory()).map(e => e.name);
if (specDirs.length === 0) {
- console.log('No specs found.');
+ console.log(LIST_MESSAGES.noSpecsFound);
return;
}
@@ -183,7 +184,7 @@ export class ListCommand {
}
specs.sort((a, b) => a.id.localeCompare(b.id));
- console.log('Specs:');
+ console.log(LIST_MESSAGES.specsHeader);
const padding = ' ';
const nameWidth = Math.max(...specs.map(s => s.id.length));
for (const spec of specs) {
diff --git a/src/core/migration.ts b/src/core/migration.ts
index 48aaa41eee..5250b911be 100644
--- a/src/core/migration.ts
+++ b/src/core/migration.ts
@@ -5,6 +5,7 @@
* Called by both init and update commands before profile resolution.
*/
+import { MIGRATION_MESSAGES } from '../messages/index.js';
import type { AIToolOption } from './config.js';
import { getGlobalConfig, getGlobalConfigPath, saveGlobalConfig, type Delivery } from './global-config.js';
import { CommandAdapterRegistry } from './command-generation/index.js';
@@ -126,6 +127,6 @@ export function migrateIfNeeded(projectPath: string, tools: AIToolOption[]): voi
}
saveGlobalConfig(config);
- console.log(`Migrated: custom profile with ${installedWorkflows.length} workflows`);
- console.log("New in this version: /opsx:propose. Try 'openspec config profile core' for the streamlined experience.");
+ console.log(MIGRATION_MESSAGES.migrated(installedWorkflows.length));
+ console.log(MIGRATION_MESSAGES.newInThisVersion);
}
diff --git a/src/core/parsers/markdown-parser.ts b/src/core/parsers/markdown-parser.ts
index abad78df22..903e813117 100644
--- a/src/core/parsers/markdown-parser.ts
+++ b/src/core/parsers/markdown-parser.ts
@@ -78,11 +78,11 @@ export class MarkdownParser {
const requirementsSection = this.findSection(sections, 'Requirements');
if (!purpose) {
- throw new Error('Spec must have a Purpose section');
+ throw new Error('A especificação deve ter uma seção Purpose');
}
if (!requirementsSection) {
- throw new Error('Spec must have a Requirements section');
+ throw new Error('A especificação deve ter uma seção Requirements');
}
const requirements = this.parseRequirements(requirementsSection);
@@ -104,11 +104,11 @@ export class MarkdownParser {
const whatChanges = this.findSection(sections, 'What Changes')?.content || '';
if (!why) {
- throw new Error('Change must have a Why section');
+ throw new Error('A alteração deve ter uma seção Why');
}
if (!whatChanges) {
- throw new Error('Change must have a What Changes section');
+ throw new Error('A alteração deve ter uma seção What Changes');
}
const deltas = this.parseDeltas(whatChanges);
diff --git a/src/core/project-config.ts b/src/core/project-config.ts
index 6c1ea04a5b..7bc4788e73 100644
--- a/src/core/project-config.ts
+++ b/src/core/project-config.ts
@@ -1,3 +1,4 @@
+import { PROJECT_CONFIG_MESSAGES } from '../messages/index.js';
import { existsSync, readFileSync, statSync } from 'fs';
import path from 'path';
import { parse as parseYaml } from 'yaml';
@@ -90,7 +91,7 @@ export function readProjectConfig(projectRoot: string): ProjectConfig | null {
if (schemaResult.success) {
config.schema = schemaResult.data;
} else if (raw.schema !== undefined) {
- console.warn(`Invalid 'schema' field in config (must be non-empty string)`);
+ console.warn(PROJECT_CONFIG_MESSAGES.invalidSchemaField);
}
// Parse context field with size limit
@@ -102,14 +103,14 @@ export function readProjectConfig(projectRoot: string): ProjectConfig | null {
const contextSize = Buffer.byteLength(contextResult.data, 'utf-8');
if (contextSize > MAX_CONTEXT_SIZE) {
console.warn(
- `Context too large (${(contextSize / 1024).toFixed(1)}KB, limit: ${MAX_CONTEXT_SIZE / 1024}KB)`
+ PROJECT_CONFIG_MESSAGES.contextTooLarge((contextSize / 1024).toFixed(1), String(MAX_CONTEXT_SIZE / 1024))
);
- console.warn(`Ignoring context field`);
+ console.warn(PROJECT_CONFIG_MESSAGES.ignoringContextField);
} else {
config.context = contextResult.data;
}
} else {
- console.warn(`Invalid 'context' field in config (must be string)`);
+ console.warn(PROJECT_CONFIG_MESSAGES.invalidContextField);
}
}
@@ -134,12 +135,12 @@ export function readProjectConfig(projectRoot: string): ProjectConfig | null {
}
if (validRules.length < rulesArrayResult.data.length) {
console.warn(
- `Some rules for '${artifactId}' are empty strings, ignoring them`
+ PROJECT_CONFIG_MESSAGES.emptyRulesForArtifact(artifactId)
);
}
} else {
console.warn(
- `Rules for '${artifactId}' must be an array of strings, ignoring this artifact's rules`
+ PROJECT_CONFIG_MESSAGES.rulesMustBeArrayOfStrings(artifactId)
);
}
}
@@ -148,7 +149,7 @@ export function readProjectConfig(projectRoot: string): ProjectConfig | null {
config.rules = parsedRules;
}
} else {
- console.warn(`Invalid 'rules' field in config (must be object)`);
+ console.warn(PROJECT_CONFIG_MESSAGES.invalidRulesField);
}
}
diff --git a/src/core/templates/skill-templates.ts b/src/core/templates/skill-templates.ts
index ff687d900a..ee8eee728b 100644
--- a/src/core/templates/skill-templates.ts
+++ b/src/core/templates/skill-templates.ts
@@ -18,3 +18,4 @@ export { getVerifyChangeSkillTemplate, getOpsxVerifyCommandTemplate } from './wo
export { getOnboardSkillTemplate, getOpsxOnboardCommandTemplate } from './workflows/onboard.js';
export { getOpsxProposeSkillTemplate, getOpsxProposeCommandTemplate } from './workflows/propose.js';
export { getFeedbackSkillTemplate } from './workflows/feedback.js';
+export { getUpstreamSyncSkillTemplate, getOpsxUpstreamSyncCommandTemplate } from './workflows/upstream-sync.js';
diff --git a/src/core/templates/workflows/apply-change.ts b/src/core/templates/workflows/apply-change.ts
index be60210a7a..65d7bbc1ac 100644
--- a/src/core/templates/workflows/apply-change.ts
+++ b/src/core/templates/workflows/apply-change.ts
@@ -9,154 +9,154 @@ import type { SkillTemplate, CommandTemplate } from '../types.js';
export function getApplyChangeSkillTemplate(): SkillTemplate {
return {
name: 'openspec-apply-change',
- description: 'Implement tasks from an OpenSpec change. Use when the user wants to start implementing, continue implementation, or work through tasks.',
- instructions: `Implement tasks from an OpenSpec change.
+ description: 'Implementa tarefas de uma change do BR-OpenSpec. Use quando o usuário quiser iniciar a implementação, continuar a implementação ou trabalhar nas tarefas.',
+ instructions: `Implementa tarefas de uma change do BR-OpenSpec.
-**Input**: Optionally specify a change name. If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
+**Entrada**: Opcionalmente especifique um nome de change. Se omitido, verifique se pode ser inferido do contexto da conversa. Se vago ou ambíguo, você DEVE solicitar as changes disponíveis.
-**Steps**
+**Passos**
-1. **Select the change**
+1. **Selecione a change**
- If a name is provided, use it. Otherwise:
- - Infer from conversation context if the user mentioned a change
- - Auto-select if only one active change exists
- - If ambiguous, run \`openspec list --json\` to get available changes and use the **AskUserQuestion tool** to let the user select
+ Se um nome for fornecido, use-o. Caso contrário:
+ - Infira do contexto da conversa se o usuário mencionou uma change
+ - Selecione automaticamente se existir apenas uma change ativa
+ - Se ambíguo, execute \`openspec list --json\` para obter as changes disponíveis e use a ferramenta **AskUserQuestion** para permitir que o usuário selecione
- Always announce: "Using change: " and how to override (e.g., \`/opsx:apply \`).
+ Sempre anuncie: "Usando change: " e como substituir (por exemplo, \`/opsx:apply \`).
-2. **Check status to understand the schema**
+2. **Verifique o status para entender o schema**
\`\`\`bash
- openspec status --change "" --json
+ openspec status --change "" --json
\`\`\`
- Parse the JSON to understand:
- - \`schemaName\`: The workflow being used (e.g., "spec-driven")
- - Which artifact contains the tasks (typically "tasks" for spec-driven, check status for others)
+ Analise o JSON para entender:
+ - \`schemaName\`: O workflow sendo usado (por exemplo, "spec-driven")
+ - Qual artifact contém as tarefas (tipicamente "tasks" para spec-driven, verifique o status para outros)
-3. **Get apply instructions**
+3. **Obtenha as instruções de apply**
\`\`\`bash
- openspec instructions apply --change "" --json
+ openspec instructions apply --change "" --json
\`\`\`
- This returns:
- - \`contextFiles\`: artifact ID -> array of concrete file paths (varies by schema - could be proposal/specs/design/tasks or spec/tests/implementation/docs)
- - Progress (total, complete, remaining)
- - Task list with status
- - Dynamic instruction based on current state
+ Isso retorna:
+ - \`contextFiles\`: artifact ID -> array de caminhos de arquivos concretos (varia por schema - pode ser proposal/specs/design/tasks ou spec/tests/implementation/docs)
+ - Progresso (total, completo, restante)
+ - Lista de tarefas com status
+ - Instrução dinâmica baseada no estado atual
- **Handle states:**
- - If \`state: "blocked"\` (missing artifacts): show message, suggest using openspec-continue-change
- - If \`state: "all_done"\`: congratulate, suggest archive
- - Otherwise: proceed to implementation
+ **Trate os estados:**
+ - Se \`state: "blocked"\` (artifacts ausentes): exiba mensagem, sugira usar openspec-continue-change
+ - Se \`state: "all_done"\`: parabenize, sugira arquivar
+ - Caso contrário: prossiga para a implementação
-4. **Read context files**
+4. **Leia os arquivos de contexto**
- Read every file path listed under \`contextFiles\` from the apply instructions output.
- The files depend on the schema being used:
+ Leia cada caminho de arquivo listado em \`contextFiles\` da saída das instruções de apply.
+ Os arquivos dependem do schema sendo usado:
- **spec-driven**: proposal, specs, design, tasks
- - Other schemas: follow the contextFiles from CLI output
+ - Outros schemas: siga os contextFiles da saída do CLI
-5. **Show current progress**
+5. **Mostre o progresso atual**
- Display:
- - Schema being used
- - Progress: "N/M tasks complete"
- - Remaining tasks overview
- - Dynamic instruction from CLI
+ Exiba:
+ - Schema sendo usado
+ - Progresso: "N/M tarefas concluídas"
+ - Visão geral das tarefas restantes
+ - Instrução dinâmica do CLI
-6. **Implement tasks (loop until done or blocked)**
+6. **Implemente as tarefas (loop até concluir ou bloquear)**
- For each pending task:
- - Show which task is being worked on
- - Make the code changes required
- - Keep changes minimal and focused
- - Mark task complete in the tasks file: \`- [ ]\` → \`- [x]\`
- - Continue to next task
+ Para cada tarefa pendente:
+ - Mostre qual tarefa está sendo trabalhada
+ - Faça as alterações de código necessárias
+ - Mantenha as alterações mínimas e focadas
+ - Marque a tarefa como concluída no arquivo de tasks: \`- [ ]\` → \`- [x]\`
+ - Continue para a próxima tarefa
- **Pause if:**
- - Task is unclear → ask for clarification
- - Implementation reveals a design issue → suggest updating artifacts
- - Error or blocker encountered → report and wait for guidance
- - User interrupts
+ **Pare se:**
+ - A tarefa estiver incerta → peça esclarecimento
+ - A implementação revelar um problema de design → sugira atualizar artifacts
+ - Encontrar erro ou bloqueio → reporte e aguarde orientação
+ - O usuário interromper
-7. **On completion or pause, show status**
+7. **Ao concluir ou pausar, mostre o status**
- Display:
- - Tasks completed this session
- - Overall progress: "N/M tasks complete"
- - If all done: suggest archive
- - If paused: explain why and wait for guidance
+ Exiba:
+ - Tarefas concluídas nesta sessão
+ - Progresso geral: "N/M tarefas concluídas"
+ - Se tudo concluído: sugira arquivar
+ - Se pausado: explique o porquê e aguarde orientação
-**Output During Implementation**
+**Saída Durante a Implementação**
\`\`\`
-## Implementing: (schema: )
+## Implementando: (schema: )
-Working on task 3/7:
-[...implementation happening...]
-✓ Task complete
+Trabalhando na tarefa 3/7:
+[...implementação acontecendo...]
+✓ Tarefa concluída
-Working on task 4/7:
-[...implementation happening...]
-✓ Task complete
+Trabalhando na tarefa 4/7:
+[...implementação acontecendo...]
+✓ Tarefa concluída
\`\`\`
-**Output On Completion**
+**Saída ao Concluir**
\`\`\`
-## Implementation Complete
+## Implementação Concluída
-**Change:**
-**Schema:**
-**Progress:** 7/7 tasks complete ✓
+**Change:**
+**Schema:**
+**Progresso:** 7/7 tarefas concluídas ✓
-### Completed This Session
-- [x] Task 1
-- [x] Task 2
+### Concluídas Nesta Sessão
+- [x] Tarefa 1
+- [x] Tarefa 2
...
-All tasks complete! Ready to archive this change.
+Todas as tarefas concluídas! Pronto para arquivar esta change.
\`\`\`
-**Output On Pause (Issue Encountered)**
+**Saída ao Pausar (Problema Encontrado)**
\`\`\`
-## Implementation Paused
+## Implementação Pausada
-**Change:**
-**Schema:**
-**Progress:** 4/7 tasks complete
+**Change:**
+**Schema:**
+**Progresso:** 4/7 tarefas concluídas
-### Issue Encountered
-
+### Problema Encontrado
+
-**Options:**
-1.
-2.
-3. Other approach
+**Opções:**
+1.
+2.
+3. Outra abordagem
-What would you like to do?
+O que você gostaria de fazer?
\`\`\`
**Guardrails**
-- Keep going through tasks until done or blocked
-- Always read context files before starting (from the apply instructions output)
-- If task is ambiguous, pause and ask before implementing
-- If implementation reveals issues, pause and suggest artifact updates
-- Keep code changes minimal and scoped to each task
-- Update task checkbox immediately after completing each task
-- Pause on errors, blockers, or unclear requirements - don't guess
-- Use contextFiles from CLI output, don't assume specific file names
+- Continue pelas tarefas até concluir ou bloquear
+- Sempre leia os arquivos de contexto antes de começar (da saída das instruções de apply)
+- Se a tarefa for ambígua, pause e pergunte antes de implementar
+- Se a implementação revelar problemas, pause e sugira atualizar artifacts
+- Mantenha as alterações de código mínimas e limitadas a cada tarefa
+- Atualize a checkbox da tarefa imediatamente após concluir cada tarefa
+- Pare em erros, bloqueios ou requisitos incertos - não adivinhe
+- Use os contextFiles da saída do CLI, não assuma nomes de arquivos específicos
-**Fluid Workflow Integration**
+**Integração com Fluxo Fluido**
-This skill supports the "actions on a change" model:
+Esta skill suporta o modelo de "ações em uma change":
-- **Can be invoked anytime**: Before all artifacts are done (if tasks exist), after partial implementation, interleaved with other actions
-- **Allows artifact updates**: If implementation reveals design issues, suggest updating artifacts - not phase-locked, work fluidly`,
+- **Pode ser invocada a qualquer momento**: Antes de todos os artifacts estarem prontos (se tasks existirem), após implementação parcial, intercalada com outras ações
+- **Permite atualizações de artifacts**: Se a implementação revelar problemas de design, sugira atualizar artifacts - não está travada em fases, trabalhe de forma fluida`,
license: 'MIT',
- compatibility: 'Requires openspec CLI.',
+ compatibility: 'Requer openspec CLI.',
metadata: { author: 'openspec', version: '1.0' },
};
}
@@ -164,153 +164,153 @@ This skill supports the "actions on a change" model:
export function getOpsxApplyCommandTemplate(): CommandTemplate {
return {
name: 'OPSX: Apply',
- description: 'Implement tasks from an OpenSpec change (Experimental)',
+ description: 'Implementa tarefas de uma change do BR-OpenSpec (Experimental)',
category: 'Workflow',
tags: ['workflow', 'artifacts', 'experimental'],
- content: `Implement tasks from an OpenSpec change.
+ content: `Implementa tarefas de uma change do BR-OpenSpec.
-**Input**: Optionally specify a change name (e.g., \`/opsx:apply add-auth\`). If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
+**Entrada**: Opcionalmente especifique um nome de change (por exemplo, \`/opsx:apply add-auth\`). Se omitido, verifique se pode ser inferido do contexto da conversa. Se vago ou ambíguo, você DEVE solicitar as changes disponíveis.
-**Steps**
+**Passos**
-1. **Select the change**
+1. **Selecione a change**
- If a name is provided, use it. Otherwise:
- - Infer from conversation context if the user mentioned a change
- - Auto-select if only one active change exists
- - If ambiguous, run \`openspec list --json\` to get available changes and use the **AskUserQuestion tool** to let the user select
+ Se um nome for fornecido, use-o. Caso contrário:
+ - Infira do contexto da conversa se o usuário mencionou uma change
+ - Selecione automaticamente se existir apenas uma change ativa
+ - Se ambíguo, execute \`openspec list --json\` para obter as changes disponíveis e use a ferramenta **AskUserQuestion** para permitir que o usuário selecione
- Always announce: "Using change: " and how to override (e.g., \`/opsx:apply \`).
+ Sempre anuncie: "Usando change: " e como substituir (por exemplo, \`/opsx:apply \`).
-2. **Check status to understand the schema**
+2. **Verifique o status para entender o schema**
\`\`\`bash
- openspec status --change "" --json
+ openspec status --change "" --json
\`\`\`
- Parse the JSON to understand:
- - \`schemaName\`: The workflow being used (e.g., "spec-driven")
- - Which artifact contains the tasks (typically "tasks" for spec-driven, check status for others)
+ Analise o JSON para entender:
+ - \`schemaName\`: O workflow sendo usado (por exemplo, "spec-driven")
+ - Qual artifact contém as tarefas (tipicamente "tasks" para spec-driven, verifique o status para outros)
-3. **Get apply instructions**
+3. **Obtenha as instruções de apply**
\`\`\`bash
- openspec instructions apply --change "" --json
+ openspec instructions apply --change "" --json
\`\`\`
- This returns:
- - \`contextFiles\`: artifact ID -> array of concrete file paths (varies by schema)
- - Progress (total, complete, remaining)
- - Task list with status
- - Dynamic instruction based on current state
+ Isso retorna:
+ - \`contextFiles\`: artifact ID -> array de caminhos de arquivos concretos (varia por schema)
+ - Progresso (total, completo, restante)
+ - Lista de tarefas com status
+ - Instrução dinâmica baseada no estado atual
- **Handle states:**
- - If \`state: "blocked"\` (missing artifacts): show message, suggest using \`/opsx:continue\`
- - If \`state: "all_done"\`: congratulate, suggest archive
- - Otherwise: proceed to implementation
+ **Trate os estados:**
+ - Se \`state: "blocked"\` (artifacts ausentes): exiba mensagem, sugira usar \`/opsx:continue\`
+ - Se \`state: "all_done"\`: parabenize, sugira arquivar
+ - Caso contrário: prossiga para a implementação
-4. **Read context files**
+4. **Leia os arquivos de contexto**
- Read every file path listed under \`contextFiles\` from the apply instructions output.
- The files depend on the schema being used:
+ Leia cada caminho de arquivo listado em \`contextFiles\` da saída das instruções de apply.
+ Os arquivos dependem do schema sendo usado:
- **spec-driven**: proposal, specs, design, tasks
- - Other schemas: follow the contextFiles from CLI output
+ - Outros schemas: siga os contextFiles da saída do CLI
-5. **Show current progress**
+5. **Mostre o progresso atual**
- Display:
- - Schema being used
- - Progress: "N/M tasks complete"
- - Remaining tasks overview
- - Dynamic instruction from CLI
+ Exiba:
+ - Schema sendo usado
+ - Progresso: "N/M tarefas concluídas"
+ - Visão geral das tarefas restantes
+ - Instrução dinâmica do CLI
-6. **Implement tasks (loop until done or blocked)**
+6. **Implemente as tarefas (loop até concluir ou bloquear)**
- For each pending task:
- - Show which task is being worked on
- - Make the code changes required
- - Keep changes minimal and focused
- - Mark task complete in the tasks file: \`- [ ]\` → \`- [x]\`
- - Continue to next task
+ Para cada tarefa pendente:
+ - Mostre qual tarefa está sendo trabalhada
+ - Faça as alterações de código necessárias
+ - Mantenha as alterações mínimas e focadas
+ - Marque a tarefa como concluída no arquivo de tasks: \`- [ ]\` → \`- [x]\`
+ - Continue para a próxima tarefa
- **Pause if:**
- - Task is unclear → ask for clarification
- - Implementation reveals a design issue → suggest updating artifacts
- - Error or blocker encountered → report and wait for guidance
- - User interrupts
+ **Pare se:**
+ - A tarefa estiver incerta → peça esclarecimento
+ - A implementação revelar um problema de design → sugira atualizar artifacts
+ - Encontrar erro ou bloqueio → reporte e aguarde orientação
+ - O usuário interromper
-7. **On completion or pause, show status**
+7. **Ao concluir ou pausar, mostre o status**
- Display:
- - Tasks completed this session
- - Overall progress: "N/M tasks complete"
- - If all done: suggest archive
- - If paused: explain why and wait for guidance
+ Exiba:
+ - Tarefas concluídas nesta sessão
+ - Progresso geral: "N/M tarefas concluídas"
+ - Se tudo concluído: sugira arquivar
+ - Se pausado: explique o porquê e aguarde orientação
-**Output During Implementation**
+**Saída Durante a Implementação**
\`\`\`
-## Implementing: (schema: )
+## Implementando: (schema: )
-Working on task 3/7:
-[...implementation happening...]
-✓ Task complete
+Trabalhando na tarefa 3/7:
+[...implementação acontecendo...]
+✓ Tarefa concluída
-Working on task 4/7:
-[...implementation happening...]
-✓ Task complete
+Trabalhando na tarefa 4/7:
+[...implementação acontecendo...]
+✓ Tarefa concluída
\`\`\`
-**Output On Completion**
+**Saída ao Concluir**
\`\`\`
-## Implementation Complete
+## Implementação Concluída
-**Change:**
-**Schema:**
-**Progress:** 7/7 tasks complete ✓
+**Change:**
+**Schema:**
+**Progresso:** 7/7 tarefas concluídas ✓
-### Completed This Session
-- [x] Task 1
-- [x] Task 2
+### Concluídas Nesta Sessão
+- [x] Tarefa 1
+- [x] Tarefa 2
...
-All tasks complete! You can archive this change with \`/opsx:archive\`.
+Todas as tarefas concluídas! Você pode arquivar esta change com \`/opsx:archive\`.
\`\`\`
-**Output On Pause (Issue Encountered)**
+**Saída ao Pausar (Problema Encontrado)**
\`\`\`
-## Implementation Paused
+## Implementação Pausada
-**Change:**
-**Schema:**
-**Progress:** 4/7 tasks complete
+**Change:**
+**Schema:**
+**Progresso:** 4/7 tarefas concluídas
-### Issue Encountered
-
+### Problema Encontrado
+
-**Options:**
-1.
-2.
-3. Other approach
+**Opções:**
+1.
+2.
+3. Outra abordagem
-What would you like to do?
+O que você gostaria de fazer?
\`\`\`
**Guardrails**
-- Keep going through tasks until done or blocked
-- Always read context files before starting (from the apply instructions output)
-- If task is ambiguous, pause and ask before implementing
-- If implementation reveals issues, pause and suggest artifact updates
-- Keep code changes minimal and scoped to each task
-- Update task checkbox immediately after completing each task
-- Pause on errors, blockers, or unclear requirements - don't guess
-- Use contextFiles from CLI output, don't assume specific file names
+- Continue pelas tarefas até concluir ou bloquear
+- Sempre leia os arquivos de contexto antes de começar (da saída das instruções de apply)
+- Se a tarefa for ambígua, pause e pergunte antes de implementar
+- Se a implementação revelar problemas, pause e sugira atualizar artifacts
+- Mantenha as alterações de código mínimas e limitadas a cada tarefa
+- Atualize a checkbox da tarefa imediatamente após concluir cada tarefa
+- Pare em erros, bloqueios ou requisitos incertos - não adivinhe
+- Use os contextFiles da saída do CLI, não assuma nomes de arquivos específicos
-**Fluid Workflow Integration**
+**Integração com Fluxo Fluido**
-This skill supports the "actions on a change" model:
+Esta skill suporta o modelo de "ações em uma change":
-- **Can be invoked anytime**: Before all artifacts are done (if tasks exist), after partial implementation, interleaved with other actions
-- **Allows artifact updates**: If implementation reveals design issues, suggest updating artifacts - not phase-locked, work fluidly`
+- **Pode ser invocada a qualquer momento**: Antes de todos os artifacts estarem prontos (se tasks existirem), após implementação parcial, intercalada com outras ações
+- **Permite atualizações de artifacts**: Se a implementação revelar problemas de design, sugira atualizar artifacts - não está travada em fases, trabalhe de forma fluida`
};
}
diff --git a/src/core/templates/workflows/archive-change.ts b/src/core/templates/workflows/archive-change.ts
index 1c37ffde0e..47d9057f76 100644
--- a/src/core/templates/workflows/archive-change.ts
+++ b/src/core/templates/workflows/archive-change.ts
@@ -9,112 +9,112 @@ import type { SkillTemplate, CommandTemplate } from '../types.js';
export function getArchiveChangeSkillTemplate(): SkillTemplate {
return {
name: 'openspec-archive-change',
- description: 'Archive a completed change in the experimental workflow. Use when the user wants to finalize and archive a change after implementation is complete.',
- instructions: `Archive a completed change in the experimental workflow.
+ description: 'Arquiva uma change concluída no workflow experimental. Use quando o usuário quiser finalizar e arquivar uma change após a implementação estar completa.',
+ instructions: `Arquiva uma change concluída no workflow experimental.
-**Input**: Optionally specify a change name. If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
+**Entrada**: Opcionalmente especifique um nome de change. Se omitido, verifique se pode ser inferido do contexto da conversa. Se vago ou ambíguo, você DEVE solicitar as changes disponíveis.
-**Steps**
+**Passos**
-1. **If no change name provided, prompt for selection**
+1. **Se nenhum nome de change for fornecido, solicite a seleção**
- Run \`openspec list --json\` to get available changes. Use the **AskUserQuestion tool** to let the user select.
+ Execute \`openspec list --json\` para obter as changes disponíveis. Use a ferramenta **AskUserQuestion** para permitir que o usuário selecione.
- Show only active changes (not already archived).
- Include the schema used for each change if available.
+ Mostre apenas as changes ativas (não arquivadas).
+ Inclua o schema usado para cada change, se disponível.
- **IMPORTANT**: Do NOT guess or auto-select a change. Always let the user choose.
+ **IMPORTANTE**: NÃO adivinhe ou selecione automaticamente uma change. Sempre deixe o usuário escolher.
-2. **Check artifact completion status**
+2. **Verifique o status de conclusão dos artifacts**
- Run \`openspec status --change "" --json\` to check artifact completion.
+ Execute \`openspec status --change "" --json\` para verificar a conclusão dos artifacts.
- Parse the JSON to understand:
- - \`schemaName\`: The workflow being used
- - \`artifacts\`: List of artifacts with their status (\`done\` or other)
+ Analise o JSON para entender:
+ - \`schemaName\`: O workflow sendo usado
+ - \`artifacts\`: Lista de artifacts com seu status (\`done\` ou outro)
- **If any artifacts are not \`done\`:**
- - Display warning listing incomplete artifacts
- - Use **AskUserQuestion tool** to confirm user wants to proceed
- - Proceed if user confirms
+ **Se algum artifact não estiver \`done\`:**
+ - Exiba um aviso listando os artifacts incompletos
+ - Use a ferramenta **AskUserQuestion** para confirmar se o usuário deseja prosseguir
+ - Prossiga se o usuário confirmar
-3. **Check task completion status**
+3. **Verifique o status de conclusão das tarefas**
- Read the tasks file (typically \`tasks.md\`) to check for incomplete tasks.
+ Leia o arquivo de tarefas (tipicamente \`tasks.md\`) para verificar tarefas incompletas.
- Count tasks marked with \`- [ ]\` (incomplete) vs \`- [x]\` (complete).
+ Conte as tarefas marcadas com \`- [ ]\` (incompleto) vs \`- [x]\` (concluído).
- **If incomplete tasks found:**
- - Display warning showing count of incomplete tasks
- - Use **AskUserQuestion tool** to confirm user wants to proceed
- - Proceed if user confirms
+ **Se tarefas incompletas forem encontradas:**
+ - Exiba um aviso mostrando a quantidade de tarefas incompletas
+ - Use a ferramenta **AskUserQuestion** para confirmar se o usuário deseja prosseguir
+ - Prossiga se o usuário confirmar
- **If no tasks file exists:** Proceed without task-related warning.
+ **Se não existir arquivo de tarefas:** Prossiga sem aviso relacionado a tarefas.
-4. **Assess delta spec sync state**
+4. **Avalie o estado de sincronização dos delta specs**
- Check for delta specs at \`openspec/changes//specs/\`. If none exist, proceed without sync prompt.
+ Verifique se existem delta specs em \`openspec/changes//specs/\`. Se não existirem, prossiga sem prompt de sync.
- **If delta specs exist:**
- - Compare each delta spec with its corresponding main spec at \`openspec/specs//spec.md\`
- - Determine what changes would be applied (adds, modifications, removals, renames)
- - Show a combined summary before prompting
+ **Se delta specs existirem:**
+ - Compare cada delta spec com seu spec principal correspondente em \`openspec/specs//spec.md\`
+ - Determine quais alterações seriam aplicadas (adições, modificações, remoções, renomeações)
+ - Mostre um resumo combinado antes de solicitar
- **Prompt options:**
- - If changes needed: "Sync now (recommended)", "Archive without syncing"
- - If already synced: "Archive now", "Sync anyway", "Cancel"
+ **Opções de prompt:**
+ - Se alterações forem necessárias: "Sincronizar agora (recomendado)", "Arquivar sem sincronizar"
+ - Se já estiver sincronizado: "Arquivar agora", "Sincronizar mesmo assim", "Cancelar"
- If user chooses sync, use Task tool (subagent_type: "general-purpose", prompt: "Use Skill tool to invoke openspec-sync-specs for change ''. Delta spec analysis: "). Proceed to archive regardless of choice.
+ Se o usuário escolher sincronizar, use a ferramenta Task (subagent_type: "general-purpose", prompt: "Use a ferramenta Skill para invocar openspec-sync-specs para a change ''. Análise de delta spec: "). Prossiga para o arquivamento independentemente da escolha.
-5. **Perform the archive**
+5. **Realize o arquivamento**
- Create the archive directory if it doesn't exist:
+ Crie o diretório de arquivo se não existir:
\`\`\`bash
mkdir -p openspec/changes/archive
\`\`\`
- Generate target name using current date: \`YYYY-MM-DD-\`
+ Gere o nome do destino usando a data atual: \`YYYY-MM-DD-\`
- **Check if target already exists:**
- - If yes: Fail with error, suggest renaming existing archive or using different date
- - If no: Move the change directory to archive
+ **Verifique se o destino já existe:**
+ - Se sim: Falhe com erro, sugira renomear o arquivo existente ou usar uma data diferente
+ - Se não: Mova o diretório da change para o arquivo
\`\`\`bash
- mv openspec/changes/ openspec/changes/archive/YYYY-MM-DD-
+ mv openspec/changes/ openspec/changes/archive/YYYY-MM-DD-
\`\`\`
-6. **Display summary**
+6. **Exiba o resumo**
- Show archive completion summary including:
- - Change name
- - Schema that was used
- - Archive location
- - Whether specs were synced (if applicable)
- - Note about any warnings (incomplete artifacts/tasks)
+ Mostre o resumo de conclusão do arquivamento incluindo:
+ - Nome da change
+ - Schema que foi usado
+ - Local do arquivo
+ - Se os specs foram sincronizados (se aplicável)
+ - Observação sobre quaisquer avisos (artifacts/tarefas incompletos)
-**Output On Success**
+**Saída em Sucesso**
\`\`\`
-## Archive Complete
+## Arquivamento Concluído
-**Change:**
-**Schema:**
-**Archived to:** openspec/changes/archive/YYYY-MM-DD-/
-**Specs:** ✓ Synced to main specs (or "No delta specs" or "Sync skipped")
+**Change:**