Stage 2: Copilot integration — proof of concept with shared template primitives#2035
Stage 2: Copilot integration — proof of concept with shared template primitives#2035mnriem merged 24 commits intogithub:mainfrom
Conversation
- base.py: added granular primitives (shared_commands_dir, shared_templates_dir, list_command_templates, command_filename, commands_dest, copy_command_to_directory, record_file_in_manifest, write_file_and_record, process_template) - CopilotIntegration: uses primitives to produce .agent.md commands, companion .prompt.md files, and .vscode/settings.json - Verified byte-for-byte parity with old release script output - Copilot auto-registered in INTEGRATION_REGISTRY - 70 tests (22 new: base primitives + copilot integration) Part of github#1924
- Added --integration flag to init() (mutually exclusive with --ai) - --ai copilot auto-promotes to integration path with migration nudge - Integration setup writes .specify/agent.json with integration key - _install_shared_infra() copies scripts and templates to .specify/ - init-options.json records 'integration' key when used - 4 new CLI tests: mutual exclusivity, unknown rejection, copilot end-to-end, auto-promote (74 total integration tests) Part of github#1924
…red manifest - Added copilot/scripts/update-context.sh and .ps1 (thin wrappers that delegate to the shared update-agent-context script) - CopilotIntegration.setup() installs integration scripts to .specify/integrations/copilot/scripts/ - Renamed agent.json → integration.json with script paths - _install_shared_infra() now tracks files in integration-shared.manifest.json - Updated tests: scripts installed, integration.json has script paths, shared manifest recorded (74 tests) Part of github#1924
Cleaner naming — the shared infrastructure (scripts, templates) belongs to spec-kit itself, not to any specific integration.
Scripts now source shared functions (via SPECKIT_SOURCE_ONLY=1) and call update_agent_file directly with .github/copilot-instructions.md, rather than delegating back to the shared case statement.
Integration scripts now contain only copilot-specific logic (target path + agent name). The dispatcher is responsible for sourcing shared functions before calling the integration script.
These scripts ARE the implementation — the dispatcher calls them. They source common.sh + update-agent-context functions, gather feature/plan data, then call update_agent_file with the copilot target path (.github/copilot-instructions.md).
Validates every single file (37 total) produced by specify init --integration copilot --script sh --no-git.
Validates all 37 files produced by --script ps variant, including .specify/scripts/powershell/ instead of bash.
- test_base.py: IntegrationOption, IntegrationBase, MarkdownIntegration, primitives - test_manifest.py: IntegrationManifest, path traversal, persistence, validation - test_registry.py: INTEGRATION_REGISTRY - test_copilot.py: CopilotIntegration unit tests - test_cli.py: --integration flag, auto-promote, file inventories (sh + ps) - conftest.py: shared StubIntegration helper 76 integration tests + 48 consistency tests = 124 total, all passing.
File inventories are copilot-specific. test_cli.py now only tests CLI flag mechanics (mutual exclusivity, unknown rejection, auto-promote).
There was a problem hiding this comment.
Pull request overview
Stage 2 of the “Agents → Integrations” migration, introducing shared integration scaffolding primitives and a first migrated integration (Copilot) wired into specify init via a new --integration flag, with comprehensive integration-focused tests.
Changes:
- Added shared integration primitives (shared template discovery, command install helpers, template processing) and automatic built-in integration registration.
- Implemented
CopilotIntegration(agent + prompt file generation, VS Code settings handling, integration-specific update-context scripts). - Wired
specify initto support--integration(mutually exclusive with--ai) and added integration test coverage + full file-inventory assertions.
Reviewed changes
Copilot reviewed 12 out of 13 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
src/specify_cli/integrations/base.py |
Adds shared template discovery + granular setup primitives and template processing. |
src/specify_cli/integrations/__init__.py |
Registers built-in integrations (Copilot) at import time. |
src/specify_cli/integrations/copilot/__init__.py |
Implements Copilot integration install flow (agents/prompts/settings/scripts). |
src/specify_cli/integrations/copilot/scripts/update-context.sh |
Adds Copilot-specific context updater script (staged for later activation). |
src/specify_cli/integrations/copilot/scripts/update-context.ps1 |
PowerShell variant of the staged context updater. |
src/specify_cli/__init__.py |
Adds --integration CLI routing, integration scaffolding path, and shared infra install helper. |
tests/integrations/conftest.py |
Adds a stub integration used across integration unit tests. |
tests/integrations/test_base.py |
Tests new base primitives and default setup behavior. |
tests/integrations/test_registry.py |
Tests integration registry registration and lookup semantics. |
tests/integrations/test_manifest.py |
Refocuses manifest tests to manifest-only behavior. |
tests/integrations/test_copilot.py |
Validates CopilotIntegration behavior + full file inventories for sh/ps. |
tests/integrations/test_cli.py |
CLI-level tests for --integration and --ai copilot auto-promotion. |
tests/integrations/__init__.py |
Adds package marker for integration tests. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- _merge_vscode_settings() now returns early (skips merge) when existing settings.json can't be parsed (e.g. JSONC with comments), instead of overwriting with empty settings - Updated _install_shared_infra() docstring to match implementation (scripts + templates, speckit.manifest.json)
User now sees the exact settings they should add manually.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 12 out of 13 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- base.py setup() docstring now explicitly states raw copy behavior and directs to CopilotIntegration for process_template example - _install_shared_infra() uses merge/overwrite instead of rmtree to preserve user-added files under .specify/scripts/
Only write files that don't already exist — preserves any user modifications to shared scripts (common.sh etc.) and templates.
Lists all shared scripts and templates that were not copied because they already existed in the project.
Verifies that _install_shared_infra() preserves user-modified scripts and templates while still installing missing ones.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 12 out of 13 changed files in this pull request and generated 7 comments.
Comments suppressed due to low confidence (3)
tests/integrations/test_copilot.py:225
- Same as the
shinventory:str(p.relative_to(project))is OS-dependent. Use.as_posix()for deterministic path strings.
assert result.exit_code == 0
actual = sorted(str(p.relative_to(project)) for p in project.rglob("*") if p.is_file())
expected = sorted([
tests/integrations/test_manifest.py:123
test_force_removes_modifiedno longer asserts that the modified file was actually deleted. Without that check, a regression whereforce=Truestill skips modified files would pass. Add an assertion thattmp_path / 'f.txt'does not exist after uninstall(force=True).
tests/integrations/test_manifest.py:148test_cleans_empty_parent_dirsonly asserts thata/is removed, but not the intermediate directories (a/banda/b/c). Since the uninstall code attempts to rmdir parents repeatedly, keeping the deeper assertions would better validate directory cleanup behavior.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
src/specify_cli/integrations/copilot/scripts/update-context.ps1
Outdated
Show resolved
Hide resolved
…est accuracy - CopilotIntegration.setup() adds dest containment check (relative_to) - Companion prompts generated from templates list, not directory glob - _install_shared_infra() only records files actually copied (not pre-existing) - VS Code settings tests made unconditional (assert template exists) - Inventory tests use .as_posix() for cross-platform paths
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 12 out of 13 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
src/specify_cli/integrations/copilot/scripts/update-context.ps1
Outdated
Show resolved
Hide resolved
src/specify_cli/integrations/copilot/scripts/update-context.ps1
Outdated
Show resolved
Hide resolved
|
@copilot apply changes based on the comments in this thread |
…isite - Fixed Get-FeaturePaths → Get-FeaturePathsEnv, Read-PlanData → Parse-PlanData - Documented that shared scripts must guard Main with SPECKIT_SOURCE_ONLY before these integration scripts can be activated (Stage 7)
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 12 out of 13 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
src/specify_cli/integrations/copilot/scripts/update-context.ps1
Outdated
Show resolved
Hide resolved
- _merge_vscode_settings() skips merge with warning if parsed JSON is not a dict (array, null, etc.) - PS1 update-context.ps1 uses & invocation instead of dot-sourcing since the shared script runs Main unconditionally
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 12 out of 13 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…list - _merge_vscode_settings() only writes when keys were actually added - update-context.sh uses exec subprocess like PS1 version - Unknown integration error lists available integrations dynamically
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 12 out of 13 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
… fix Path rewrite regex matches the release script's rewrite_paths() exactly (verified byte-identical output). Added .specify/.specify/ double-prefix fix for additional safety.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 12 out of 13 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Stage 2 of #1924 — migrates Copilot as the first integration to validate the architecture. Byte-for-byte identical output to the old release script path.
What's in this PR
src/specify_cli/integrations/base.py— Shared primitivesshared_commands_dir(),shared_templates_dir(),list_command_templates()command_filename(),commands_dest()copy_command_to_directory(),record_file_in_manifest(),write_file_and_record()process_template()— replaces{SCRIPT},{ARGS},__AGENT__, strips frontmatter script blocks, rewrites pathssrc/specify_cli/integrations/copilot/— CopilotIntegration.agent.mdcommands, companion.prompt.mdfiles,.vscode/settings.jsonmergeupdate-context.sh/.ps1scripts (staged for Stage 7 activation)src/specify_cli/__init__.py— CLI wiring--integrationflag (mutually exclusive with--ai)--ai copilotauto-promotes to integration path with migration nudgeintegration.jsonwith integration key + script paths_install_shared_infra()withspeckit.manifest.jsontrackingtests/integrations/— 76 tests across 6 filestest_base.py,test_manifest.py,test_registry.py,test_copilot.py,test_cli.pyshandpsvariantsVerification
specify init . --integration copilotvalidated--ai claude --offline(old path) confirmed working