mirror of
https://github.com/github/spec-kit.git
synced 2026-08-03 06:26:30 +08:00
2355fcb350aabcfdd39897f3eb852e2d027bb7c7
1593 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
2355fcb350 |
Update AGENTS.md (#2626)
* docs: layer contributor-onboarding sections onto AGENTS.md Rebased onto current main and reworked so the additions match the current architecture rather than the stale base this branch was written against. The original revision documented the retired Windsurf integration and a CLI-managed `context_file` field that no longer exists (context files are now owned by the opt-in agent-context extension), and described the manifest at the wrong path with a non-existent API. This version keeps all current AGENTS.md content unchanged and adds four onboarding-focused sections, verified against the code: - Quickstart — Add a New Integration in 5 Steps (links into the existing step-by-step section; notes context files are extension-owned) - IntegrationManifest — File Tracking (correct path .specify/integrations/<key>.manifest.json and real API: record_file / record_existing / hash-guarded uninstall) - Error Handling and Debugging (symptom/cause/fix table + debug tips) - Contribution Checklist Purely additive (+88 lines, no deletions); all internal anchors resolve. Assisted-by: Claude Opus 4.8 (model: claude-opus-4-8, autonomous) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> |
||
|
|
98c9e67ce2 |
fix(extensions): tolerate non-string catalog name in display-name lookup (#3747)
* fix(extensions): tolerate non-string catalog name in display-name lookup
_resolve_catalog_extension() filters catalog search results by display
name with `ext["name"].lower() == argument.lower()`. Extension catalog
JSON is user-editable, so a hand-authored non-string name (e.g.
`name: 123`) crashes the filter with `AttributeError: 'int' object has
no attribute 'lower'`, taking down `extension info <name>` and
`extension add <name>`. A missing `name` key would likewise KeyError.
Coerce defensively with `str(ext.get("name", "")).lower()`, matching the
ambiguous-match display block just below (which already str()-coerces
name for the same reason). A bad-named entry simply doesn't match,
yielding a clean not-found error instead of a traceback.
Adds a regression test invoking `extension info <name>` against a
mocked catalog whose search result has `name: 123`; it fails pre-fix
with AttributeError.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
|
||
|
|
6136706ef3 |
fix(presets): coerce non-string catalog tags before joining (#3743)
* fix(presets): coerce non-string catalog tags before joining Preset catalog payloads are user-editable YAML/JSON, so a `tags:` list can legitimately contain non-strings (e.g. numeric tags). The preset list/search/info display paths and the catalog search backend joined tags with a raw `", ".join(...)` / used `t.lower()`, which raised `TypeError: sequence item N: expected str instance, int found` (or `AttributeError` on `.lower()`) and crashed the command. Sibling command surfaces already guard this — extensions, integrations, and workflows coerce with `str(t) for t in ...`. This aligns presets: - `_commands.py`: `preset list`, `preset search`, and both `preset info` branches now join `str(t) for t in ...`. - `__init__.py` `PresetCatalog.search`: tag filter uses `str(t).lower()` and the searchable-text join coerces tags to `str`. Adds regression tests driving `preset search` and `preset info` through CliRunner with numeric tags; both fail before the fix with the TypeError. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> |
||
|
|
683bfd00c9 |
fix: register extensions for the active integration only (#3459)
* fix: register extensions for the active integration only extension add registered commands for every detected agent, and integration upgrade back-filled enabled extensions for non-active integrations. Maintainer direction on #2948: treat the project as single-active. Only the active integration gets extension artifacts; use/switch rescaffold the target when the user selects it. - extension add now routes through the all-agents pass restricted to the active integration (only_agent), keeping detection and missing-skills-dir recovery safeguards. Projects without recorded init-options fall back to detection-based registration. - integration upgrade re-registers extensions only when upgrading the active integration, reversing the #2886 back-fill for non-active targets at maintainer request. Fixes #2948 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: address review feedback on active-only extension registration - Restrict the extension-add active-integration fallback to projects with no recorded active key at all. A recorded but unsupported key (e.g. "generic", deliberately excluded from AGENT_CONFIGS) no longer falls back to registering every detected agent. - Apply the same single-active rule to preset command overrides: PresetManager._register_commands now scopes registration to the active integration via only_agent. - Add PresetManager.register_enabled_presets_for_agent, mirroring ExtensionManager.register_enabled_extensions_for_agent, and call it from integration use/switch/upgrade (active only) alongside the existing extension re-registration so presets are rescaffolded on activation instead of being written for inactive integrations. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: address second round of review feedback (priority order, fail-closed, docs) - register_enabled_presets_for_agent now processes presets in reverse priority order (lowest-precedence first) so the highest-precedence preset is written last and actually wins after `integration use` rescaffolds two overlapping preset command overrides. Verified this reproduces the previously reported reversed-priority bug and that the fix resolves it. - _register_commands_for_active_agent now checks for the "ai" key's presence separately from its value: a missing key still falls back to detection-based registration for all agents, but a recorded, malformed value (non-string or empty, e.g. [] or null) now fails closed (registers nothing) instead of being treated as "no active integration" or reaching AGENT_CONFIGS.get() with an unhashable key and raising TypeError. - Updated docs/reference/presets.md and docs/reference/integrations.md to describe active-only preset/extension registration and clarify that `integration use`/`switch` is the activation point for installed extensions and presets, and that `upgrade` only re-registers them for the active integration. Adds regression tests: two enabled presets overriding the same command with different priorities (priority winner must survive `use` rescaffolding), and a malformed recorded `ai` value ([]) for `extension add`. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: address third round of review feedback (multi-integration semantics) Fixes five deeper active-only registration bugs surfaced by Copilot review after |
||
|
|
42c7230aa9 |
fix(extensions): tolerate non-string tags in catalog search (#3746)
* fix(extensions): tolerate non-string tags in catalog search ExtensionCatalog.search() assumed catalog `tags` were always strings: the tag filter called `t.lower()` and the query path did `" ".join([...] + tags)`. Extension catalog JSON is user-editable, so a hand-authored `tags: [1, 2]` crashed search with AttributeError (tag filter) or TypeError (query join). Coerce defensively by filtering to `isinstance(t, str)` and guarding the tags value as a list, matching the reference-correct sibling in integrations/catalog.py. Non-string tags are now skipped rather than raising. Adds a regression test driving search(tag=...) and search(query=...) against a catalog with mixed string/int tags; both fail pre-fix. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(extensions): also coerce non-string author/name in catalog search The same ExtensionCatalog.search() method had two more string assumptions on user-editable catalog fields: the author filter called `ext_data.get("author", "").lower()` (AttributeError on a numeric author) and the query searchable-text joined `name`/`description` uncoerced (TypeError on a numeric name). Coerce both defensively, matching the reference-correct integrations/catalog.py::search. Extends the regression test with non-string author/name coverage; fails pre-fix with AttributeError at the author filter. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
e6a3ccfb27 |
fix(extensions): hyphenate command names in 'extension info' listing (#3744)
The 'Commands:' section of 'specify extension info' for a locally installed extension printed each command in its manifest dotted form (e.g. speckit.jira.sync). Cline and Forge register hyphenated command names (/speckit-jira-sync), so on those projects the displayed names did not match what the user actually invokes. Format each name through the active agent's command-name formatter, mirroring the parity 'extension add' already applies to its 'Provided commands' listing (#3669) and completing the Forge/Cline command-name parity from #3641/#3642. Adds a regression test asserting the hyphenated form appears (and the dotted form does not) for a Forge project. |
||
|
|
962f9f0765 |
fix(workflows): escape remaining untrusted fields in workflow info (#3731)
* fix(workflows): escape remaining untrusted fields in `workflow info` Follow-up to #3690, which escaped only the step-graph brackets. Every other metadata field `workflow info` prints is untrusted content (workflow.yml or catalog JSON), and console.print has Rich markup enabled, so an unescaped `[...]` in any of them is parsed as a style tag and silently swallowed: - definition path: name, version, author, description, integration, and each input's name/type - catalog path: name, version, description, tags, and the "not found" workflow id A description of `Does [stuff] nicely` rendered as `Does nicely`; an integration of `claude [code]` rendered as `claude `. Route every field through _escape_markup, matching the sibling `workflow list` / catalog `search` commands, so bracketed text renders literally. Add two regression tests covering the definition and catalog paths; both fail on the pre-fix source (fields with brackets come back truncated). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test: cover version + not-found-id escapes in workflow info Addresses Copilot review feedback on the workflow-info markup-escape tests: - The definition-path and catalog-path regression tests left `version` bracket-free and never asserted it, so the version escapes could be removed without failing. Use bracketed version values and assert they survive verbatim. - The newly escaped not-found identifier is a separate output path that no test reached. Add a case where local load raises FileNotFoundError and catalog lookup returns None, invoke `workflow info` with a bracketed ID, and assert the literal ID is preserved in the error. Verified each new assertion fails when its source escape is removed (test-the-test). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
c1028e5506 |
fix(extensions): guard non-numeric catalog downloads in search/info rendering (#3710)
* fix(extensions): guard non-numeric catalog downloads in search/info rendering `specify extension search` and `specify extension info <id>` format a catalog entry's `downloads` field with the `:,` thousands separator, guarded only by `is not None`. Catalog payloads are only shape-validated -- individual fields are never type-checked and `_get_merged_extensions` returns raw catalog dicts -- so an entry with a non-numeric `downloads` (e.g. the JSON string "1500", realistic from a community / SPECKIT_CATALOG_URL / project catalog) makes the `:,` format raise `ValueError: Cannot specify ',' with 's'`, aborting the whole command with an uncaught traceback. Group-format `downloads` only when it is actually numeric; otherwise render it as-is. Numeric values (int/float, incl. bool) format identically, so correct catalogs are byte-for-byte unchanged. Every other field in these two renderers is already `str()`-wrapped; this closes the one unguarded field. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(extensions): escape the non-numeric downloads fallback for Rich markup Address review feedback: the fallback interpolated the untrusted catalog value straight into a Rich-rendered string, so guarding the ``:,`` ValueError just traded it for a MarkupError -- a catalog entry with downloads "[/red]foo" still aborted `extension search`/`info`, and balanced tags could restyle the output. Wrap the fallback in _escape_markup(str(...)) at both sites, matching how every other catalog field in these renderers is already escaped. Numeric values keep the identical ``:,`` branch, so correct catalogs are unchanged. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(extensions): escape 'stars' too, in the same stats string Follow-up to the downloads escaping: `stars` is the other catalog-controlled value joined into the same Rich-rendered stats line, and it was still raw -- verified that stars "[/red]x" raises the same MarkupError and aborts `extension info`/`search`. Hardening one of the two adjacent values would have left the reported defect reachable through the sibling field. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
9e150cd3b2 |
fix(agent-context): apply default markers when config markers are blank (bash) (#3736)
When the extension config omits context_markers (or sets them blank),
relying on the built-in defaults, the Bash port aborted with "malformed
config parser output" and never updated the context file, while the
Python (`or DEFAULT_*`) and PowerShell (default-initialized) ports handled
it correctly.
The config parser prints three lines (context_files JSON, marker_start,
marker_end), captured via `_raw_opts="$(...)"`. Command substitution strips
trailing newlines, so blank marker lines collapse the output to fewer than
three, tripping the `(( ${#_opts_lines[@]} < 3 ))` guard and making the
DEFAULT_START/END substitution unreachable — the exact case it was written
for.
Require only the context_files line and default the marker lines to empty
(`${_opts_lines[1]:-}` / `${_opts_lines[2]:-}`) so the existing
DEFAULT_START/END fallback fills them in. Add a parity regression test with
blank markers (it fails on the old guard and passes with the fix).
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
|
||
|
|
99dc915ae3 |
fix: escape Rich markup in catalog list output (#3738)
The `catalog list` subcommands for workflows, workflow steps, presets, and integrations printed user-editable catalog fields (name/url/ description from the `*-catalogs.yml` files) through `console.print` with Rich markup enabled. Any bracketed content such as a description `Does [stuff] nicely` was parsed as a style tag and silently swallowed, and a malformed tag could raise while rendering. Route each untrusted field through the module's already-imported `escape` helper, matching the pattern already used by `extension catalog list`. Adds regression tests for all four commands that inject bracketed name/url/description and assert the brackets survive verbatim in the output. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
103ad73775 |
fix(workflows): guard non-mapping 'workflow:' block in WorkflowDefinition (#3694)
* fix(workflows): guard non-mapping 'workflow:' block in WorkflowDefinition
A present-but-non-mapping top-level `workflow:` block (bare `workflow:` ->
YAML null, or `workflow: <str>` / `workflow: [..]`) crashed
WorkflowDefinition.__init__ with AttributeError: the `{}` default of
`data.get("workflow", {})` only applies when the key is ABSENT, so a non-dict
value reached `workflow.get("id", ...)`. This fires inside from_yaml/
from_string — before validate_workflow can report the malformed shape — and
in the CLI escapes as a raw traceback (load_workflow is wrapped to catch only
FileNotFoundError/ValueError).
Normalize the local `workflow` to {} when it is not a mapping (self.data keeps
the raw value so validate_workflow still reports it), mirroring the adjacent
default_options guard.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(workflows): assert self.data preserves the raw non-mapping workflow value
Address review: the previous assertion only proved the key stayed present; it
would pass even if construction replaced the malformed value with {}. Assert
definition.data["workflow"] equals the original parsed value and is still a
non-mapping, proving the guard normalizes only the local variable.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
||
|
|
59e63699b8 |
fix(bundler): reject unsupported schema_version in _merge_config (align readers) (#3711)
bundle-catalogs.yml has two readers that are meant to agree: commands_impl/ catalog_config._read (bundle catalog list/add/remove) and models/catalog. _merge_config (the resolution path feeding bundle search/info/install via load_source_stack). _read rejects an unsupported MAJOR schema_version; _merge_config never checked it, so a file written by a newer/incompatible Spec Kit (e.g. schema_version '2.0') was silently parsed under v1 assumptions on the exact path where install_policy governs trust — the two readers disagreed. #3623 (non-list catalogs) and #3659 (top-level non-mapping) already aligned these two readers guard-by-guard; this is the last unaligned guard. Add the same forward-compatible major-version check to _merge_config. Promote CONFIG_SCHEMA_VERSION to models/catalog.py as the single source of truth and import it in catalog_config.py (was a local duplicate) so the two cannot drift. Absent schema_version stays valid (backward compatible); matching major stays valid. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
015d125667 |
Update Linear Weave extension to v1.0.1 (#3762)
Update linear-weave extension submitted by @tonydwoodhouse: - extensions/catalog.community.json (version, download_url, documentation, updated_at) Closes #3758 Assisted-by: GitHub Copilot (model: claude-sonnet-4.6, autonomous) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
3ca0eb169e |
Add Intake Sequencing Governance preset to community catalog (#3761)
Add intake-sequencing-governance preset submitted by @hindermath to: - presets/catalog.community.json (alphabetical order) - docs/community/presets.md community presets table Closes #3742 Assisted-by: GitHub Copilot (model: claude-sonnet-4.6, autonomous) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
c6cb25cb4a |
Update Quality Gates (Enforcement Layer) extension to v0.3.3 (#3760)
Update gates extension submitted by @schwichtgit: - extensions/catalog.community.json (version, download_url, updated_at) - docs/community/extensions.md community extensions table (no changes needed) Closes #3755 Assisted-by: GitHub Copilot (model: claude-sonnet-4.6, autonomous) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
eb8108e7b3 |
Update Verify Review Ship extension to v0.4.1 (#3759)
Update verify-review-ship extension submitted by @cadugevaerd to: - extensions/catalog.community.json (version, download_url, sha256, description, requires, provides, tags, updated_at) - docs/community/extensions.md community extensions table Closes #3751 Assisted-by: GitHub Copilot (model: claude-sonnet-4.6, autonomous) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
403fcdc6fd |
fix(agent-context): discover nested plans in Python port mtime fallback (#3734)
The Python port of update-agent-context reintroduced a one-level plan scan (specs/*/plan.md) in its mtime fallback, while the Bash and PowerShell ports search recursively (specs/**/plan.md) per the fix for issue #3024. The three ports were therefore not in parity: for nested scoped layouts such as specs/<scope>/<feature>/plan.md, the Python port found no plan and omitted the plan link from the managed context section. Switch the fallback to `(root / "specs").rglob("plan.md")` and update the module docstring to match the documented recursive-discovery contract. Add a parity regression test covering the nested layout (it fails on the one-level glob and passes with the recursive scan). Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
2fb94e0f9c |
fix(extensions): make shipped scripts executable after install (#3723)
Extension archives are unpacked with zipfile.extractall and directory installs are copied; neither restores a stripped Unix mode. A bundled *.sh therefore lands non-executable, so a documented `.specify/extensions/<id>/scripts/bash/foo.sh` invocation fails with "Permission denied" — e.g. a CI step that runs an extension's gate. It only worked incidentally, after a later `specify init`. Restore permissions at the shared sink. Every extension install route funnels through ExtensionManager.install_from_directory (install_from_zip delegates to it; extension add, extension update, and bundle installs all reach it), so calling the existing ensure_executable_scripts() there covers every route — present and future — by construction rather than by patching each command. The helper already makes .specify scripts executable (init, migrate, and integration-install all call it); it is called plainly, re-establishing the same idempotent "scripts are executable" invariant those flows restore. Deliberately the whole-project call rather than a scoped one: a scan-scope argument would only spare re-walking already-correct files — negligible beside the copy/extract just performed — while widening a simple, widely-used interface for a single caller. Existing callers were audited: init's end-of-init call still covers core .specify/scripts and is untouched; integration-install and migrate do no manager install. Nothing is removed. No-op on Windows; best-effort per file; does not change which files are executable or their mode. Tests: a manager-level regression test asserts a mode-0644 script comes out executable via both install_from_directory and install_from_zip(force=True) (the latter also covering the remove-then-reinstall shape of extension update), plus an end-to-end `extension add --dev` test. Both fail without the change; skipped on Windows. Fixes #3722. |
||
|
|
446ee329b1 |
docs(assess): clarify the pipeline works on an empty project (#3732)
* docs(assess): clarify the pipeline works on an empty project State explicitly in the README and intake command that the assess pipeline requires no existing source code. An empty, freshly initialized project and an existing codebase are equally valid starting points — the input is just an idea (pasted text, a URL, a ticket, or a codebase pointer). Assisted-by: GitHub Copilot (model: Claude Opus 4.8, autonomous) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9df2615e-6a99-4cdc-b4b2-fc72029bc1d9 * docs(assess): distinguish empty project from no project Clarify that assess still runs inside an initialized Spec Kit project (writing under .specify/assessments/) — only existing source code is optional. Reword 'no repo at all'/'need no repo' to 'need no existing codebase' so users don't expect intake to work outside a Spec Kit project. Assisted-by: GitHub Copilot (model: Claude Opus 4.8, autonomous) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9df2615e-6a99-4cdc-b4b2-fc72029bc1d9 --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9df2615e-6a99-4cdc-b4b2-fc72029bc1d9 |
||
|
|
c0fe0e43cd |
chore: release 0.14.2, begin 0.14.3.dev0 development (#3730)
* chore: bump version to 0.14.2 * chore: begin 0.14.3.dev0 development --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> |
||
|
|
ae0b8ca2b0 |
Update Intake Review Governance preset to v0.1.1 (#3729)
Update intake-review-governance preset submitted by @hindermath to: - presets/catalog.community.json (version, download_url, documentation, description) - docs/community/presets.md community presets table Closes #3727 Assisted-by: GitHub Copilot (model: claude-sonnet-4.6, autonomous) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
2fe35bf898 |
Update Verify Review Ship extension to v0.3.0 (#3728)
Update verify-review-ship extension submitted by @cadugevaerd: - extensions/catalog.community.json (version, download_url, description, effect, tags, sha256, updated_at) - docs/community/extensions.md community extensions table Closes #3726 Assisted-by: GitHub Copilot (model: claude-sonnet-4.6, autonomous) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
73908f798a |
Update Architecture Guard extension to v1.13.1 (#3724)
Update architecture-guard extension submitted by @DyanGalih: - extensions/catalog.community.json (version 1.8.17 -> 1.13.1, download_url, provides.commands 10 -> 14, tags: add hygiene, updated_at) Closes #3564 Assisted-by: GitHub Copilot (model: claude-sonnet-5, autonomous) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> |
||
|
|
ffe2a7ffd6 |
docs(upgrade): Claude Code files live in .claude/skills, not .claude/commands (#3708)
The Claude Code integration installs skills into `.claude/skills` (see integrations/claude: `"dir": ".claude/skills"`), and the "what gets kept" list earlier in this same doc already says `.claude/skills/`. But three troubleshooting/reference spots still point users at `.claude/commands/`, which does not exist for a Claude Code install -- so the "verify files exist" checks list an empty/missing directory. Correct all three to `.claude/skills/`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
ae82c74339 |
fix(kilocode): install commands under .kilo/commands (#3672)
* fix(kilocode): write commands to .kilo/commands * fix: guard Kilo legacy command migration --------- Co-authored-by: root <kinsonnee@gmail.com> |
||
|
|
71e6201790 |
fix(auth): normalize whitespace in auth-config env-var/id references at store time (#3691)
* fix(auth): normalize whitespace in auth-config env-var/id references at store time token_env, client_secret_env, tenant_id, and client_id were VALIDATED on their .strip()ed form but STORED raw, so an accidentally padded value passed validation yet silently broke the downstream verbatim os.environ.get(name) / OAuth-URL lookups — load_auth_config succeeded but resolve_token returned None and the request quietly downgraded to unauthenticated (401/403) with no diagnostic. Normalize these whitespace-insignificant string references with a _norm helper at store time, mirroring how `hosts` is already normalized (h.strip().lower()). `token` is unchanged (already stripped at resolve time). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test(auth): cover tenant_id/client_id/client_secret_env normalization Address review: the regression test only covered token_env, but the fix also normalizes tenant_id, client_id, and client_secret_env. Add a padded azure-ad entry asserting all three are stored stripped. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
ea6843c1fe |
fix(workflows): guard non-mapping 'inputs:' block in engine._resolve_inputs (#3696)
execute()/resume() run UNVALIDATED definitions (load_workflow does not
validate). WorkflowDefinition stores `inputs` raw, so a non-mapping
`inputs:` block (bare `inputs:` -> None, or `inputs: []`) crashed
_resolve_inputs at `for name, input_def in definition.inputs.items()` with
AttributeError, aborting the whole run.
Return {} when inputs is not a mapping, mirroring validate_workflow's own
`isinstance(definition.inputs, dict)` check. Protects both call sites
(execute and resume); normal dict resolution is unchanged.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
||
|
|
b0850c97e6 |
Update Intake Authoring Governance preset to v0.2.0 (#3721)
Update intake-authoring-governance preset submitted by @hindermath to: - presets/catalog.community.json (version, download_url, documentation, description, provides, tags) - docs/community/presets.md community presets table Closes #3720 Assisted-by: GitHub Copilot (model: claude-sonnet-4.6, autonomous) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
781a14a6d2 |
docs: clarify shell-step interpolation safety (#3719)
* docs: clarify shell-step interpolation safety
Shell step `run` fields are executed by the system shell and `{{ ... }}`
expressions are substituted as raw, unquoted text. Document that untrusted
sources — workflow `inputs.*` and prior-step output, including AI-generated
`prompt` output — must be quoted, enum-constrained, validated, or gated before
they reach a `run` field.
- docs/reference/workflows.md: add an "Interpolation and shell safety" section.
- workflows/README.md: add a warning under the Shell Steps example, link to the
new section, and quote the `inputs.project_dir` example.
- workflows/PUBLISHING.md: strengthen the interpolation guidance and call out
prior-step/agent output as untrusted.
Assisted-by: GitHub Copilot (model: Claude Opus 4.8, autonomous)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c0fd6900-69bf-4fcb-b377-de37f98f5835
* docs: correct shell-step interpolation guidance
Address review feedback that the previous wording over-promised. Clarify that
none of the mitigations neutralise a hostile interpolated value:
- Quoting is not a security boundary — there is no shell-escaping filter, and a
value containing the matching quote can break out. Present quoting as
correctness handling for already-constrained values only.
- Remove the "pass data via environment or files" guidance: ShellStep has no
`env` mapping (it only copies the process environment and sets
SPECKIT_WORKFLOW_DIR), so that transport does not exist.
- Drop the claim that routing through a command/prompt step validates or safely
binds a value; it does not.
- Correct the gate guidance: a gate renders only its own message/show_file and
does not inspect, resolve, or sanitise the following step. Authors must
surface the exact command/data in the gate themselves, and approval does not
neutralise an injectable interpolation.
Frame constraining values at the source (enum/allowlist) as the only reliable
control, and keeping unconstrained values out of `run` fields entirely.
Assisted-by: GitHub Copilot (model: Claude Opus 4.8, autonomous)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c0fd6900-69bf-4fcb-b377-de37f98f5835
* docs: remove unsafe interpolation from example and gate guidance
Address further review feedback:
- workflows/README.md: the shell example interpolated an unconstrained path
into shell source, which contradicted the warning beneath it. Shell steps
already run from the project root, so drop the `cd '{{ inputs.project_dir }}'`
prefix and model a plain `run: "npm test"` with no interpolation.
- docs/reference/workflows.md: GateStep prints `message` verbatim with no
control-character stripping (stripping applies only to `show_file` path and
contents), so recommending that authors surface untrusted data in `message`
was itself unsafe — agent/caller output could inject terminal escapes to
alter or hide the prompt. Direct authors to keep `message` to trusted text
and surface untrusted material via `show_file`, whose contents are stripped.
Assisted-by: GitHub Copilot (model: Claude Opus 4.8, autonomous)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c0fd6900-69bf-4fcb-b377-de37f98f5835
* docs: use correct prompt-step output key in example
A `prompt` step stores agent-generated text under `output.stdout`, not
`output.value`, so the example expression `{{ steps.plan.output.value }}`
would resolve to None. Reference `output.stdout` so the example correctly
demonstrates untrusted agent output flowing into a shell step.
Assisted-by: GitHub Copilot (model: Claude Opus 4.8, autonomous)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c0fd6900-69bf-4fcb-b377-de37f98f5835
---------
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c0fd6900-69bf-4fcb-b377-de37f98f5835
|
||
|
|
be0c741ebb |
[extension] Add Blueprint Index — Living Architecture Map extension to community catalog (#3718)
* Add Blueprint Index extension to community catalog Add blueprint-index extension submitted by @ogil109 to: - extensions/catalog.community.json (alphabetical order) - docs/community/extensions.md community extensions table Closes #3628 Assisted-by: GitHub Copilot (model: claude-sonnet-4.6, autonomous) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+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> |
||
|
|
36754522f7 |
fix(github-http): return None on malformed host in resolve_github_release_asset_api_url (#3715)
Accessing the parsed authority (via urlparse/.hostname) raises ValueError on a malformed bracketed host, e.g. https://[not-an-ip]/..., mirroring the existing .port guard below. download_url is server-controlled (a catalog download_url payload), so the function's resolve-or-return-None contract must hold rather than leaking a raw traceback to the caller. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
391cc0dff8 |
fix(integrations): declare PiIntegration multi_install_safe (#3652)
* fix(integrations): declare PiIntegration multi_install_safe PiIntegration writes only to its isolated, static root .pi/prompts, disjoint from every other integration, yet never declared multi_install_safe — so it inherited the IntegrationBase default False, leaving `specify integration status` in a permanent unsafe-multi-install ERROR state when pi is co-installed alongside another agent. Add `multi_install_safe = True`, mirroring the isolated MarkdownIntegration cohort (qwen, shai, qodercli) and the kiro-cli #3471 fix. The parametrized registry isolation contracts auto-include pi and pass. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(integrations): list pi in the multi-install-safe reference table Declaring PiIntegration multi_install_safe means the reference table in docs/reference/integrations.md (which states it lists all currently declared multi-install-safe integrations) should include it. Add the alphabetized pi row with its .pi/prompts isolation path. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
1631c0a50f |
harden: remove shell parameter from run_command() (#3716)
run_command() enforces a list[str] argv contract, so a shell parameter served no purpose beyond keeping an unnecessary shell-injection surface that a future refactor could re-enable. Remove the parameter (and its now-dead ValueError guard) so shell=False is the only possible behavior. Assisted-by: GitHub Copilot (model: Claude Opus 4.8, autonomous) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 74a1bd02-f6cd-412a-b5a8-a7767a5e058d |
||
|
|
6385250264 |
chore(deps): bump github/codeql-action/init from 4.37.1 to 4.37.3 (#3699)
* chore(deps): bump github/codeql-action/init from 4.37.1 to 4.37.3
Bumps [github/codeql-action/init](https://github.com/github/codeql-action) from 4.37.1 to 4.37.3.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](
|
||
|
|
bfe4772b79 |
fix: auto-correct conflicting feature prefixes (#1829)
Treat an explicit feature number as a preference when an existing spec directory already uses that prefix. Advance to the next available spec prefix and warn without fetching or scanning git branches. Keep Bash, PowerShell, and Python variants aligned. Preserve 64-bit numbering, timestamp mode, dry-run output, matching-file behavior, and exact-directory reuse through the allow-existing option. Assisted-by: Codex (model: GPT-5, autonomous) |
||
|
|
c0ba81190b |
chore(deps): bump actions/checkout from 6.0.3 to 7.0.1 (#3703)
Bumps [actions/checkout](https://github.com/actions/checkout) from 6.0.3 to 7.0.1. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v6.0.3...3d3c42e5aac5ba805825da76410c181273ba90b1) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 7.0.1 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
e53ddcb0cc |
chore(deps): bump DavidAnson/markdownlint-cli2-action (#3702)
Bumps [DavidAnson/markdownlint-cli2-action](https://github.com/davidanson/markdownlint-cli2-action) from 24.0.0 to 24.1.0.
- [Release notes](https://github.com/davidanson/markdownlint-cli2-action/releases)
- [Commits](
|
||
|
|
769acafcab |
chore(deps): bump actions/setup-node from 6.4.0 to 7.0.0 (#3701)
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 6.4.0 to 7.0.0. - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/v6.4.0...820762786026740c76f36085b0efc47a31fe5020) --- updated-dependencies: - dependency-name: actions/setup-node dependency-version: 7.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
2a397aad6c |
chore(deps): bump astral-sh/setup-uv from 8.3.2 to 9.0.0 (#3700)
Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 8.3.2 to 9.0.0.
- [Release notes](https://github.com/astral-sh/setup-uv/releases)
- [Commits](
|
||
|
|
4d3a4281bc |
chore: release 0.14.1, begin 0.14.2.dev0 development (#3698)
* chore: bump version to 0.14.1 * chore: begin 0.14.2.dev0 development --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> |
||
|
|
58f5730dd5 |
Update Agent Parity Governance preset to v0.4.0 (#3697)
Update agent-parity-governance preset submitted by @hindermath: - presets/catalog.community.json (version, download_url, description, documentation, updated_at) - docs/community/presets.md community presets table Closes #3684 Assisted-by: GitHub Copilot (model: claude-sonnet-4.6, autonomous) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
52b20f1a82 |
fix(bundler): InstallResult.changed counts uninstalled as a change (#3692)
* fix(bundler): InstallResult.changed counts uninstalled as a change The `changed` property only considered `installed` and `refreshed`, omitting `uninstalled`. A `bundle update` whose new manifest drops components (removing them via the refresh path) with no new install/refresh produces installed=[], refreshed=[], uninstalled=[dropped set] — yet `changed` returned False, misreporting a mutating update as a no-op. Include `uninstalled` in the disjunction (it is the third mutating outcome list on the same dataclass, also the sole output of the remove_bundle path). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * ci: pin ruff to 0.15.0 to avoid 0.16.0 default-ruleset breakage ruff 0.16.0 expanded its default rule set from ~59 to ~413 rules, causing the unpinned `uvx ruff check` step to report ~1475 pre-existing violations unrelated to this change. Pin to 0.15.0 to restore green lint. Assisted-by: GitHub Copilot (model: Claude Opus 4.8, autonomous) --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Manfred Riem <15701806+mnriem@users.noreply.github.com> |
||
|
|
579579ba80 |
[preset] Update Cross-Platform Governance preset to v0.2.1 (#3695)
* Update Cross-Platform Governance preset to v0.2.1 Update cross-platform-governance preset submitted by @hindermath to: - presets/catalog.community.json (version, download_url, documentation, description, updated_at) - docs/community/presets.md community presets table Closes #3683 Assisted-by: GitHub Copilot (model: claude-sonnet-4.6, autonomous) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * ci: pin ruff to 0.15.0 to avoid 0.16.0 default-ruleset breakage ruff 0.16.0 expanded its default rule set from ~59 to ~413 rules, causing the unpinned `uvx ruff check` step to report 1476 pre-existing violations. Pin to 0.15.0 to restore green lint until the codebase is audited against the new defaults. Assisted-by: GitHub Copilot (model: Claude Opus 4.8, autonomous) --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Manfred Riem <15701806+mnriem@users.noreply.github.com> |
||
|
|
34a086940f |
Update A11Y Governance preset to v0.4.1 (#3693)
Update a11y-governance preset submitted by @hindermath to: - presets/catalog.community.json (version, download_url, documentation, description, updated_at) - docs/community/presets.md community presets table Closes #3682 Assisted-by: GitHub Copilot (model: claude-sonnet-4.6, autonomous) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
0b6bf865c1 |
fix(workflows): escape step-graph brackets in workflow info so the type shows (#3690)
`workflow info` rendered each step as `→ <id> [<type>]`, but console.print has Rich markup enabled, so `[<type>]` was parsed as a style tag named after the step type (command/gate/prompt/…) and silently swallowed — every step printed as `→ <id> ` with the type gone. Escape the literal bracket with `\[` (and escape id/type via _escape_markup, as the sibling workflow_list does), so Rich renders `[<type>]` literally. Mirrors the in-file `\[disabled]` precedent. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
043c4ec572 |
fix(workflows): filter parser rejects trailing tokens (fullmatch, not match) (#3689)
_apply_filter parsed a name(arg) filter with an UNANCHORED regex (re.match(r"(\w+)\((.+)\)")), so any tokens after the closing paren were silently discarded. Because _evaluate_simple_expression splits the top-level pipe before comparison/boolean operators, `count | default(0) > 5` was split into value `count` and filter segment `default(0) > 5`; the segment matched as `default(0)` and `> 5` vanished — the filter's value was returned as the whole expression, giving a silently wrong result. Use re.fullmatch so a mis-wired segment falls through to the existing "unsupported form" ValueError, mirroring the from_json branch's strict trailing-token handling. The greedy `.+` still matches legitimate forms (literal `)` / `|` inside quoted args), so registered/chained/quoted-pipe filters are unaffected. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
5ad312863f |
Update iSAQB Architecture Governance preset to v0.2.1 (#3687)
Update isaqb-architecture-governance preset submitted by @hindermath: - presets/catalog.community.json (version, download_url, description, documentation, updated_at) - docs/community/presets.md community presets table Closes #3681 Assisted-by: GitHub Copilot (model: claude-sonnet-4.6, autonomous) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
58b3cadb39 |
fix(extensions): parse SKILL.md on the --- delimiter line during removal (#3634)
* fix(extensions): parse SKILL.md on the --- delimiter line during removal
ExtensionManager._unregister_extension_skills verified an installed skill
before deleting it by reading metadata.source back from its SKILL.md with a
raw split("---", 2). That substring split stops at the first "---" anywhere
after the opening delimiter, including one embedded in a command description
(e.g. "Separate sections with --- markers"). The frontmatter was then
truncated mid-value, metadata.source parsed empty, the skill looked
unrelated, and its directory was left orphaned on uninstall.
Parse on the "---" delimiter *line* instead, reusing CommandRegistrar.
parse_frontmatter (the line-anchored parser from #3590) in both the fast
(registry-driven) and fallback (directory-scan) removal paths.
Add a regression test that installs an extension whose command description
contains "---", removes it, and asserts the skill directory is gone. Fails
before the fix (dir orphaned), passes after.
* test: cover the fallback scan branch for the --- SKILL.md parse
Copilot noted the new regression test only exercised the fast removal
path (skills_project keeps ai_skills enabled, so remove() resolves the
skills dir directly). Add test_skills_removed_with_dashes_via_fallback_scan,
which deletes init-options.json after install so _get_skills_dir() returns
None and removal takes the fallback directory-scan branch. That branch
re-reads metadata.source with an independently duplicated parser; reverting
it to the old substring split now fails this test (dir orphaned) while the
fast-path test still passes.
|
||
|
|
cce47f6900 |
fix(cli): guard lazy .hostname ValueError in extension/preset add --from (#3651)
* fix(cli): guard lazy .hostname ValueError in extension/preset add --from `extension add --from <url>` and `preset add --from <url>` validated the URL by reading `parsed.hostname` OUTSIDE their `try/except ValueError` guards. A bracketed-but-invalid IPv6 authority (e.g. "https://[not-an-ip]/x.zip") parses cleanly under urlparse() on Python < 3.14 and only raises ValueError lazily on the first .hostname access. On the interpreters spec-kit supports (>=3.11) that raw ValueError leaked past the CLI, printing an uncaught traceback instead of the clean "Invalid URL" error. (The raise moved eager into urlparse() only in 3.14.) Same bug class as the catalog/download fixes #3433/#3435/#3437/#3577. - extensions/_commands.py: read parsed.hostname inside the existing try and reuse it for the localhost check. - presets/_commands.py: guard the up-front `urlparse(from_url).hostname` read (preserves the "Invalid URL" message), and harden the nested `_is_allowed_download_url` to take a URL string and parse+read .hostname inside its own try/except -> returns False on malformed input. This also covers the redirect-validator and final-URL (post-redirect) checks, where the URL is server-controlled. Regression tests for each command: a bracketed-non-IP URL, plus a monkeypatched lazy-.hostname raiser that reproduces the pre-3.14 shape independently of the running interpreter (fails with a raw ValueError before the fix, verified via test-the-test). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * fix(cli): address Copilot review on --from URL guard comments/tests Copilot's review on #3651 flagged two accuracy problems: 1. The guard comments asserted a specific (and incorrect) CPython version history -- that "https://[not-an-ip]/..." parses cleanly under urlparse() on Python < 3.14 and only raises ValueError lazily on the first .hostname access. In fact the eager bracketed-host check (gh-103848, CVE-2024-11168) was backported to the 3.11 branch and shipped in 3.11.4, so on every interpreter spec-kit supports (>=3.11) that URL is rejected eagerly at urlparse(). Reworded the three source comments to state the guard as a defensive policy (parsing OR the .hostname read can raise ValueError, guard both) without asserting version history. 2. The two monkeypatched lazy-.hostname tests were described as reproducing "the exact production path" / "the Python < 3.14 shape". They are synthetic defensive cases. Relabeled them as synthetic defensive coverage that does not reproduce any specific CPython behavior, and dropped the version-history claims from the bracketed-non-IP test docstrings. The second-round suggestion (_is_allowed_download_url(final_url) instead of _is_allowed_download_url(_urlparse(final_url))) was already applied in the original commit. Behavior unchanged; comments/docstrings only. URL-guard tests pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> |
||
|
|
e14561f773 |
Update Architecture Governance preset to v0.5.1 (#3686)
Update architecture-governance preset submitted by @hindermath: - presets/catalog.community.json (version, download_url, documentation, description, updated_at) - docs/community/presets.md community presets table Closes #3680 Assisted-by: GitHub Copilot (model: claude-sonnet-4.6, autonomous) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |