Commit Graph

828 Commits

Author SHA1 Message Date
openspec-release-bot[bot] e062b9572b Version Packages (#1766)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
@fission-ai/openspec@1.12.0 v1.12.0
2026-09-03 00:00:56 +00:00
Tabish Bidiwale fbd4160b37 docs: reroute unfinished store reference links (#1767)
Co-authored-by: Clay Good <hi@claygood.com>
2026-09-02 23:34:01 +00:00
Clay Good 9ec0a090b8 fix(security): patch fast-uri advisories (#1768) 2026-09-02 22:50:29 +00:00
dependabot[bot] 9dfffd87b3 chore(deps): bump the website-dependencies group across 1 directory with 7 updates (#1765)
* chore(deps): bump the website-dependencies group across 1 directory with 7 updates

Bumps the website-dependencies group with 7 updates in the /website directory:

| Package | From | To |
| --- | --- | --- |
| [fumadocs-core](https://github.com/fuma-nama/fumadocs) | `16.14.5` | `16.15.2` |
| [fumadocs-mdx](https://github.com/fuma-nama/fumadocs) | `15.2.3` | `15.3.1` |
| [fumadocs-ui](https://github.com/fuma-nama/fumadocs) | `16.14.5` | `16.15.2` |
| [lucide-react](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react) | `1.31.0` | `1.34.0` |
| [next](https://github.com/vercel/next.js) | `16.3.1` | `16.3.3` |
| [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `26.2.0` | `26.3.0` |
| [@types/react-dom](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-dom) | `19.2.4` | `19.2.5` |



Updates `fumadocs-core` from 16.14.5 to 16.15.2
- [Release notes](https://github.com/fuma-nama/fumadocs/releases)
- [Commits](https://github.com/fuma-nama/fumadocs/compare/fumadocs@16.14.5...fumadocs@16.15.2)

Updates `fumadocs-mdx` from 15.2.3 to 15.3.1
- [Release notes](https://github.com/fuma-nama/fumadocs/releases)
- [Commits](https://github.com/fuma-nama/fumadocs/compare/fumadocs-mdx@15.2.3...fumadocs-mdx@15.3.1)

Updates `fumadocs-ui` from 16.14.5 to 16.15.2
- [Release notes](https://github.com/fuma-nama/fumadocs/releases)
- [Commits](https://github.com/fuma-nama/fumadocs/compare/fumadocs@16.14.5...fumadocs@16.15.2)

Updates `lucide-react` from 1.31.0 to 1.34.0
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/commits/1.34.0/packages/lucide-react)

Updates `next` from 16.3.1 to 16.3.3
- [Release notes](https://github.com/vercel/next.js/releases)
- [Commits](https://github.com/vercel/next.js/compare/v16.3.1...v16.3.3)

Updates `@types/node` from 26.2.0 to 26.3.0
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `@types/react-dom` from 19.2.4 to 19.2.5
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react-dom)

---
updated-dependencies:
- dependency-name: fumadocs-core
  dependency-version: 16.15.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: website-dependencies
- dependency-name: fumadocs-mdx
  dependency-version: 15.3.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: website-dependencies
- dependency-name: fumadocs-ui
  dependency-version: 16.15.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: website-dependencies
- dependency-name: lucide-react
  dependency-version: 1.34.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: website-dependencies
- dependency-name: next
  dependency-version: 16.3.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: website-dependencies
- dependency-name: "@types/node"
  dependency-version: 26.3.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: website-dependencies
- dependency-name: "@types/react-dom"
  dependency-version: 19.2.5
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: website-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix(website): align esbuild build approval

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Clay Good <hi@claygood.com>
2026-09-02 22:22:14 +00:00
dependabot[bot] cb5ae2cd16 ci: bump changesets/action from 1.9.0 to 2.1.1 in the github-actions group (#1746)
* ci: bump changesets/action in the github-actions group

Bumps the github-actions group with 1 update: [changesets/action](https://github.com/changesets/action).


Updates `changesets/action` from 1.9.0 to 2.1.1
- [Release notes](https://github.com/changesets/action/releases)
- [Changelog](https://github.com/changesets/action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/changesets/action/compare/a45c4d594aa4e2c509dc14a9f2b3b67ba3780d0d...8488615a623b1b9c987934bb89eae8af6a946ac1)

---
updated-dependencies:
- dependency-name: changesets/action
  dependency-version: 2.1.1
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix(ci): complete changesets action v2 migration

* fix(nix): invalidate pnpm dependency hash

* fix(nix): use calculated dependency hash

* fix(nix): refresh pnpm dependency hash

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Clay Good <hi@claygood.com>
2026-09-02 21:55:12 +00:00
Marzx13 db03c6c4b0 feat(validate): add findings-only bulk reports (#1713)
* feat(validate): propose findings report

* docs(validate): clarify findings report contract

* feat(validate): implement and harden bulk findings reports

* test(validate): canonicalize store paths natively

---------

Co-authored-by: Clay Good <hi@claygood.com>
2026-09-02 21:07:46 +00:00
Ryan de Melo a4fcdbece6 feat(validate): report the deltas archive would refuse (#1710)
* feat(validate): report the deltas archive would refuse

validate checked a change's deltas against themselves and, for MODIFIED
blocks, against the main spec's scenarios. It never checked whether the
main spec can supply the target a delta acts on, so a MODIFIED naming a
requirement that is not there, a RENAMED whose source is gone, or an
ADDED whose name already exists all validated clean and failed at
archive instead - typically weeks later, after the implementing PR had
shipped and the authoring session was gone.

Run the merge archive runs and report what it refuses. buildUpdatedSpec
returns the rebuilt content without writing it, so the preflight is the
same function on the same inputs with the result discarded, and cannot
disagree with the code that does the writing. That matters here: several
of those preconditions deliberately read a missing target as
already-synced rather than as a failure, and a second copy of the rules
would be free to drift.

Reported as INFO so no verdict changes in any mode. A MODIFIED whose
target is missing is also what a change modifying a sibling's unarchived
requirement looks like, and validate stays valid for that case today;
telling the two apart needs the opt-in marker #1112 asks for. What is
missing until then is the information, not the verdict.

Refs #1112

* fix(validate): skip preflight for deltas whose errors come after the loop

missingHeaderSpecs and emptySectionSpecs are collected inside the
per-spec loop but only become issues after it, so a suppression set
built from the issues raised so far could not see them. A headerless or
empty-section delta has nothing for the merge to apply, so the preflight
reported that as a blocker of its own, on top of the error that names
the actual mistake.

* fix(validate): harden archive preflight diagnostics

* fix(validate): preserve reports when archive preflight cannot start

---------

Co-authored-by: Clay Good <hi@claygood.com>
2026-09-02 20:59:09 +00:00
Br1an 0296401b82 fix(init): add .gitkeep files to empty directories (#786)
* fix(init): add .gitkeep files to empty directories

After running openspec init, the specs/, changes/, and changes/archive/
directories are empty. Since git does not track empty directories, these
folders are lost when the repository is cloned, causing openspec list to
recommend re-initialization.

Added .gitkeep file creation to createDirectoryStructure() for both
normal and extend modes, ensuring empty directories are preserved in
version control.

Fixes #269

* fix(init): preserve directory anchors without overwriting user files

---------

Co-authored-by: Clay Good <hi@claygood.com>
2026-09-02 20:50:59 +00:00
Aron Lee cd724449ac refactor(core): share the IDE restart hint between init and update (#1725)
* refactor(core): share the IDE restart hint between init and update

init named the surface it generated ("the new commands" / "the new skills");
update printed a generic "changes" for the same event, decided by the same
rule. Extract that rule and its wording into shared/ide-restart.ts so both
commands say the same thing, and update now names the surface too.

No condition changed: the hint still requires one tool that is both
IDE-resident and actually received a generated surface under the active
delivery, so a CLI tool's commands can never speak for an IDE tool that got
nothing.

Verified by mutation: dropping the IDE-resident filter turns 9 tests red
across the helper, init and update; swapping the commands/skills precedence
turns 5 red.

* test(core): harden shared IDE restart guidance

* fix(core): describe restart guidance for removed workflows

---------

Co-authored-by: Clay Good <hi@claygood.com>
2026-09-02 20:41:20 +00:00
Clay Good 954d4796a4 docs(community): add a community showcase (#1739)
* docs(readme): list the independent openspec ui project

* docs(community): move the showcase out of the readme
2026-09-02 20:32:42 +00:00
Clay Good 98bf53e59e fix(workflows): ground proposals in relevant project code (#1737) 2026-09-02 20:25:06 +00:00
Howard 2fd175c8b0 docs(cli): document managed PowerShell completion setup (#1070)
* docs(cli): add Windows PowerShell completion example

The shell completion documentation only showed Unix/bash examples,
making it unusable for Windows users. Added platform-specific examples
for both Unix/macOS (bash) and Windows (PowerShell).

Changes:
- Add Unix/macOS (bash) example with ~/.bash_completion.d path
- Add Windows (PowerShell) example with C:\Users\y00031947\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1 path
- Improve clarity with platform labels

Fixes: Windows users cannot use shell completion manual installation

* fix(cli): use append operator for PowerShell profile to avoid data loss

Critical fix: Using '>' operator would overwrite the user's PowerShell
profile, deleting existing configurations. Changed to '>>' to append
instead of overwrite, preserving user's existing settings.

* docs(cli): harden PowerShell completion setup

---------

Co-authored-by: Clay Good <hi@claygood.com>
2026-09-02 20:14:57 +00:00
Dan (Danilo) Rio (Ribeiro) b976106d95 fix(explore): guide planning with focused discovery questions (#1017)
* feat: improve explore discovery questions

* chore: add changeset for explore guidance

---------

Co-authored-by: Clay Good <hi@claygood.com>
2026-09-02 20:07:20 +00:00
openspec-cloud[bot] cdd06a0594 docs(specs): align four requirements with current behavior (#1707)
* docs(openspec): correct 4 requirements that the code has outgrown

- ai-tool-paths/path-configuration-for-supported-tools#2: Changed the windsurf scenario's required skillsDir from `.windsurf` to `.devin`.
- cli-update/slash-command-updates#6: Require $ARGUMENTS to be placed in the file body (not frontmatter) for OpenCode archive commands.
- rules-injection/validate-artifact-ids-during-instruction-loading#6: Updated the expected warning text to use double quotes and to state it matches no artifact in any available schema, listing known artifact IDs.
- specs-sync-skill/skill-output#3: Changed the expected no-changes message to 'Specs already in sync; no files changed.' to match the code.

None of these reduce what a requirement demands.

Scanned at 1ebddd17f4 by openai/gpt-5-mini.

* docs(openspec): correct 3 requirements that the code has outgrown

- ai-tool-paths/path-configuration-for-supported-tools#2: Updated the Windsurf scenario to expect skillsDir '.devin' instead of '.windsurf'.
- cli-artifact-workflow/experimental-isolation#8: Updated the file-path in the Single file implementation scenario from src/commands/artifact-workflow.ts to src/commands/workflow to match current code organization.
- command-generation/toolcommandadapter-interface#2: Updated the Windsurf adapter file path pattern to use '.devin/workflows/opsx-<id>.md' to match the implemented adapter.

None of these reduce what a requirement demands.

Scanned at 1ebddd17f4 by openai/gpt-5-mini.

* docs(openspec): correct 4 requirements that the code has outgrown

- ai-tool-paths/path-configuration-for-supported-tools#2: Updated the windsurf scenario to require skillsDir `.devin` instead of `.windsurf` to match current mapping.
- cli-artifact-workflow/experimental-isolation#8: Updated the path in the 'Single file implementation' scenario from src/commands/artifact-workflow.ts to src/commands/workflow/*.
- context-injection/format-context-with-xml-style-tags#2: Updated tag name from <context> to <project_context> in the requirement and scenarios to match implementation.
- specs-sync-skill/skill-output#3: Updated the No changes needed scenario message to match the actual output: changed text to 'Specs already in sync; no files changed.'

None of these reduce what a requirement demands.

Scanned at 1ebddd17f4 by openai/gpt-5-mini.

* docs(openspec): correct 5 requirements that the code has outgrown

- cli-artifact-workflow/experimental-isolation#8: Updated the single-file path from src/commands/artifact-workflow.ts to src/cli/index.ts to match code.
- ai-tool-paths/path-configuration-for-supported-tools#2: Updated the Windsurf scenario to require skillsDir `.devin` instead of `.windsurf` to match the alias to Devin.
- command-generation/toolcommandadapter-interface#2: Updated the Windsurf adapter file path requirement to use the .devin/workflows/opsx-<id>.md path.
- cli-artifact-workflow/schema-apply-block#9: Updated the default instruction text to include the word "required", matching the implemented string.
- opsx-onboard-skill/graceful-exit-handling#8: Updated the continuation command from `/opsx:continue <name>` to `/openspec-continue-change <name>` to match the implemented command.

None of these reduce what a requirement demands.

Scanned at f1b521dffa by openai/gpt-5-mini.

* docs(openspec): correct 5 requirements that the code has outgrown

- ai-tool-paths/path-configuration-for-supported-tools#2: Updated the 'windsurf' scenario to require skillsDir '.devin' to match the current mapping of 'windsurf' to 'devin'.
- cli-init/exit-codes#7: Updated the exit code for user-cancelled operations from 3 to 130.
- context-injection/format-context-with-xml-style-tags#2: Replaced <context> tag name with <project_context> in requirement text and both scenarios to match the implemented tag.
- specs-sync-skill/skill-output#3: Replaced the no-changes message text to match the actual logged message ('Specs already in sync; no files changed.').
- telemetry/first-run-telemetry-notice#5: Updated the quoted one-line notice text to include the additional opt-out instruction 'or openspec config set telemetry.enabled false' to match the implemented message.

None of these reduce what a requirement demands.

Scanned at f1b521dffa by openai/gpt-5-mini.

* docs(openspec): correct 4 requirements that the code has outgrown

- ai-tool-paths/path-configuration-for-supported-tools#2: Updated the Windsurf scenario to require skillsDir '.devin' instead of '.windsurf'.
- cli-init/progress-indicators#1: Replaced the grouped spinner text '⠋ Configuring AI tools...' with the per-tool spinner text 'Setting up <tool.name>...'.
- specs-sync-skill/skill-output#3: Replaced the no-changes message to match the code: "Specs already in sync; no files changed."
- telemetry/first-run-telemetry-notice#5: Updated the quoted first-run notice text to include the alternative opt-out command 'or openspec config set telemetry.enabled false'.

None of these reduce what a requirement demands.

Scanned at f1b521dffa by openai/gpt-5-mini.

* docs(openspec): correct 6 requirements that the code has outgrown

- ai-tool-paths/path-configuration-for-supported-tools#2: Updated the Windsurf scenario to require skillsDir '.devin' to match the code mapping.
- cli-change/legacy-compatibility#2: Changed the deprecated command in both scenarios from 'openspec list' to 'openspec change list' and updated the deprecation notice to point users to 'openspec list'.
- cli-init/exit-codes#7: Updated the exit code for user-cancelled operations from 3 to 130 to match implemented behavior.
- cli-artifact-workflow/schema-apply-block#9: Updated default instruction text to match code: changed "All artifacts complete. Proceed with implementation." to "All required artifacts complete. Proceed with implementation."
- cli-artifact-workflow/output-messaging#12: Updated the expected skipped-commands message to match the actual output format: "Commands skipped for: <tools> (no adapter)".
- specs-sync-skill/skill-output#3: Updated the exact no-changes message to match the code's wording.

None of these reduce what a requirement demands.

Scanned at a0ddb60d04 by openai/gpt-5-mini-2025-08-07.

* docs(specs): verify drift corrections against current behavior

---------

Co-authored-by: openspec-cloud[bot] <311461291+openspec-cloud[bot]@users.noreply.github.com>
Co-authored-by: Clay Good <hi@claygood.com>
2026-09-02 19:59:42 +00:00
Pablo Formoso 1bcdf1b032 fix(build): prepare npm git installs without pnpm (#792)
* fix: handle npm git dep installation for GitHub installs

npm v11's git dep preparation runs `prepare` before node_modules exist
in the temp clone directory, causing TypeScript compilation to fail.

Changes:
- build.js: skip build gracefully when node_modules absent
- package.json: use `node build.js` directly in prepare/prepack for
  npm compatibility (avoids pnpm dependency during git dep install)

Note: postinstall.js already handles all errors internally via
main().catch(() => process.exit(0)), so no `|| true` wrapper needed.

Install from GitHub with:
  npm pack github:user/repo#branch
  npm install -g ./fission-ai-openspec-x.y.z.tgz

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(build): prepare npm git installs without pnpm

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Clay Good <hi@claygood.com>
2026-09-02 19:49:03 +00:00
Александр Мелентьев 44a39eb24b feat(core): add codeassistant support (#1171)
* feat(core): add codeassistant support

Signed-off-by: Александр Мелентьев <aleksandr4842@ya.ru>

* chore: change format file and add test

Signed-off-by: Александр Мелентьев <aleksandr4842@ya.ru>

* chore: add tests

Signed-off-by: Александр Мелентьев <aleksandr4842@ya.ru>

* fix: escaped description yaml values

Signed-off-by: Александр Мелентьев <aleksandr4842@ya.ru>

* chore: add test

Signed-off-by: Александр Мелентьев <aleksandr4842@ya.ru>

* chore: change adapter

Signed-off-by: Александр Мелентьев <aleksandr4842@ya.ru>

* chore: handle \r in description

Signed-off-by: Александр Мелентьев <aleksandr4842@ya.ru>

* chore: use common escapeYamlValue helper

Signed-off-by: Александр Мелентьев <aleksandr4842@ya.ru>

* chore(release): track sourcecraft support

---------

Signed-off-by: Александр Мелентьев <aleksandr4842@ya.ru>
Co-authored-by: Clay Good <hi@claygood.com>
2026-09-02 19:40:20 +00:00
Jason Hindley 142b8a9203 fix(docs): route OpenSpec pixel through Pages (#1757)
* Route /openspec-pixel.svg to the docs Pages deployment

The docs nav logo is referenced via the root-relative path
/openspec-pixel.svg, which isn't matched by isDocsRoute() and so falls
through to the Astro landing site instead of the docs Pages project
that actually has the asset - a 404. /icon.svg already has this exact
special case; this adds the same for the pixel logo.

Fixes #1756

* fix(docs): route pixel logo through worker

---------

Co-authored-by: Clay Good <hi@claygood.com>
2026-09-02 19:31:59 +00:00
dependabot[bot] 6911f55175 fix(deps): preserve Node 20 chalk compatibility (#1747)
* chore(deps): bump chalk from 5.6.2 to 6.0.0

Bumps [chalk](https://github.com/chalk/chalk) from 5.6.2 to 6.0.0.
- [Release notes](https://github.com/chalk/chalk/releases)
- [Commits](https://github.com/chalk/chalk/compare/v5.6.2...v6.0.0)

---
updated-dependencies:
- dependency-name: chalk
  dependency-version: 6.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* chore(nix): refresh dependency hash

* fix(nix): use calculated dependency hash

* fix(deps): preserve Node 20 chalk compatibility

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Clay Good <hi@claygood.com>
2026-09-02 19:24:39 +00:00
dependabot[bot] c5c38a7aca chore(deps-dev): bump eslint from 10.8.1 to 10.9.0 in the development-dependencies group (#1745)
* chore(deps-dev): bump eslint in the development-dependencies group

Bumps the development-dependencies group with 1 update: [eslint](https://github.com/eslint/eslint).


Updates `eslint` from 10.8.1 to 10.9.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Commits](https://github.com/eslint/eslint/compare/v10.8.1...v10.9.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-version: 10.9.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>

* chore(nix): refresh dependency hash

* fix(nix): use calculated dependency hash

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Clay Good <hi@claygood.com>
2026-09-02 19:15:51 +00:00
Clay Good d0071d7326 docs(archive): show how to retire capabilities (#1751) 2026-09-01 00:16:02 +00:00
openspec-release-bot[bot] a0ddb60d04 Version Packages (#1728)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
v1.11.0
2026-08-26 21:19:57 +00:00
Ryan de Melo 2fa679f180 fix(schema): make schema init --default actually set the default (#1709)
* fix(schema): make schema init --default actually set the default

--default wrote defaultSchema to openspec/config.yaml, but the config
loader only reads schema, so new changes kept using spec-driven while
the command reported success. Write the key that is read, and drop the
dead one a previous run may have left behind.

Fixes #1708

* fix(schema): preserve supported configs when setting default

* docs(schema): specify default config file handling

* docs(schema): protect default config migration

* fix(schema): make default initialization atomic

* fix(schema): hide init staging and backup dirs from discovery

`schema init` stages into `.init-staging-<rand>` and moves an existing
schema aside to `<name>.init-backup-<pid>-<ts>`, both inside the schemas
dir. `schema fork` already did this and the resolver filters its temp
names out of discovery; the init names were never added, so `listSchemas`
and `listSchemasWithInfo` surfaced them as real schemas -- in shell
completions, "available schemas" error lists, and change-metadata
validation.

The backup is the durable case: cleanup failure is deliberately tolerated
with a warning, so a blocked cleanup (or a crash mid-transaction) leaves a
permanent phantom schema behind.

Generalize the fork-only filter to cover both commands' staging and backup
names. Real schema names are kebab-case, so excluding these dot-bearing
names can never hide a legitimate schema.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Clay Good <hi@claygood.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 20:42:30 +00:00
Shooks e5e350d04b fix(explore): use ASCII in diagram examples (#1010)
* fix: Use ASCII arrows instead of unicode

This fixes the issue of ambiguous unicode character width when visualizing on terminals

* fix: Update remaining docs within explore to use ASCII

* fix(explore): finish the ASCII conversion and guard it

Rebase onto main and close the gaps in the original fix:

- Regenerate skills/openspec-explore/SKILL.md. The static skills/ mirror
  landed after this branch was cut, so the parity test would have failed
  with the template and the mirror out of sync.
- Regenerate the three parity hashes through scripts/regen-parity-hashes.mjs.
- Convert the ambiguous-width glyphs the first pass missed: the bullets in
  the CLI-storage example, and the check/cross marks in its comparison
  table, which sat in the column-aligned block the bug is about.
- Tighten the ASCII guidance to two lines. It ships into every user
  project on both delivery surfaces, so the paragraph was pure overhead.
- Add regression tests (#983): every fenced example in both the skill and
  the command body must be free of box-drawing, arrow, bullet, and
  check/cross glyphs, and the guidance must state the rule and the reason.
- Add a patch changeset.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* test(explore): cover every check/cross dingbat in the ASCII guard

The matcher listed U+2713 and U+2717 only, so a fenced example could use
✕ (U+2715) or ✘ (U+2718) — same ambiguous width, same misalignment — and
still pass. Widen to the U+2713-U+2718 run.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(explore): require explicit confirmation before writing files

* test(explore): harden write confirmation guardrail

* fix(explore): scope write confirmation precisely

---------

Co-authored-by: Clay Good <hi@claygood.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Ayman D. <ayman.bacc@gmail.com>
2026-08-26 20:18:06 +00:00
bsmedberg-xometry dd7cea3ffe feat(show): diff delta requirements against the main specs (#980)
* Proposed feature: openspec show --diff to see changed requirements more clearly

* Implementation of the --diff feature, which led to some spec changes during implementation.

* Update the proposal to be clearer. Thanks coderabbit

* Fix a bug identified by coderabbit with excessive trimming, and add a testcase for it.

* fix(show): harden --diff for review feedback

Keeps `openspec show <change>` without `--diff` a raw proposal
passthrough, reports when a change has no delta specs instead of
returning silently, preserves the Reason/Migration body of a REMOVED
requirement, and resolves main specs through the command's root so
`--store <id>` diffs against that store.

Text mode and JSON mode now render from one shared collection pass, the
CLI tests drive argv arrays from a mkdtemp project instead of
interpolated shell strings, `--diff` is registered for shell
completions, and the stray package-lock.json is gone.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* build(deps): declare the diff dependency and refresh the flake hash

Adds the `diff` runtime dependency that requirement-diff.ts imports,
updates pnpm-lock.yaml, and regenerates the flake's pnpmDeps hash so
`nix build` matches the new lockfile.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(show): diff nested capabilities too

collectSpecDiffs enumerated only top-level directories under the
change's specs/, so a nested capability (specs/<area>/<id>/spec.md) was
skipped: text mode printed nothing for it and its MODIFIED deltas came
back from --json with no diff. It now uses the same discoverSpecFiles()
helper ChangeParser uses, so the capability ids match the `spec` field
of the JSON deltas.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(show): report header mismatches instead of hiding them

Two cases where --diff quietly showed something misleading:

A MODIFIED requirement whose capability has no main spec was rendered as
all-additions, which reads like a new capability. It is an authoring
error archive will reject, so it now prints the raw text with a warning
naming the missing spec.

A header that differs from the main spec only in case or interior
spacing found no match at all under exact lookup, or matched under a
lowercase-only comparison that let a real mismatch through silently.
Lookup is now exact first, then the shared foldRequirementName fallback,
and a folded match prints the diff the author meant alongside a warning
that archive matches names exactly.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* refactor(show): name the main spec as such in collectSpecDiffs

Comment and locals still called the main spec the "base" spec, and the
no-main-spec comment described the old all-additions behavior.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* chore(deps-dev): bump the development-dependencies group with 2 updates

Bumps the development-dependencies group with 2 updates: [smol-toml](https://github.com/squirrelchat/smol-toml) and [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint).


Updates `smol-toml` from 1.7.1 to 1.8.0
- [Release notes](https://github.com/squirrelchat/smol-toml/releases)
- [Commits](https://github.com/squirrelchat/smol-toml/compare/v1.7.1...v1.8.0)

Updates `typescript-eslint` from 8.66.0 to 8.67.0
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.67.0/packages/typescript-eslint)

---
updated-dependencies:
- dependency-name: smol-toml
  dependency-version: 1.8.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development-dependencies
- dependency-name: typescript-eslint
  dependency-version: 8.67.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>

* chore(nix): invalidate pnpm dependency hash

* fix(nix): update pnpm dependency hash

* fix(show): harden requirement diff output

* build(nix): pin combined dependency hash

* test(show): assert proposal precedes diffs

* docs(show): clarify JSON diff diagnostics

* fix(show): retain unified diff hunk headers

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Clay Good <hi@claygood.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-26 20:18:03 +00:00
Leonardo Rojas ab81a4b43a fix(completions): stop Fish completions falling back to filenames (#1199)
* fix(completions): suppress filesystem fallback in Fish completions

* fix(completions): force files back on for path positionals in Fish

Fish never restores filesystem completion once a matching rule sets
--no-files, so a path positional needs an explicit --force-files rule.
Without it, `openspec store register <TAB>` lost file completion because
the sibling subcommand rules in the same context now carry -f.

Also drop retired "context store" vocabulary from the test fixtures.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(completions): preserve workset member paths in fish

* fix(completions): force Fish path fallback

* fix(completions): harden Fish option handling

* fix(completions): scope Fish path fallback

* fix(completions): match Fish command paths exactly

* fix(completions): skip parent options in Fish paths

---------

Co-authored-by: Clay Good <hi@claygood.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 19:27:27 +00:00
Alfred 109f81f17d fix(antigravity): update skill and workflow paths from .agent to .agents (#830)
* fix(antigravity): update skill and workflow paths from .agent to .agents

Antigravity has migrated from .agent (singular) to .agents (plural) for
workspace skills and workflows. The old .agent path still works via
backward compatibility, but the official docs now specify .agents.

Changes:
- config.ts: skillsDir '.agent' -> '.agents'
- antigravity adapter: workflow path '.agent/workflows/' -> '.agents/workflows/'
- legacy-cleanup: add patterns for old .agent/ artifacts cleanup
- docs: update supported-tools.md table
- tests: update expected path assertions

Closes #0 (reported by BugsCreator and Minh Pham in Discord)

* fix(antigravity): migrate an existing .agent install to .agents

Pointing Antigravity at `.agents` leaves every existing `.agent/` install
behind, so this registers the move instead of only changing the target:

- `.agent` becomes Antigravity's legacy skills root and legacy tool root, so
  update relocates managed skills and commands after generating their
  replacement, keeping a file the user customized.
- Detection keys off `.agent` and `.agents/workflows`. The bare `.agents` root
  is shared with Codex, Zed, and the vendor-neutral target, so it cannot stand
  in for "Antigravity is set up here".
- Delivery inference reads a tool's legacy roots for command files too.
  Without it the first update after the move saw skills but no commands,
  wrote `delivery: skills`, and the next update deleted every slash command.
- Legacy slash-command cleanup stays scoped to the pre-opsx `openspec-*` names
  under `.agent`; the migration owns the `opsx-*` files, and a shared root is
  never glob-swept.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs: record the Antigravity root move

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(antigravity): require a generated command before moving its legacy copy

migrateCommandFiles relocated a legacy command file whether or not the
current root held a replacement. Codex never reached that path — it has no
command adapter — so Antigravity is the first after-generation move where it
matters: under skills-only delivery, or for a deselected workflow, the move
recreated a command OpenSpec had just decided not to install.

Gate the move on an existing destination, the same way migrateSkillDirs
already does for after-generation timing.

Reported by CodeRabbit on #830.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(antigravity): arbitrate shared agent skills

* test(antigravity): cover Windows migration paths

* fix(antigravity): harden shared-root migration

---------

Co-authored-by: Clay Good <hi@claygood.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 19:25:46 +00:00
Marzx13 04b37ac1d5 fix(archive): preserve requirement order when renaming (#1712)
* fix(archive): preserve requirement order when renaming

* chore(archive): add rename-order changeset

---------

Co-authored-by: Clay Good <hi@claygood.com>
2026-08-26 19:25:43 +00:00
mark 126c5d6c59 fix(validate): report a Purpose left as the archive placeholder (#1671)
* docs(openspec): propose warn-on-purpose-placeholder

When a delta introduces a capability with no usable `## Purpose`, archive
writes `TBD - created by archiving change <name>. Update Purpose after
archive.` into the new main spec. Three places already tell authors to
replace it -- the `specs` instruction ("including a leftover `TBD`
placeholder"), the sync-specs summary step ("so it gets written now rather
than lingering"), and the cli-archive contract -- but nothing reports that
it is still there.

`--strict` cannot reach it. The check meant to catch a Purpose nobody wrote
is a 50-character floor and the placeholder is 91 characters, so the one
rule that exists to catch a thin Purpose is satisfied by the exact text
meaning nobody wrote one: a Purpose reading "Does stuff." fails --strict
today, while one saying nothing at all passes.

Proposes reporting it as a warning against the spec's Purpose -- silent by
default, failing under --strict, so a project already carrying placeholders
keeps validating until it opts into the stricter gate. Detection is narrow:
the generated sentence wherever it appears, and otherwise only a `TBD`
opening the Purpose, so prose raising an open question is left alone.

Planning artifacts only; no source changes.

Refs #369

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(validate): report a Purpose left as the archive placeholder

When a delta introduces a capability with no usable `## Purpose`, archive
writes a placeholder into the new main spec. Nothing read it afterwards, so
the capability kept a to-do in it while every command reported success.

`--strict` could not reach it. The check that exists to catch a Purpose
nobody wrote is a 50-character floor, and the placeholder clears it: a spec
whose Purpose read "Does stuff." failed --strict, while a spec whose Purpose
said nothing at all passed. #369 reported agents leaving the placeholder
behind and stayed open seven months; every remedy since has been an
instruction, which is the mechanism that report described as unreliable.

validate now reports it as a warning against the Purpose, naming the line
and saying to edit the main spec directly -- a delta's `## Purpose` is read
only when the capability is created, so it cannot replace an existing one.

Warning rather than error, because strict mode already means "warnings
fail": a project carrying placeholders keeps validating by default and only
--strict fails. Archive is untouched -- it validates rebuilt specs without
--strict, so a spec archive writes still passes the validation it would have
passed before, and the text archive writes is byte-identical.

The placeholder is recognised through the same constants the writer composes
it from, so the check cannot drift from the sentence it looks for -- the
failure mode of a second, hand-copied spelling being a check that matches
nothing and looks exactly like a check that found nothing. The one case that
cannot be a lookup is an agent-written placeholder, kept to a `TBD` opening
the Purpose: "the retry budget is TBD pending benchmarks" is authored prose
and is left alone.

Verified: 209 archive tests pass unchanged (the placeholder text is
asserted literally, so the output is provably identical); full suite 138
files / 3993 tests; 36/36 strict spec validations; build, lint and typecheck
clean. Against a project carrying four real placeholders, default mode still
exits 0 and --strict fails exactly those four.

Cross-platform CI is not yet confirmed -- it needs a pushed branch. Line
endings are covered by tests asserting a CRLF spec and an LF spec produce
identical findings, and the module does no path handling.

Refs #369

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* test(validate): make every placeholder guard load-bearing

A mutation pass over the seven guards -- revert one, see which tests die --
found two that no test held.

The prefix/suffix test did not exercise the guard it named. Its Purpose read
"Explains what happens when archiving change my-change runs twice", which
contains neither half of the generated sentence, so it passed whether or not
the suffix was required. Matching on the prefix alone killed nothing. The
Purpose now embeds the real prefix constant and asserts the suffix is absent,
so the case is the one the name claims; the mutation kills it.

The empty-Purpose early return was genuinely dead. Neither rule matches empty
text, so removing the branch changed no behaviour and failed no test. Rather
than keep a guard nothing can hold, the branch is gone and the comment says
why an empty Purpose still yields null. The tests asserting that behaviour
are unchanged and still pass.

Every guard now dies under mutation:

  whole check removed from applySpecRules ......... 6 tests
  brevity no longer suppressed (else -> if) ....... 1
  word boundary dropped from the TBD marker ....... 1
  generated placeholder matched on prefix alone ... 1
  line-ending normalisation removed ............... 2
  section-boundary guard removed from locator ..... 1

Full suite 138 files / 3993 tests, lint and typecheck clean.

Refs #1670

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(openspec): record the mutation pass in the task list

The mutation work changed the implementation -- a test rewritten and a dead
branch removed -- but no task covered it, so the plan claimed less work than
was done. Added as group 6, marked complete, with why it was not planned.

5.4 now says what blocks it. It needs a pushed branch for the cross-platform
matrix, and the note records that line endings are covered locally by tests
asserting a CRLF spec and an LF spec produce identical findings, so a reader
can tell the difference between unverified and unverifiable-from-here.

The specs, proposal and design are unchanged and were checked: the delta's
empty-Purpose clause constrains behaviour, not structure, and that behaviour
is the same -- the redundant branch went, the rule did not.

26 of 27 tasks complete; the change still validates --strict.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(openspec): close 5.4 on a green cross-platform matrix

CI dispatched on the fork against this branch: lint & typecheck, and the test
suite on linux-bash, macos-bash and windows-pwsh -- all green. The Windows job
installed, built and ran the suite rather than short-circuiting, which is the
part 5.4 existed to check, since the placeholder locator counts lines in files
that may carry either ending.

Recorded as a workflow_dispatch run on the fork, not the upstream pull-request
run, because those are not the same gate and the note should not let a reader
assume otherwise. Nix Flake Validation and Validate Release Tracking skipped:
this branch touches neither the flake nor release tracking.

27 of 27 tasks complete.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(validate): name the placeholder's line, not the prose above it

The warning tells you which line to fix, and named the wrong one when the
generated sentence did not open the Purpose:

     3  ## Purpose
     4  Handles widget retries.            <- warning pointed here
     5
     6  TBD - created by archiving ...     <- placeholder is here

The locator asked "what is the first non-blank line after ## Purpose?"
rather than "where is the placeholder?". Those are the same line in five of
the six shapes a placeholder can take -- a leading TBD marker is the first
non-blank line by definition, and archive writes the generated sentence as
the section's only content -- so the two questions only diverge when a human
types prose above a leftover placeholder.

Pointing at that prose is worse than pointing nowhere: the reader sees a
sentence that is plainly fine and concludes the check is broken. design.md
already said a wrong line number is worse than none, and the delta already
required naming the line the placeholder is on, so this is the
implementation meeting a contract that was already written, not a change of
contract.

The locator is now told which rule matched. A leading marker keeps the
first-non-blank behaviour, because that is where it sits; the generated
sentence is located by its own text. When both match the leading marker
wins, being the earlier of the two.

Found by CodeRabbit on #1671. The finding was real despite its own
"Addressed" marker, which only tracked the file changing in a later commit.

Two test gaps let it through. The case that covered this input asserted
only that something was reported, never which line -- so it now asserts the
line, and a table pins every position a placeholder can occupy, each case
first checking that the line it expects really carries the placeholder. The
mutation pass could not have caught it either: mutation proves a test dies
when a guard is broken, and cannot invent an assertion nobody wrote.

Reverting the branch fails exactly the three new expectations. Full suite
4000 tests / 138 files, lint and typecheck clean.

Refs #1670

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* refactor(validate): set the placeholder line unconditionally

ValidationIssue.line is optional and the project does not enable
exactOptionalPropertyTypes, so a plain assignment typechecks and
JSON output is unchanged - JSON.stringify drops undefined values.
findPurposePlaceholderIssue already returns the key unconditionally,
and the neighbouring push sites assign line plainly, so the
conditional spread was the odd one out.

* fix(validate): widen the placeholder check to TODO and read fences as quoted

#1670 left two questions open. Both are answered here, against how OpenSpec
already reads a spec.

A `TODO` opening the Purpose now reports as the same finding as a `TBD`.
Nothing OpenSpec writes produces one, but the marker an author leaves behind is
whichever word they reached for, and a Purpose reading `TODO: fill this in` is
as unwritten as one reading `TBD`. Only the opening position counts, as before,
so `TODOs are tracked in the linked issue` is still authored prose.

Fenced code inside a Purpose is now read as quoted material rather than as the
Purpose speaking, through the `buildCodeFenceMask` the requirement and structure
parsers already share. Without it a spec documenting the sentence archive writes
is reported as carrying it, which is the check failing the one document that
explains it - and a warning that fires on the docs teaches people to ignore the
warning. Fenced lines are skipped when locating the placeholder too, so a
`## Purpose` or `## Requirements` quoted in a fence can neither be mistaken for
the section header nor end the section early.

The message now names both what archive writes and a marker left in its place,
since one message covers both. Severity is unchanged: still a warning, so a
project carrying placeholders keeps validating and only --strict fails.

Every new guard is mutation-checked: dropping `TODO` kills 3 tests, unmasking
detection kills 2, unmasking the line locator kills 3, unmasking the header
search kills 1.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(validate): read the marker boundary in any script, not just ASCII

Review found `\b` reading `TODOé` and `TBD١` as a marker followed by
punctuation, because `\b` only knows ASCII word characters. A Purpose is prose
and prose is not always Latin script, so the rule that a longer word beginning
with those letters is not a marker has to hold in any script.

The lookahead rejects letters, digits, combining marks and `_`, and nothing
else, so `TODO:`, `TBD -` and `TODO(owner):` are still the marker they look
like. Held in both directions: loosening it back to `\b` kills 1 test,
tightening it to reject punctuation kills 4.

Also reworded a task line that opened with `#1670`, which markdownlint reads as
a heading missing its space.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(validate): locate the matched purpose placeholder

* docs(validate): remove trailing task whitespace

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Clay Good <hi@claygood.com>
2026-08-26 19:25:40 +00:00
Tanner a7353aea9a feat(status): add --all for batch status of every active change (#1301)
* feat(status): add --all for batch status of every active change

`openspec status --all --json` reports every active change in one
process instead of one CLI spawn (~500ms module-load) per change,
mirroring the existing `validate --all`. Emits a single
`{ changes: [ChangeStatus, ...], root }` envelope sorted by change
name; a change that fails to load contributes a per-change error entry
instead of failing the sweep. `--all` and `--change` are mutually
exclusive, honoring the --json null-shape on failure.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(status): harden --all per adversarial review findings

- Validate --schema before the no-changes early return so a bogus
  schema fails consistently whether or not any change exists.
- Text mode now exits 1 when any change fails to load (mirrors
  validate --all); JSON mode still exits 0 with per-change diagnostics.
- Add tests for the --all --schema interaction (unknown schema
  null-shape, override propagation, broken-metadata precedence) and
  text-mode failure rendering.
- Changeset heading to "### New Features" per repo convention; add
  status --all to the agent quick-reference table in docs/cli.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(status): thread batch null-shape through root resolution, align sort with validate

Code-review findings on --all:
- Pass failurePayload: { changes: [] } to resolveRootForCommand so a
  root-selection failure under --all --json still emits the documented
  batch null-shape (siblings like list/doctor/context already do this).
- Sort with localeCompare to match validate --all's ordering for
  mixed-case change names.
- Extract a shared loadStatus helper so the batch and single-change
  payloads cannot drift apart.
- Changeset no longer claims exact validate --all parity (JSON exit
  semantics deliberately differ).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* refactor(status): give the --all failure null-shape a single owner

Simplify pass on the --all diff: hoist the { changes: [] } batch
null-shape into an exported BATCH_STATUS_FAILURE_PAYLOAD constant so
the root-resolution and CLI-wrapper failure paths cannot drift, replace
the conditional spread with the plain ternary the sibling call site
already uses, drop a redundant array copy before sort, and narrow the
text-mode failure counter to the boolean it actually is.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(status): point the missing-target error at --all, correct the docs

`openspec status` with neither --change nor --all listed the available
changes and named only --change, so the batch path was discoverable
only from --help. The error now offers both.

Also corrects two stale claims in the status section of docs/cli.md
that the new row sits next to: the command never prompts for a change
(it errors), and bare `openspec status` is not an interactive check.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* test(status): assert --all carries store context like the single-change path

The batch sweep resolves the root once and threads the store id into
every entry. Nothing pinned that: a regression would have shown up only
as a wrong path inside an agent's JSON. Assert the sweep's envelope root
and per-change payload match `status --change` in a registered store.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(status): fail incomplete batch reports

* docs(status): clarify empty and batch output

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Clay Good <hi@claygood.com>
2026-08-26 19:25:39 +00:00
dependabot[bot] c0c50f9a4c chore(deps-dev): bump the development-dependencies group with 2 updates (#1718)
* chore(deps-dev): bump the development-dependencies group with 2 updates

Bumps the development-dependencies group with 2 updates: [smol-toml](https://github.com/squirrelchat/smol-toml) and [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint).


Updates `smol-toml` from 1.7.1 to 1.8.0
- [Release notes](https://github.com/squirrelchat/smol-toml/releases)
- [Commits](https://github.com/squirrelchat/smol-toml/compare/v1.7.1...v1.8.0)

Updates `typescript-eslint` from 8.66.0 to 8.67.0
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.67.0/packages/typescript-eslint)

---
updated-dependencies:
- dependency-name: smol-toml
  dependency-version: 1.8.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development-dependencies
- dependency-name: typescript-eslint
  dependency-version: 8.67.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>

* chore(nix): invalidate pnpm dependency hash

* fix(nix): update pnpm dependency hash

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Clay Good <hi@claygood.com>
2026-08-26 19:25:07 +00:00
Ayman A. 7010e26890 fix(explore): require explicit confirmation before writing files (#1716)
* fix(explore): require explicit confirmation before writing files

* test(explore): harden write confirmation guardrail

* fix(explore): scope write confirmation precisely

---------

Co-authored-by: Clay Good <hi@claygood.com>
2026-08-26 19:24:57 +00:00
dependabot[bot] 6926ccb18a chore(deps): bump the website-dependencies group (#1719)
Bumps the website-dependencies group in /website with 2 updates: [fumadocs-core](https://github.com/fuma-nama/fumadocs) and [fumadocs-ui](https://github.com/fuma-nama/fumadocs).


Updates `fumadocs-core` from 16.14.4 to 16.14.5
- [Release notes](https://github.com/fuma-nama/fumadocs/releases)
- [Commits](https://github.com/fuma-nama/fumadocs/compare/fumadocs@16.14.4...fumadocs@16.14.5)

Updates `fumadocs-ui` from 16.14.4 to 16.14.5
- [Release notes](https://github.com/fuma-nama/fumadocs/releases)
- [Commits](https://github.com/fuma-nama/fumadocs/compare/fumadocs@16.14.4...fumadocs@16.14.5)

---
updated-dependencies:
- dependency-name: fumadocs-core
  dependency-version: 16.14.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: website-dependencies
- dependency-name: fumadocs-ui
  dependency-version: 16.14.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: website-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-24 14:00:04 +00:00
Tabish Bidiwale f1b521dffa docs: rebuild docs site from docs-lab (#1649)
* docs: rebuild docs site from docs-lab

Replace the docs site's source tree with docs-lab, a page-by-page rebuild
of the OpenSpec docs (40 pages: Start / Guides / Customize / Multi-repo /
Reference / Help).

- Point website/docs.sync.config.mjs at ../docs-lab and restructure the
  sidebar into nested groups; sync script gains nested meta.json emission,
  leading-quote descriptions, idempotent writes, and diagram asset copying
- Remove the marketing landing page; / now redirects to /docs
  (meta-refresh page + Cloudflare _redirects)
- Add remark plugins (faq, file-steps, gfm-alert) and the FileSteps
  component backing the new page formats
- Add install.md at the repo root, curled by docs-lab/start/installation.md
  as an agent-executable install prompt
- Add the docs authoring skills (.agents/skills/{write,draft,verify}-
  openspec-docs); docs-lab/README.md links into write-openspec-docs

The old docs/ tree is now unused by the site and left for a follow-up.

Claude-Session: https://claude.ai/code/session_01BMMLYNJQPKXx1QHpnDn4ho

* docs: hold back unwritten pages, add worksets, drop diagram drafts

- website: comment out Overview, Guides, Architecture, Help, Legacy in
  docs.sync.config.mjs until those pages are written; temporary
  /docs -> /docs/installation redirect (Cloudflare _redirects + static
  export meta-refresh fallback in page.tsx)
- docs-lab: new multi-repo/worksets.md page, published under Multi-repo
- docs-lab: content revisions across start/, customize/, reference/,
  help/, multi-repo/; add review notes (Notes.md)
- remove docs-lab/diagrams option-* drafts and their website copies
- write-openspec-docs skill: add spoken-flow sentence rule

* docs: address review on PR #1649

- sync-docs: read the existing output directly instead of exists-then-read
  (CodeQL TOCTOU alert)
- hold back the headings-only Environment variables and Stores reference
  pages until written; links to them fall back to their GitHub source
- sources.md: cutover keeps docs/ in place and points at public/_redirects
- setup.md: label the workflow tree as the default set plus two optional ones

* docs: two review nits (spoken-flow rule, XDG_DATA_HOME note)
2026-08-21 20:45:19 +00:00
openspec-release-bot[bot] 1ebddd17f4 Version Packages (#1705)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
v1.10.0
2026-08-19 22:23:30 +00:00
Clay Good 7da3f34fb6 fix(tasks): include verification in generated plans (#1660)
* fix(tasks): include verification in generated plans

* test(tasks): enforce inline verification guidance

* fix(tasks): harden verification guidance

* test(tasks): verify every onboarding checkbox
2026-08-19 21:07:20 +00:00
Clay Good 7276c6c268 fix(packaging): print the completions tip from the CLI, not a postinstall script (#1704)
* fix(packaging): print the completions tip from the CLI, not a postinstall script

The package's only install script existed to print one line suggesting
`openspec completion install`. Shipping it made every `npm install -g`
emit an npm allow-scripts warning, and `npm approve-scripts` then failed
with ENOMATCH because it looks in the local project, not a global install
— so the warning looked like a packaging fault with no way to clear it.

The tip now prints once on the CLI's first run, recorded via a
`completionTipSeen` flag in the existing global config alongside the
telemetry notice's `noticeSeen`. It writes to stderr so it can never
contaminate piped stdout, and is suppressed under CI,
OPENSPEC_NO_COMPLETIONS=1, `--json` runs, and `openspec completion`
itself. The published package now ships no lifecycle scripts at all.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(completions): stop the first-run tip from corrupting global config

Adversarial review of the previous commit found it wrote a defaults-merged
config: `saveGlobalConfig({ ...getGlobalConfig(), completionTipSeen: true })`
stamped `profile: "core"` into every user's config.json on first run.
`migrateIfNeeded` treats a raw `profile` as "already migrated", so the
one-time profile migration would never run again — and `openspec update`
then deleted the user's installed workflow skills. Reproduced: 2 skill
directories removed where main reports "Migrated: custom profile with 8
workflows". The same write also overwrote an unparsable config with
defaults and made `openspec config list` report defaults as explicit.

The tip now reads and writes the raw config file and touches only its own
key, leaving an unreadable config strictly alone.

Other hardening from the same review:

- Suppress the tip for the hidden `__complete` resolver. Generated
  completion scripts call it on every Tab press with stderr discarded, so
  the one-shot tip was consumed where nobody could see it.
- Defer, never consume, when stderr is not a terminal. Agents and pipes
  drive this CLI far more often than humans do and would otherwise spend
  the tip into a log nobody opens.
- Skip the tip when completions are already installed. Previously the CLI
  advertised `completion install` to users who had run it — including on
  the very next command after installing. Adds `isInstalled()` to the
  bash/fish/powershell installers, mirroring the zsh one.
- Use the repo's `isCiEnvironment()` instead of a `CI === 'true'` string
  check, so `CI=yes`/`True`/`on` are as quiet as telemetry is.
- Move the call to `postAction` so the tip trails the command's output
  instead of pushing errors and `init`'s setup summary down the screen.
- Record before printing, so an unwritable config dir means silence rather
  than nagging on every run.

Tests: assert the message literal (mutation testing showed the message text
was the one unguarded behavior), the raw-write shape, corrupt-config
safety, the already-installed path, the defer policy, and an e2e case
pinning the non-TTY contract.

Docs: SECURITY.md no longer claims zero lifecycle scripts — `prepare` is
still declared and runs for git/directory installs; the registry-install
claim is the accurate one. `OPENSPEC_NO_COMPLETIONS` is now documented.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* test(completions): make the unwritable-config case portable to Windows

fs.chmodSync(dir, 0o555) does not stop a write on Windows, so this test's
unwritable condition never existed there: markTipSeen succeeded, the tip
printed, and windows-pwsh was the only failing job.

Occupy the config directory's path with a file instead. mkdirSync with
recursive: true tolerates an existing directory but throws on an existing
file on every platform, so the persist fails where a real permission error
would - before anything is printed. Also asserts the path is still a file,
so a partial write through the failure would be caught.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(completions): retire the first-run tip instead of advising a dead end

Second adversarial pass over the tip, covering the hardening commit itself.

- An undetected or unsupported shell now retires the tip quietly. It used
  to print, but `openspec completion install` exits 1 for exactly those
  users ("Shell 'tcsh' is not supported yet" / "Could not auto-detect
  shell"), so the one message they would ever get about completions sent
  them to a command that fails.
- `markTipSeen` re-reads the config immediately before writing and swaps
  the file in by rename. Deciding whether to show the tip costs a `ps`
  spawn plus a stat, and a sibling process writing config in that window
  got clobbered — on a first run that is exactly when telemetry mints
  `anonymousId`. Concurrent-process loss drops from 15/40 to ~2/40, and
  what now usually loses is the tip's own flag (it simply shows once
  more) rather than telemetry identity. The residual is the non-atomic
  read-modify-write shape shared with telemetry's own writer.
- `isInstalled()` uses stat().isFile(), so a directory at the install
  path no longer counts as an installed completion script.
- Documented what `isInstalled()` actually promises: the script file, not
  the profile sourcing line that bash and PowerShell also need. Callers
  deciding whether to *advertise* completions want the loose reading — a
  user whose profile config failed has already met the installer.
- Corrected a comment claiming the probe costs "one stat": detectShell()
  forks `ps` to read the parent process on every non-Windows run.

Tests: mutation testing found four surviving mutants — dropping
isCompletionRun from the defer policy, reverting isCiEnvironment to a
CI==='true' string check, failing closed on an undetected shell, and
neutering the non-object config guard (which lets a JSON array config be
rewritten as {"0":...}). All four now fail a test. Adds direct coverage
for the three new isInstalled() implementations, which had none.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(validate): stop `change validate` exiting past commander's postAction

`change validate` on a failing change called process.exit(exitCode). That
tears down before commander's postAction hook, which is the same trap the
`update` command documents 165 lines earlier: "exiting here would skip
commander's postAction hook, killing the telemetry flush mid-request".

A change that fails validation is a routine outcome, not an error, so this
silently dropped the telemetry flush and — since the completions tip moved
to postAction — the first-run tip for anyone whose first command was a
failing validate. Verified under a pty: before, the tip never printed and
completionTipSeen was never recorded; after, both happen and the exit code
is still 1 (validate() already sets process.exitCode, which Node honours at
natural exit — top-level `validate --all` has always relied on exactly
that). The existing e2e in validate-scenario-loss.test.ts pins the exit
code.

Also wraps the postAction tip in try/finally so the telemetry flush runs
even if the hint throws: program.parse() is synchronous, so a rejection
there has no catch above it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 20:19:51 +00:00
Clay Good 9643888a75 fix(schema): resolve main-spec reads against the store-aware root (#1703)
* fix(schema): resolve main-spec reads against the store-aware root

The spec-driven `specs` instruction named
`openspec/specs/<capability-path>/spec.md` — a cwd-relative path — for the
two operations that touch a capability's main spec: step 1 of the MODIFIED
workflow ("locate the existing requirement") and the edit that fixes a
leftover TBD Purpose.

When the change lives in a registered store, the main spec is under the
store root. Verified against one: `openspec instructions specs --store
mystore --json` returns `planningHome.root` pointing at the store while the
instruction sent the read to the working repo, where the capability does
not exist. Where a local capability happens to share the name it is worse
than a miss — the read succeeds against a different capability and step 2
copies the wrong requirement block into the delta, silently.

Both now use `<planningHome.root>/openspec/specs/...`, the root the same
JSON already returns, matching what sync-specs.ts and archive-change.ts
have said since they were written: use the store-aware root, not a
hardcoded repo path.

Guidance text only — no CLI, parser, or archive behavior changes. The two
remaining `openspec/specs/` mentions describe the shape of a capability
path rather than a file operation, and are left alone.

Closes #1702

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(schema): make the store-aware root unconditional, and prove it resolves

Two hardening findings.

The wording said the root "points at the store when a store is selected."
Verified across all four root configurations, that undersells it: a project
`store:` pointer (source `declared`) and a global default store (source
`global_default`) both resolve to the store with no `--store` flag passed.
An agent reading the old sentence could conclude the case did not apply to
it and fall back to a repo-relative path. It now says to always use the
field and not to reason about which case applies.

The test only pinned the placeholder text, which would still pass if
`planningHome.root` were renamed or the suffix were wrong. Added a guard
that substitutes the placeholder with a real resolved planning home and
asserts the composed path lands on an actual main spec. Mutation-tested:
inserting a path segment and renaming the field each fail it.

Verified end to end that the composed path exists under all three
store-selecting configurations, and under a plain local repo.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* test: compose the main-spec path from segments, not string substitution

The guard substituted `planningHome.root` into a template spelled with
forward slashes. On Windows that yields a mixed-separator path, so the
assertion passed because Node accepts forward slashes there rather than
because the path was built correctly. Windows CI was green either way;
this makes the construction right instead of merely tolerated.

The suffix is now captured on its own and joined to the root with
path.join, so the assertion uses native separators everywhere. All three
mutations (cwd-relative path, extra segment, renamed field) still fail
the guard.

Addresses CodeRabbit review on #1703.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 20:19:46 +00:00
Clay Good 18688c8b27 fix(archive): never dead-end a capability retirement (#1699)
* fix(archive): never dead-end a capability retirement

A change whose delta removes the last requirement a capability has
rebuilds the main spec empty, which can never validate. Archive already
knows retiring is the fix and names the `retire_capabilities: true`
marker that authorises deleting the spec - but only when the marker is
the single thing missing.

If the spec also holds a line the merge cannot account for (a `## Notes`
section, a comment under a requirement - both ordinary), that hint was
suppressed, and the hint that names such lines only spoke to authors who
had already set the marker. Neither fired, so the archive aborted on
"Spec must have at least one requirement" with no guidance at all: the
exact dead end the marker exists to close.

Archive now names the blocking content in that case. It deliberately
does not name the marker there - adding it would not have let this run
through, and the marker is only ever named when it really is the one
thing missing. Once the content is resolved, the rerun names the marker.

Closes #1696

* fix(archive): harden the blocked-retirement abort

Three follow-ups to the same message.

The blocking lines are authored spec content printed verbatim to a
terminal, so they now get the treatment `describeChangeName` already
gives a change directory name: control characters replaced, since a raw
CR could forge a line of its own and an ESC could redraw the screen.
Each line is bounded too - one very long line would push the way out of
the abort off the reader's screen - and the cut counts code points so it
can never leave half a surrogate pair. Both the declared and undeclared
branches share the helper, so the marker-declared abort that shipped
with #1484 is hardened with it.

The wording no longer claims retiring is "the way through". It is not,
in the one case this fires on that has a live requirement hiding in a
second `## Requirements` section: merging the sections fixes that spec
without deleting anything.

`openspec/specs/cli-archive/spec.md` records the behavior change - the
blocking lines are named whether or not the marker was declared, and the
marker is still named only when adding it would let the archive through.

* refactor(archive): drop a helper the revised wording made single-use

The marker sentence is said in one place again, so it goes back inline
rather than through a function that now has one caller. Also corrects
the comment above `emptiedByThisRun`: retiring is not the only fix in
every case it covers, which is exactly why the message stopped saying so.

* docs(openspec): record the change as a delta, not a direct spec edit

Both conventions exist in this repo's history, but the two most recent
behavior fixes (#1609, #1616) carry an `openspec/changes/` delta rather
than editing the main spec in place, which is also the workflow this
project asks of everyone else.

The delta reproduces the whole Capability Retirement requirement, so
archiving it drops no scenario. Verified by archiving into a scratch
copy of `openspec/`: the merged main spec differs from today's by
exactly the three added bullets.

* fix(archive): report an unhonorable marker alongside the blocking content

An author who set `retire_capabilities: yes-please` believes they have
authorised the deletion. Clearing the blocking content first, only to
then learn the marker was never read, is two aborts for one mistake.

The abort still never invites the marker to be added while content
blocks the retirement - it only reports the one already there. The spec
delta records that distinction, which the old bullet ("say nothing about
the marker") did not draw.

* style(archive): use one sentence for an unhonorable marker in both aborts

* fix(metadata): strip control characters from an unhonorable marker reason

Every reason a boolean change-metadata marker gives quotes something the
author wrote - a schema name, a parser message carrying one, a
filesystem error carrying a path - and two commands print it straight to
a terminal. A schema name carrying a raw ESC, with the marker set, put
that ESC on screen through `openspec archive`; `openspec validate`
prints the same reason.

Fixed at the source in `readBooleanMarker` rather than at either call
site, so no consumer has to remember. The reason still quotes the name
recognisably; only control characters are replaced.

Reported by CodeRabbit on #1699. Pre-existing on main, and this PR would
have added a second place it reaches the terminal.

* test(archive): fix a comment left behind by the reworded abort
2026-08-19 20:19:34 +00:00
Clay Good c747ed1f34 feat(init): add language option (#1685)
* feat(init): add language option

* fix(init): harden language configuration

* fix(init): fail when language config cannot be written
2026-08-19 20:19:28 +00:00
Clay Good 15e50d6889 fix(opencode): pass command arguments to workflows (#1664)
* fix(opencode): pass command arguments to workflows

* test(opencode): recognize existing argument placeholders

* test(opencode): harden argument generation

* test(opencode): cover commands-only upgrades

* test(opencode): verify repaired command content
2026-08-19 20:19:23 +00:00
Clay Good cf06d45f91 fix(profiles): include sync with archive workflows (#1663)
* fix(profiles): install sync with archive workflows

* test(profiles): harden archive dependency coverage

* fix(config): preserve custom profile ownership
2026-08-19 20:19:15 +00:00
Clay Good f3aa167d6e feat(tools): add Zed Agent support (#1659)
* feat(tools): add Zed Agent support

* fix(tools): detect Zed projects
2026-08-19 20:19:11 +00:00
Clay Good a72a74de65 fix(update): only suggest IDE restarts when needed (#1656)
* fix(update): only suggest IDE restarts when needed

* test(update): cover restart hint edge cases
2026-08-19 20:19:06 +00:00
Clay Good a2b965aa5e fix(workflow): keep no-spec schema changes valid (#1655)
* fix(workflow): scaffold valid no-spec changes

* fix(workflow): normalize specs artifact paths
2026-08-19 20:19:01 +00:00
Clay Good 98c79324ac docs(workflows): fix sequence diagram rendering (#1654) 2026-08-19 20:18:56 +00:00
Clay Good fc0fec1250 fix(feedback): keep full reports in issue bodies (#1653)
* fix(feedback): keep full reports in issue bodies

* fix(feedback): preserve report formatting
2026-08-19 20:18:51 +00:00
Ryan de Melo 91813641cf chore(deps): migrate to @inquirer/prompts v8 + @inquirer/core v11 (#1667)
* chore(deps): migrate to @inquirer/prompts v8 + @inquirer/core v11

Bumps both packages together. The two Dependabot attempts each moved one
half (#1450 prompts->8, #1422 core->11) and failed: prompts@8 pulls
checkbox@5 -> core@^11, while package.json depends on core@^10 directly
for two custom prompts, so a one-sided bump leaves two copies of
@inquirer/core in the tree — custom prompts on v10 internals alongside
bundled prompts on v11.

Resolves the `instructions` removal in checkbox v5 by dropping the
option: the built-in keys help tip now renders a superset of the hint
that was being passed, so no theme override is needed.

Closes #1458

* fix(nix): regenerate pnpmDeps hash for the inquirer v8 lockfile

The pnpmDeps fixed-output hash is pinned to the contents of pnpm-lock.yaml,
so the inquirer v8/core v11 migration invalidated it and Nix Flake Validation
failed with 'pnpm failed to install dependencies'.

Regenerated against this branch's lockfile and verified: nix build .#default
completes (exit 0) through openspec-1.9.0.drv, not just past the fetch.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Clay Good <hi@claygood.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 18:39:33 +00:00
Ryan de Melo db981f279d fix(telemetry): print first-run notice to stderr, not stdout (#1666)
console.log put the notice on stdout, so any non-JSON command (e.g.
spec show, change show) had it prepended to raw/passthrough output on
a fresh machine with no prior telemetry config — breaking pipes and
consumers expecting exact file content. --json mode already avoided
this by deferring the notice; stderr fixes it for every mode at the
source instead of special-casing each one.
2026-08-19 18:39:30 +00:00
Ryan de Melo d56f9fc766 test: opt the suite out of telemetry (#1668)
34 test files spawn the real CLI across ~62 call sites. Each spawn runs
the preAction hook exactly like a user invocation, so a local `pnpm test`
persisted an anonymousId into the developer's real global config
(~/.config/openspec/config.json) and POSTed a command_executed event per
spawn to the telemetry endpoint.

CI never saw this because CI=<truthy> already disables telemetry; it only
happens on contributor machines, where it also skews the maintainers'
usage data with test traffic.

Set OPENSPEC_TELEMETRY=0 / DO_NOT_TRACK=1 via vitest's env so workers and
the CLI children they spawn are both covered. Telemetry's own tests
delete these vars before asserting, so they are unaffected.
2026-08-19 18:39:27 +00:00
dependabot[bot] cfc74eeb05 chore(deps): bump the website-dependencies group (#1680)
Bumps the website-dependencies group in /website with 4 updates: [fumadocs-core](https://github.com/fuma-nama/fumadocs), [fumadocs-ui](https://github.com/fuma-nama/fumadocs), [next](https://github.com/vercel/next.js) and [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node).


Updates `fumadocs-core` from 16.14.0 to 16.14.4
- [Release notes](https://github.com/fuma-nama/fumadocs/releases)
- [Commits](https://github.com/fuma-nama/fumadocs/compare/fumadocs@16.14.0...fumadocs@16.14.4)

Updates `fumadocs-ui` from 16.14.0 to 16.14.4
- [Release notes](https://github.com/fuma-nama/fumadocs/releases)
- [Commits](https://github.com/fuma-nama/fumadocs/compare/fumadocs@16.14.0...fumadocs@16.14.4)

Updates `next` from 16.3.0 to 16.3.1
- [Release notes](https://github.com/vercel/next.js/releases)
- [Commits](https://github.com/vercel/next.js/compare/v16.3.0...v16.3.1)

Updates `@types/node` from 26.1.2 to 26.2.0
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: fumadocs-core
  dependency-version: 16.14.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: website-dependencies
- dependency-name: fumadocs-ui
  dependency-version: 16.14.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: website-dependencies
- dependency-name: next
  dependency-version: 16.3.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: website-dependencies
- dependency-name: "@types/node"
  dependency-version: 26.2.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: website-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-19 18:39:20 +00:00