Commit Graph

796 Commits

Author SHA1 Message Date
Copilot
282dd3da56 feat: Integration catalog — discovery, versioning, and community distribution (#2130)
* Initial plan

* feat: add integration catalog system with catalog files, IntegrationCatalog class, list --catalog flag, upgrade command, integration.yml descriptor, and tests

Agent-Logs-Url: https://github.com/github/spec-kit/sessions/bbcd44e8-c69c-4735-adc1-bdf1ce109184

Co-authored-by: mnriem <15701806+mnriem@users.noreply.github.com>

* fix: address PR review feedback

- Replace empty except with cache cleanup in _fetch_single_catalog
- Log teardown failure warning instead of silent pass in upgrade
- Validate catalog_data and integrations are dicts before use
- Catch OSError/UnicodeError in IntegrationDescriptor._load
- Add isinstance checks for integration/requires/provides/commands
- Enforce semver (X.Y.Z) instead of PEP 440 for descriptor versions
- Fix docstring and CONTRIBUTING.md to match actual block-on-modified behavior
- Restore old manifest on upgrade failure for transactional safety

* refactor: address second round of PR review feedback

- Remove dead cache_file/cache_metadata_file attributes from IntegrationCatalog
- Deduplicate non-default catalog warning (show once per process)
- Anchor version regex to reject partial matches like 1.0.0beta
- Fix 'Preserved modified' message to 'Skipped' for accuracy
- Make upgrade transactional: install new files first, then remove stale
  old-only files, so a failed setup leaves old integration intact
- Update CONTRIBUTING.md: speckit_version validates presence only

* Potential fix for pull request finding 'Empty except'

Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>

* fix: address third round of PR review feedback

- Fix CONTRIBUTING.md JSON examples to show full catalog structure with
  schema_version and integrations wrapper
- Wrap cache writes in try/except OSError for read-only project dirs
- Validate _load_catalog_config YAML root is a dict
- Skip non-dict integ_data entries in merged catalog
- Normalize tags to list-of-strings before filtering/searching
- Add path traversal containment check for stale file deletion
- Clarify docstring: lower numeric priority = higher precedence

* fix: address fourth round of PR review feedback

- Remove unused _write_catalog helper from test file
- Fix comment: tests use monkeypatched urlopen, not file:// URLs
- Wrap cache unlink calls in OSError handler
- Add explicit encoding='utf-8' to all cache read_text/write_text calls
- Restore packaging.version.Version for descriptor version validation
  to align with extension/preset validators
- Add missing goose entry to integrations/catalog.json

* fix: remove unused Path import, add comment to empty except

* fix: validate descriptor root is dict, add shared infra to upgrade

- Add isinstance(self.data, dict) check at start of _validate() so
  non-mapping YAML roots raise IntegrationDescriptorError
- Run _install_shared_infra() and ensure_executable_scripts() in
  upgrade command to match install/switch behavior

* fix: address sixth round of PR review feedback

- Validate integration.id/name/version/description are strings
- Catch TypeError in pkg_version.Version() for non-string versions
- Swap validation order: check catalogs type before emptiness
- Isolate TestActiveCatalogs from user ~/.specify/ via monkeypatch

* fix: address seventh round of PR review feedback

- Update docs: version field uses PEP 440, not semver
- Harden search() against non-string author/name/description fields
- Validate requires.speckit_version is a non-empty string
- Validate command name/file are non-empty strings, file is safe relative path
- Handle stale symlinks in upgrade cleanup
- Document catalog configuration stack in README.md

* fix: validate script entries, remove destructive teardown from upgrade rollback

- Validate provides.scripts entries are non-empty strings with safe relative paths
- Remove teardown from upgrade rollback since setup overwrites in-place —
  teardown would delete files that were working before the upgrade

* fix: use consistent resolved root for stale-file cleanup paths

* fix: validate redirect URL and reject drive-qualified paths

- Validate final URL after redirects with _validate_catalog_url()
- Reject paths with Path.drive or Path.anchor for Windows safety
- Update FakeResponse mocks with geturl() method

* fix: fix docstring backticks, assert file modification in upgrade tests

* docs: clarify directory naming convention for hyphenated integration keys

* fix: correct key type hint, isolate all catalog tests from env

- Fix key parameter type to str | None (defaults to None)
- Add HOME/USERPROFILE monkeypatch and clear SPECKIT_INTEGRATION_CATALOG_URL
  in all TestCatalogFetch tests for full environment isolation

* fix: neutralize catalog table title, handle non-dict cache metadata

* fix: validate requires.tools entries in descriptor

* fix: show discovery-only status, clear metadata files in clear_cache

* fix: catch OSError/UnicodeError in cache read path

* refactor: reuse IntegrationManifest.uninstall for stale-file cleanup

* fix: normalize null tools to empty list in descriptor accessor

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: mnriem <15701806+mnriem@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
2026-04-16 08:59:32 -05:00
Quratulain-bilal
e0fd355dad Add Catalog CI extension to community catalog (#2239)
- Adds catalog-ci entry to catalog.community.json (between canon and ci-guard)
- Adds Catalog CI row to community extensions table in README.md
- Bumps top-level updated_at
2026-04-16 08:57:25 -05:00
Aaron Sun
db8131441e Added issues extension (#2194)
* Added issues extension

* Removed duplicate extension

* Renamed extension

* Addressed Copilot comments

---------

Co-authored-by: Aaron Sun <aaronsun@mac.lan>
Co-authored-by: Aaron Sun <aaronsun@Aarons-MacBook-Pro.local>
Co-authored-by: Aaron Sun <aaronsun@Mac.hsd1.wa.comcast.net>
2026-04-16 07:49:15 -05:00
Manfred Riem
752683d347 chore: release 0.7.1, begin 0.7.2.dev0 development (#2235)
* chore: bump version to 0.7.1

* chore: begin 0.7.2.dev0 development

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-15 15:41:23 -05:00
Manfred Riem
9988a46d96 ci: add windows-latest to test matrix (#2233)
* ci: add windows-latest to test matrix

Add windows-latest to the pytest job OS matrix so tests run on both
Ubuntu and Windows for all Python versions.

Closes #2232

* test: skip bash-specific tests on Windows

Add sys.platform skip markers to all test classes and methods that
execute bash scripts via subprocess, so they are skipped on Windows
where bash is not available. Mixed classes with both bash and pwsh
tests have markers on individual bash methods only.

* test: fix 3 Windows-specific test failures

- test_manifest: use platform-appropriate absolute path (C:\ on Windows
  vs /tmp on POSIX) since /tmp is not absolute on Windows
- test_extensions: add agent_scripts.ps entry and platform-conditional
  assertions for codex skill fallback variant test
- test_timestamp_branches: use json.dumps() instead of f-string to
  properly escape Windows backslash paths in feature.json

* test: extract requires_bash marker and fix PS test skip

Address PR review feedback:
- Define a reusable requires_bash marker in conftest.py and use it
  across all 3 test files instead of repeating the skipif inline
- Move test_powershell_scanner_uses_long_tryparse_for_large_prefixes
  into its own TestSequentialBranchPowerShell class so it is not
  incorrectly skipped on Windows by the class-level bash marker

* test: use runtime bash check instead of platform check

Replace sys.platform == 'win32' with an actual bash invocation test
to handle environments where bash exists but is non-functional (e.g.,
WSL stub on Windows without an installed distro).

* test: reject WSL bash, accept only MSYS/MINGW on Windows

On Windows, verify uname -s reports MSYS, MINGW, or CYGWIN so the WSL
launcher (System32\bash.exe) is rejected — it cannot handle native
Windows paths used by test fixtures. Add SPECKIT_TEST_BASH=1 env var
escape hatch to force-enable bash tests in non-standard setups.

* ci: add comment explaining Windows bash test behavior

* test: early-reject WSL launcher, fix remaining f-string JSON

- Check resolved bash path for System32 before spawning any subprocess
  to avoid WSL init prompts and timeout during test collection
- Convert remaining feature_json f-string writes to json.dumps() so
  paths with backslashes produce valid JSON on Windows

* test: use bare 'bash' for detection to match test invocation

On Windows, subprocess.run(['bash', ...]) uses CreateProcess which
searches System32 before PATH — finding WSL bash even when
shutil.which('bash') returns Git-for-Windows. Probe with bare 'bash'
(same as test helpers) so the detection matches actual test behavior.
2026-04-15 15:37:27 -05:00
Ayesha Aziz
27b4fd2e32 docs: remove deprecated --skip-tls references from local-development guide (#2231)
* docs: remove deprecated --skip-tls references from local-development guide

* docs: refine wording and fix formatting for deprecated --skip-tls

* docs: polish TLS guidance wording
2026-04-15 15:16:21 -05:00
Manfred Riem
8fc2bd3489 fix: allow Claude to chain skills for hook execution (#2227)
* fix: allow Claude to chain skills for hook execution (#2178)

- Set disable-model-invocation to false so Claude can invoke extension
  skills (e.g. speckit-git-feature) from within workflow skills
- Inject dot-to-hyphen normalization note into Claude SKILL.md hook
  sections so the model maps extension.yml command names to skill names
- Replace Unicode checkmark with ASCII [OK] in auto-commit scripts to
  fix PowerShell encoding errors on Windows
- Move Claude-specific frontmatter injection to ClaudeIntegration via
  post_process_skill_content() hook on SkillsIntegration, wired through
  presets and extensions managers
- Add positive and negative tests for all changes

Fixes #2178

* refactor: address PR review feedback

- Preserve line-ending style (CRLF/LF) in _inject_hook_command_note
  instead of always inserting \n, matching the convention used by other
  injection helpers in the same module.

- Extract duplicated _post_process_skill() from extensions.py and
  presets.py into a shared post_process_skill() function in agents.py.
  Both modules now import and call the shared helper.

* fix: match full hook instruction line in regex

The regex in _inject_hook_command_note only matched lines ending
immediately after 'output the following', but the actual template
lines continue with 'based on its `optional` flag:'. Use [^\r\n]*
to capture the rest of the line before the EOL.

* refactor: use integration object directly for post_process_skill_content

Instead of a free function in agents.py that re-resolves the
integration by key, callers in extensions.py and presets.py now
resolve the integration once via get_integration() and call
integration.post_process_skill_content() directly. The base
identity method lives on SkillsIntegration.
2026-04-15 14:35:05 -05:00
Manfred Riem
b78a3cdd88 docs: merge TESTING.md into CONTRIBUTING.md, remove TESTING.md (#2228)
* docs: merge TESTING.md into CONTRIBUTING.md, remove TESTING.md

Merge relevant testing content (automated checks, manual testing process,
reporting template, test-selection prompt) into CONTRIBUTING.md. Remove
obsolete content referencing deleted zip bundles and the non-existent
test_core_pack_scaffold.py file. Update DEVELOPMENT.md to remove the
TESTING.md entry.

Closes #2226

* docs: address review — narrow automated checks intro, use cross-platform temp path
2026-04-15 09:57:06 -05:00
与子同説
2f5417f0ad Add agent-assign extension to community catalog (#2030)
* Add agent-assign extension to community catalog

* Fix author name to xuyang in catalog entry

* Update extensions/catalog.community.json

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update updated_at date in catalog.community.json

* Update README.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: xuyang <xuyangxy@rd.netease.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 08:26:46 -05:00
Michal Bachorik
33a28ec8f7 fix: unofficial PyPI warning (#1982) and legacy extension command name auto-correction (#2017) (#2027)
* docs: warn about unofficial PyPI packages and recommend version verification (#1982)

Clarify that only packages from github/spec-kit are official, and add
`specify version` as a post-install verification step to help users
catch accidental installation of an unrelated package with the same name.

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

* fix(extensions): auto-correct legacy command names instead of hard-failing (#2017)

Community extensions that predate the strict naming requirement use two
common legacy formats ('speckit.command' and 'extension.command').
Instead of rejecting them outright, auto-correct to the required
'speckit.{extension}.{command}' pattern and emit a compatibility warning
so authors know they need to update their manifest. Names that cannot be
safely corrected (e.g. single-segment names) still raise ValidationError.

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

* fix(tests): isolate preset catalog search test from community catalog network calls

test_search_with_cached_data asserted exactly 2 results but was getting 4
because _get_merged_packs() queries the full built-in catalog stack
(default + community). The community catalog had no local cache and hit
the network, returning real presets. Writing a project-level
preset-catalogs.yml that pins the test to the default URL only makes
the count assertions deterministic.

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

* fix(extensions): extend auto-correction to aliases (#2017)

The upstream #1994 added alias validation in _collect_manifest_command_names,
which also rejected legacy 2-part alias names (e.g. 'speckit.verify').
Extend the same auto-correction logic from _validate() to cover aliases,
so both 'speckit.command' and 'extension.command' alias formats are
corrected to 'speckit.{ext_id}.{command}' with a compatibility warning
instead of hard-failing.

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

* fix(extensions): address PR review feedback (#2017)

- _try_correct_command_name: only correct 'X.Y' to 'speckit.ext_id.Y'
  when X matches ext_id, preventing misleading warnings followed by
  install failure due to namespace mismatch
- _validate: add aliases type/string guards matching _collect_manifest
  _command_names defensive checks
- _validate: track command renames and rewrite any hook.*.command
  references that pointed at a renamed command, emitting a warning
- test: fix test_command_name_autocorrect_no_speckit_prefix to use
  ext_id matching the legacy namespace; add namespace-mismatch test
- test: replace redundant preset-catalogs.yml isolation with
  monkeypatch.delenv("SPECKIT_PRESET_CATALOG_URL") so the env var
  cannot bypass catalog restriction in CI environments

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

* Update docs/installation.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix(extensions): warn when hook command refs are silently canonicalized; fix grammar

- Hook rewrites (alias-form or rename-map) now always emit a warning so
  extension authors know to update their manifests. Previously only
  rename-map rewrites produced a warning; pure alias-form lifts were
  silent.
- Pluralize "command/commands" in the uninstall confirmation message so
  single-command extensions no longer print "1 commands".

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

* fix(extensions): raise ValidationError for non-dict hook entries

Silently skipping non-dict hook entries left them in manifest.hooks,
causing HookExecutor.register_hooks() to crash with AttributeError
when it called hook_config.get() on a non-mapping value.

Also updates PR description to accurately reflect the implementation
(no separate _try_correct_alias_name helper; aliases use the same
_try_correct_command_name path).

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

* fix(extensions): derive remove cmd_count from registry, fix wording

Previously cmd_count used len(ext_manifest.commands) which only counted
primary commands and missed aliases. The registry's registered_commands
already tracks every command name (primaries + aliases) per agent, so
max(len(v) for v in registered_commands.values()) gives the correct
total.

Also changes "from AI agent" → "across AI agents" since remove()
unregisters commands from all detected agents.

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

* fix(extensions): distinguish missing vs empty registered_commands in remove prompt

Using get() without a default lets us tell apart:
- key missing (legacy registry entry) → fall back to manifest count
- key present but empty dict (installed with no agent dirs) → show 0

Previously the truthiness check `if registered_commands and ...` treated
both cases the same, so an empty dict fell back to len(manifest.commands)
and overcounted commands that would actually be removed.

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

* fix(extensions): clarify removal prompt wording to 'per agent'

'across AI agents' implied a total count, but cmd_count uses max()
across agents (per-agent count). Using sum() would double-count since
users think in logical commands, not per-agent files. 'per agent'
accurately describes what the number represents.

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

* fix(extensions): clarify cmd_count comment — per-agent max, not total

The comment said 'covers all agents' implying a total, but cmd_count uses
max() across agents (per-agent count). Updated comment to explain the
max() choice and why sum() would double-count.

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

* test(extensions): add CLI tests for remove confirmation pluralization

Adds TestExtensionRemoveCLI with two CliRunner tests:
- singular: 1 registered command → '1 command per agent'
- plural:   2 registered commands → '2 commands per agent'

These prevent regressions on the cmd_count pluralization logic
and the 'per agent' wording introduced in this PR.

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

* fix(agents): remove orphaned SKILL.md parent dirs on unregister

For SKILL.md-based agents (codex, kimi), each command lives in its own
subdirectory (e.g. .agents/skills/speckit-ext-cmd/SKILL.md). The previous
unregister_commands() only unlinked the file, leaving an empty parent dir.

Now attempts rmdir() on the parent when it differs from the agent commands
dir. OSError is silenced so non-empty dirs (e.g. user files) are safely left.

Adds test_unregister_skill_removes_parent_directory to cover this.

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

* fix(extensions): drop alias pattern enforcement from _validate()

Aliases are intentionally free-form to preserve community extension
compatibility (e.g. 'speckit.verify' short aliases used by spec-kit-verify
and other existing extensions). This aligns _validate() with the intent of
upstream commit 4deb90f (fix: restore alias compatibility, #2110/#2125).

Only type and None-normalization checks remain for aliases. Pattern
enforcement continues for primary command names only.

Updated tests to verify free-form aliases pass through unchanged with
no warnings instead of being auto-corrected.

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

* fix(extensions): guard against non-dict command entries in _validate()

If provides.commands contains a non-mapping entry (e.g. an int or string),
'name' not in cmd raises TypeError instead of a user-facing ValidationError.
Added isinstance(cmd, dict) check at the top of the loop.

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

---------

Co-authored-by: iamaeroplane <michal.bachorik@gmail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-04-15 07:35:49 -05:00
Umm e Habiba
f0886bd089 feat: register architect-preview in community catalog (#2214)
* Add Architect Impact Previewer to catalog

Added a new architect impact previewer with metadata.

* Fix description formatting in architect-preview

* Add Architect Impact Previewer extension details

* Update catalog.community.json

* Add Architect Impact Previewer extension details

Added 'Architect Impact Previewer' extension with details including name, description, author, version, and URLs.

* Add Architect Impact Previewer extension to README
2026-04-14 16:08:28 -05:00
Manfred Riem
39c7b04e5e chore: deprecate --ai flag in favor of --integration on specify init (#2218)
* chore: deprecate --ai flag in favor of --integration on specify init

- Adds deprecation warning when --ai is used
- Shows equivalent --integration command replacement
- Handles generic integration with --commands-dir mapping
- Adds comprehensive test coverage for deprecation behavior
- Warning displays as prominent red panel above Next Steps
- --ai flag continues to function (non-breaking change)

Fixes #2169

* Address PR review feedback for issue #2169

- Use existing strip_ansi helper from conftest instead of duplicating ANSI escape pattern
- Properly escape ai_commands_dir with shlex.quote() to handle paths with spaces
- Add shlex import to support proper command-line argument escaping
2026-04-14 15:12:27 -05:00
Manfred Riem
3467d26b1c chore: release 0.7.0, begin 0.7.1.dev0 development (#2217)
* chore: bump version to 0.7.0

* chore: begin 0.7.1.dev0 development

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-14 13:06:06 -05:00
Copilot
a00e679918 Add workflow engine with catalog system (#2158)
* Initial plan

* Add workflow engine with step registry, expression engine, catalog system, and CLI commands

Agent-Logs-Url: https://github.com/github/spec-kit/sessions/72a7bb5d-071f-4d67-a507-7e1abae2384d

Co-authored-by: mnriem <15701806+mnriem@users.noreply.github.com>

* Add comprehensive tests for workflow engine (94 tests)

Agent-Logs-Url: https://github.com/github/spec-kit/sessions/72a7bb5d-071f-4d67-a507-7e1abae2384d

Co-authored-by: mnriem <15701806+mnriem@users.noreply.github.com>

* Address review feedback: do-while condition preservation and URL scheme validation

Agent-Logs-Url: https://github.com/github/spec-kit/sessions/72a7bb5d-071f-4d67-a507-7e1abae2384d

Co-authored-by: mnriem <15701806+mnriem@users.noreply.github.com>

* Address review feedback, add CLI dispatch, interactive gates, and docs

Review comments (7/7):
- Add explanatory comment to empty except block
- Implement workflow catalog download with cleanup on failure
- Add input type coercion for number/boolean/enum
- Fix example workflow to remove non-existent output references
- Fix while_loop and if_then condition defaults (string 'false' → bool False)
- Fix resume step index tracking with step_offset parameter

CLI dispatch:
- Add build_exec_args() and dispatch_command() to IntegrationBase
- Override for Claude (skills: /speckit-specify), Gemini (-m flag),
  Codex (codex exec), Copilot (--agent speckit.specify)
- CommandStep invokes installed commands by name via integration CLI
- Add PromptStep for arbitrary inline prompts (10th step type)
- Stream CLI output live to terminal (no silent blocking)
- Remove timeout when streaming (user can Ctrl+C)
- Ctrl+C saves state as PAUSED for clean resume

Interactive gates:
- Gate steps prompt [1] approve [2] reject in TTY
- Fall back to PAUSED in non-interactive environments
- Resume re-executes the gate for interactive prompting

Documentation:
- workflows/README.md — user guide
- workflows/ARCHITECTURE.md — internals with Mermaid diagrams
- workflows/PUBLISHING.md — catalog submission guide

Tests: 94 → 122 workflow tests, 1362 total (all passing)

* Fix ruff lint errors: unused imports, f-string placeholders, undefined name

* Address second review: registry-backed validation, shell failures, loop/fan-out execution, URL validation

- VALID_STEP_TYPES now queries STEP_REGISTRY dynamically
- Shell step returns FAILED on non-zero exit code
- Persist workflow YAML in run directory for reliable resume
- Resume loads from run copy, falls back to installed workflow
- Engine iterates while/do-while loops up to max_iterations
- Engine expands fan-out per item with context.item
- HTTPS URL validation for catalog workflow installs (HTTP allowed for localhost)
- Fix catalog merge priority docstring (lower number wins)
- Fix dispatch_command docstring (no build_exec_args_for_command)
- Gate on_reject=retry pauses for re-prompt on resume
- Update docs to 10 step types, add prompt step to tables and README

* Potential fix for pull request finding 'Empty except'

Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>

* Address third review: fan-out IDs, catalog guards, shell coercion, docs

- Fan-out generates unique per-item step IDs and collects results
- Catalog merge skips non-dict workflow entries (malformed data guard)
- Shell step coerces run_cmd to str after expression evaluation
- urlopen timeout=30 for catalog workflow installs
- yaml.dump with sort_keys=False, allow_unicode=True for catalog configs
- Document streaming timeout as intentionally unbounded (user Ctrl+C)
- Document --allow-all-tools as required for non-interactive + future enhancement
- Update test docstring and PUBLISHING.md to 10 step types with prompt

* Validate final URL after redirects in catalog fetch

urlopen follows redirects, so validate the response URL against the
same HTTPS/localhost rules to prevent redirect-based downgrade attacks.

* Address fourth review: filter arg eval, tags normalization, install redirect check

- Filter arguments now evaluated via _evaluate_simple_expression() so
  default(42) returns int not string
- Tags normalized: non-list/non-string values handled gracefully
- Install URL redirect validation (same as catalog fetch)
- Remove unused 'skipped' variable in catalog config parsing
- Author 'github' → 'GitHub' in example workflow
- Document nested step resume limitation (re-runs parent step)

* Add explanatory comment to empty except ValueError block

* Address fifth review: expression parsing, fan-out output, URL install, gate options

- Move string literal parsing before operator detection in expressions
  so quoted strings with operators (e.g. 'a in b') are not mis-parsed
- Fan-out: remove max_concurrency from persisted output, fix docstring
  to reflect sequential execution
- workflow add: support URL sources with HTTPS/redirect validation,
  validate workflow ID is non-empty before writing files
- Deduplicate local install logic via _validate_and_install_local()
- Remove 'edit' gate option from speckit workflow (not implemented)

* Add comments to empty except ValueError blocks in URL install

* Address sixth review: operator precedence, fan_in cleanup, registry resilience, docs

- Fix or/and operator precedence (or parsed first = lower precedence)
- Restore context.fan_in after fan-in step completes
- Catch JSONDecodeError in registry load for corrupted files
- Replace print() with on_step_start callback (library-safe)
- Gate validation warns when on_reject set but no reject option
- Shell step: document shell=True security tradeoff
- README: sdd-pipeline → speckit, parallel → sequential for fan-out
- ARCHITECTURE.md: parallel → fan-out/fan-in in diagram

* Address seventh review: string literal before pipe, type annotations, validate on install

- Move string literal check above pipe filter parsing so 'a | b' works
- Fix type annotations: input_values list[str] | None, run_id str | None
- Run validate_workflow() before installing from local path/URL
- Remove duplicate string literal check from expression parser

* Address eighth review: fan-out namespaced IDs, early return, catalog validation

- Fan-out per-item step IDs use _fanout_{step_id}_{base}_{idx} namespace
  to avoid collisions with user-defined step IDs
- Early return after fan-out loop when state is paused/failed/aborted
- Catalog installs parse + validate downloaded YAML before registering,
  using definition metadata instead of catalog entry for registry

* Address ninth review: populate catalog, fix indentation, priority, README

- Add speckit workflow entry to catalog.json so it's discoverable
- Fix shell step output dict indentation
- Catalog add_catalog priority derived from max existing + 1
- README Quick Start clarified with install + local file examples

* Address tenth review: max_iterations validation, catalog config guard, version alignment

- Validate max_iterations is int >= 1 in while and do-while steps
- Guard add_catalog against corrupted config (non-dict/non-list)
- Align speckit_version requirement to >=0.6.1 (current package version)
- Fan-out template validation uses separate seen_ids set to avoid
  false duplication errors with user-defined step IDs

* Address eleventh review: command step fails without CLI, ID mismatch warning, state persistence

- Command step returns FAILED when CLI not installed (was silent COMPLETED)
- Catalog install warns on workflow ID vs catalog key mismatch
- Engine persists state.save() before returning on unknown step type
- Update tests to expect FAILED for command steps without CLI
- Integration tests use shell steps for CLI-independent execution

* Address twelfth review: type annotations, version examples, streaming docs, requires

- Fix workflow_search type annotations (str | None)
- PUBLISHING.md: speckit_version >=0.15.0 → >=0.6.1
- Document that exit_code is captured and referenceable by later steps
- Mark requires as declared-but-not-enforced (planned enhancement)
- Note full stdout/stderr capture as planned enhancement

* Enforce catalog key matches workflow ID (fail instead of warn)

* Bundle speckit workflow: auto-install during specify init

- Add workflows/speckit to pyproject.toml force-include for wheel builds
- Add _locate_bundled_workflow() helper (mirrors _locate_bundled_extension)
- Auto-install speckit workflow during specify init (after git extension)
- Update all integration file inventory tests to expect workflow files

* Address fourteenth review: prompt fails without CLI, resolved step data, fan-out normalization

- PromptStep returns FAILED when CLI not installed (was silent COMPLETED)
- Engine step_data prefers resolved values from step output
- Fan-out normalizes output.results=[] for empty item lists
- subprocess.run inherits stdout/stderr (no explicit sys.stdout)
- Registry tests use issubset for extensibility

* Address fifteenth review: fan_in docstring, gate defaults, validation guards, reserved prefix

- FanInStep docstring: aggregate-only, no blocking semantics
- FanInStep: guard output_config as dict, handle None
- Gate validate: use same default options as execute
- Validate inputs is dict and steps is list before iterating
- Reserve _fanout_ prefix in step ID validation
- PUBLISHING.md: remove unenforced checklist items, add _fanout_ note

* Address sixteenth review: docs regex, fan_in try/finally, hyphenated dot-path keys

- PUBLISHING.md: update ID regex docs to match implementation (single-char OK)
- FanInStep: wrap expression evaluation in try/finally for context.fan_in
- Expression dot-path: allow hyphens in keys before list index (e.g. run-tests[0])

* Make speckit workflow integration-agnostic, document Copilot CLI requirement

- Workflow integration selectable via input (default: claude)
- Each command step uses {{ inputs.integration }} instead of hardcoded copilot
- Copilot docstring documents CLI requirement for workflow dispatch
- Added install_url for Copilot CLI docs

* Address seventeenth review: project checks, catalog robustness

- Add .specify/ project check to workflow run/resume/status/search/info
- remove_catalog validates config shape (dict + list) before indexing
- _fetch_single_catalog validates response is a dict
- _get_merged_workflows raises when all catalogs fail to fetch
- add_catalog guards against non-dict catalog entries in config

* Address eighteenth review: condition coercion, gate abort result, while default, cache guard, resume log

- evaluate_condition treats plain 'false'/'true' strings as booleans
- Gate abort returns StepResult(FAILED) instead of raising exception
  so step output is persisted in state for inspection
- while_loop max_iterations optional (default 10), validation aligned
- Catalog cache fallback catches invalid JSON gracefully
- resume() appends workflow_finished log entry like execute()

* Address nineteenth review: allow-all-tools opt-in, empty catalogs, abort dead code, while docstring

- --allow-all-tools controlled by SPECKIT_ALLOW_ALL_TOOLS env var (default: 1)
  Set to 0 to disable automatic tool approval for Copilot CLI
- Empty catalogs list falls back to built-in defaults (not an error)
- Remove unreachable WorkflowAbortError catches from execute/resume
  (gate abort now returns StepResult(FAILED) instead of raising)
- while_loop docstring updated: max_iterations is optional (default 10)

* Address twentieth review: gate abort maps to ABORTED status, do-while max_iterations optional

- Engine detects output.aborted from gate step and sets RunStatus.ABORTED
  (was unreachable — gate abort returned FAILED but status was always FAILED)
- do-while max_iterations now optional (default 10), aligned with while_loop
- do-while docstring and validation updated accordingly

* Coerce default_options to dict, align bundled workflow ID regex with validator

* Gate validates string options, prompt uses resolved integration, loop normalizes max_iterations

* Use parentId:childId convention for nested step IDs

- Fan-out per-item IDs use parentId:templateId:index (e.g. parallel:impl:0)
- Reserve ':' in user step IDs (validation rejects)
- Replaces _fanout_ prefix with cleaner namespacing
- Expressions like {{ steps.parallel:impl:0.output.file }} work naturally

* Validate workflow version is semantic versioning (X.Y.Z)

* Schema version validation, strict semver, load_workflow docstring, preserve max_concurrency

- Validate schema_version is '1.0' (reject unknown future schemas)
- Strict semver regex: ^\d+\.\d+\.\d+$ (rejects 1.0.0beta etc.)
- load_workflow docstring: 'parsed' not 'validated'
- Keep max_concurrency in fan-out output (was dropped)
- do_while docstring: engine re-evaluates step_config condition
- ARCHITECTURE.md: document nested resume limitation

* Path traversal prevention, loop step ID namespacing

- RunState validates run_id is alphanumeric+hyphens (no path separators)
- workflow_add validates catalog source doesn't escape workflows_dir
- Loop iterations namespace nested step IDs as parentId:childId:iteration
  so multiple iterations don't overwrite each other in context/state

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: mnriem <15701806+mnriem@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
2026-04-14 10:11:56 -05:00
Rafa Gomes
c0152e4f3d docs(catalog): add claude-ask-questions to community preset catalog (#2191)
* feat: add claude-ask-questions preset for AskUserQuestion rendering

Delivers the /speckit.clarify and /speckit.checklist AskUserQuestion
integration as a stackable preset under presets/claude-ask-questions/
instead of modifying core templates or ClaudeIntegration.

- presets/claude-ask-questions/preset.yml registers command overrides
  for speckit.clarify and speckit.checklist following the same pattern
  as the bundled lean preset.
- Override commands replace the Markdown-table question-rendering
  blocks with AskUserQuestion instructions. Option | Description maps
  to {label, description} for clarify; Option | Candidate | Why It
  Matters maps to {label: Candidate, description: Why It Matters} for
  checklist. Recommended option is placed first with a
  "Recommended — <reasoning>" prefix; a final "Custom"/"Short" option
  preserves the free-form ≤5-word escape hatch.
- Registered in presets/catalog.json as a bundled preset.

Core templates, ClaudeIntegration, and the existing test suite are
left untouched, so non-Claude agents and users who do not install
this preset see no behavior change.

Closes github/spec-kit#2181

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

* refactor: move claude-ask-questions preset to external repo

Per maintainer feedback on #2191, presets should be hosted on the
author's own GitHub repository and registered in catalog.community.json
rather than bundled in spec-kit. Removes the bundled preset directory
and its entry from the official catalog, and adds a community catalog
entry pointing at the external repository and release archive.

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

* docs(catalog): sync claude-ask-questions description with upstream preset

* revert: keep presets/catalog.json updated_at unchanged

No entries in the official catalog changed in this PR, so the timestamp
bump was spurious. Addresses Copilot review feedback on #2191.

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-14 08:17:28 -05:00
ysumanth06
03a9163633 Add SFSpeckit — Salesforce SDD Extension (#2208)
* Add SFSpeckit — Salesforce SDD Extension

* chore: update catalog updated_at timestamp
2026-04-13 18:12:27 -05:00
Gabriel Henrique
4687c33b0f feat(scripts): optional single-segment branch prefix for gitflow (#2202)
* feat(scripts): optional single-segment branch prefix for gitflow

- Add spec_kit_effective_branch_name / Get-SpecKitEffectiveBranchName:
  when branch matches prefix/rest with exactly one slash, validate and
  resolve specs/ using only the rest (e.g. feat/001-my-feature).
- Wire into check_feature_branch, find_feature_dir_by_prefix (bash) and
  Test-FeatureBranch, Find-FeatureDirByPrefix + Get-FeaturePathsEnv (PS).
- Align git extension git-common with core validation; remove unused
  get_feature_dir / Get-FeatureDir helpers.
- Extend tests in test_timestamp_branches.py and test_git_extension.py.

Made-with: Cursor

* Update scripts/powershell/common.ps1

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix(ps): align feature-dir resolution errors with bash (no throw under Stop)

Find-FeatureDirByPrefix: on ambiguous prefix matches, write errors to stderr
and return $null instead of throwing, matching find_feature_dir_by_prefix.

Get-FeaturePathsEnv: narrow try/catch to ConvertFrom-Json only; add
Get-FeatureDirFromBranchPrefixOrExit to mirror bash get_feature_paths
(stderr + exit 1) when prefix lookup fails, avoiding unhandled terminating
errors under $ErrorActionPreference = 'Stop' in check-prerequisites,
setup-plan, and update-agent-context.

Made-with: Cursor

* Update tests/test_timestamp_branches.py

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update extensions/git/scripts/powershell/git-common.ps1

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update scripts/powershell/common.ps1

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-04-13 18:11:17 -05:00
Manfred Riem
de93528fad chore: release 0.6.2, begin 0.6.3.dev0 development (#2205)
* chore: bump version to 0.6.2

* chore: begin 0.6.3.dev0 development

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-13 14:35:22 -05:00
dango85
bb7da09b65 Add Worktrees extension to community catalog (#2207)
- Extension ID: worktrees
- Version: 1.0.0
- Author: dango85
- Description: Default-on worktree isolation for parallel agents

Made-with: Cursor

Co-authored-by: Abishek Yadav <abiyadav@publicisgroupe.net>
2026-04-13 14:34:54 -05:00
adaumann
fe75a45627 feat: Update catalog.community.json for preset-fiction-book-writing (#2199)
* feat: Update catalog.community.json for preset-fiction-book-writing

* Add fiction-book-writing preset to community catalog

- Preset ID: fiction-book-writing
- Version: 1.3.0
- Author: Andreas Daumann
- Description: Spec-Driven Development for novel and long-form fiction. Replaces software engineering terminology with storytelling craft: specs become story briefs, plans become story structures, and tasks become scene-by-scene writing tasks. Supports 8 POV modes, all major plot structure frameworks, 5 humanized-AI prose profiles, and exports to DOCX/EPUB/LaTeX via pandoc.

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* doc: added fiction-book-writing preset link in README.md

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Manfred Riem <15701806+mnriem@users.noreply.github.com>
2026-04-13 13:04:40 -05:00
Abdullah Khan
aa85b2f166 feat: Register "What-if Analysis" community extension (#2182)
* feat: implement read-only what-if analysis command

* chore: polish what-if analysis (Claude hints + optional tasks)

* refactor: deliver what-if analysis as a standalone extension

* Move What-if extension to standalone repo and update community catalog

* Fix: Reorder whatif extension alphabetically in community catalog
2026-04-13 12:01:37 -05:00
Fatima367
e27896e681 feat: add GitHub Issues Integration to community catalog (#2188)
* feat: add GitHub Issues Integration to community catalog

Add GitHub Issues Integration extension to the community catalog and README.

Extension provides:
- /speckit.github-issues.import - Import GitHub Issue and generate spec.md
- /speckit.github-issues.sync - Keep specs updated with issue changes
- /speckit.github-issues.link - Add bidirectional traceability

Resolves #2175

* Modify created_at and updated_at timestamps

Updated timestamps for created_at and updated_at fields.

* Update updated_at date in catalog.community.json
2026-04-13 11:22:46 -05:00
Furkan Köykıran
b67b2856b1 feat(agents): add Goose AI agent support (#2015)
* feat(integrations): add YamlIntegration base class for YAML recipe agents

Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>

* feat(integrations): add Goose integration subpackage with YAML recipe support

Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>

* feat(integrations): register GooseIntegration in the integration registry

Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>

* feat(agents): add YAML format support to CommandRegistrar for extension/preset commands

Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>

* feat(scripts): add goose agent type to bash update-agent-context script

Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>

* feat(scripts): add goose agent type to PowerShell update-agent-context script

Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>

* docs(agents): add Goose to supported agents table and integration notes

Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>

* docs(readme): add Goose to supported agents table

Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>

* test(integrations): add YamlIntegrationTests base mixin for YAML agent testing

Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>

* test(integrations): add Goose integration tests

Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>

* test(consistency): add Goose consistency checks for config, registrar, and scripts

Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>

* docs(agents): move Goose to YAML Format section in Command File Formats

Goose uses YAML recipes, not Markdown. Remove it from the Markdown Format
list and add a dedicated YAML Format subsection with a representative
recipe example showing prompt: | and {{args}} placeholders.

* refactor(agents): delegate render_yaml_command to YamlIntegration

Remove the duplicate header dict, yaml.safe_dump call, body indentation,
and _human_title logic from CommandRegistrar.render_yaml_command(). Delegate
to YamlIntegration._render_yaml() and _human_title() so YAML recipe output
stays consistent across the init-time generation and command-registration
code paths.

* fix(agents): guard alias output path against directory traversal

Validate that alias_file resolves within commands_dir before writing.
Uses the same resolve().relative_to() pattern already established in
extensions.py for ZIP path containment checks.

* docs(agents): add Goose to Multi-Agent Support comment list in update-agent-context.sh

* fix(agents): add goose to print_summary Usage line in bash context script

The print_summary() function listed all supported agents in its Usage
output but omitted goose, making it inconsistent with the header docs
and the error message in update_specific_agent().

Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>

* fix(agents): add goose to Print-Summary Usage line in PowerShell context script

The Print-Summary function listed all supported agents in its Usage
output but omitted goose, making it inconsistent with the ValidateSet
and the header documentation.

Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>

* fix(agents): normalize description and title types in YamlIntegration.setup()

YAML frontmatter can contain non-string types (null, list, int).
Add isinstance checks matching TomlIntegration._extract_description()
to ensure Goose recipes always receive valid string fields.

Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>

* fix(agents): validate shared script exists before exec in Goose bash wrapper

Add Forge-style check that the shared update-agent-context.sh is
present and executable, producing a clear error instead of a cryptic
shell exec failure when the shared script is missing.

Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>

* fix(agents): validate shared script exists before invoke in Goose PowerShell wrapper

Add Forge-style Test-Path check that the shared update-agent-context.ps1
exists, producing a clear error instead of a cryptic PowerShell failure
when the shared script is missing.

Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>

* fix(agents): normalize title and description types in render_yaml_command()

Extension/preset frontmatter can contain non-string types. Add
isinstance checks matching the normalization in YamlIntegration.setup()
so both code paths produce valid Goose recipe fields.

Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>

* fix(agents): replace $ARGUMENTS with arg_placeholder in process_template()

Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>

* test(agents): assert $ARGUMENTS absent from generated YAML recipes

Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>

* test(agents): assert $ARGUMENTS absent from generated TOML commands

Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>

* fix(tests): rewrite docstring to avoid embedded triple-quote in TOML test

Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>

---------

Signed-off-by: Furkan Köykıran <furkankoykiran@gmail.com>
2026-04-13 07:55:44 -05:00
Ben Lawson
52ed84d723 Update ralph extension to v1.0.1 in community catalog (#2192)
- Extension ID: ralph
- Version: 1.0.0 → 1.0.1
- Author: Rubiss
- Changes: Fixed bash task count bug, removed hardcoded model,
  added regression tests, CI workflow, and release pipeline.
- Release: https://github.com/Rubiss/spec-kit-ralph/releases/tag/v1.0.1

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-13 07:42:08 -05:00
Manfred Riem
cdbea09e1a fix: skip docs deployment workflow on forks (#2171)
Add repository check to build and deploy jobs so they skip
with success on forks, avoiding failed Pages deployments for
contributors.
2026-04-10 17:57:47 -05:00
Manfred Riem
1cb794e516 chore: release 0.6.1, begin 0.6.2.dev0 development (#2162)
* chore: bump version to 0.6.1

* chore: begin 0.6.2.dev0 development

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-10 16:22:42 -05:00
Manfred Riem
43cb0fa7ab feat: add bundled lean preset with minimal workflow commands (#2161)
* feat: add bundled lean preset with minimal workflow commands

Add a lean preset that overrides the 5 core workflow commands (specify,
plan, tasks, implement, constitution) with minimal prompts that produce
exactly one artifact each — no extension hooks, no scripts, no git
branching, no templates.

Bundled preset infrastructure:
- Add _locate_bundled_preset() mirroring _locate_bundled_extension()
- Update 'specify init --preset' to try bundled -> catalog fallback
- Update 'specify preset add' to try bundled -> catalog fallback
- Add bundled guard in download_pack() for presets without download URLs
- Add lean to presets/catalog.json with 'bundled: true' marker
- Add lean to pyproject.toml force-include for wheel packaging
- Align error messages with bundled extension error pattern

Tests: 15 new tests (TestLeanPreset + TestBundledPresetLocator)

* refactor: address review — clean up unused imports, strengthen test assertions

- Remove unused MagicMock import and cache_dir setup in download test
- Assert 'bundled' and 'reinstall' in CLI error output (not just exit code)
- Mock catalog in missing-locally test for deterministic bundled error path
- Fix test versions to satisfy updated speckit_version >=0.6.0 requirement

* refactor: address review — fix constitution paths, add REINSTALL_COMMAND to presets.py

- Fix constitution path to .specify/memory/constitution.md in plan, tasks,
  implement commands (matching core command convention)
- Include REINSTALL_COMMAND in download_pack() bundled guard for consistent
  recovery instructions across bundled extensions and presets

* refactor: address review — explicit feature_directory paths, ZIP cleanup in finally

- Prefix spec.md/plan.md/tasks.md with <feature_directory>/ in plan, tasks,
  and implement commands so the agent doesn't operate on repo root by mistake
- Move ZIP unlink into finally block in init --preset path so cleanup runs
  even when install_from_zip raises (matching preset_add pattern)

* refactor: address review — replace Unicode em dashes with ASCII, fix grammar

- Replace all Unicode em dashes with ASCII hyphens in preset.yml and
  catalog.json to avoid decode errors on non-UTF-8 environments
- Fix grammar: 'store it in tasks.md' -> 'store them in tasks.md'

* refactor: address review - align task format between tasks and implement

- Remove undefined [P] marker from implement (lean uses sequential execution)
- Clarify checkbox update: 'change - [ ] to - [x]' instead of ambiguous '[X]'
- Simplify implement to execute tasks in order without parallel complexity

* refactor: address review - parse frontmatter instead of raw substring search

- Use CommandRegistrar.parse_frontmatter() to check for scripts/agent_scripts
  keys in YAML frontmatter instead of brittle 'scripts:' substring search
2026-04-10 16:18:06 -05:00
Quratulain-bilal
74e3f45aa9 Add Brownfield Bootstrap extension to community catalog (#2145)
- 4 commands: scan, bootstrap, validate, migrate for existing codebases
- 1 hook: after_init for auto-scanning project after spec-kit initialization
- Addresses community request in issue #1436 (30+ reactions)
2026-04-10 13:16:26 -05:00
Quratulain-bilal
97ea7cf6a0 Add CI Guard extension to community catalog (#2157)
* Add CI Guard extension to community catalog

Adds spec-kit-ci-guard: spec compliance gates for CI/CD pipelines.

5 commands:
- /speckit.ci.check — run all compliance checks with pass/fail
- /speckit.ci.report — generate requirement traceability matrix
- /speckit.ci.gate — configure merge gate rules and thresholds
- /speckit.ci.drift — detect bidirectional spec-to-code drift
- /speckit.ci.badge — generate spec compliance badges

2 hooks: before_implement, after_implement

Bridges the gap between SDD workflow and CI/CD enforcement.

* Fix updated_at to monotonically increase per Copilot review

Set to 2026-04-10T15:00:00Z (later than previous 2026-04-10T12:34:56Z).
2026-04-10 12:20:55 -05:00
Quratulain-bilal
f43b85096c Add SpecTest extension to community catalog (#2159)
* Add SpecTest extension to community catalog

Adds spec-kit-spectest: auto-generate test scaffolds from spec criteria.

4 commands:
- /speckit.test.generate — generate framework-native test scaffolds
- /speckit.test.coverage — map spec requirements to test coverage
- /speckit.test.gaps — find untested requirements with suggestions
- /speckit.test.plan — generate structured test plan documents

1 hook: after_implement (gap detection)

Bridges the spec-to-test gap in the SDD workflow.

* Update extensions/catalog.community.json

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Fix spectest created_at/updated_at to use current timestamp per Copilot review

Set both to 2026-04-10T16:00:00Z instead of midnight.

---------

Co-authored-by: Manfred Riem <15701806+mnriem@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-04-10 12:11:25 -05:00
Manfred Riem
d1b95c2f59 fix: bundled extensions should not have download URLs (#2155)
* fix: bundled extensions should not have download URLs (#2151)

- Remove selftest from default catalog (not a published extension)
- Replace download_url with 'bundled: true' flag for git extension
- Add bundled check in extension add flow with clear error message
  when bundled extension is missing from installed package
- Add bundled check in download_extension() with specific error
- Direct users to reinstall via uv with full GitHub URL
- Add 3 regression tests for bundled extension handling

* refactor: address review - move bundled check up-front, extract reinstall constant

- Move bundled check before download_url inspection in download_extension()
  so bundled extensions can never be downloaded even with a URL present
- Extract REINSTALL_COMMAND constant to avoid duplicated install strings

* fix: allow bundled extensions with download_url to be updated

Bundled extensions should only be blocked from download when they have
no download_url. If a newer version is published to the catalog with a
URL, users should be able to install it to get bug fixes.

Add test for bundled-with-URL download path.
2026-04-10 11:29:18 -05:00
Quratulain-bilal
8bb08ae1a0 Add PR Bridge extension to community catalog (#2148)
- 3 commands: generate PR descriptions, reviewer checklists, and change summaries
- 1 hook: after_implement for auto-generating PR description
- Closes the SDD workflow loop: specify → plan → tasks → implement → PR
2026-04-10 09:51:20 -05:00
Gabriel Henrique
5732de60d0 feat(cursor-agent): migrate from .cursor/commands to .cursor/skills (#2156)
Use SkillsIntegration so workflows ship as speckit-*/SKILL.md. Update
init next-steps, extension hook invocation, docs, and tests.

Made-with: Cursor
2026-04-10 09:35:19 -05:00
Quratulain-bilal
b6e19b49ec Add TinySpec extension to community catalog (#2147)
* Add TinySpec extension to community catalog

- 3 commands: tinyspec, implement, classify for lightweight single-file workflow
- 1 hook: before_specify for auto-classifying task complexity
- Addresses community request in issue #1174 (22+ reactions)

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Manfred Riem <15701806+mnriem@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-04-10 09:10:42 -05:00
Ismael
7f1e38491f chore: bump spec-kit-verify to 1.0.3 and spec-kit-review to 1.0.1 (#2146)
* chore: bump spec-kit-verify to 1.0.3 and spec-kit-review to 1.0.1

*  Removed invalid aliases

* Change updated at
2026-04-10 07:32:48 -05:00
Wes Etheredge
bc0288832e Add Status Report extension to community catalog (#2123)
- Extension ID: status-report
- Version: 1.2.5
- Author: Open-Agent-Tools
- Description: Project status, feature progress, and next-action recommendations for spec-driven workflows

Co-authored-by: Unserious AI <121459476+unseriousAI@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 07:27:15 -05:00
Manfred Riem
e70495c2b8 chore: release 0.6.0, begin 0.6.1.dev0 development (#2144)
* chore: bump version to 0.6.0

* chore: begin 0.6.1.dev0 development

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-09 14:17:11 -05:00
Quratulain-bilal
674a66449a Add Bugfix Workflow community extension to catalog and README (#2135)
* Add Bugfix Workflow community extension to catalog and README

Adds the spec-kit-bugfix extension (3 commands, 1 hook) that provides a
structured bugfix workflow — capture bugs, trace to spec artifacts, and
surgically patch specs without regenerating from scratch.

Addresses community request in issue #619 (25+ upvotes, maintainer-approved).

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

* Bump catalog updated_at to 2026-04-09 to match new entry date

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

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 14:02:03 -05:00
Quratulain-bilal
efeb5489c3 Add Worktree Isolation extension to community catalog (#2143)
- 3 commands: create, list, clean worktrees for parallel feature development
- 1 hook: after_specify for auto-worktree creation
- Addresses community request in issue #61 (36+ upvotes)
2026-04-09 13:53:54 -05:00
Sakit
8013d0b57e Add multi-repo-branching preset to community catalog (#2139)
* Add nested-repos to community catalog

- Preset ID: nested-repos
- Version: 1.0.0
- Author: sakitA
- Description: Multi-module nested repository support for independent repos and git submodules

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Update presets/catalog.community.json

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Bump catalog updated_at timestamp

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Update nested-repos preset: commands-only, 0 templates

Removed template overrides to reduce core content duplication.
Commands instruct AI to add nested-repo sections dynamically.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Rename preset: nested-repos -> multi-repo-branching

Updated preset ID, name, description, and all URLs to reflect
the new repository name and clearer preset identity.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Remove templates: 0 from catalog provides section

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Remove accidentally committed .claude folder

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Address review: restore templates key and add README entry

- Add templates: 0 back to provides for catalog consistency
- Add multi-repo-branching to Community Presets table in README.md

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-04-09 13:35:03 -05:00
PChemGuy
0a121b073c Readme clarity (#2013)
* Specify CLI Reference formatting

Improves formatting of Specify CLI Reference

* Available Slash Commands clarity

Improve "Available Slash Commands" clarity in README.md.

* Add extension/preset commands to cli reference

* Extensions & Presets section clarity

Improves Extensions & Presets section clarity in README.md

* Removes `$` from Agent Skill

* Reverts Supported AI Agents Table

* Added missing Agent Skill column

* Trailing whitespaces

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Adds missing code block language

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Revised wording

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Revised specify synopsis

* Update specify command reference table

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Removes extra (duplicate) slashes

* Update README.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Removed old section

* missing /speckit.taskstoissues

* integration command

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update README.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update README.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update README.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update README.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-04-09 13:23:10 -05:00
Dhilip
6af2e64e88 Rewrite AGENTS.md for integration architecture (#2119)
* Rewrite AGENTS.md for integration subpackage architecture

Replaces the old AGENT_CONFIG dict-based 7-step process with documentation
reflecting the integration subpackage architecture shipped in #1924.

Removed: Supported Agents table, old step-by-step guide referencing
AGENT_CONFIG/release scripts/case statements, Agent Categories lists,
Directory Conventions section, Important Design Decisions section.

Kept: About Spec Kit and Specify, Command File Formats, Argument Patterns,
Devcontainer section.

Added: Architecture overview, decision tree for base class selection,
configure/register/scripts/test/override steps with real code examples
from existing integrations (Windsurf, Gemini, Codex, Copilot).

Agent-Logs-Url: https://github.com/github/spec-kit/sessions/71b25c53-7d0c-492a-9503-f40a437d5ece

Co-authored-by: mnriem <15701806+mnriem@users.noreply.github.com>

* Fix JSONC comment syntax in devcontainer example

Agent-Logs-Url: https://github.com/github/spec-kit/sessions/71b25c53-7d0c-492a-9503-f40a437d5ece

Co-authored-by: mnriem <15701806+mnriem@users.noreply.github.com>

* docs(AGENTS.md): address Copilot PR review comments

- Clarify that integrations are registered by _register_builtins() in
  __init__.py, not self-registered at import time
- Scope the key-must-match-executable rule to CLI-based integrations
  (requires_cli: True); IDE-based integrations use canonical identifiers
- Replace <commands_dir> placeholder in test snippet with a concrete
  example path (.windsurf/workflows/)
- Document that hyphens in keys become underscores in test filenames
  (e.g. cursor-agent -> test_integration_cursor_agent.py)
- Note that the argument placeholder is integration-specific
  (registrar_config["args"]); add Forge's {{parameters}} as an example
- Apply consistency fixes to Required fields table, Key design rule
  callout, and Common Pitfalls #1

* docs(AGENTS.md): clarify scripts path uses Python-safe package_dir not key

The scripts step previously referenced src/specify_cli/integrations/<key>/scripts/
but for hyphenated keys the actual directory is underscored (e.g. kiro-cli -> kiro_cli/).
Rename the placeholder to <package_dir> and add a note explaining:
- <package_dir> matches <key> for non-hyphenated keys
- <package_dir> uses underscores for hyphenated keys (e.g. kiro-cli -> kiro_cli/)
- IntegrationBase.key always retains the original hyphenated value

Addresses: https://github.com/github/spec-kit/pull/2119#discussion_r3054946896

* docs(AGENTS.md): use <key_with_underscores> in pytest example command

The pytest command previously used <key> as a placeholder, but test
filenames always use underscores even for hyphenated keys. This was
internally inconsistent since the preceding sentence already explained
the hyphen→underscore mapping. Switch to <key_with_underscores> to
match the actual filename on disk.

Addresses: https://github.com/github/spec-kit/pull/2119#discussion_r3054962863

* docs(AGENTS.md): use <package_dir> in step 2 subpackage path

The path src/specify_cli/integrations/<key>/__init__.py was inaccurate
for hyphenated keys (e.g. kiro-cli lives in kiro_cli/, not kiro-cli/).
Rename the placeholder to <package_dir>, define it inline (hyphens
become underscores), and note that IntegrationBase.key always retains
the original hyphenated value.

Addresses: https://github.com/github/spec-kit/pull/2119#discussion_r3058050583

* docs(AGENTS.md): qualify 'single source of truth' to Python metadata only

The registry is only authoritative for Python integration metadata.
Context-update dispatcher scripts (bash + PowerShell) still require
explicit per-agent cases and maintain their own supported-agent lists
until they are migrated to registry-based dispatch. Tighten the claim
to avoid misleading contributors into skipping the script updates.

Addresses: https://github.com/github/spec-kit/pull/2119#pullrequestreview-4083090261

* docs(AGENTS.md): mention ValidateSet update in PowerShell dispatcher step

The update-agent-context.ps1 script has a [ValidateSet(...)] on the
AgentType parameter. Without adding the new key to that list, the script
rejects the argument before reaching Update-SpecificAgent. Add this as
an explicit step alongside the switch case and Update-AllExistingAgents.

Addresses: https://github.com/github/spec-kit/pull/2119#pullrequestreview-4083217694

* fix(integrations): sort codebuddy before codex in _register_builtins()

Both the import list and the _register() call list had codex before
codebuddy, violating the alphabetical ordering that AGENTS.md documents.
Swap them so the file matches the documented convention.

Addresses: https://github.com/github/spec-kit/pull/2119#pullrequestreview-4083341590

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: mnriem <15701806+mnriem@users.noreply.github.com>
2026-04-09 10:29:35 -05:00
Alfredo Perez
66125a80a9 docs: add SpecKit Companion to Community Friends section (#2140)
Add SpecKit Companion VS Code extension to the Community Friends
listing alongside existing community projects.
2026-04-09 10:07:30 -05:00
Hamilton Snow
55515093a2 feat: add memorylint extension to community catalog (#2138)
* feat: add memorylint extension to community catalog

* chore: update speckit_version requirement to >=0.5.1 for memorylint extension

* docs: register memorylint extension in README and update requirements
2026-04-09 08:14:21 -05:00
Manfred Riem
aa2282ea04 chore: release 0.5.1, begin 0.5.2.dev0 development (#2137)
* chore: bump version to 0.5.1

* chore: begin 0.5.2.dev0 development

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-08 17:51:35 -05:00
Manfred Riem
1c41aacbac fix: pin typer>=0.24.0 and click>=8.2.1 to fix import crash (#2136)
typer <0.24.0 under-constrains its click dependency (click>=8.0.0),
allowing resolvers to pick click <8.2 which lacks __class_getitem__
on click.Choice. This causes 'TypeError: type Choice is not
subscriptable' at import time on any Python version.

Pin typer>=0.24.0 (which correctly requires click>=8.2.1) and
click>=8.2.1 to prevent incompatible combinations.

Fixes #2134
2026-04-08 17:49:19 -05:00
Sharath Satish
cb0d9612ef feat: update fleet extension to v1.1.0 (#2029) 2026-04-08 15:25:57 -05:00
toxicafunk
71143598be fix(forge): use hyphen notation in frontmatter name field (#2075)
* fix(forge): use hyphen notation in frontmatter name field

- Changed injected name field from 'speckit.{command}' to 'speckit-{command}'
- Keeps standard filename format 'speckit.{command}.md'
- Aligns with Forge's command naming convention requirements
- All tests pass

* feat(forge): centralize name formatting to fix extension/preset command names

Address PR feedback by centralizing Forge command name formatting to ensure
consistent hyphenated names across both core template setup and
extension/preset command registration.

Changes:
- Add format_forge_command_name() utility function in forge integration
- Update ForgeIntegration._apply_forge_transformations() to use centralized formatter
- Add _format_name_for_agent() helper in CommandRegistrar to apply agent-specific formatting
- Update CommandRegistrar.register_commands() to format names for Forge (both primary commands and aliases)
- Add comprehensive test coverage for the formatter and registrar behavior

Impact:
- Extension commands installed for Forge now use 'name: speckit-my-extension-example'
  instead of 'name: speckit.my-extension.example'
- Fixes ZSH/shell compatibility issues with dot notation in command names
- Maintains backward compatibility for all other agents (they continue using dot notation)
- Eliminates duplication between integration setup and registrar paths

Example transformation:
  Before: name: speckit.jira.sync-status  (breaks in ZSH/Forge)
  After:  name: speckit-jira-sync-status  (works everywhere)

Fixes inconsistency where core templates used hyphens but extension/preset
commands preserved dots, breaking Forge's naming requirements.

* refactor(forge): move name formatting logic to integration module

Move _format_name_for_agent function logic into Forge integration's
registrar_config as a 'format_name' callback, improving separation of
concerns and keeping Forge-specific logic within its integration module.

Changes:
- Remove _format_name_for_agent() from agents.py (shared module)
- Add 'format_name' callback to Forge's registrar_config pointing to format_forge_command_name
- Update CommandRegistrar to use format_name callback when available
- Maintains same behavior: Forge commands use hyphenated names, others use dot notation

Benefits:
- Better encapsulation: Forge-specific logic lives in forge integration
- More extensible: Other integrations can provide custom formatters via registrar_config
- Cleaner separation: agents.py doesn't need to know about specific agent requirements

* fix(forge): make format_forge_command_name idempotent

Handle already-hyphenated names (speckit-foo) to prevent double-prefixing
(speckit-speckit-foo). The function now returns already-formatted names
unchanged, making it safe to call multiple times.

Changes:
- Add early return for names starting with 'speckit-'
- Update docstring to clarify accepted input formats
- Add examples showing idempotent behavior
- Add test coverage for idempotent behavior

Examples:
  format_forge_command_name('speckit-plan') -> 'speckit-plan' (unchanged)
  format_forge_command_name('speckit.plan') -> 'speckit-plan' (converted)
  format_forge_command_name('plan') -> 'speckit-plan' (prefixed)

* test(forge): strengthen name field assertions and clarify comments

Improve test_name_field_uses_hyphenated_format to fail loudly when
the name field is missing instead of silently passing.

Changes:
- Add explicit assertion that name_match is not None before validating value
- Ensures test fails if regex doesn't match (e.g., frontmatter rendering changes)
- Clarify Claude comment: it doesn't use inject_name path but SKILL.md
  frontmatter still includes hyphenated name via build_skill_frontmatter()

Before: Test would silently pass if 'name:' field was missing from frontmatter
After: Test explicitly asserts field presence before validating format

* docs(forge): clarify frontmatter name requirement and improve test isolation

Fix misleading docstring and improve test to properly validate that the
format_name callback is Forge-specific.

Changes to src/specify_cli/integrations/forge/__init__.py:
- Reword module docstring to clarify the requirement is specifically for
  the frontmatter 'name' field value, not command files or invocation
- Before: 'Requires hyphenated command names ... instead of dot notation'
  (implied dot notation unsupported overall)
- After: 'Uses a hyphenated frontmatter name value ... for shell compatibility'
  (clarifies it's the frontmatter field, and Forge still supports dot filenames)

Changes to tests/integrations/test_integration_forge.py:
- Replace Claude with Windsurf in test_registrar_does_not_affect_other_agents
- Claude uses build_skill_frontmatter() which always includes hyphenated names,
  so testing it didn't validate that format_name callback is Forge-only
- Windsurf is a standard markdown agent without inject_name
- Now asserts NO 'name:' field is present, proving format_name isn't invoked
- This properly validates the callback mechanism is isolated to Forge

* test(forge): use parse_frontmatter for precise YAML validation

Replace regex and string searches with CommandRegistrar.parse_frontmatter()
to validate only YAML frontmatter, not entire file content. Prevents false
positives if command body contains 'name:' lines.

Changes:
- test_forge_specific_transformations: Parse frontmatter dict instead of string search
- test_name_field_uses_hyphenated_format: Replace regex with frontmatter parsing
- test_registrar_formats_extension_command_names_for_forge: Use dict validation
- test_registrar_formats_alias_names_for_forge: Use dict validation

Benefits: More precise, robust against body content, better error messages,
consistent with existing codebase utilities.

---------

Co-authored-by: ericnoam <eric.rodriguez@leovegas.com>
2026-04-08 14:37:19 -05:00
404prefrontalcortexnotfound
9c73e68528 fix(bash): sed replacement escaping, BSD portability, dead cleanup in update-agent-context.sh (#2090)
* fix(bash): sed replacement escaping, BSD portability, dead cleanup code

Three bugs in update-agent-context.sh:

1. **sed escaping targets wrong side** (line 318-320): The escaping
   function escapes regex pattern characters (`[`, `.`, `*`, `^`, `$`,
   `+`, `{`, `}`, `|`) but these variables are used as sed
   *replacement* strings, not patterns. Only `&` (insert matched text),
   `\` (escape char), and `|` (our sed delimiter) are special in the
   replacement context. Also adds escaping for `project_name` which
   was used unescaped.

2. **BSD sed newline insertion fails on macOS** (line 364-366): Uses
   bash variable expansion to insert a literal newline into a sed
   replacement string. This works on GNU sed (Linux) but fails silently
   on BSD sed (macOS). Replaced with portable awk approach that works
   on both platforms.

3. **cleanup() removes non-existent files** (line 125-126): The
   cleanup trap attempts `rm -f /tmp/agent_update_*_$$` and
   `rm -f /tmp/manual_additions_$$` but the script never creates files
   matching these patterns — all temp files use `mktemp`. The wildcard
   with `$$` (PID) in /tmp could theoretically match unrelated files.

Fixes #154 (macOS sed failure)
Fixes #293 (sed expression errors)
Related: #338 (shellcheck findings)

* fix: restore forge case and revert copilot path change

Address PR review feedback:
- Restore forge) case in update_specific_agent since
  src/specify_cli/integrations/forge/__init__.py still exists
- Revert COPILOT_FILE path from .github/agents/ back to .github/
  to stay consistent with Python integration and tests
- Restore FORGE_FILE variable, comments, and usage strings

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

* refactor: extract repeated sed escaping into _esc_sed helper

Address Gemini review feedback — the inline sed escaping pattern
appeared 7 times in create_new_agent_file(). Extract to a single
helper function for maintainability and readability.

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

* fix: restore combined AGENTS_FILE label in update_all_existing_agents

Gemini correctly identified that splitting AGENTS_FILE updates into
individual calls is redundant — _update_if_new deduplicates by
realpath, so only the first call logs. Restore the combined label
and add back missing Pi reference.

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

* fix: remove pre-escaped && in JS/TS commands now that _esc_sed handles it

The old code manually pre-escaped & as \& in get_commands_for_language
because the broken escaping function didn't handle &. Now that _esc_sed
properly escapes replacement-side specials, the pre-escaping causes
double-escaping: && becomes \&\& in generated files.

Found by blind audit.

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

* fix: split awk && mv to let set -e catch awk failures

Under set -e, the left side of && does not trigger errexit on failure.
Split into two statements so awk failures are fatal instead of silent.

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

* fix: guard empty _CLEANUP_FILES array for Bash 3.2 compatibility

On Bash 3.2, the ${arr[@]+"${arr[@]}"} pattern expands to a single
empty string when the array is empty, causing rm to target .bak and
.tmp in the current directory. Use explicit length check instead,
which also avoids the word-splitting risk of unquoted expansion.

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

---------

Co-authored-by: Bo Bobson <bo@noneofyourbusiness.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 14:29:50 -05:00
Quratulain-bilal
8472e44215 Add Spec Diagram community extension to catalog and README (#2129)
Adds the spec-kit-diagram extension (3 commands, 1 hook) that auto-generates
Mermaid diagrams for SDD workflow visualization, feature progress tracking,
and task dependency graphs.

Addresses community request in issue #467 (50+ upvotes).

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 14:01:47 -05:00