mirror of
https://github.com/Fission-AI/OpenSpec.git
synced 2026-10-25 07:03:52 +08:00
@fission-ai/openspec@1.14.0
29
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
f197804a38 |
feat(nix): expose openspec as a consumable overlay (#1439)
* feat(nix): expose openspec as a consumable overlay
Refactor the flake so the package derivation is defined once, in
`overlays.default`, and every other output consumes it. Previously the
derivation lived inline in `packages.default`, so anyone who wanted
`openspec` in their own package set had to copy the derivation rather than
import it.
What changed:
- Add `overlays.default`, a standard `final: _prev:` overlay that exposes
`pkgs.openspec`. The derivation is written against `final`, so downstream
overlay composition and `overrideAttrs` behave as expected.
- Route `packages.{default,openspec}` through the overlay via a `pkgsFor`
helper (`import nixpkgs { overlays = [ self.overlays.default ]; }`), so the
flake's own package resolves exactly as a consumer's would. No more
duplicated build definition.
- Refresh the nixpkgs pin in `flake.lock`.
`apps` and `devShells` are unchanged in behaviour.
Usage — a downstream flake:
nixpkgs.overlays = [ openspec.overlays.default ];
# -> pkgs.openspec
or devenv, via `devenv.yaml`:
inputs:
openspec:
url: github:Fission-AI/OpenSpec
overlays:
- default
Assisted-by: Claude Opus 4.8 <noreply@anthropic.com>
* test(nix): cover downstream overlay composition and updater warnings
* fix(ci): compare Nix dependencies across multiple outputs
* chore: add Nix overlay changeset
---------
Co-authored-by: John Muchovej <jmuchovej@users.noreply.github.com>
Co-authored-by: Clay Good <hi@claygood.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
|
||
|
|
f7d426ab9d |
chore(deps-dev): bump the development-dependencies group with 2 updates (#1990)
* chore(deps-dev): bump the development-dependencies group with 2 updates Bumps the development-dependencies group with 2 updates: [eslint](https://github.com/eslint/eslint) and [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint). Updates `eslint` from 10.10.0 to 10.11.0 - [Release notes](https://github.com/eslint/eslint/releases) - [Commits](https://github.com/eslint/eslint/compare/v10.10.0...v10.11.0) Updates `typescript-eslint` from 8.70.0 to 8.70.1 - [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.70.1/packages/typescript-eslint) --- updated-dependencies: - dependency-name: eslint dependency-version: 10.11.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: development-dependencies - dependency-name: typescript-eslint dependency-version: 8.70.1 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: development-dependencies ... Signed-off-by: dependabot[bot] <support@github.com> * ci(nix): keep dependabot on github cache * chore(nix): update 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> |
||
|
|
f179ed4e40 |
chore(deps): bump @inquirer/core to 12.0.0 and @changesets/cli to 3.0.3 (#1954)
* chore(deps): bump @inquirer/core to 12.0.0 and @changesets/cli to 3.0.3 Consolidates Dependabot #1930 and #1931 into one PR so the flake.nix pnpmDeps hash is computed once against the final lockfile. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * chore(nix): refresh pnpmDeps hash for the new lockfile Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
fe81461d51 |
chore(deps): bump the production-dependencies group with 2 updates (#1929)
* chore(deps): bump the production-dependencies group with 2 updates Bumps the production-dependencies group with 2 updates: [yaml](https://github.com/eemeli/yaml) and [zod](https://github.com/colinhacks/zod). Updates `yaml` from 2.9.0 to 2.9.1 - [Release notes](https://github.com/eemeli/yaml/releases) - [Commits](https://github.com/eemeli/yaml/compare/v2.9.0...v2.9.1) Updates `zod` from 4.5.4 to 4.6.5 - [Release notes](https://github.com/colinhacks/zod/releases) - [Commits](https://github.com/colinhacks/zod/compare/v4.5.4...v4.6.5) --- updated-dependencies: - dependency-name: yaml dependency-version: 2.9.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies - dependency-name: zod dependency-version: 4.6.5 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: production-dependencies ... Signed-off-by: dependabot[bot] <support@github.com> * chore(nix): update pnpm dependency hash Matches the production dependency lockfile update and fixes Nix Flake Validation. --------- 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> |
||
|
|
086c93b40b |
chore(deps-dev): bump changesets, eslint and typescript-eslint (#1901)
Applies dependabot #1898 (lockfile-only: @changesets/changelog-github 1.0.1, @changesets/cli 3.0.2, eslint 10.10.0, typescript-eslint 8.70.0) plus the two follow-ups its CI needed: the transitive esbuild 0.28.1 -> 0.28.2 bump in allowBuilds, and the pnpmDeps hash in flake.nix computed by the Nix job. Co-authored-by: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
e571b5b9ae |
fix(security): harden CLI against hostile-repository inputs and clear dependency advisories (#1835)
* fix(deps): upgrade vitest to 4.1.11 and override fflate
Clears GHSA-82fw-gwwq-j7x9 (path traversal / arbitrary file read via
@vitest/mocker redirect mock), the subject of all three open Dependabot
alerts. No patched 3.x exists — 4.1.11 is the first fixed release — so the
major bump is unavoidable.
Two things the plain Dependabot bump (#1823) got wrong, which is why its
tests failed on every platform:
- It left @vitest/ui on 3.x, which dragged vite/esbuild to 0.28.2 and broke
the allowBuilds pin assertion in pnpm-workspace-config.test.ts. Upgrading
@vitest/ui in lockstep keeps esbuild on 0.28.1.
- Vitest 4 no longer lets an arrow function stand in as a constructor
implementation, so the ZshInstaller module mock threw "is not a
constructor" across 8 completion tests. Converted the three mock factories
to function expressions.
Also adds a pnpm override for fflate (GHSA-px8p-9vwx-vf98, infinite loop on
malformed ZIP64), which @vitest/ui 4.1.11 still pulls at 0.8.2.
`pnpm audit` is now clean: 0 vulnerabilities across all severities.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(core): bound schema size and stop prototype keys shadowing worksets
Two low-severity robustness defects found during the security review.
Workset lookups tested membership with `state.worksets[name] !== undefined`
on a plain-prototype object. `constructor`, `toString`, `valueof` and
friends are all valid kebab ids, so `openspec workset add constructor`
reported "already exists" against empty state, `getWorkset` returned a
function off the prototype, and `withoutWorkset` took the found branch for a
workset that was never there. All three sites now use `hasOwnProperty`.
This was never prototype *pollution* — nothing is written through these
keys and Zod's `z.record` drops `__proto__` — only a correctness defect.
`SchemaYamlSchema.artifacts` was unbounded while `validateNoCycles` walks it
with a recursive DFS, so a project-local schema declaring a long `requires`
chain crashed the CLI with an uncaught `RangeError: Maximum call stack size
exceeded` instead of a validation error. Capped at 1000 artifacts, which
also bounds the reference-resolution and graph work.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(security): stop repo-supplied text forging agent instructions
OpenSpec prints a pseudo-XML envelope that an AI coding agent consumes as
instructions, and interpolated repo content went in raw. The tags carry
authority - <project_context> means "background only", <task> means "do
this" - so a value that closes its own block is promoted from data to
directive.
Confirmed against a fresh build: a config.yaml `context:` value containing
`</project_context><system_override priority="critical">` landed a top-level
override block outside every "do NOT treat as instructions" guard. The same
breakout worked from `rules`, `description`, a dependency description, and a
schema `instruction`. A change directory name containing a quote forged
attributes on the <artifact> tag. In markdown output, a `context` line
starting with `##` forged a peer of the printer's own headings.
src/core/references.ts already had sanitizeInline written for exactly this
threat, documented as such, and simply was not applied here - it also only
flattened newlines, which one line of markup is enough to defeat. Extended it
and added three siblings beside it: escapeEnvelopeText, escapeEnvelopeAttribute,
and escapeEnvelopeCloseTags for content that must stay verbatim.
Template bodies deliberately get only their closing tags neutralized: the
shipped templates are full of `<!-- ... -->` comments and <placeholder>
markers that are copied into the generated artifact, so blanket escaping
would write <!-- into every file. A block can only end at a closing tag,
so that is the load-bearing control.
Rules and operation guidance are flattened but explicitly not truncated -
they are instructions an agent must follow in full.
Separately, `openspec update` decided skill freshness from the generatedBy:
line alone and never compared bodies, so appending a step to a generated
SKILL.md still printed "All 1 tool(s) up to date". Skills now get the same
byte-comparison command files already had, and the plan names the reason.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(security): remove super-linear scans and tighten write containment
Three regexes ran over whole repository files with a `\s` class that crosses
newlines under the `m` flag, so `^\s*` re-scanned from every line start. The
blowup is in the *failing* scan - a file with no `generatedBy:` line at all -
which is also the realistic attack file. Measured on this machine:
extractGeneratedByVersion, 63 KB whitespace SKILL.md 3,103 ms -> <5 ms
legacy-skill compare, 63 KB whitespace frontmatter 8,131 ms -> <5 ms
buildUpdatedSpec, 195 KB of `<!--` openers 6,817 ms -> ~90 ms
The first two are reached by `openspec update`, the first command run after
cloning. The third is reached from extractPurposeSection during `openspec
archive`, on the write path.
The scans now use `[ \t]` and walk lines, and maskHtmlComments is an indexOf
scan that visits each character once instead of a lazy regex that re-scans to
EOF from every `<!--`. Both rewrites were fuzzed against the originals -
200,000 random inputs each, 0 mismatches - so the `--!>` terminator and the
"unterminated comment runs to EOF" rule from #1413 are preserved exactly.
resolveTrustedSpecPath treated a failed containment check as permission to
re-root trust on the symlink's own target, on the theory that monorepo
symlinks may be intentional. A repo shipping openspec/specs/<cap> as a link
out of the tree therefore got `openspec archive` to write attacker-controlled
markdown to <external>/spec.md while printing the in-project path. The
fallback root must now still be inside the project, matching retireSpec,
which already refused to delete an external target.
Also: `validate <id> --type spec|change` short-circuited the name guard that
`show` applies, so a traversing id reached a bare path.join; and markTipSeen
wrote the global config through a predictable <config>.<pid>.tmp at default
0644 instead of the repo's existing writeFileAtomically (random name, 0600).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(security): harden subprocess and shell-config write paths
Defense in depth. The audit confirmed there is no shell injection anywhere in
src/ - no `shell: true`, no user value concatenated into a command line - so
none of these are live exploits; they are the sharp edges next to that line.
Completion install wrote the completions directory into .bashrc/.zshrc inside
double quotes, so a `$(...)` or backtick in HOME/XDG_DATA_HOME became command
execution on every future shell start. Both installers now single-quote the
path through a shared helper.
`feedback` shelled out for two probes (`which gh`, `gh auth status`) directly
alongside free-form user title and body text - the most plausible site for a
future injection regression. Both are execFileSync now, behavior unchanged.
Git subprocesses inherited the default 1 MB maxBuffer with no timeout, so a
large dirty tree made `git status --porcelain` throw ENOBUFS, which gitProbe's
bare catch turned into "no git facts" - `openspec doctor` then silently stopped
reporting uncommitted changes. They now share GIT_EXEC_OPTIONS (15s timeout,
16 MB buffer) the way readCliVersion already did, and the catch distinguishes
a resource failure from "git absent" so the degraded path is no longer silent.
The GITHUB_OUTPUT heredoc in validate-changesets used a fixed EOF delimiter
over a list of PR-authored paths; it is now run-unique.
Finally, both package.json files still carried a `pnpm` block. pnpm 10 uses
that block *instead of* pnpm-workspace.yaml rather than merging with it, which
is exactly the override-displacement trap dependabot.yml documents as #1812 -
and it is where Dependabot writes when it bumps an overridden package. The
block only duplicated `allowBuilds`, so removing it leaves both lockfiles
byte-identical with every advisory override intact, and denies Dependabot the
block to write into. The workspace test now asserts `pnpm` is absent entirely.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(security): pin the update check to TLS and honor telemetry opt-out
The update check asked whatever `npm_config_registry` named, over any
protocol. A code comment asserted that file contents deliberately cannot
choose the destination; that was not true. npm exports every config source it
reads, including a `registry=` line in a repository-local .npmrc that travels
with a clone - reproduced: `registry=http://169.254.169.254/` came straight
through `npm run`.
That is a cleartext GET at an address of the repository's choosing, and it
escalates. The attacker's reply says `{"version":"99.0.0"}`, which triggers
the upgrade prompt whose default is Yes; accepting runs `npm install -g`,
which npm resolves against that same attacker registry. Cloning a repository
and answering one prompt installs an attacker-chosen global package.
Both halves are now closed. The registry override is honored only over https,
falling back to the public registry otherwise, and canSelfUpgrade() refuses
when the resolved registry is not the public origin - a private mirror can
still inform the check but can never drive an install prompt. Redirects must
stay https and on the origin resolved up front, not merely the previous hop,
so no single reply can steer the request elsewhere. The comment now describes
what the code actually guarantees.
Separately, the opt-out env vars were exact-string matches, so DO_NOT_TRACK=true
and OPENSPEC_TELEMETRY=false both silently left telemetry ON - the spellings a
user is most likely to reach for, and inconsistent with the tolerant
isCiEnvironment() helper beside them. Parsing is now tolerant, shared between
both call sites, and fails safe: an unparseable value suppresses the request.
The first --json run also sent an event before the disclosure was ever shown -
the notice is correctly deferred so it cannot corrupt machine-readable output,
but trackCommand fired regardless, and agent-driven --json may be a user's only
mode. No event is sent and no anonymous id is created until the notice has
actually been printed.
No existing guard was weakened: the 256 KB body cap, 3-redirect cap, single
budget timer, strict version regex, argv-based spawn, CI/test guards and the
four-field payload are untouched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(security): make the close-tag escape linear
CodeQL js/polynomial-redos on the escape added in
|
||
|
|
3b8e5b6616 |
fix(nix): install shell completions with the flake package (#1785)
* fix(nix): install shell completions with the flake package The flake exposed `openspec completion generate SHELL` but installed no completion scripts, so a Nix install had no completions at the standard locations. Generate the Bash, Fish, and Zsh scripts during postInstall and place them with installShellCompletion. Closes #1740 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs: note that cross-compiled Nix builds omit completions Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * ci: run the Nix job when the completion generator changes The Nix build now runs `openspec completion generate`, so a change under src/core/completions can break packaging without touching flake.nix. Also drops the cross-compilation caveat from the Nix install docs: every package this flake exposes is native (`legacyPackages.<system>` has buildPlatform == hostPlatform), so `canExecute` is always true and the completions are never omitted. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs: move the Nix completions note to the canonical pages docs-lab/README.md makes docs-lab/ canonical and the old docs/ tree legacy, so the fact is recorded in the two docs-lab pages that own it and docs/cli.md and docs/installation.md are back to their state on main. - docs-lab/start/installation.md, Nix: the package ships the scripts at the standard locations, so completion install is not needed. - docs-lab/reference/cli.md, openspec completion: the same exception, stated where a reader looking up the command will hit it, linking to the Nix section rather than repeating the paths. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
6981c84df0 |
chore(deps): bump zod to 4.5.4 and eslint to 10.9.1 (#1814)
Consolidates the two open root-lockfile dependabot bumps (#1810, #1811) into one PR so the pinned flake.nix pnpmDeps hash only has to be regenerated once. Co-authored-by: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
3281f1f068 |
fix(deps): patch js-yaml and nanoid advisories via pnpm overrides (#1635)
Resolve all three open Dependabot alerts (all high severity): - GHSA-5p4m-2wfm-xmqj — js-yaml quadratic-CPU !!omap DoS (#96, #97). Root tree carried js-yaml 3.15.0 (via read-yaml-file) and 4.3.0 (via @changesets/parse). Dev-only; never in the published CLI, which uses `yaml`, not `js-yaml`. Pinned to >=3.15.1 / >=4.3.1. - GHSA-2v37-7h3g-55p8 / CVE-2026-67213 — nanoid size=0 infinite loop (#99). Present in both root (dev, via postcss<-vitest) and website (build-time, via postcss<-next) trees. Pinned to >=3.3.17 (resolves to 3.3.18). Overrides added to all four override surfaces (pnpm-workspace.yaml + package.json, root and website) to keep them in sync, each YAML entry annotated with its advisory id and removal condition. flake.nix pnpmDeps FOD hash regenerated for the root lockfile change (verified via nix build; hash-mismatch-count 0). dependabot.yml gains a note documenting the two surfaces Dependabot cannot manage (pnpm overrides + the Nix flake). Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
4b114aade9 |
chore(deps-dev): bump development-dependencies group + refresh flake hash (#1633)
* chore(deps-dev): bump development-dependencies group + refresh flake pnpmDeps hash Supersedes #1630. Dependabot's PR bumps two dev dependencies within their existing package.json semver ranges (eslint 10.8.0 -> 10.8.1, typescript-eslint 8.65.0 -> 8.66.0), touching only pnpm-lock.yaml. That lockfile change invalidates the flake's fixed-output pnpmDeps.hash, so #1630 fails Nix Flake Validation ("pnpm failed to install dependencies"). Dependabot cannot update the Nix FOD hash, so this PR carries the same bump together with the refreshed hash. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(nix): set pnpmDeps hash for updated lockfile Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
3e50944fb0 |
fix(build): allow esbuild install scripts (#1196)
* Add pnpm-workspace.yaml to allow esbuild build scripts pnpm 10+ blocks all dependency build scripts by default unless explicitly approved via allowBuilds or onlyBuiltDependencies in pnpm-workspace.yaml. esbuild (transitive dependency of vitest -> vite) has a postinstall script that downloads a platform-specific native binary. Without this config, pnpm install exits non-zero with [ERR_PNPM_IGNORED_BUILDS], breaking any downstream packaging (AUR, Nix, Docker) or local setup using pnpm >=10. Refs: #1195 * fix(build): declare pnpm workspace root * fix(build): harden pnpm workspace policies --------- Co-authored-by: Clay Good <hi@claygood.com> |
||
|
|
02b124e6b6 |
fix(security): patch fast-uri, postcss, and brace-expansion advisories (#1510)
* fix(security): patch fast-uri, postcss, and brace-expansion advisories Resolve the two open Dependabot alerts plus a third high-severity advisory the repo's own audit surfaces but Dependabot had not filed, all via version-ranged pnpm overrides (they lapse once the upstream tree moves past them): - fast-uri 3.1.4 -> 3.1.5 (website): GHSA-7p8r-x3mc-p8w7, high. Host confusion via backslash authority introducer. Pulled in transitively by ajv@8.18.0; bounded to ^3.1.5 so it stays on the 3.x line ajv expects. - postcss 8.5.22 -> 8.5.25 (root): GHSA-fxqj-rqcc-2cmp, moderate. Arbitrary .map file read via attacker-controlled sourceMappingURL. Pulled in by vite (dev/test tooling). - brace-expansion 5.0.8 -> 5.0.9 (website): GHSA-rgw5-rvv9-x895, high. DoS via unbounded recursion. The existing override capped at >=5.0.8, and 5.0.8 is itself vulnerable under this newer advisory; the root already resolved to 5.0.9. Root and website audits are clean at --audit-level high (and any-severity for the website). Full test suite: 3662 passing. * harden(security): bound overrides, scope release perms, add website lockfile drift check, document archive TOCTOU intent Hardening pass over the security fixes, from a parallel review of the dependency, CI, archive, and adjacent-code surfaces. Each item is low-risk and verified; resolved dependency versions are unchanged. - deps: bound the three security overrides to their current major (brace-expansion ">=5.0.9 <6", postcss ">=8.5.23 <9"). A bare ">=X" pin would take a future major on the next lockfile regen without review; the website already models the caret-bounded idiom. - ci: scope release-prepare.yml permissions per job. The top-level block dropped "pull-requests: write"; only the "prepare" job (which opens the Version Packages PR) now holds it. The "beta" job only tags/releases and publishes via OIDC, so it inherits the narrower default (least privilege). - ci: add a "Website Lockfile Drift" job to security.yml. The website keeps its own lockfile and is never installed in CI, so a website override that stops resolving would go unnoticed and `pnpm audit` would scan a stale graph. A `pnpm install --frozen-lockfile --ignore-scripts --dir website` fails fast on that drift (root drift is already caught in ci.yml). - archive: add intent comments at the 7 js/file-system-race sites in src/core/archive.ts. The stat->read->re-stat pattern is a deliberate concurrent-change detector; the comments record why, so no future refactor (human or scanner-driven) collapses it to fd I/O and blinds the guard. Verified: 3662 tests pass, build clean, website build clean, root+website audits clean at --audit-level high, and the new frozen-lockfile check passes locally. * chore(nix): refresh pnpmDeps hash for the lockfile change The root pnpm-lock.yaml changed (postcss + brace-expansion overrides), which stales the fixed-output pnpmDeps hash and fails Nix Flake Validation. Repin to the value CI computed from the new lockfile. |
||
|
|
23c2787789 |
chore(deps-dev): bump eslint from 10.7.0 to 10.8.0 in the development-dependencies group (#1494)
* 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.7.0 to 10.8.0 - [Release notes](https://github.com/eslint/eslint/releases) - [Commits](https://github.com/eslint/eslint/compare/v10.7.0...v10.8.0) --- updated-dependencies: - dependency-name: eslint dependency-version: 10.8.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: development-dependencies ... Signed-off-by: dependabot[bot] <support@github.com> * 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> |
||
|
|
87312900f5 |
fix(telemetry): send the usage event directly instead of via posthog-node (#1476)
* fix(telemetry): send the usage event directly instead of via posthog-node Installing OpenSpec shipped posthog-node's transitive tree (@posthog/core, @posthog/types) to every consumer. Those packages release several times a day, so any freshly resolved install tripped supply-chain age policies — pnpm's minimumReleaseAge failed with ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION on entries younger than the policy window (#1390). No pinning fixes this: exact-pinning posthog-node leaves its own ranges floating, npm overrides only apply at a consumer's root, pnpm ignores a dependency's npm-shrinkwrap, and bundledDependencies under a pnpm-managed node_modules packs the virtual-store layout and breaks module resolution (verified: the bundled CLI crashes on import). The SDK's only remaining job here was the wire format: the client was already configured to send one event immediately, time-bounded, with no retries, through an injected fetch that never throws. Post the same capture payload to the same /batch/ endpoint with that fetch directly. Same event name, properties, distinct id, and opt-out guards; shutdown still flushes in-flight events, each bounded by the request timeout. Verified end to end: the packed tarball contains zero posthog files, a pnpm consumer with minimumReleaseAge: 1440 installs cleanly with zero posthog lockfile entries, and the live endpoint answers 200 OK to the new payload. Regression tests pin the manifest and src free of posthog. Fixes #1390 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * build(nix): update the pnpm deps hash for the posthog-node removal Value taken from the CI mismatch report. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(telemetry): dispose the response body so no socket outlives shutdown undici keeps the connection occupied until the response body is consumed or canceled, and telemetry never reads it — on both the success and non-2xx paths the socket could linger after shutdown() returned. Cancel the body before the tracked promise resolves, with coverage for both paths (bodyUsed asserted after shutdown), and the live endpoint re-verified with disposal in place. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
17af60c66e |
fix(archive): make the scenario-drift check fence-aware, plus release-audit follow-ups (#1475)
* fix(archive): make the scenario-drift check fence-aware parseScenarioBlocks matched #### Scenario: headers on raw lines while the validator's countScenarios masks fenced code blocks (#1151). The drift check (#1391) inherited the raw scan, so a fenced scenario example in the current spec aborted an archive that validate had passed, and a fenced name in the MODIFIED block counted as keeping a scenario the block had actually dropped. Build the shared code-fence mask and skip masked lines in both the header scan and the block-end scan. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(update): tear down the redirected request when the budget expires The overall request budget was armed inside the first send() and its callback closed over that hop's request. After a redirect the timer destroyed the already-dead first request, so a redirect target that trickled bytes kept resetting its idle timeout and held the socket open until the body-size cap. Track the in-flight request and have the budget timer destroy whichever one is open. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * chore(release): add changesets for user-facing changes missing from the 1.7.0 notes 18 feat/fix commits merged since v1.6.0 without a changeset, so the pending Version Packages PR would have released them silently: five tool integrations (ZCode, Hermes, CodeArts, Kimi Code rename, Codex skills-only), skills.sh distribution, symlinked schema dirs, nested spec discovery, drift multiplicity, checkbox markers, Windows welcome input, npx avoidance, doctor store drift, local dates, missing-core-workflows warning, store-aware main specs, open-questions guidance, and spec content guidance. Plus changesets for this branch's two fixes. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(adapters): escape TOML-active characters in Gemini command files The gemini adapter interpolated the description into a TOML basic string and the body into a multiline basic string with no escaping. Every current template value happens to be safe; the first description with a double quote or backslash would silently produce invalid TOML for all Gemini command files. Escape both contexts (#1447 fixed the same class for the YAML adapters but scoped itself to YAML). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(update): harden install detection and redirect handling Three follow-ups from the release audit: - A path segment literally named volta (a user or project directory) classified the install as volta-managed and swallowed the upgrade offer. The undotted spelling now requires volta's own tools/image layout, matching how pnpm and yarn already demand corroboration. - The Windows npm-ownership fallback checked that the npm prefix exists, which is true of any X\node_modules\pkg tree, hand-copied ones included. Corroborate with the openspec.cmd shim npm actually writes. - A https registry redirecting to plain http was followed; a MITM on that reply controls the newer-version answer. Refuse the downgrade. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * chore(cli): export zcodeAdapter from the barrel and sync a completion description zcode was registered but missing from the adapters barrel (its test imported the module directly), and the completion registry still carried the pre-#1062 description for the instructions command. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(parser): strip a UTF-8 BOM before parsing specs and deltas A BOM-prefixed delta spec (Windows editors, PowerShell Out-File) failed validate and archive with 'No delta sections found' because the first line never matched '## ADDED Requirements'. Strip the BOM in both normalizers, the same way tool detection already does. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(cli): reject over-long change names with a validation message A 300-character change name surfaced two raw ENAMETOOLONG errno dumps from stat and mkdir. Bound the name at 200 characters in validateChangeName so the failure is a normal validation error. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(archive): finish the early-sync no-op rules for MODIFIED and RENAMED Two asymmetries left over from the #1376/#1386/#1437 no-op work: - MODIFIED counted every delta as applied even when the block was byte-equal to the main spec, so a fully early-synced change rewrote the file (normalization churn), printed '~ N modified', and reported specsUpdated: true where its ADDED/REMOVED/RENAMED twins print 'Specs already in sync; no files changed.' Count only real replacements. - RENAMED's already-synced skip (source gone, target present) had no near-miss guard: a case/whitespace variant of the source still in the spec means a typo'd header, and REMOVED already hard-aborts on that signal. Apply the same guard, excluding the target itself so a case-only rename still no-ops. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(validate): stop reporting an unreadable specs dir as 'no deltas' The delta-validation loop swallowed every error as 'if no specs dir, treat as no deltas', so an EACCES capability folder produced the misleading 'Change must have at least one delta' while archive let the same error propagate. Tolerate only ENOENT and ENOTDIR (a stray specs file); anything else stays loud, matching discoverSpecFiles' documented fail-loud contract. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(update): say when commands-only delivery leaves a tool with nothing Under delivery: commands, update removed the skills of adapterless skills-only tools (Hermes, Kimi Code, Vibe, CodeArts, ForgeCode) without a word — leaving zero OpenSpec artifacts while the tool's detection dir kept re-suggesting an init that would also generate nothing. Print the same per-tool configuration correction init already prints, pointing at 'openspec config set delivery both'. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(completion): honor $ZSH and $ZSH_CUSTOM for Oh My Zsh installs The installer used a set $ZSH only as an is-installed signal and then wrote to ~/.oh-my-zsh regardless, so a custom OMZ location got a freshly created ~/.oh-my-zsh tree that no shell ever loads — and isInstalled/uninstall looked in the same wrong place. Route every path through the $ZSH/$ZSH_CUSTOM-aware helpers. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(init): make the static welcome screen wait for the Enter it asks for The static branch printed 'Press Enter to select tools...' and returned immediately, so the Enter landed in the tool picker and submitted the pre-selected set sight-unseen. #1462 routed reduced-motion, OPENSPEC_NO_ANIMATION, --no-animation, NO_COLOR, and narrow-terminal users onto this path. Wait in a TTY; drop the prompt line when there is no TTY to wait on. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(feedback): keep the manual fallback on every gh failure Only missing-gh and unauthenticated flows showed the formatted feedback and pre-filled submission URL; issues-disabled, network, or rate-limit failures printed gh's stderr and discarded the path to submit what the user had already typed. Route those through the same manual fallback, preserving gh's exit code. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * test(update): model the npm shim in the Windows prefix fixture The ownership corroboration now checks for the openspec.cmd shim npm writes beside node_modules; the Homebrew-prefix fixture built the layout without it, so the test failed on windows-pwsh. Write the shim in the fixture and pin the inverse: the same shape with nothing npm wrote (a hand-copied portable tree) is not an npm install. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(update): require volta's full tools/image layout for the undotted spelling The corroboration used has('tools', 'image'), which is some() — volta AND (tools OR image) — so /srv/volta/tools/apps/... still classified as a Volta install and swallowed the upgrade offer. Require both segments, matching the real %LOCALAPPDATA%\Volta\tools\image layout. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(adapters): escape control characters in Gemini multiline prompts escapeTomlMultilineBasicString handled backslashes and quote-triples but not the C0 controls that are as invalid in a multiline basic string as in a single-line one. Reuse TOML_CONTROL_CHARS, applied last so the escapes it introduces are not re-doubled. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(completion): finish the $ZSH_CUSTOM support and isolate it in tests The fpath verification advice still grepped the literal custom/completions, which a relocated $ZSH_CUSTOM need never contain — grep the actual directory instead. The installer tests cleared only $ZSH, so on a machine exporting $ZSH_CUSTOM they would have written into (and deleted from) the developer's real OMZ custom dir — the same leakage class #1400 fixed for $ZSH. Clear/restore both, and pin the custom-location paths with two new tests. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * chore(release): correct the hermes and zcode changeset wording Hermes is skills-only (no command adapter), and zcode's namespaced commands register /opsx:<id>, not /opsx-* — the release notes must not reintroduce the invocation-spelling confusion #1471 removed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * test(feedback): pin the manual fallback on a non-label gh failure The new reportGhFailure output (formatted feedback + pre-filled URL) had no coverage; the network-failure test now asserts it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(completion): match fpath entries as literal strings in the OMZ guidance The verification advice interpolated the completions dir into grep "<dir>" where regex metacharacters make the check unreliable and quotes could break the displayed command. Print one fpath entry per line and match with grep -F on a shell-quoted literal. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(adapters): never emit a bare carriage return in Gemini TOML prompts A lone CR is illegal in a multiline basic string — Python 3.13 tomllib rejects the file — and the control-char pass deliberately skipped it on the assumption it only appears as CRLF. Normalize CRLF to LF and escape any remaining CR as \r. The escaping guarantee is now parser-backed: smol-toml (new devDependency) round-trips every hostile body in the regression matrix (lone CR, CRLF, CR before a quote run, NUL/VT/FF, trailing backslash, four- and five-quote runs), and the same outputs were verified against Python tomllib. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * build(nix): update the pnpm deps hash for the smol-toml devDependency The lockfile changed, so the fixed-output derivation hash moved; value taken from the CI mismatch report. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
05c701970a |
chore(security): override brace-expansion to fix the failing audit (#1461)
* chore(security): override brace-expansion to fix the failing audit A new advisory (GHSA-mh99-v99m-4gvg, high) flags brace-expansion <= 5.0.7 with the only patched release being 5.0.8. The scheduled Security workflow has failed on every run since 2026-07-27. pnpm audit --fix adds a scoped override in both the root and website packages; the lockfile diffs touch only brace-expansion and its subtree. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * chore(nix): blank pnpmDeps hash to surface the new lockfile hash Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * chore(nix): pin pnpmDeps hash for the updated lockfile Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
abb422a04b |
chore(deps): consolidate dependabot bumps with flake hash update (#1457)
* chore(deps): consolidate dependabot bumps (typescript 6, @types/node 26, ora 9, commander, posthog-node) Replaces #1448, #1451, #1452 and #1453 with a single lockfile resolution. Each of those PRs changed pnpm-lock.yaml, so merging them serially would invalidate the flake.nix pnpmDeps hash four times over. - typescript 5.9.3 -> 6.0.3 (#1452) - @types/node 24.2.0 -> 26.x (#1451) - ora 8.2.0 -> 9.4.1 (#1453) - commander 14.0.0 -> 14.0.3, posthog-node 5.46.0 -> 5.46.1 (#1448, lockfile only) #1450 (@inquirer/prompts 8) is deliberately excluded: it needs a code migration, not a version bump. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * chore(nix): update pnpmDeps hash for bumped lockfile Hash taken from this PR's first Nix Flake Validation run. Note it differs from the hash any individual dependabot PR would have produced -- the combined lockfile resolves to its own content hash. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * chore(deps): align @types/node with the Node 20.19 runtime floor Addresses review feedback: compiling against Node 26 declarations lets the type checker admit APIs that are unavailable on the runtimes OpenSpec actually supports (engines: node >=20.19.0). Pins @types/node to ^20.19.43, the latest release in the line matching the declared floor. This also corrects a pre-existing drift -- main was on @types/node 24 against the same 20.19 floor, so the types were already ahead of the supported runtime before this PR. Verified: build clean, tsc --noEmit clean, eslint clean, 112 files / 2253 tests passing, dist/ emit byte-identical to origin/main, and no peer dependency warnings. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * chore(nix): update pnpmDeps hash for the realigned lockfile The @types/node downgrade to the 20.19 line changed the dependency set again (it pulls undici-types 6.21.0), so the previous hash no longer matches. Value taken from a forced-mismatch Nix run on this branch. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
5406c8b3ff |
chore(deps): consolidate dependabot bumps with flake hash update (#1427)
* chore(deps): consolidate dependabot bumps (chalk, posthog-node, zod, changesets, typescript-eslint, eslint 10) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * chore(nix): update pnpmDeps hash for bumped lockfile Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
e2f748c64f |
chore(security): add security policy, dependabot config, and config key guards (#1415)
* chore(security): add security policy, dependabot config, and config key guards Adds a SECURITY.md with a private disclosure path and an explicit threat model, a Dependabot configuration covering the CLI package, the docs site, and CI actions, and closes a prototype-pollution path in `config set`. `--allow-unknown` was meant to relax the known-key check but skipped every key check, so `openspec config set --allow-unknown __proto__.polluted x` reported success and assigned onto Object.prototype for the process lifetime. Unsafe segments are now rejected at the command layer regardless of `--allow-unknown`, and setNestedValue/deleteNestedValue refuse them for any caller. Also bumps the bundled yaml dependency from 2.8.2 to 2.9.0, the only advisory in this repo that affects code shipped in the npm package. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(nix): update pnpmDeps hash for the yaml bump fetchPnpmDeps pins a fixed-output hash over the whole dependency set, so changing pnpm-lock.yaml invalidates it. Recovered the new value from a hash-mismatch build. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(security): clear dependency advisories and automate future checks Refreshes both lockfiles so every open advisory in the CLI package is resolved, replaces a quadratically-backtracking heading parser, and adds the automation to catch the next one. Dependency refresh (in-range, lockfile only): brace-expansion, flatted, js-yaml, minimatch, postcss, rollup, and vite all move to patched versions in the root lockfile; fast-uri and brace-expansion move in the website lockfile. Only @changesets/cli needed a declared floor bump, to reach a patched js-yaml. Production dependencies now report zero advisories. extractFirstPurposeLine parsed ATX headings with /\s+#+\s*$/, which backtracks quadratically on a whitespace-padded title. Replaced with a linear hand-rolled scan, verified identical to the old implementation across 303,000 generated inputs. Automation: a Security workflow runs dependency review on pull requests, blocks on advisories in published dependencies, and re-audits weekly; every GitHub Action is pinned to a commit SHA so a moved tag cannot change what CI executes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(ci): drop the pnpm cache from the audit job Nothing is installed there, so setup-node's cache-save post step failed on the missing store path even though both audit steps passed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(nix): repin pnpmDeps hash after the dependency refresh Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(security): apply opengrep findings and fix a dependency-review permission gap Ran opengrep against the repository to check the claims in #1414. Of 208 findings, 201 are one path-traversal rule firing on joins built from module constants, argv, or readdir entry names; 1 non-literal-regexp is fed only by LEGACY_SLASH_COMMAND_PATHS. Neither is reachable from untrusted input. The actionable results are applied here. - dependabot: add a cooldown so a freshly published version is not adopted immediately. Security updates ignore the cooldown, so this delays only routine bumps, long enough for a compromised release to be yanked. - getNestedValue now refuses prototype-reaching segments, matching the guards already on setNestedValue and deleteNestedValue. - dependency-review no longer asks to comment on the pull request. That needs `pull-requests: write`, which the workflow does not grant and a fork's token never gets, so a real finding would have failed on the comment instead of reporting the vulnerable dependency. - SECURITY.md: show the command that proves build tooling is absent from an installed copy, rather than asking readers to take it on trust. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(dependabot): drop semver cooldown keys unsupported by github-actions Dependabot rejected the whole config file, which would have silently disabled every version update. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(security): make the audit advisory and document runtime behavior The published-dependency audit no longer fails the job. A newly published advisory should not block an unrelated pull request, and the step depends on registry availability; Dependabot alerts and dependency review remain the gates. SECURITY.md is corrected to match — it claimed the audit was blocking. Also documents what the CLI does on your machine, all verified rather than asserted: the install script prints one line and makes no network request or file write; every shell-invoking call uses a fixed literal while anything carrying user input uses an argument array with shell:false; telemetry sends a command name, a version, and a local random UUID, with IP capture disabled. Secret scanning is now listed, confirmed enabled by a repository admin. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(ci): keep the production audit blocking off pull requests Making the step advisory on every event meant a newly published high-severity advisory in a shipped dependency could not fail any run unless a dependency changed. It stays advisory on pull requests, so an unrelated change is never blocked by an advisory published that morning, and blocks on the weekly schedule and on pushes to main, where a failure is the signal rather than a tax on someone else's work. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
9d40ae98f0 |
fix(nix): build with Node.js 22 now that nixpkgs marks Node 20 insecure (#1406)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
737518b36f |
[codex] Refresh security dependency locks (#1249)
* fix: refresh security dependency locks * fix: refresh nix pnpm dependency hash |
||
|
|
86d2e04cae |
chore(nix): improve flake with dynamic version and build optimization (#550)
* chore(nix): improve flake with dynamic version and source filtering - Read version dynamically from package.json instead of hardcoding - Add lib.fileset source filtering to exclude node_modules and build artifacts - Update update-flake.sh to support dynamic version pattern - Add hash change detection to skip unnecessary rebuilds - Improve error handling with automatic rollback on failure - Update specs to reflect dynamic version behavior * chore(ci): bump Nix actions to latest versions - nix-installer-action: v13 → v21 - magic-nix-cache-action: v8 → v13 - Update validation message for unchanged flake.nix * chore: add changeset for Nix improvements * fix(nix): make update-flake.sh portable to macOS - Fix grep pattern on line 37 to include opening parenthesis - Replace GNU grep -oP with portable sed alternatives (lines 53, 68, 70) - Ensures script works on both Linux and macOS (BSD sed/grep) * fix(nix): properly check build verification exit status Fix logic bug where build failures were incorrectly reported as success. The script now: - Captures build exit code and output separately - Fails fast if build returns non-zero exit code - Only checks for 'dirty tree' warning if build succeeded This addresses CodeRabbit review feedback on line 101-107. --------- Co-authored-by: Tabish Bidiwale <30385142+TabishB@users.noreply.github.com> |
||
|
|
ae83b4e16d |
feat(cli): add interactive UI for artifact experimental setup (#560)
* feat(cli): add interactive UI for artifact experimental setup Add animated welcome screen and searchable multi-select prompt when running `openspec artifact-experimental-setup` without the --tool flag in interactive mode. Users can now browse and select multiple tools for setup instead of requiring the --tool flag. - Add welcome screen with ASCII art animation - Add searchable multi-select prompt component - Support multi-tool setup in single command invocation * fix(nix): update flake version and reset hash for rebuild - Update version from 0.20.0 to 0.23.0 to match package.json - Set pnpmDeps hash to empty string to trigger rebuild - Fix update-flake.sh to work on macOS (use portable grep/sed) CI will fail with correct hash which we'll then apply. * fix(nix): set correct pnpmDeps hash * feat(cli): improve error handling for multi-tool setup - Continue setup for remaining tools when one fails - Collect and report all failures at the end - Only throw if all tools fail - Show partial success summary (configured vs failed) |
||
|
|
ed4d965208 |
feat: add nix flake support (sorry for this duplicate) (#459)
* add nix flake support * feat: add Nix flake maintenance automation * Add Nix Flake CI Validation * fix updatescript, update flake * make update-script compatible with macos --------- Co-authored-by: Tabish Bidiwale <30385142+TabishB@users.noreply.github.com> |