Commit Graph
9 Commits
Author SHA1 Message Date
Clay GoodandClaude Opus 4.8 ffe27de18d chore(scripts): add a parity-hash regeneration helper (#1416)
skill-templates-parity.test.ts pins a SHA-256 per workflow template so an
unintended template edit fails loudly. The cost lands on every intended
edit: the pinned hashes go stale, and because all 37 live in two maps in
one file, two branches editing different templates collide there on rebase.
Resolving that means hand-editing 64-character hashes, which is where
transcription mistakes come from - and the test proves a hash matches its
source, never that the source is right, so a bad value regenerated over a
bad merge passes CI in silence.

Recompute every pinned hash from the built dist/ and rewrite the map in
place, reporting which entries moved. The skill-directory mapping comes
from getSkillTemplates(), the same helper the skills.sh generator uses, so
adding a workflow needs no second list here; function labels resolve
dynamically against the module exports, so there is no hard-coded list at
all.

"Nothing to update" has to mean it, so four things abort the run without
writing:
  - dist/ missing or older than src/, which would pin hashes from a stale
    build that the parity test - which reads src/ - then rejects
  - a pinned label with no matching export, from a renamed or deleted
    template
  - a pinned hash whose line the patterns do not recognise, counted by
    comparing 64-hex literals found against literals rewritten; the count
    uses a deliberately broader pattern so it is a real cross-check rather
    than a restatement of the same patterns
  - a skill the registry deploys that nothing pins, compared in the other
    direction: pins-to-registry only sees pins that already exist

That last direction closes a hole that predates this script. A workflow
added to getSkillTemplates() but never pinned was invisible to the parity
test too, which compares only the entries it already lists - so it shipped
with no golden hash while everything reported success. skill-templates-
parity.test.ts now pins the registry itself, so CI catches it whether or
not anyone runs this script.

The rewriting lives in parity-hash-shared.mjs, following the split between
generate-skillssh.mjs and skillssh-shared.mjs, so those guards can be
exercised against fabricated input. Running the script for real from a test
would rewrite the repository's own parity test file mid-suite. Each case in
parity-hash-shared.test.ts was mutation-checked: removing the guard it
covers makes it fail.

The script cannot silently emit a wrong hash: the parity test recomputes
the same values independently and compares, so a drift between the two
copies of stableStringify fails the test. The test stays the authority.

Dev tooling only. scripts/ is not published (package.json files ships just
scripts/postinstall.js), no src/ is touched, and no runtime behaviour
changes - hence no changeset.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 18:54:13 +00:00
Clay GoodandClaude Fable 5 a84ae70e8c fix(init): use skill references for tools without a command adapter (#1404)
* fix(init): use skill references for tools without a command adapter

Adapterless tools (kimi, vibe, hermes, forgecode, codeartsagent, agents)
skip command generation even under the default 'both' delivery, but their
generated SKILL.md files still told agents to run /opsx:* commands that
were never created, and the init summary suggested /opsx:propose. Route
the existing skill-reference transform by command-surface capability so
these tools get /openspec-* references, and point the getting-started
hint at the skill when no selected tool got commands.

Fixes #1155

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

* fix(init): address adversarial review findings for adapterless skill references

- transform the committed skills.sh distribution too: pass
  transformToSkillReferences in generate-skillssh.mjs and the parity
  test, regenerate skills/ (that channel installs SKILL.md files only,
  so /opsx:* commands never exist there)
- key the getting-started hint purely on whether any selected tool got
  commands, so the delivery=commands + adapterless corner can no longer
  print /opsx:propose
- make the one-time profile-migration message capability-aware for
  projects whose detected tools have no command adapter
- import CommandSurfaceCapability type-only instead of duplicating the
  union inline (a value import would close a module cycle)
- cover the update path: the kimi migration test now asserts refreshed
  skills contain no /opsx references

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

* fix(init): honor Kimi Code's documented /skill: invocation syntax

Per review: the blanket /openspec-* rewrite contradicted Kimi's
documented invocation contract (/skill:openspec-*, see
docs/supported-tools.md). Skill-reference transforms are now selected
per tool via getSkillReferenceTransformer, with Kimi mapped to
/skill:<name> and every other tool keeping the documented /<name>
form; the getting-started hint and migration message use the same
per-tool syntax. End-to-end Kimi assertions cover generated skill
content, the refreshed update path, and the hint.

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

* fix(init): gate the getting-started hint on a generated surface

Per review: with delivery=commands and only adapterless tools selected,
init generated neither skills nor commands yet still advertised an
invocation. Print a configuration correction instead, with the exact
'openspec config set delivery both' remedy, covered by an end-to-end
commands-only adapterless test. Also from the adversarial review round:
mixed selections that disagree on invocation syntax (kimi + vibe) now
fall back to the default /openspec-* form in the shared hint and
migration message instead of picking the first tool's syntax; add the
missing changeset; correct the codex doc comment.

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

* fix(init): suppress the restart hint when no surface was generated

From the third adversarial review round: the 'Restart your IDE for
slash commands' line printed directly after the message saying nothing
was generated. Gate it on an actually generated surface and pin that in
the commands-only adapterless test. Also: use randomUUID() for init
test temp dirs (matches update.test.ts, removes a theoretical Date.now
collision), and clarify the changeset wording about the skills.sh
channel's default reference form.

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

* fix(init): print one usable getting-started hint per invocation syntax

Per review: the mixed-syntax fallback advertised /openspec-propose,
which Mistral Vibe accepts but Kimi Code does not. Group successful
tools by their transformed reference and print one labeled hint line
per distinct form, so every advertised instruction is usable by the
tool it names; the mixed-tool test asserts exactly that. The migration
message compares transformed outputs instead of function identities
(also per review) and stays syntax-neutral ('the openspec-propose
skill') when detected tools disagree.

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

* fix(init): keep codex hints syntax-neutral (skills-invocable, no slash surface)

Codex has no slash-command surface: docs direct users to
.codex/skills/openspec-*. The getting-started hint and the one-time
migration message now name the skill ('the openspec-propose skill')
instead of advertising a /openspec-* form Codex does not accept, and the
restart line only claims slash commands when commands were generated.

Hint lines are also limited to tools that actually got skills: under
delivery=commands, codex+kimi previously advertised /skill:openspec-propose
for Kimi while .kimi-code was never created.

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

* fix(init): advertise a usable instruction for every configured tool

Adversarial-review round fixes:

- Mixed adapter-backed + skill-only selections (claude+kimi, claude+codex)
  printed a single unlabeled /opsx:propose hint that the skill-only tool
  cannot use; hints are now derived per tool from its generated surface
  and labeled when the selection disagrees.
- The delivery=commands configuration correction keyed on the global
  aggregate, so a tool that got zero artifacts lost its correction as
  soon as any other tool generated something; it is now per-tool.
- The migration message advertised /opsx:propose under an explicit
  'delivery: skills' config where commands will never exist; the command
  form is now gated on the effective delivery.
- Migration-message coverage extended (kimi, codex+kimi, delivery=skills,
  commands-installed); profile-describe init tests use randomUUID temp
  dirs like the first describe block.

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

* fix(update): derive migration and legacy-upgrade references per tool surface

The one-time migration message collapsed mixed command + skill-only
selections to /opsx:propose (Claude commands + a Kimi skill told the
Kimi user to run a command it cannot invoke); the reference is now
computed per detected tool and falls back to the syntax-neutral form on
disagreement. The legacy-upgrade getting-started menu had the same
capability blindness with hard-coded /opsx:new/continue/apply — a legacy
Codex upgrade advertised commands Codex lost in #1283; menu lines are
now derived the same way (byte-identical for command-tool upgrades).

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

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-22 13:53:49 +00:00
Clay GoodandClaude Fable 5 46a4d78222 feat(skills): publish workflow skills to skills.sh (#1357)
* feat(skills): publish workflow skills to skills.sh

Commit the 12 OpenSpec workflow skills as static skills/<name>/SKILL.md so
`npx skills add Fission-AI/OpenSpec` can install them (skills.sh reads static
files from the repo; OpenSpec otherwise only generates skills at init time).

Files are generated from the existing templates via `pnpm generate:skills`,
not hand-copied, and skillssh-parity.test.ts fails CI if a template changes
without regenerating. The volatile generatedBy frontmatter line is stripped so
the committed copies stay byte-stable across releases.

Closes #1258

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

* fix(skills): force LF on committed skills/ so Windows CI parity holds

The skills.sh distribution files are generated LF-only and compared
byte-for-byte by skillssh-parity.test.ts. Windows autocrlf checked them
out as CRLF, failing the parity assertion. A scoped .gitattributes pins
them to LF on checkout.

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

* fix(skills): reject symlinks and assert the exact committed skill set

Review feedback (alfred): the parity test only visited expected templates,
so an extra or renamed skills/ directory shipped with green CI, and the
generator would write through a pre-existing symlinked skill directory to
anywhere on disk.

- generator: refuse to run if skills/ contains any symlink (checked before
  any deletion, so a bad tree is left intact), validate dirNames against a
  path-segment allowlist, and lstat the target before writing.
- parity test: assert skills/ holds exactly README.md plus one real
  directory per template, each containing a single real SKILL.md.
- focused tests cover symlink refusal (no partial deletion), traversal
  names, and stale-directory cleanup.

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

* fix(templates): abort archive on Cancel, honest summary, fence languages

CodeRabbit review on #1357, fixed at the template source and regenerated:

- archive-change: choosing "Cancel" at the sync prompt now stops the flow
  instead of archiving anyway (skill + command templates).
- archive-change skill: the success output no longer hardcodes "All
  artifacts complete. All tasks complete." when archiving incomplete work.
- archive/bulk-archive/sync-specs/verify-change: language identifiers on
  previously plain code fences (MD040), skill and command twins alike.

Golden hashes in skill-templates-parity.test.ts recomputed from dist/;
skills/ regenerated via pnpm generate:skills.

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

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-17 21:41:11 +00:00
Tabish Bidiwale 144528257d fix: make completion install opt-in, fix PowerShell encoding corruption (#949)
* fix: make shell completion install opt-in and fix PowerShell profile encoding corruption (#948)

The postinstall hook silently modified users' shell profiles and corrupted
UTF-16 LE PowerShell profiles by forcing all reads/writes through UTF-8.
Now postinstall only prints a tip, and the PowerShell installer preserves
file encoding via BOM detection on read/write.

* Address review: skip profile on any read error, log warnings, clean up UTF-16 BE handling

- configureProfile: skip profile on any non-ENOENT error instead of falling
  through with empty content (could overwrite real profile)
- removeProfileConfig: log warning on unexpected read errors instead of
  silently swallowing
- detectEncoding: throw directly for UTF-16 BE instead of using sentinel value
- Add test for UTF-16 BE profile rejection
2026-04-11 13:58:24 +00:00
Jérôme BenoitandTabish Bidiwale 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>
2026-01-27 14:23:11 -08:00
Tabish Bidiwale 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)
2026-01-22 18:39:38 -08:00
Pim SnelandTabish Bidiwale 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>
2026-01-16 13:00:11 -08:00
1adf3cea88 feature/oh-my-zsh-completions (#289)
* shell completions for zsh

* after code review changes

* expose only postinstall.js script

* Replace _openspec "$@" with compdef in zsh-generator.ts to prevent execution during load

* Update test/commands/completion.test.ts

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* - Fix dispatcher to use $words instead of $line for subcommand routing
  - Add __complete endpoint with tab-separated output for safe parsing
  - Replace brittle awk parsing with __complete in completion helpers
  - Add uninstall confirmation prompt with --yes flag to skip
  - Prefer $ZSH env var for Oh My Zsh detection before dir check
  - Add fpath verification guidance for OMZ installations
  - Update cli-completion spec to document generate subcommand

* improve shell detection and installation handling

  - Return structured result from detectShell() with shell and detected name
  - Detect already-installed completions and skip reinstall
  - Add update detection with automatic backup of previous version
  - Add debug logging to silent catch blocks for diagnostics
  - Quote fpath directories to handle paths with spaces
  - Verify Oh My Zsh fpath configuration and add to .zshrc if needed
  - Show helpful error for detected but unsupported shells
  - Update all tests for new detection API

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Tabish Bidiwale <30385142+TabishB@users.noreply.github.com>
2025-12-12 21:30:40 +11:00
Tabish Bidiwale d070d08aa8 fix: correct CLI version mismatch and add release guard (0.8.1) (#123)
* fix: correct CLI version mismatch and add release guard\n\n- Add patch changeset for 0.8.1\n- Add pack-version check to validate tarball version\n- Update release script to include versioning and guard

* chore(release): simplify release script and harden pack-version-check\n\n- Run pack-version check before publish only\n- Remove redundant changeset version + explicit build in release script\n- Always cleanup temp dir and tgz\n- Quieter, faster npm install during guard

* chore(release): clarify CI vs local release scripts; refine pack guard\n\n- Add scripts: release:ci (no version), release:local (runs changeset version)\n- Workflow uses release:ci to ensure version PR bump precedes publish\n- Pack guard: document npm vs pnpm choice; improve JSON fallback handling
2025-10-08 14:46:15 +11:00