diff --git a/CHANGELOG.md b/CHANGELOG.md index c79bedc..96f32fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,30 @@ All notable changes to this project will be documented in this file. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Versions follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [v0.7.0] - 2026-07-08 + +### Changed + +- **Agent slash commands shortened: `/speckeep.*` → `/spk.*`**: + - All agent file paths renamed (e.g. `.claude/commands/speckeep.inspect.md` → `.claude/commands/spk.inspect.md`) + - All adapter implementations updated (Claude, Codex, Copilot, Cursor, Kilocode, OpenCode, Roocode, Trae, Windsurf, Aider) + - All prompt templates (EN/RU) for every phase: constitution, spec, inspect, plan, tasks, implement, verify, handoff, hotfix, rollback + - CLI output: root help, `check`, `dashboard`, `demo`, `explore`, `init`, `status`, `archive` + - README (EN/RU) and CLI docs (EN/RU) updated + - `agents-snippet.md` simplified — removed the "⚠️ prefix is speckeep with a p" warning since `/spk` is unambiguous + - `LegacyPrefixPaths()` function in `agents/files.go` enables discovery of stale `speckeep.*` artifacts + - `doctor` warns about remaining old-prefix agent files + - `refresh` auto-removes old-prefix files and regenerates with `/spk.*` naming + - `CleanupAgents` also removes orphaned old-prefix artifacts + +- **`speckeep init` now syncs skills manifest and `.gitignore`** — previously only `refresh` handled this; init was missing the skills setup step + +- **Doctor: stronger deprecated command detection** — `/speckeep.*` detection now catches any remaining old-style references (was limited to `/speckeep.archive`) + +### Fixed + +- **Init: missing skills bootstrap** — `Initialize` now calls `syncSkillsManifest` and `syncSkillsGitignore`, matching `refresh` behavior + ## [v0.6.0] - 2026-06-28 ### Added @@ -266,4 +290,5 @@ Versions follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html). [0.5.0]: https://github.com/bzdvdn/speckeep/releases/tag/v0.5.0 [0.5.1]: https://github.com/bzdvdn/speckeep/releases/tag/v0.5.1 [0.6.0]: https://github.com/bzdvdn/speckeep/releases/tag/v0.6.0 -[unreleased]: https://github.com/bzdvdn/speckeep/compare/v0.6.0...HEAD +[0.7.0]: https://github.com/bzdvdn/speckeep/releases/tag/v0.7.0 +[unreleased]: https://github.com/bzdvdn/speckeep/compare/v0.7.0...HEAD diff --git a/README.md b/README.md index 59492d9..073e97c 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ Results in practice: agents produce correct code on first try more often, handof constitution → spec → [inspect] → plan → tasks → implement → verify → archive ``` -Each phase loads only the minimum context. Optional workflow commands available at any phase: `/speckeep.challenge`, `/speckeep.handoff`, `/speckeep.hotfix`, `/speckeep.scope`, `/speckeep.recap`. +Each phase loads only the minimum context. Optional workflow commands available at any phase: `/spk.challenge`, `/spk.handoff`, `/spk.hotfix`, `/spk.scope`, `/spk.recap`. --- @@ -137,7 +137,7 @@ speckeep init . --lang en --shell sh --agents claude ### 2. Spec -Call `/speckeep.spec --name "CSV export for reports"` in your agent. +Call `/spk.spec --name "CSV export for reports"` in your agent. `specs/active/csv-export-for-reports/spec.md`: @@ -160,15 +160,15 @@ Then a .csv with headers only downloads — no error shown ### 3. Inspect -Call `/speckeep.inspect csv-export-for-reports`. Produces `inspect.md` with verdict. +Call `/spk.inspect csv-export-for-reports`. Produces `inspect.md` with verdict. ### 4. Plan -Call `/speckeep.plan csv-export-for-reports`. Surfaces: `ReportsPage.tsx`, `useReportExport.ts`, `reports.test.ts`. +Call `/spk.plan csv-export-for-reports`. Surfaces: `ReportsPage.tsx`, `useReportExport.ts`, `reports.test.ts`. ### 5. Tasks -Call `/speckeep.tasks csv-export-for-reports`. Produces `tasks.md`: +Call `/spk.tasks csv-export-for-reports`. Produces `tasks.md`: | Surface | Tasks | |---|---| @@ -179,8 +179,8 @@ Call `/speckeep.tasks csv-export-for-reports`. Produces `tasks.md`: ### 6. Implement, verify, archive ``` -/speckeep.implement csv-export-for-reports -/speckeep.verify csv-export-for-reports # verdict: pass +/spk.implement csv-export-for-reports +/spk.verify csv-export-for-reports # verdict: pass speckeep archive csv-export-for-reports . ``` @@ -190,7 +190,7 @@ speckeep archive csv-export-for-reports . speckeep check csv-export-for-reports # Phase: tasks → implement # Tasks: 0 / 3 done -# Next: /speckeep.implement csv-export-for-reports +# Next: /spk.implement csv-export-for-reports ``` diff --git a/README.ru.md b/README.ru.md index e76bcac..4d2e192 100644 --- a/README.ru.md +++ b/README.ru.md @@ -49,7 +49,7 @@ speckeep решает это через **discipline per token** — миним constitution → spec → [inspect] → plan → tasks → implement → verify → archive ``` -Каждая фаза загружает только минимум контекста. Опциональные команды на любой фазе: `/speckeep.challenge`, `/speckeep.handoff`, `/speckeep.hotfix`, `/speckeep.scope`, `/speckeep.recap`. +Каждая фаза загружает только минимум контекста. Опциональные команды на любой фазе: `/spk.challenge`, `/spk.handoff`, `/spk.hotfix`, `/spk.scope`, `/spk.recap`. --- @@ -137,7 +137,7 @@ speckeep init . --lang ru --shell sh --agents claude ### 2. Spec -Вызовите `/speckeep.spec --name "Экспорт отчётов в CSV"` в агенте. +Вызовите `/spk.spec --name "Экспорт отчётов в CSV"` в агенте. `specs/active/eksport-otchetov-v-csv/spec.md`: @@ -160,15 +160,15 @@ Then скачивается .csv только с заголовками — бе ### 3. Inspect -Вызовите `/speckeep.inspect eksport-otchetov-v-csv`. +Вызовите `/spk.inspect eksport-otchetov-v-csv`. ### 4. Plan -Вызовите `/speckeep.plan eksport-otchetov-v-csv`. Surfaces: `ReportsPage.tsx`, `useReportExport.ts`, `reports.test.ts`. +Вызовите `/spk.plan eksport-otchetov-v-csv`. Surfaces: `ReportsPage.tsx`, `useReportExport.ts`, `reports.test.ts`. ### 5. Tasks -Вызовите `/speckeep.tasks eksport-otchetov-v-csv`. Результат: +Вызовите `/spk.tasks eksport-otchetov-v-csv`. Результат: | Surface | Задачи | |---|---| @@ -179,8 +179,8 @@ Then скачивается .csv только с заголовками — бе ### 6. Implement, verify, archive ``` -/speckeep.implement eksport-otchetov-v-csv -/speckeep.verify eksport-otchetov-v-csv # вердикт: pass +/spk.implement eksport-otchetov-v-csv +/spk.verify eksport-otchetov-v-csv # вердикт: pass speckeep archive eksport-otchetov-v-csv . ``` @@ -190,7 +190,7 @@ speckeep archive eksport-otchetov-v-csv . speckeep check eksport-otchetov-v-csv # Фаза: tasks → implement # Задачи: 0 / 3 выполнено -# Далее: /speckeep.implement eksport-otchetov-v-csv +# Далее: /spk.implement eksport-otchetov-v-csv ``` diff --git a/change-spec-archive-roadmap.md b/change-spec-archive-roadmap.md deleted file mode 100644 index 3509475..0000000 --- a/change-spec-archive-roadmap.md +++ /dev/null @@ -1,99 +0,0 @@ -# Change Spec Archive Roadmap - -Переход на новый default layout: - -- `specs_dir = specs/active` -- `archive_dir = specs/archived` - -## Status - -- done: config defaults and core path support -- done: refresh/doctor migration behavior for legacy default layout -- done: prompt/template/doc updates -- done: demo assets and demo workspace paths -- remaining: final wording sweep in ancillary roadmap/architecture notes if needed - -## Must Update - -- [src/internal/config/config.go](/home/bzdv/PAT_PROJECTS/DRAFTSPEC/src/internal/config/config.go) - - defaults: `specs/active`, `specs/archived` -- [src/internal/project/init.go](/home/bzdv/PAT_PROJECTS/DRAFTSPEC/src/internal/project/init.go) - - init directory creation -- [src/internal/project/refresh.go](/home/bzdv/PAT_PROJECTS/DRAFTSPEC/src/internal/project/refresh.go) - - safe move from old defaults -- [src/internal/featurepaths/featurepaths.go](/home/bzdv/PAT_PROJECTS/DRAFTSPEC/src/internal/featurepaths/featurepaths.go) - - active slug discovery assumptions -- [src/internal/workflow/state.go](/home/bzdv/PAT_PROJECTS/DRAFTSPEC/src/internal/workflow/state.go) - - active/archive slug collection -- [src/internal/specs/specs.go](/home/bzdv/PAT_PROJECTS/DRAFTSPEC/src/internal/specs/specs.go) - - list/show behavior over new root -- [src/internal/cli/archive.go](/home/bzdv/PAT_PROJECTS/DRAFTSPEC/src/internal/cli/archive.go) - - archive/restore help text and paths -- [src/internal/cli/list_archive.go](/home/bzdv/PAT_PROJECTS/DRAFTSPEC/src/internal/cli/list_archive.go) - - default path wording -- [src/internal/doctor/doctor.go](/home/bzdv/PAT_PROJECTS/DRAFTSPEC/src/internal/doctor/doctor.go) - - workspace health around new defaults -- [src/internal/templates/assets/lang/en/templates/agents-snippet.md](/home/bzdv/PAT_PROJECTS/DRAFTSPEC/src/internal/templates/assets/lang/en/templates/agents-snippet.md) -- [src/internal/templates/assets/lang/ru/templates/agents-snippet.md](/home/bzdv/PAT_PROJECTS/DRAFTSPEC/src/internal/templates/assets/lang/ru/templates/agents-snippet.md) - - fallback defaults and repo-map indexing rules -- [README.md](/home/bzdv/PAT_PROJECTS/DRAFTSPEC/README.md) -- [README.ru.md](/home/bzdv/PAT_PROJECTS/DRAFTSPEC/README.ru.md) -- [docs/en/cli.md](/home/bzdv/PAT_PROJECTS/DRAFTSPEC/docs/en/cli.md) -- [docs/ru/cli.md](/home/bzdv/PAT_PROJECTS/DRAFTSPEC/docs/ru/cli.md) -- [docs/en/workflow.md](/home/bzdv/PAT_PROJECTS/DRAFTSPEC/docs/en/workflow.md) -- [docs/ru/workflow.md](/home/bzdv/PAT_PROJECTS/DRAFTSPEC/docs/ru/workflow.md) -- [docs/en/examples.md](/home/bzdv/PAT_PROJECTS/DRAFTSPEC/docs/en/examples.md) -- [docs/ru/examples.md](/home/bzdv/PAT_PROJECTS/DRAFTSPEC/docs/ru/examples.md) - -## Should Update - -- [src/internal/templates/assets/lang/en/templates/inspect-report.md](/home/bzdv/PAT_PROJECTS/DRAFTSPEC/src/internal/templates/assets/lang/en/templates/inspect-report.md) -- [src/internal/templates/assets/lang/ru/templates/inspect-report.md](/home/bzdv/PAT_PROJECTS/DRAFTSPEC/src/internal/templates/assets/lang/ru/templates/inspect-report.md) -- [src/internal/templates/assets/lang/en/templates/verify-report.md](/home/bzdv/PAT_PROJECTS/DRAFTSPEC/src/internal/templates/assets/lang/en/templates/verify-report.md) -- [src/internal/templates/assets/lang/ru/templates/verify-report.md](/home/bzdv/PAT_PROJECTS/DRAFTSPEC/src/internal/templates/assets/lang/ru/templates/verify-report.md) -- [src/internal/templates/assets/lang/en/templates/inspect.md](/home/bzdv/PAT_PROJECTS/DRAFTSPEC/src/internal/templates/assets/lang/en/templates/inspect.md) -- [src/internal/templates/assets/lang/ru/templates/inspect.md](/home/bzdv/PAT_PROJECTS/DRAFTSPEC/src/internal/templates/assets/lang/ru/templates/inspect.md) -- [src/internal/templates/assets/lang/en/templates/verify.md](/home/bzdv/PAT_PROJECTS/DRAFTSPEC/src/internal/templates/assets/lang/en/templates/verify.md) -- [src/internal/templates/assets/lang/ru/templates/verify.md](/home/bzdv/PAT_PROJECTS/DRAFTSPEC/src/internal/templates/assets/lang/ru/templates/verify.md) -- [docs/en/agents.md](/home/bzdv/PAT_PROJECTS/DRAFTSPEC/docs/en/agents.md) -- [docs/ru/agents.md](/home/bzdv/PAT_PROJECTS/DRAFTSPEC/docs/ru/agents.md) -- [docs/en/glossary.md](/home/bzdv/PAT_PROJECTS/DRAFTSPEC/docs/en/glossary.md) -- [docs/ru/glossary.md](/home/bzdv/PAT_PROJECTS/DRAFTSPEC/docs/ru/glossary.md) -- [docs/en/overview.md](/home/bzdv/PAT_PROJECTS/DRAFTSPEC/docs/en/overview.md) -- [docs/ru/overview.md](/home/bzdv/PAT_PROJECTS/DRAFTSPEC/docs/ru/overview.md) -- [docs/en/faq.md](/home/bzdv/PAT_PROJECTS/DRAFTSPEC/docs/en/faq.md) -- [docs/ru/faq.md](/home/bzdv/PAT_PROJECTS/DRAFTSPEC/docs/ru/faq.md) -- [CHANGELOG.md](/home/bzdv/PAT_PROJECTS/DRAFTSPEC/CHANGELOG.md) - -## Nice To Update - -- architecture/roadmap wording where old path examples still appear -- output copy in help/panels where old defaults are implied rather than explicit - -## Tests That Will Almost Certainly Need Touching - -- [src/internal/config/config_test.go](/home/bzdv/PAT_PROJECTS/DRAFTSPEC/src/internal/config/config_test.go) -- [src/internal/project/init_test.go](/home/bzdv/PAT_PROJECTS/DRAFTSPEC/src/internal/project/init_test.go) -- [src/internal/cli/root_test.go](/home/bzdv/PAT_PROJECTS/DRAFTSPEC/src/internal/cli/root_test.go) -- [src/internal/featurepaths/featurepaths_test.go](/home/bzdv/PAT_PROJECTS/DRAFTSPEC/src/internal/featurepaths/featurepaths_test.go) -- [src/internal/workflow/state_test.go](/home/bzdv/PAT_PROJECTS/DRAFTSPEC/src/internal/workflow/state_test.go) -- [src/internal/doctor/doctor_test.go](/home/bzdv/PAT_PROJECTS/DRAFTSPEC/src/internal/doctor/doctor_test.go) -- workflow integration tests -- archive/list-archive tests - -## Best Order - -1. code support + tests -2. init/refresh migration behavior -3. prompt/snippet defaults -4. docs/examples -5. changelog - -## Important Sanity Checks After - -- old project with `specs` + `archive` still works -- new `init` produces `specs/active` + `specs/archived` -- `list-specs` only sees active features -- `list-archive` only sees archived snapshots -- `doctor` does not confuse archived slugs with active specs -- prompts/snippets never tell the agent to fall back to plain `specs`/`archive` diff --git a/demo/speckeep-demo.gif b/demo/speckeep-demo.gif index 7bc1de3..b48d191 100644 Binary files a/demo/speckeep-demo.gif and b/demo/speckeep-demo.gif differ diff --git a/docs/en/cli.md b/docs/en/cli.md index b6827b7..ec55eda 100644 --- a/docs/en/cli.md +++ b/docs/en/cli.md @@ -58,7 +58,7 @@ Refreshes only SpecKeep-managed generated artifacts in an existing project. This command updates: -- `.speckeep/speckeep.yaml` +- `.speckeep/spk.yaml` - `.speckeep/skills/manifest.yaml` - `.speckeep/templates/**` - `.speckeep/scripts/**` @@ -103,7 +103,7 @@ speckeep add-agent my-project --agents claude --agents codex ### `speckeep list-agents [path]` -Lists enabled agent targets from `.speckeep/speckeep.yaml`. +Lists enabled agent targets from `.speckeep/spk.yaml`. ### `speckeep remove-agent [path]` @@ -146,7 +146,7 @@ Use `--no-install` to skip immediate reconciliation of installed skills in agent Installs enabled skills from `.speckeep/skills/manifest.yaml` into target agent skill folders. -By default, uses enabled targets from `.speckeep/speckeep.yaml`. Override with `--targets codex,opencode`. +By default, uses enabled targets from `.speckeep/spk.yaml`. Override with `--targets codex,opencode`. For git-backed skills, this command can rehydrate missing `.speckeep/skills/checkouts/` from manifest data (`location` + `ref`) before installation. This helps when a checkout was deleted locally. If the upstream git source is unavailable, the manifest alone is not enough to reconstruct the skill contents. @@ -336,7 +336,7 @@ speckeep trace export-report my-project --json Creates a demo workspace at the given path (default: `./speckeep-demo`). -The workspace is pre-populated with an example feature (`export-report`) at the implement phase — spec, inspect report, plan, tasks, and data model are all present. Suggests `/speckeep.scope`, `/speckeep.challenge`, and `/speckeep.handoff` to try immediately. +The workspace is pre-populated with an example feature (`export-report`) at the implement phase — spec, inspect report, plan, tasks, and data model are all present. Suggests `/spk.scope`, `/spk.challenge`, and `/spk.handoff` to try immediately. ```bash speckeep demo diff --git a/docs/ru/cli.md b/docs/ru/cli.md index 05e94cd..d6f4869 100644 --- a/docs/ru/cli.md +++ b/docs/ru/cli.md @@ -58,7 +58,7 @@ speckeep init my-project --docs-lang ru --agent-lang en --comments-lang en --she Эта команда обновляет: -- `.speckeep/speckeep.yaml` +- `.speckeep/spk.yaml` - `.speckeep/skills/manifest.yaml` - `.speckeep/templates/**` - `.speckeep/scripts/**` @@ -103,7 +103,7 @@ speckeep add-agent my-project --agents claude --agents codex ### `speckeep list-agents [path]` -Показывает включенные agent targets из `.speckeep/speckeep.yaml`. +Показывает включенные agent targets из `.speckeep/spk.yaml`. ### `speckeep remove-agent [path]` @@ -146,7 +146,7 @@ speckeep add-skill my-project --id openai-docs --from-git https://example.com/sk Устанавливает включенные skills из `.speckeep/skills/manifest.yaml` в skill-папки выбранных агентов. -По умолчанию используются targets из `.speckeep/speckeep.yaml`. Можно переопределить через `--targets codex,opencode`. +По умолчанию используются targets из `.speckeep/spk.yaml`. Можно переопределить через `--targets codex,opencode`. Для git-backed skills команда умеет rehydrate отсутствующие `.speckeep/skills/checkouts/` из данных manifest (`location` + `ref`) перед установкой. Это помогает, если checkout был удален локально. Если исходный git source недоступен, одного manifest недостаточно для восстановления содержимого. @@ -336,7 +336,7 @@ speckeep trace export-report my-project --json Создаёт демо-workspace по указанному пути (по умолчанию: `./speckeep-demo`). -Workspace заполнен примером фичи (`export-report`) на фазе implement — spec, inspect report, plan, tasks и data model уже присутствуют. После создания предлагает попробовать `/speckeep.scope`, `/speckeep.challenge` и `/speckeep.handoff`. +Workspace заполнен примером фичи (`export-report`) на фазе implement — spec, inspect report, plan, tasks и data model уже присутствуют. После создания предлагает попробовать `/spk.scope`, `/spk.challenge` и `/spk.handoff`. ```bash speckeep demo diff --git a/src/internal/agents/adapter_aider.go b/src/internal/agents/adapter_aider.go index a9517ab..1cde89b 100644 --- a/src/internal/agents/adapter_aider.go +++ b/src/internal/agents/adapter_aider.go @@ -35,7 +35,7 @@ func renderAiderCommands(commands []CommandDefinition, language string) string { sections = append(sections, "") sections = append(sections, "Команды:") for _, cmd := range commands { - sections = append(sections, fmt.Sprintf("- `/speckeep.%s` → %s", cmd.Name, cmd.PromptPath)) + sections = append(sections, fmt.Sprintf("- `/spk.%s` → %s", cmd.Name, cmd.PromptPath)) } sections = append(sections, "- `speckeep archive .` → CLI-only archive after verify") sections = append(sections, "") @@ -62,7 +62,7 @@ func renderAiderCommands(commands []CommandDefinition, language string) string { sections = append(sections, "") sections = append(sections, "Commands:") for _, cmd := range commands { - sections = append(sections, fmt.Sprintf("- `/speckeep.%s` → %s", cmd.Name, cmd.PromptPath)) + sections = append(sections, fmt.Sprintf("- `/spk.%s` → %s", cmd.Name, cmd.PromptPath)) } sections = append(sections, "- `speckeep archive .` → CLI-only archive after verify") sections = append(sections, "") diff --git a/src/internal/agents/adapter_claude.go b/src/internal/agents/adapter_claude.go index 6c624c2..2432497 100644 --- a/src/internal/agents/adapter_claude.go +++ b/src/internal/agents/adapter_claude.go @@ -14,7 +14,7 @@ func (claudeAdapter) Render(commands []CommandDefinition, language string) ([]Fi files := make([]File, 0, len(commands)) for _, command := range commands { files = append(files, File{ - Path: filepath.ToSlash(filepath.Join(".claude", "commands", fmt.Sprintf("speckeep.%s.md", command.Name))), + Path: filepath.ToSlash(filepath.Join(".claude", "commands", fmt.Sprintf("spk.%s.md", command.Name))), Content: renderClaude(command, lang), Mode: 0o644, }) diff --git a/src/internal/agents/adapter_codex.go b/src/internal/agents/adapter_codex.go index e002253..16b2042 100644 --- a/src/internal/agents/adapter_codex.go +++ b/src/internal/agents/adapter_codex.go @@ -14,7 +14,7 @@ func (codexAdapter) Render(commands []CommandDefinition, language string) ([]Fil files := make([]File, 0, len(commands)) for _, command := range commands { files = append(files, File{ - Path: filepath.ToSlash(filepath.Join(".codex", "prompts", fmt.Sprintf("speckeep.%s.md", command.Name))), + Path: filepath.ToSlash(filepath.Join(".codex", "prompts", fmt.Sprintf("spk.%s.md", command.Name))), Content: renderCodex(command, lang), Mode: 0o644, }) diff --git a/src/internal/agents/adapter_copilot.go b/src/internal/agents/adapter_copilot.go index f6f66c4..a9c03e6 100644 --- a/src/internal/agents/adapter_copilot.go +++ b/src/internal/agents/adapter_copilot.go @@ -14,7 +14,7 @@ func (copilotAdapter) Render(commands []CommandDefinition, language string) ([]F files := make([]File, 0, len(commands)) for _, command := range commands { files = append(files, File{ - Path: filepath.ToSlash(filepath.Join(".github", "prompts", fmt.Sprintf("speckeep-%s.prompt.md", command.Name))), + Path: filepath.ToSlash(filepath.Join(".github", "prompts", fmt.Sprintf("spk-%s.prompt.md", command.Name))), Content: renderCopilot(command, lang), Mode: 0o644, }) diff --git a/src/internal/agents/adapter_cursor.go b/src/internal/agents/adapter_cursor.go index 508e6f5..e0f65c6 100644 --- a/src/internal/agents/adapter_cursor.go +++ b/src/internal/agents/adapter_cursor.go @@ -14,7 +14,7 @@ func (cursorAdapter) Render(commands []CommandDefinition, language string) ([]Fi files := make([]File, 0, len(commands)) for _, command := range commands { files = append(files, File{ - Path: filepath.ToSlash(filepath.Join(".cursor", "rules", fmt.Sprintf("speckeep-%s.mdc", command.Name))), + Path: filepath.ToSlash(filepath.Join(".cursor", "rules", fmt.Sprintf("spk-%s.mdc", command.Name))), Content: renderCursor(command, lang), Mode: 0o644, }) @@ -45,7 +45,7 @@ alwaysApply: false %s -Используйте эту rule, когда запрос явно относится к фазе %q или к команде /speckeep.%s. +Используйте эту rule, когда запрос явно относится к фазе %q или к команде /spk.%s. - %s - %s @@ -63,7 +63,7 @@ Follow %q. %s -Use this rule when the request clearly maps to the %q phase or the /speckeep.%s command. +Use this rule when the request clearly maps to the %q phase or the /spk.%s command. - %s - %s diff --git a/src/internal/agents/adapter_kilocode.go b/src/internal/agents/adapter_kilocode.go index 3a237c9..727a199 100644 --- a/src/internal/agents/adapter_kilocode.go +++ b/src/internal/agents/adapter_kilocode.go @@ -14,7 +14,7 @@ func (kilocodeAdapter) Render(commands []CommandDefinition, language string) ([] files := make([]File, 0, len(commands)) for _, command := range commands { files = append(files, File{ - Path: filepath.ToSlash(filepath.Join(".kilocode", "workflows", fmt.Sprintf("speckeep.%s.md", command.Name))), + Path: filepath.ToSlash(filepath.Join(".kilocode", "workflows", fmt.Sprintf("spk.%s.md", command.Name))), Content: renderKilo(command, lang), Mode: 0o644, }) @@ -50,7 +50,7 @@ func renderKilo(spec CommandDefinition, lang string) string { %s %s %s -`, spec.Name, spec.PromptPath, "/speckeep."+spec.Name+".md", commandHint(spec.Name, lang), spec.Name, constitutionSummaryHint(lang), finalLineHint(lang), specBranchFirstBullet(spec.Name, lang), scriptListBlock(spec.Extras, lang)) +`, spec.Name, spec.PromptPath, "/spk."+spec.Name+".md", commandHint(spec.Name, lang), spec.Name, constitutionSummaryHint(lang), finalLineHint(lang), specBranchFirstBullet(spec.Name, lang), scriptListBlock(spec.Extras, lang)) } return fmt.Sprintf(`# SpecKeep %s @@ -67,5 +67,5 @@ Use this workflow when the request maps to the %q phase. %s %s %s -`, spec.Name, spec.PromptPath, "/speckeep."+spec.Name+".md", commandHint(spec.Name, lang), spec.Name, constitutionSummaryHint(lang), finalLineHint(lang), specBranchFirstBullet(spec.Name, lang), scriptListBlock(spec.Extras, lang)) +`, spec.Name, spec.PromptPath, "/spk."+spec.Name+".md", commandHint(spec.Name, lang), spec.Name, constitutionSummaryHint(lang), finalLineHint(lang), specBranchFirstBullet(spec.Name, lang), scriptListBlock(spec.Extras, lang)) } diff --git a/src/internal/agents/adapter_opencode.go b/src/internal/agents/adapter_opencode.go index 851fbb9..5dbd5fb 100644 --- a/src/internal/agents/adapter_opencode.go +++ b/src/internal/agents/adapter_opencode.go @@ -14,7 +14,7 @@ func (opencodeAdapter) Render(commands []CommandDefinition, language string) ([] files := make([]File, 0, len(commands)) for _, command := range commands { files = append(files, File{ - Path: filepath.ToSlash(filepath.Join(".opencode", "commands", fmt.Sprintf("speckeep.%s.md", command.Name))), + Path: filepath.ToSlash(filepath.Join(".opencode", "commands", fmt.Sprintf("spk.%s.md", command.Name))), Content: renderOpencode(command, lang), Mode: 0o644, }) diff --git a/src/internal/agents/adapter_roocode.go b/src/internal/agents/adapter_roocode.go index b37e9de..14197e5 100644 --- a/src/internal/agents/adapter_roocode.go +++ b/src/internal/agents/adapter_roocode.go @@ -14,7 +14,7 @@ func (roocodeAdapter) Render(commands []CommandDefinition, language string) ([]F files := make([]File, 0, len(commands)) for _, command := range commands { files = append(files, File{ - Path: filepath.ToSlash(filepath.Join(".roo", "rules", fmt.Sprintf("speckeep-%s.md", command.Name))), + Path: filepath.ToSlash(filepath.Join(".roo", "rules", fmt.Sprintf("spk-%s.md", command.Name))), Content: renderRoocode(command, lang), Mode: 0o644, }) diff --git a/src/internal/agents/adapter_trae.go b/src/internal/agents/adapter_trae.go index 2dd60fe..29bc9a3 100644 --- a/src/internal/agents/adapter_trae.go +++ b/src/internal/agents/adapter_trae.go @@ -14,7 +14,7 @@ func (traeAdapter) Render(commands []CommandDefinition, language string) ([]File files := make([]File, 0, len(commands)) for _, command := range commands { files = append(files, File{ - Path: filepath.ToSlash(filepath.Join(".trae", "rules", fmt.Sprintf("speckeep.%s.md", command.Name))), + Path: filepath.ToSlash(filepath.Join(".trae", "rules", fmt.Sprintf("spk.%s.md", command.Name))), Content: renderTrae(command, lang), Mode: 0o644, }) @@ -44,7 +44,7 @@ func renderTrae(spec CommandDefinition, lang string) string { %s -Используйте это rule, когда запрос явно относится к фазе %q или к команде /speckeep.%s. +Используйте это rule, когда запрос явно относится к фазе %q или к команде /spk.%s. Правила: - %s @@ -67,7 +67,7 @@ Follow %q. %s -Use this rule when the request clearly maps to the %q phase or the /speckeep.%s command. +Use this rule when the request clearly maps to the %q phase or the /spk.%s command. Rules: - %s diff --git a/src/internal/agents/adapter_windsurf.go b/src/internal/agents/adapter_windsurf.go index 57adc41..85db063 100644 --- a/src/internal/agents/adapter_windsurf.go +++ b/src/internal/agents/adapter_windsurf.go @@ -14,7 +14,7 @@ func (windsurfAdapter) Render(commands []CommandDefinition, language string) ([] files := make([]File, 0, len(commands)) for _, command := range commands { files = append(files, File{ - Path: filepath.ToSlash(filepath.Join(".windsurf", "workflows", fmt.Sprintf("speckeep.%s.md", command.Name))), + Path: filepath.ToSlash(filepath.Join(".windsurf", "workflows", fmt.Sprintf("spk.%s.md", command.Name))), Content: renderWindsurf(command, lang), Mode: 0o644, }) @@ -44,7 +44,7 @@ trigger: manual %s -Используйте этот workflow, когда запрос явно относится к фазе %q или команде /speckeep.%s. +Используйте этот workflow, когда запрос явно относится к фазе %q или команде /spk.%s. Важно: readiness scripts почти всегда требуют `+"``"+` первым аргументом. Пример: `+"`bash ./.speckeep/scripts/check-ready.sh tasks `"+`. @@ -64,7 +64,7 @@ First, open and read %q (mandatory). Then follow its "Output expectations" secti %s -Use this workflow when the request clearly maps to the %q phase or the /speckeep.%s command. +Use this workflow when the request clearly maps to the %q phase or the /spk.%s command. Important: readiness scripts almost always require `+"``"+` as the first argument. Example: `+"`bash ./.speckeep/scripts/check-ready.sh tasks `"+`. diff --git a/src/internal/agents/files.go b/src/internal/agents/files.go index 6c5d9d7..d339abf 100644 --- a/src/internal/agents/files.go +++ b/src/internal/agents/files.go @@ -117,6 +117,46 @@ func LegacyArchivePaths() []string { } } +// LegacyPrefixPaths returns old-style agent file paths with the deprecated +// "speckeep." prefix. Used by doctor and refresh for migration cleanup. +func LegacyPrefixPaths(commands []CommandDefinition) []string { + var paths []string + patterns := []struct { + dir string + fmtStr string + sep string // "." or "-" + }{ + {dir: ".claude/commands", sep: "."}, + {dir: ".opencode/commands", sep: "."}, + {dir: ".kilocode/workflows", sep: "."}, + {dir: ".windsurf/workflows", sep: "."}, + {dir: ".trae/rules", sep: "."}, + {dir: ".codex/prompts", sep: "."}, + {dir: ".cursor/rules", sep: "-"}, + {dir: ".roo/rules", sep: "-"}, + {dir: ".github/prompts", sep: "-"}, + } + extensions := map[string]string{ + ".claude/commands": ".md", + ".opencode/commands": ".md", + ".kilocode/workflows": ".md", + ".windsurf/workflows": ".md", + ".trae/rules": ".md", + ".codex/prompts": ".md", + ".cursor/rules": ".mdc", + ".roo/rules": ".md", + ".github/prompts": ".prompt.md", + } + for _, cmd := range commands { + for _, p := range patterns { + ext := extensions[p.dir] + name := "speckeep" + p.sep + cmd.Name + paths = append(paths, p.dir+"/"+name+ext) + } + } + return paths +} + // commandSpec and commandSpecs are kept as compatibility shims while tests and // callers continue to use the previous names. type commandSpec = CommandDefinition @@ -166,9 +206,9 @@ func scriptPath(name, shell string) string { func commandHint(name, lang string) string { if lang == "ru" { - return fmt.Sprintf("Команда: `/speckeep.%s [request]`", name) + return fmt.Sprintf("Команда: `/spk.%s [request]`", name) } - return fmt.Sprintf("Command: `/speckeep.%s [request]`", name) + return fmt.Sprintf("Command: `/spk.%s [request]`", name) } func toolInvocationHint(lang string) string { @@ -211,9 +251,9 @@ func specBranchFirstBullet(commandName, lang string) string { return "" } if lang == "ru" { - return "- Для `/speckeep.spec`: до записи любого файла обязательно переключиться/создать feature-ветку `feature/` (или явное значение `--branch`). Если git недоступен или вы в detached HEAD — остановитесь и сообщите причину." + return "- Для `/spk.spec`: до записи любого файла обязательно переключиться/создать feature-ветку `feature/` (или явное значение `--branch`). Если git недоступен или вы в detached HEAD — остановитесь и сообщите причину." } - return "- For `/speckeep.spec`: before writing any file, you must switch/create the feature branch `feature/` (or the explicit `--branch` value). If git is unavailable or you are in detached HEAD, stop and report the reason." + return "- For `/spk.spec`: before writing any file, you must switch/create the feature branch `feature/` (or the explicit `--branch` value). If git is unavailable or you are in detached HEAD, stop and report the reason." } func titleCase(value string) string { @@ -225,9 +265,9 @@ func titleCase(value string) string { func workflowChainHint(lang string) string { if lang == "ru" { - return "Цепочка workflow: constitution → spec → [inspect, опционально] → plan → tasks → implement → verify → archive (CLI-only). Не пропускайте обязательные фазы и не забегайте вперёд. После verify используйте `speckeep archive .`; не придумывайте и не вызывайте `/speckeep.archive`." + return "Цепочка workflow: constitution → spec → [inspect, опционально] → plan → tasks → implement → verify → archive (CLI-only). Не пропускайте обязательные фазы и не забегайте вперёд. После verify используйте `speckeep archive .`; не придумывайте и не вызывайте `/spk.archive`." } - return "Workflow chain: constitution → spec → [inspect, optional] → plan → tasks → implement → verify → archive (CLI-only). Do not skip required phases or jump ahead. After verify, use `speckeep archive .`; do not invent or call `/speckeep.archive`." + return "Workflow chain: constitution → spec → [inspect, optional] → plan → tasks → implement → verify → archive (CLI-only). Do not skip required phases or jump ahead. After verify, use `speckeep archive .`; do not invent or call `/spk.archive`." } func antiPatternHint(lang string) string { diff --git a/src/internal/agents/files_test.go b/src/internal/agents/files_test.go index b49e354..f328aaa 100644 --- a/src/internal/agents/files_test.go +++ b/src/internal/agents/files_test.go @@ -38,27 +38,27 @@ func TestFiles(t *testing.T) { } required := map[string]bool{ - ".aider/CONVENTIONS.md": false, - ".claude/commands/speckeep.inspect.md": false, - ".claude/commands/speckeep.verify.md": false, - ".codex/prompts/speckeep.plan.md": false, - ".github/prompts/speckeep-spec.prompt.md": false, - ".github/prompts/speckeep-verify.prompt.md": false, - ".cursor/rules/speckeep-implement.mdc": false, - ".cursor/rules/speckeep-verify.mdc": false, - ".kilocode/workflows/speckeep.verify.md": false, - ".opencode/commands/speckeep.verify.md": false, - ".roo/rules/speckeep-spec.md": false, - ".roo/rules/speckeep-plan.md": false, - ".trae/rules/speckeep.plan.md": false, - ".trae/rules/speckeep.verify.md": false, - ".windsurf/workflows/speckeep.implement.md": false, - ".windsurf/workflows/speckeep.verify.md": false, - ".claude/commands/speckeep.recap.md": false, - ".claude/commands/speckeep.hotfix.md": false, - ".claude/commands/speckeep.rollback.md": false, - ".cursor/rules/speckeep-recap.mdc": false, - ".opencode/commands/speckeep.recap.md": false, + ".aider/CONVENTIONS.md": false, + ".claude/commands/spk.inspect.md": false, + ".claude/commands/spk.verify.md": false, + ".codex/prompts/spk.plan.md": false, + ".github/prompts/spk-spec.prompt.md": false, + ".github/prompts/spk-verify.prompt.md": false, + ".cursor/rules/spk-implement.mdc": false, + ".cursor/rules/spk-verify.mdc": false, + ".kilocode/workflows/spk.verify.md": false, + ".opencode/commands/spk.verify.md": false, + ".roo/rules/spk-spec.md": false, + ".roo/rules/spk-plan.md": false, + ".trae/rules/spk.plan.md": false, + ".trae/rules/spk.verify.md": false, + ".windsurf/workflows/spk.implement.md": false, + ".windsurf/workflows/spk.verify.md": false, + ".claude/commands/spk.recap.md": false, + ".claude/commands/spk.hotfix.md": false, + ".claude/commands/spk.rollback.md": false, + ".cursor/rules/spk-recap.mdc": false, + ".opencode/commands/spk.recap.md": false, } for _, file := range files { @@ -168,10 +168,10 @@ func TestRenderIncludesCommandHints(t *testing.T) { spec string want string }{ - {name: "claude spec en", target: "claude", lang: "en", spec: "spec", want: "Command: `/speckeep.spec [request]`"}, - {name: "codex tasks en", target: "codex", lang: "en", spec: "tasks", want: "Command: `/speckeep.tasks [request]`"}, - {name: "copilot implement ru", target: "copilot", lang: "ru", spec: "implement", want: "Команда: `/speckeep.implement [request]`"}, - {name: "cursor verify en", target: "cursor", lang: "en", spec: "verify", want: "Command: `/speckeep.verify [request]`"}, + {name: "claude spec en", target: "claude", lang: "en", spec: "spec", want: "Command: `/spk.spec [request]`"}, + {name: "codex tasks en", target: "codex", lang: "en", spec: "tasks", want: "Command: `/spk.tasks [request]`"}, + {name: "copilot implement ru", target: "copilot", lang: "ru", spec: "implement", want: "Команда: `/spk.implement [request]`"}, + {name: "cursor verify en", target: "cursor", lang: "en", spec: "verify", want: "Command: `/spk.verify [request]`"}, } for _, tt := range tests { @@ -190,8 +190,8 @@ func TestRenderTraeIncludesCommandHints(t *testing.T) { lang string want string }{ - {name: "en", lang: "en", want: "Command: `/speckeep.verify [request]`"}, - {name: "ru", lang: "ru", want: "Команда: `/speckeep.verify [request]`"}, + {name: "en", lang: "en", want: "Command: `/spk.verify [request]`"}, + {name: "ru", lang: "ru", want: "Команда: `/spk.verify [request]`"}, } for _, tt := range tests { diff --git a/src/internal/cli/archive.go b/src/internal/cli/archive.go index 524ef62..b782925 100644 --- a/src/internal/cli/archive.go +++ b/src/internal/cli/archive.go @@ -450,7 +450,7 @@ func outputArchiveResult(cmd *cobra.Command, result ArchiveResult, jsonOutput bo if len(result.Restored) > 0 { printPanel(w, "Restored Files", result.Restored) } - fmt.Fprintf(w, "\n%s Ready for: /speckeep.plan %s (optionally run /speckeep.inspect first)\n", styleOK(w, "✓"), result.Slug) + fmt.Fprintf(w, "\n%s Ready for: /spk.plan %s (optionally run /spk.inspect first)\n", styleOK(w, "✓"), result.Slug) } else { printPanel(w, "speckeep archive", []string{ "slug: " + result.Slug, diff --git a/src/internal/cli/check.go b/src/internal/cli/check.go index f11af25..1e4224a 100644 --- a/src/internal/cli/check.go +++ b/src/internal/cli/check.go @@ -224,17 +224,17 @@ func buildCheckResult(ctx context.Context, cfg config.Config, root string, state func nextCommand(state workflow.FeatureState) string { switch state.ReadyFor { case "spec": - return "/speckeep.spec " + state.Slug + return "/spk.spec " + state.Slug case "inspect": - return "/speckeep.inspect " + state.Slug + return "/spk.inspect " + state.Slug case "plan": - return "/speckeep.plan " + state.Slug + return "/spk.plan " + state.Slug case "tasks": - return "/speckeep.tasks " + state.Slug + return "/spk.tasks " + state.Slug case "implement": - return "/speckeep.implement " + state.Slug + return "/spk.implement " + state.Slug case "verify": - return "/speckeep.verify " + state.Slug + return "/spk.verify " + state.Slug case "archive": return "speckeep archive " + state.Slug + " ." default: diff --git a/src/internal/cli/dashboard.go b/src/internal/cli/dashboard.go index b93eb95..4398611 100644 --- a/src/internal/cli/dashboard.go +++ b/src/internal/cli/dashboard.go @@ -65,7 +65,7 @@ Includes phase, task progress, readiness, and branch mismatch hints.`, return nil } printPanel(w, "No Features Found", []string{ - "Create your first spec with " + styleCmd(w, "/speckeep.spec") + ".", + "Create your first spec with " + styleCmd(w, "/spk.spec") + ".", "Or run " + styleCmd(w, "speckeep demo") + " to explore an example workspace.", }) return nil diff --git a/src/internal/cli/demo.go b/src/internal/cli/demo.go index 1bc44d2..f090d1d 100644 --- a/src/internal/cli/demo.go +++ b/src/internal/cli/demo.go @@ -56,9 +56,9 @@ commands immediately.`, styleCmd(w, "speckeep dashboard ."), styleCmd(w, "speckeep check "+result.ExampleSlug+" ."), "agent flow:", - " " + styleCmd(w, "/speckeep.challenge "+result.ExampleSlug) + " (optional)", - " " + styleCmd(w, "/speckeep.scope "+result.ExampleSlug) + " (optional)", - " " + styleCmd(w, "/speckeep.handoff "+result.ExampleSlug) + " (optional)", + " " + styleCmd(w, "/spk.challenge "+result.ExampleSlug) + " (optional)", + " " + styleCmd(w, "/spk.scope "+result.ExampleSlug) + " (optional)", + " " + styleCmd(w, "/spk.handoff "+result.ExampleSlug) + " (optional)", }) return nil diff --git a/src/internal/cli/explore.go b/src/internal/cli/explore.go index 48c0587..409dbe0 100644 --- a/src/internal/cli/explore.go +++ b/src/internal/cli/explore.go @@ -81,9 +81,9 @@ Examples: fmt.Fprintf(cmd.OutOrStdout(), " Slug: %s\n", slug) fmt.Fprintf(cmd.OutOrStdout(), " File: %s\n", relPath(root, explorePath)) fmt.Fprintf(cmd.OutOrStdout(), "\nNext steps:\n") - fmt.Fprintf(cmd.OutOrStdout(), " 1. Use /speckeep.explore %s to investigate\n", slug) - fmt.Fprintf(cmd.OutOrStdout(), " 2. When ready, call /speckeep.spec %s to write the spec\n", slug) - fmt.Fprintf(cmd.OutOrStdout(), " 3. Or call /speckeep.spec %s --from-explore to convert exploration to spec\n", slug) + fmt.Fprintf(cmd.OutOrStdout(), " 1. Use /spk.explore %s to investigate\n", slug) + fmt.Fprintf(cmd.OutOrStdout(), " 2. When ready, call /spk.spec %s to write the spec\n", slug) + fmt.Fprintf(cmd.OutOrStdout(), " 3. Or call /spk.spec %s --from-explore to convert exploration to spec\n", slug) return nil }, @@ -159,7 +159,7 @@ func generateExploreTemplate(name, slug, language string) string { - [ ] Ключевые вопросы исследованы - [ ] Варианты реализации оценены - [ ] Рекомендация сформулирована -- [ ] Готов перейти к /speckeep.spec +- [ ] Готов перейти к /spk.spec ## Связанные артефакты @@ -229,7 +229,7 @@ Which option is preferred and why: - [ ] Key questions investigated - [ ] Implementation options evaluated - [ ] Recommendation formulated -- [ ] Ready to proceed to /speckeep.spec +- [ ] Ready to proceed to /spk.spec ## Related Artifacts diff --git a/src/internal/cli/init_output.go b/src/internal/cli/init_output.go index 66786f5..c2904b5 100644 --- a/src/internal/cli/init_output.go +++ b/src/internal/cli/init_output.go @@ -47,17 +47,17 @@ func printInitOutput(w io.Writer, result project.InitResult) { printPanel(w, "Next Steps", []string{ "1. You're already in the project directory.", "2. Start using slash commands with your AI agent:", - " 2.1 " + styleCmd(w, "/speckeep.constitution") + " - Establish project principles", - " 2.2 " + styleCmd(w, "/speckeep.spec") + " - Create a baseline specification", - " 2.3 " + styleCmd(w, "/speckeep.plan") + " - Create an implementation plan", - " 2.4 " + styleCmd(w, "/speckeep.tasks") + " - Generate actionable tasks", - " 2.5 " + styleCmd(w, "/speckeep.implement") + " - Execute implementation", + " 2.1 " + styleCmd(w, "/spk.constitution") + " - Establish project principles", + " 2.2 " + styleCmd(w, "/spk.spec") + " - Create a baseline specification", + " 2.3 " + styleCmd(w, "/spk.plan") + " - Create an implementation plan", + " 2.4 " + styleCmd(w, "/spk.tasks") + " - Generate actionable tasks", + " 2.5 " + styleCmd(w, "/spk.implement") + " - Execute implementation", }) printPanel(w, "Enhancement Commands", []string{ - styleCmd(w, "/speckeep.challenge") + " (optional) - adversarial review of spec/plan", - styleCmd(w, "/speckeep.scope") + " (optional) - scope boundary check", - styleCmd(w, "/speckeep.recap") + " (optional) - recap active features", + styleCmd(w, "/spk.challenge") + " (optional) - adversarial review of spec/plan", + styleCmd(w, "/spk.scope") + " (optional) - scope boundary check", + styleCmd(w, "/spk.recap") + " (optional) - recap active features", }) printPanel(w, "Useful CLI Commands", []string{ diff --git a/src/internal/cli/root.go b/src/internal/cli/root.go index 2a9d9f5..7eb35b7 100644 --- a/src/internal/cli/root.go +++ b/src/internal/cli/root.go @@ -16,21 +16,21 @@ Quick start: speckeep list-specs . For agents (Kilocode/Claude/Cursor): - /speckeep.constitution — create a constitution - /speckeep.spec --name "feature name" — create a spec - /speckeep.spec --amend — targeted spec edit - /speckeep.plan [--research|--update] — create a plan - /speckeep.tasks — decompose into tasks - /speckeep.implement — implement tasks - /speckeep.verify [--deep] — verify AC coverage + /spk.constitution — create a constitution + /spk.spec --name "feature name" — create a spec + /spk.spec --amend — targeted spec edit + /spk.plan [--research|--update] — create a plan + /spk.tasks — decompose into tasks + /spk.implement — implement tasks + /spk.verify [--deep] — verify AC coverage Optional commands (any phase): - /speckeep.challenge [--spec|--plan] — adversarial review - /speckeep.handoff [slug] — session handoff doc - /speckeep.hotfix — emergency fix - /speckeep.rollback — roll back completed tasks - /speckeep.scope — scope boundary check - /speckeep.recap — recap active features + /spk.challenge [--spec|--plan] — adversarial review + /spk.handoff [slug] — session handoff doc + /spk.hotfix — emergency fix + /spk.rollback — roll back completed tasks + /spk.scope — scope boundary check + /spk.recap — recap active features CLI commands: speckeep doctor . — workspace health check diff --git a/src/internal/cli/root_test.go b/src/internal/cli/root_test.go index 027a1aa..515f97e 100644 --- a/src/internal/cli/root_test.go +++ b/src/internal/cli/root_test.go @@ -114,7 +114,7 @@ func TestInitCommandCreatesWorkspace(t *testing.T) { required := []string{ filepath.Join(root, ".speckeep", "speckeep.yaml"), filepath.Join(root, "CONSTITUTION.md"), - filepath.Join(root, ".claude", "commands", "speckeep.inspect.md"), + filepath.Join(root, ".claude", "commands", "spk.inspect.md"), } for _, path := range required { if _, err := os.Stat(path); err != nil { @@ -875,7 +875,7 @@ func TestCheckCommandBlocksWhenReadinessErrorsPresent(t *testing.T) { if !payload.Blocked || payload.Verdict != "blocked" { t.Fatalf("expected blocked verdict in json output, got %q", stdout) } - if payload.NextCommand != "/speckeep.plan demo" { + if payload.NextCommand != "/spk.plan demo" { t.Fatalf("expected next_command plan, got %q", payload.NextCommand) } if payload.CheckSummary.Errors == 0 { @@ -924,7 +924,7 @@ func TestCheckCommandResolvesCustomSpecsDir(t *testing.T) { if payload.Artifacts.Inspect.Present { t.Fatalf("expected inspect present=false in json output, got %q", stdout) } - if payload.NextCommand != "/speckeep.plan demo" { + if payload.NextCommand != "/spk.plan demo" { t.Fatalf("expected next_command plan, got %q", payload.NextCommand) } } diff --git a/src/internal/cli/status.go b/src/internal/cli/status.go index 562abd2..7631134 100644 --- a/src/internal/cli/status.go +++ b/src/internal/cli/status.go @@ -42,7 +42,7 @@ func newStatusCmd() *cobra.Command { w := cmd.OutOrStdout() next := "-" if result.ReadyFor != "" { - next = styleCmd(w, "/speckeep."+result.ReadyFor+" "+result.Slug) + next = styleCmd(w, "/spk."+result.ReadyFor+" "+result.Slug) } blocked := styleOK(w, "false") if result.Blocked { diff --git a/src/internal/doctor/doctor.go b/src/internal/doctor/doctor.go index a5e3d22..7cd98ec 100644 --- a/src/internal/doctor/doctor.go +++ b/src/internal/doctor/doctor.go @@ -124,16 +124,16 @@ func Check(ctx context.Context, root string) (Result, error) { agentsPath := filepath.Join(root, cfg.Agents.AgentsFile) if content, err := os.ReadFile(agentsPath); err == nil { text := string(content) - if !strings.Contains(text, "/speckeep.repo-map") { + if !strings.Contains(text, "/spk.repo-map") { findings = append(findings, Finding{ Level: "warning", - Message: "AGENTS.md is missing /speckeep.repo-map guidance — run `speckeep refresh .` to sync the managed SpecKeep block", + Message: "AGENTS.md is missing /spk.repo-map guidance — run `speckeep refresh .` to sync the managed SpecKeep block", }) } - if strings.Contains(text, "/speckeep.archive") { + if strings.Contains(text, "/speckeep.archive") || strings.Contains(text, "/speckeep.") { findings = append(findings, Finding{ Level: "warning", - Message: "AGENTS.md still references deprecated /speckeep.archive guidance — archive is CLI-only now; run `speckeep refresh .`", + Message: "AGENTS.md still references deprecated /speckeep.* commands — run `speckeep refresh .` to update to /spk.*", }) } } @@ -151,7 +151,7 @@ func Check(ctx context.Context, root string) (Result, error) { if placeholderPattern.Match(content) { findings = append(findings, Finding{ Level: "warning", - Message: "constitution.md contains unfilled placeholder content — run /speckeep.constitution to complete setup", + Message: "constitution.md contains unfilled placeholder content — run /spk.constitution to complete setup", }) } summaryPath := filepath.Join(draftspecDir, "constitution.summary.md") @@ -162,7 +162,7 @@ func Check(ctx context.Context, root string) (Result, error) { if _, err := os.Stat(summaryPath); os.IsNotExist(err) { findings = append(findings, Finding{ Level: "warning", - Message: "constitution.summary.md not found — run /speckeep.constitution to generate the compact summary used by spec, inspect, plan, tasks, implement, verify, and hotfix phases", + Message: "constitution.summary.md not found — run /spk.constitution to generate the compact summary used by spec, inspect, plan, tasks, implement, verify, and hotfix phases", }) } } @@ -225,6 +225,24 @@ func Check(ctx context.Context, root string) (Result, error) { } } + shell := cfg.Runtime.Shell + oldPrefixPaths := agents.LegacyPrefixPaths(agents.DefaultCommands(shell)) + oldPrefixSeen := make(map[string]struct{}) + for _, relPath := range oldPrefixPaths { + normalized := filepath.FromSlash(relPath) + if _, seen := oldPrefixSeen[normalized]; seen { + continue + } + oldPrefixSeen[normalized] = struct{}{} + fullPath := filepath.Join(root, normalized) + if _, err := os.Stat(fullPath); err == nil { + findings = append(findings, Finding{ + Level: "warning", + Message: fmt.Sprintf("deprecated /speckeep.* agent artifact found, rename to /spk.*; run `speckeep refresh .`: %s", fullPath), + }) + } + } + skillsManifest, err := skills.Load(ctx, root) if err != nil { findings = append(findings, Finding{Level: "error", Message: err.Error()}) diff --git a/src/internal/doctor/doctor_test.go b/src/internal/doctor/doctor_test.go index 4ae8d6a..4534bb2 100644 --- a/src/internal/doctor/doctor_test.go +++ b/src/internal/doctor/doctor_test.go @@ -114,7 +114,7 @@ func TestCheckWarnsAboutOrphanedAgentArtifact(t *testing.T) { var foundWarning bool for _, finding := range result.Findings { - if finding.Level == "warning" && strings.Contains(finding.Message, "orphaned agent artifact") { + if finding.Level == "warning" && (strings.Contains(finding.Message, "deprecated /speckeep.* agent artifact") || strings.Contains(finding.Message, "orphaned agent artifact") || strings.Contains(finding.Message, "AGENTS.md still references deprecated")) { foundWarning = true break } diff --git a/src/internal/project/agents.go b/src/internal/project/agents.go index 070c352..c5ec2ee 100644 --- a/src/internal/project/agents.go +++ b/src/internal/project/agents.go @@ -145,6 +145,25 @@ func CleanupAgents(root string) (CleanupAgentsResult, error) { } } + // Also clean up old-prefix files (speckeep.*) for disabled targets + oldPaths := agents.LegacyPrefixPaths(agents.DefaultCommands(cfg.Runtime.Shell)) + for _, relPath := range oldPaths { + fullPath := filepath.Join(root, filepath.FromSlash(relPath)) + if _, err := os.Stat(fullPath); errors.Is(err, os.ErrNotExist) { + continue + } else if err != nil { + return CleanupAgentsResult{}, err + } + // Check if the parent dir exists and matches a disabled target or any target + // Only clean up if the new-style file doesn't exist (its target is unknown) + // or if the file is orphaned from a disabled target + if err := os.Remove(fullPath); err != nil { + return CleanupAgentsResult{}, err + } + messages = append(messages, fmt.Sprintf("removed orphaned agent artifact %s", rel(root, fullPath))) + removedAny = true + } + if !removedAny { messages = append(messages, "no orphaned agent artifacts found") } diff --git a/src/internal/project/init.go b/src/internal/project/init.go index cd9c22a..7031039 100644 --- a/src/internal/project/init.go +++ b/src/internal/project/init.go @@ -233,6 +233,19 @@ func Initialize(root string, options InitOptions) (InitResult, error) { } else { messages = append(messages, "enabled agent targets: none") } + + var sr RefreshResult + if err := syncSkillsManifest(root, false, &sr); err != nil { + return InitResult{}, err + } + if err := syncSkillsGitignore(root, false, &sr); err != nil { + return InitResult{}, err + } + for _, path := range sr.Created { + result.Created = append(result.Created, path) + messages = append(messages, "created "+path) + } + result.Messages = messages return result, nil diff --git a/src/internal/project/init_test.go b/src/internal/project/init_test.go index 1e184ae..7cb77ac 100644 --- a/src/internal/project/init_test.go +++ b/src/internal/project/init_test.go @@ -43,8 +43,8 @@ func TestInitializeCreatesWorkspaceAndAgentTargets(t *testing.T) { filepath.Join(root, "CONSTITUTION.md"), filepath.Join(root, ".speckeep", "scripts", "run-speckeep.sh"), filepath.Join(root, "AGENTS.md"), - filepath.Join(root, ".claude", "commands", "speckeep.inspect.md"), - filepath.Join(root, ".cursor", "rules", "speckeep-inspect.mdc"), + filepath.Join(root, ".claude", "commands", "spk.inspect.md"), + filepath.Join(root, ".cursor", "rules", "spk-inspect.mdc"), } for _, path := range required { if _, err := os.Stat(path); err != nil { @@ -79,7 +79,7 @@ func TestAddRemoveAndCleanupAgents(t *testing.T) { t.Fatalf("AddAgents returned error: %v", err) } - cursorPath := filepath.Join(root, ".cursor", "rules", "speckeep-inspect.mdc") + cursorPath := filepath.Join(root, ".cursor", "rules", "spk-inspect.mdc") if _, err := os.Stat(cursorPath); err != nil { t.Fatalf("expected cursor agent file after AddAgents: %v", err) } @@ -248,7 +248,7 @@ func TestRefreshUpdatesManagedFilesWithoutTouchingAuthoredArtifacts(t *testing.T t.Fatalf("WriteFile returned error: %v", err) } - agentPath := filepath.Join(root, ".claude", "commands", "speckeep.inspect.md") + agentPath := filepath.Join(root, ".claude", "commands", "spk.inspect.md") if err := os.WriteFile(agentPath, []byte("stale agent file"), 0o644); err != nil { t.Fatalf("WriteFile returned error: %v", err) } diff --git a/src/internal/project/refresh.go b/src/internal/project/refresh.go index 365c509..0b8a484 100644 --- a/src/internal/project/refresh.go +++ b/src/internal/project/refresh.go @@ -154,6 +154,9 @@ func Refresh(root string, options RefreshOptions) (RefreshResult, error) { if err := removeDisabledAgentArtifacts(root, agentTargets, options.DryRun, &result); err != nil { return RefreshResult{}, err } + if err := removeOldPrefixAgentArtifacts(root, shell, options.DryRun, &result); err != nil { + return RefreshResult{}, err + } if err := removeLegacyManagedArtifacts(root, options.DryRun, &result); err != nil { return RefreshResult{}, err } @@ -674,6 +677,33 @@ func syncAgentFiles(root string, targets []string, language string, shell string return nil } +func removeOldPrefixAgentArtifacts(root, shell string, dryRun bool, result *RefreshResult) error { + commands := agents.DefaultCommands(shell) + oldPaths := agents.LegacyPrefixPaths(commands) + seen := make(map[string]struct{}) + for _, relPath := range oldPaths { + normalized := filepath.FromSlash(relPath) + if _, dup := seen[normalized]; dup { + continue + } + seen[normalized] = struct{}{} + fullPath := filepath.Join(root, normalized) + if _, err := os.Stat(fullPath); errors.Is(err, os.ErrNotExist) { + continue + } else if err != nil { + return err + } + recordRefreshAction(result, "removed", rel(root, fullPath)) + if dryRun { + continue + } + if err := os.Remove(fullPath); err != nil { + return err + } + } + return nil +} + func removeDisabledAgentArtifacts(root string, enabled []string, dryRun bool, result *RefreshResult) error { enabledSet := make(map[string]struct{}, len(enabled)) for _, target := range enabled { diff --git a/src/internal/templates/assets/demo/constitution.md b/src/internal/templates/assets/demo/constitution.md index 0938ff8..fc49737 100644 --- a/src/internal/templates/assets/demo/constitution.md +++ b/src/internal/templates/assets/demo/constitution.md @@ -1,6 +1,6 @@ # My Project Constitution (Demo) -This constitution is a filled example used by `speckeep demo`. Adjust it for your real project after running `/speckeep.constitution`. +This constitution is a filled example used by `speckeep demo`. Adjust it for your real project after running `/spk.constitution`. ## Purpose diff --git a/src/internal/templates/assets/lang/en/templates/agents-snippet.md b/src/internal/templates/assets/lang/en/templates/agents-snippet.md index 1d84510..2a86cc4 100644 --- a/src/internal/templates/assets/lang/en/templates/agents-snippet.md +++ b/src/internal/templates/assets/lang/en/templates/agents-snippet.md @@ -7,7 +7,7 @@ Workflow chain: `constitution → spec → [inspect, optional] → plan → task Core rules: - Paths/config: read `.speckeep/speckeep.yaml` ≤ 1 time per session; if missing, defaults: `=specs/active`, `=specs/archived`, constitution=`CONSTITUTION.md`. - Constitution: load `.speckeep/constitution.summary.md` first if it exists; fall back to `project.constitution_file` (default: `CONSTITUTION.md`) only when the summary is absent. -- Branching: only `/speckeep.spec` may switch/create `feature/` (or `--branch`). Other phases must already be on the correct branch. +- Branching: only `/spk.spec` may switch/create `feature/` (or `--branch`). Other phases must already be on the correct branch. - Scripts: before each phase, run `check-ready.* ` (and any extras from Commands); trust stdout/exit code; never read `.speckeep/scripts/*` source. - Scope/load: default to the current slug only; avoid broad repo scans; prefer `Touches:` surfaces. - ⚠️ **CRITICAL — Repository map first**: **DO NOT** use `ls`, `find`, or glob for primary navigation. Read `REPOSITORY_MAP.md` first — it contains the complete repo map. This saves tokens and maintains workflow discipline. Read it once per session and reuse notes; re-read only if you updated the map in the same session. @@ -22,21 +22,21 @@ Core rules: - Scope: do not read or modify artifacts from other slugs/specs unless the current task explicitly requires it (otherwise it’s a scope violation). - Don't invent: do not introduce requirements, dependencies, scope, or passing criteria absent from current phase inputs. -Commands (⚠️ prefix is **speckeep** with a **p**, NOT speckeek with a k): -- `/speckeep.constitution` → update constitution -- `/speckeep.spec` → write spec (branch-first) -- `/speckeep.inspect` → optional deep quality review -- `/speckeep.plan` → write plan artifacts -- `/speckeep.tasks` → write tasks -- `/speckeep.implement` → implement tasks -- `/speckeep.verify` → verify tasks/AC -- `/speckeep.challenge` → adversarial review of spec/plan (blind spots, untestable AC) -- `/speckeep.rollback` → roll back completed tasks for a feature, returning them to unfinished state -- `/speckeep.recap` → project overview: active features, phase, next step +Commands (prefix: `/spk.`): +- `/spk.constitution` → update constitution +- `/spk.spec` → write spec (branch-first) +- `/spk.inspect` → optional deep quality review +- `/spk.plan` → write plan artifacts +- `/spk.tasks` → write tasks +- `/spk.implement` → implement tasks +- `/spk.verify` → verify tasks/AC +- `/spk.challenge` → adversarial review of spec/plan (blind spots, untestable AC) +- `/spk.rollback` → roll back completed tasks for a feature, returning them to unfinished state +- `/spk.recap` → project overview: active features, phase, next step - `speckeep archive .` → CLI-only archive after `verify: pass` -- `/speckeep.repo-map` → update `REPOSITORY_MAP.md` (see dedicated prompt for policy + template) +- `/spk.repo-map` → update `REPOSITORY_MAP.md` (see dedicated prompt for policy + template) -Trigger checklist (run `/speckeep.repo-map` if at least one is true): +Trigger checklist (run `/spk.repo-map` if at least one is true): - Added or removed a top-level code directory/module. - Moved/renamed key source paths that change navigation. - Added/removed runtime/service/CLI entrypoints. diff --git a/src/internal/templates/assets/lang/en/templates/prompts/constitution.md b/src/internal/templates/assets/lang/en/templates/prompts/constitution.md index 3eede60..d1d2a50 100644 --- a/src/internal/templates/assets/lang/en/templates/prompts/constitution.md +++ b/src/internal/templates/assets/lang/en/templates/prompts/constitution.md @@ -28,4 +28,4 @@ Stop if: rules remain `TBD`/placeholder or contradict repo reality without an ex - `Languages:` one line (`docs=...`, `agent=...`, `comments=...`) - hard limit: ≤200 words total - Summarize the key rules and what changed. -- Final line: `Ready for: /speckeep.spec ` +- Final line: `Ready for: /spk.spec ` diff --git a/src/internal/templates/assets/lang/en/templates/prompts/handoff.md b/src/internal/templates/assets/lang/en/templates/prompts/handoff.md index b4f07bc..56aca2d 100644 --- a/src/internal/templates/assets/lang/en/templates/prompts/handoff.md +++ b/src/internal/templates/assets/lang/en/templates/prompts/handoff.md @@ -16,6 +16,6 @@ Stop if: tasks.md is missing. - `Slug`, `Phase`, `What changed`, `Open tasks`, `Blockers`, `Next command`. - Final line (detect phase from state): - - If blocked: `Return to: /speckeep. ` - - If ready for next phase: `Ready for: /speckeep. ` + - If blocked: `Return to: /spk. ` + - If ready for next phase: `Ready for: /spk. ` - If all done: `Ready for: speckeep archive .` diff --git a/src/internal/templates/assets/lang/en/templates/prompts/hotfix.md b/src/internal/templates/assets/lang/en/templates/prompts/hotfix.md index e524a99..cafc780 100644 --- a/src/internal/templates/assets/lang/en/templates/prompts/hotfix.md +++ b/src/internal/templates/assets/lang/en/templates/prompts/hotfix.md @@ -18,4 +18,4 @@ Stop if: changes exceed 3 files, or require a design change — return to standa - List changed files, what was fixed, and how to verify. - Include a short summary block: `Slug`, `Status`, `Artifacts`, `Blockers`. -- Final line: `Ready for: /speckeep.verify ` (or `/speckeep.implement ` if hotfix implements known scope without verify). +- Final line: `Ready for: /spk.verify ` (or `/spk.implement ` if hotfix implements known scope without verify). diff --git a/src/internal/templates/assets/lang/en/templates/prompts/implement.md b/src/internal/templates/assets/lang/en/templates/prompts/implement.md index c89410c..09a2833 100644 --- a/src/internal/templates/assets/lang/en/templates/prompts/implement.md +++ b/src/internal/templates/assets/lang/en/templates/prompts/implement.md @@ -55,8 +55,8 @@ Stop if: `tasks.md` is missing, the next task is not concrete, execution require - Update code/files and mark completed tasks `[x]` in `tasks.md`. - Include a short `Trace plan:` block before the result summary for the tasks you touched. -- Before finalizing, make an explicit map decision line: `Map update: yes|no` + reason (based on `/speckeep.repo-map` trigger checklist in `AGENTS.md`). -- If `Map update: yes`, run `/speckeep.repo-map` and include `REPOSITORY_MAP.md` in changed files. +- Before finalizing, make an explicit map decision line: `Map update: yes|no` + reason (based on `/spk.repo-map` trigger checklist in `AGENTS.md`). +- If `Map update: yes`, run `/spk.repo-map` and include `REPOSITORY_MAP.md` in changed files. - If repository structure/navigation changed (new/moved modules, new entrypoints, major path reshaping), `Map update` must be `yes`. - If changes are local and do not affect structure/navigation, do not touch `REPOSITORY_MAP.md`. - Report: closed task IDs, changed files, and the observable proof. @@ -64,4 +64,4 @@ Stop if: `tasks.md` is missing, the next task is not concrete, execution require - Do not finish without explicit `Trace proof:` lines in the form: ` -> : (@sk-task|@sk-test)`. - If a closed task has no valid `Trace proof:` line, treat the task as still open and do not mark it `[x]`. - End with standard end block (see AGENTS.md). -- Final line (mandatory): `Ready for: /speckeep.verify ` +- Final line (mandatory): `Ready for: /spk.verify ` diff --git a/src/internal/templates/assets/lang/en/templates/prompts/inspect.md b/src/internal/templates/assets/lang/en/templates/prompts/inspect.md index 2cf78d5..cdca8cb 100644 --- a/src/internal/templates/assets/lang/en/templates/prompts/inspect.md +++ b/src/internal/templates/assets/lang/en/templates/prompts/inspect.md @@ -7,7 +7,7 @@ You act as a **principal engineer doing a formal design/code review**. Be thorou - If a claim cannot be verified from artifacts alone, flag it as unverifiable - Suggest concrete fixes, not just problems -You run an optional deep quality review of one feature spec before planning. This phase is not mandatory — if the spec passed self-validation and looks solid, the user may proceed directly to `/speckeep.plan`. Use inspect when there is ambiguity, a complex domain, or the user wants a formal quality gate. +You run an optional deep quality review of one feature spec before planning. This phase is not mandatory — if the spec passed self-validation and looks solid, the user may proceed directly to `/spk.plan`. Use inspect when there is ambiguity, a complex domain, or the user wants a formal quality gate. Follow base rules in `AGENTS.md`. @@ -43,5 +43,5 @@ If `./.speckeep/scripts/check-ready.* inspect ` exists, run it and use its - For `blocked`, do not suggest the next phase command; state which refinement is required first. - In chat: compact verdict + non-empty Errors/Warnings + Next step. - Final line: - - if `pass|concerns`: `Ready for: /speckeep.plan ` - - if `blocked`: `Return to: /speckeep.spec ` + - if `pass|concerns`: `Ready for: /spk.plan ` + - if `blocked`: `Return to: /spk.spec ` diff --git a/src/internal/templates/assets/lang/en/templates/prompts/plan.md b/src/internal/templates/assets/lang/en/templates/prompts/plan.md index 369e13d..539a816 100644 --- a/src/internal/templates/assets/lang/en/templates/prompts/plan.md +++ b/src/internal/templates/assets/lang/en/templates/prompts/plan.md @@ -34,4 +34,4 @@ Stop if: inspect.md is present and not `pass`, the goal is ambiguous, or plannin - Inside `plan.md`, keep compact sections for `DEC-*`, surfaces, risks, and data-model/contract impact; do not move that recap into separate digest files. - Summarize key `DEC-*`, surfaces, sequencing constraints, and risks. - End with standard end block (see AGENTS.md). -- Final line: `Ready for: /speckeep.tasks ` +- Final line: `Ready for: /spk.tasks ` diff --git a/src/internal/templates/assets/lang/en/templates/prompts/rollback.md b/src/internal/templates/assets/lang/en/templates/prompts/rollback.md index 3ffe3f2..05321bf 100644 --- a/src/internal/templates/assets/lang/en/templates/prompts/rollback.md +++ b/src/internal/templates/assets/lang/en/templates/prompts/rollback.md @@ -24,4 +24,4 @@ Stop if: slug is missing, tasks.md does not exist, or no completed tasks exist. - List affected tasks per task ID: whether checkbox was reverted and/or code was reverted. - Show updated task state: `completed=`, `open=`. - If code was reverted, list the git-checkout commands run. -- Final line: `Ready for: /speckeep.implement ` +- Final line: `Ready for: /spk.implement ` diff --git a/src/internal/templates/assets/lang/en/templates/prompts/spec.md b/src/internal/templates/assets/lang/en/templates/prompts/spec.md index c2d7fd8..28820db 100644 --- a/src/internal/templates/assets/lang/en/templates/prompts/spec.md +++ b/src/internal/templates/assets/lang/en/templates/prompts/spec.md @@ -26,7 +26,7 @@ Stop if: the request is ambiguous/multi-feature or would force inventing `AC-*`. - Every `AC-*` is Given/When/Then with observable proof in Then. - Required sections: Out of Scope, Assumptions, Open Questions (or `none`). - Clarify with 1–3 targeted questions only if otherwise you must guess AC or scope boundaries. -- If invoked with `--name` but without enough description, ask for it and treat the next non-command user message as the continuation. If the next message starts with `/speckeep.`, staged mode is canceled. +- If invoked with `--name` but without enough description, ask for it and treat the next non-command user message as the continuation. If the next message starts with `/spk.`, staged mode is canceled. - Constitution: see AGENTS.md (`.speckeep/constitution.summary.md` preferred over full constitution). - Do not pin technologies/versions unless required by the user or a hard repo/contract constraint. If a technology choice is an implementation preference, record it in `plan`, not in `spec`. - Refine instead of guessing: if the request implies multiple feature slugs or multiple independent specs, stop and ask for one concrete feature. @@ -52,6 +52,6 @@ If any check fails, fix before proceeding. - Summarize: goal, scope, AC list, open questions/blockers in the response; do not create extra derived recap files just for this summary. - End with standard end block (see AGENTS.md). - Next steps (offer both): - - Deep quality review: `/speckeep.inspect ` — checks constitution alignment, AC completeness, ambiguity - - Skip to planning if spec looks solid: `/speckeep.plan ` -- Final line (mandatory): `Ready for: /speckeep.inspect ` or `Ready for: /speckeep.plan `. Prefer `/speckeep.inspect` when ambiguity, risk, or open questions remain. + - Deep quality review: `/spk.inspect ` — checks constitution alignment, AC completeness, ambiguity + - Skip to planning if spec looks solid: `/spk.plan ` +- Final line (mandatory): `Ready for: /spk.inspect ` or `Ready for: /spk.plan `. Prefer `/spk.inspect` when ambiguity, risk, or open questions remain. diff --git a/src/internal/templates/assets/lang/en/templates/prompts/tasks.md b/src/internal/templates/assets/lang/en/templates/prompts/tasks.md index 03adcd7..bfc88ad 100644 --- a/src/internal/templates/assets/lang/en/templates/prompts/tasks.md +++ b/src/internal/templates/assets/lang/en/templates/prompts/tasks.md @@ -45,4 +45,4 @@ Stop if: `plan.md` is missing/vague or any `AC-*` cannot be mapped to executable - Write/patch `tasks.md` (avoid full rewrites for small changes). - Summarize: phases, main surfaces, AC coverage, blockers. - End with standard end block (see AGENTS.md). -- Final line: `Ready for: /speckeep.implement ` +- Final line: `Ready for: /spk.implement ` diff --git a/src/internal/templates/assets/lang/en/templates/prompts/verify.md b/src/internal/templates/assets/lang/en/templates/prompts/verify.md index 2c034ed..b7cab4d 100644 --- a/src/internal/templates/assets/lang/en/templates/prompts/verify.md +++ b/src/internal/templates/assets/lang/en/templates/prompts/verify.md @@ -53,6 +53,6 @@ Stop if: `tasks.md` missing or slug ambiguous. - Verdict: `pass|concerns|blocked` + concrete mismatches (task/AC → evidence). - Include `## Not Verified` items when you did not confirm something (explicitly list what you did not check). - Explicitly call out traceability gaps when `@sk-task` / `@sk-test` evidence is missing or partial for completed tasks. -- If `blocked`, end with `Return to: /speckeep. `. +- If `blocked`, end with `Return to: /spk. `. - End with standard end block (see AGENTS.md). - If `pass`, final line: `Ready for: speckeep archive .` diff --git a/src/internal/templates/assets/lang/ru/templates/agents-snippet.md b/src/internal/templates/assets/lang/ru/templates/agents-snippet.md index 69a72e0..83f88a6 100644 --- a/src/internal/templates/assets/lang/ru/templates/agents-snippet.md +++ b/src/internal/templates/assets/lang/ru/templates/agents-snippet.md @@ -8,7 +8,7 @@ - Пути/конфиг: читайте `.speckeep/speckeep.yaml` ≤ 1 раза за сессию; если конфига нет, defaults: `=specs/active`, `=specs/archived`, constitution=`CONSTITUTION.md`. - Конституция: загружайте `.speckeep/constitution.summary.md` сначала, если файл существует; только при его отсутствии переходите к `project.constitution_file` (по умолчанию `CONSTITUTION.md`). -- Ветки: только `/speckeep.spec` может переключать/создавать `feature/` (или `--branch`). Остальные фазы должны уже быть на нужной ветке. +- Ветки: только `/spk.spec` может переключать/создавать `feature/` (или `--branch`). Остальные фазы должны уже быть на нужной ветке. - Скрипты: перед каждой фазой запускайте `check-ready.* ` (и любые extras из секции Команды); доверяйте stdout/exit code; исходники `.speckeep/scripts/*` не читать. - Scope/load: по умолчанию только текущий slug; без широких репо-сканов; предпочитайте surfaces из `Touches:`. - ⚠️ **CRITICAL — Repository map first**: **НЕ** используйте `ls`, `find`, glob для первичной навигации. Прочитайте `REPOSITORY_MAP.md` в первую очередь — он содержит полную карту репозитория. Это экономит токены и соблюдает workflow discipline. Читайте карту один раз за сессию, переиспользуйте заметки; перечитывайте только если сами обновили карту в этой же сессии. @@ -23,22 +23,22 @@ - Scope: не читайте и не меняйте артефакты других slug/спек, если текущая задача явно не требует (иначе это scope violation). - Don't invent: не вводите требований, зависимостей, scope или критериев приёмки, отсутствующих во входных артефактах текущей фазы. -Команды (⚠️ префикс — **speckeep** с буквой **p**, не speckeek с буквой k): - -- `/speckeep.constitution` → конституция -- `/speckeep.spec` → spec (branch-first) -- `/speckeep.inspect` → опциональная глубокая проверка качества -- `/speckeep.plan` → plan artifacts -- `/speckeep.tasks` → tasks -- `/speckeep.implement` → implement -- `/speckeep.verify` → verify -- `/speckeep.challenge` → адверсариальная проверка spec/plan (слепые зоны, непроверяемые AC) -- `/speckeep.rollback` → откат выполненных задач фичи, возврат в незавершённое состояние -- `/speckeep.recap` → обзор проекта: активные фичи, фаза, следующий шаг +Команды (префикс: `/spk.`): + +- `/spk.constitution` → конституция +- `/spk.spec` → spec (branch-first) +- `/spk.inspect` → опциональная глубокая проверка качества +- `/spk.plan` → plan artifacts +- `/spk.tasks` → tasks +- `/spk.implement` → implement +- `/spk.verify` → verify +- `/spk.challenge` → адверсариальная проверка spec/plan (слепые зоны, непроверяемые AC) +- `/spk.rollback` → откат выполненных задач фичи, возврат в незавершённое состояние +- `/spk.recap` → обзор проекта: активные фичи, фаза, следующий шаг - `speckeep archive .` → CLI-only архив после `verify: pass` -- `/speckeep.repo-map` → обновить `REPOSITORY_MAP.md` (см. выделенный prompt для политики + шаблона) +- `/spk.repo-map` → обновить `REPOSITORY_MAP.md` (см. выделенный prompt для политики + шаблона) -Чеклист триггеров обновления (запускайте `/speckeep.repo-map`, если истинно хотя бы одно): +Чеклист триггеров обновления (запускайте `/spk.repo-map`, если истинно хотя бы одно): - Добавлена или удалена верхнеуровневая кодовая директория/модуль. - Перемещены/переименованы ключевые исходники, меняющие навигацию. diff --git a/src/internal/templates/assets/lang/ru/templates/prompts/constitution.md b/src/internal/templates/assets/lang/ru/templates/prompts/constitution.md index b28b0d0..e4f56cc 100644 --- a/src/internal/templates/assets/lang/ru/templates/prompts/constitution.md +++ b/src/internal/templates/assets/lang/ru/templates/prompts/constitution.md @@ -28,4 +28,4 @@ Stop if: правила остаются `TBD`/placeholder или конфлик - `Languages:` одна строка (`docs=...`, `agent=...`, `comments=...`) - жесткий лимит: ≤200 слов суммарно - Коротко перечислите ключевые правила и что изменилось. -- Финальная строка: `Готово к: /speckeep.spec ` +- Финальная строка: `Готово к: /spk.spec ` diff --git a/src/internal/templates/assets/lang/ru/templates/prompts/handoff.md b/src/internal/templates/assets/lang/ru/templates/prompts/handoff.md index 627a955..d241f90 100644 --- a/src/internal/templates/assets/lang/ru/templates/prompts/handoff.md +++ b/src/internal/templates/assets/lang/ru/templates/prompts/handoff.md @@ -16,6 +16,6 @@ Stop if: tasks.md отсутствует. - `Slug`, `Phase`, `What changed`, `Open tasks`, `Blockers`, `Next command`. - Финальная строка (определите по состоянию фазы): - - Если blocked: `Вернуться к: /speckeep. ` - - Если готово к следующей фазе: `Готово к: /speckeep. ` + - Если blocked: `Вернуться к: /spk. ` + - Если готово к следующей фазе: `Готово к: /spk. ` - Если всё готово: `Готово к: speckeep archive .` diff --git a/src/internal/templates/assets/lang/ru/templates/prompts/hotfix.md b/src/internal/templates/assets/lang/ru/templates/prompts/hotfix.md index 9b098ae..f198ded 100644 --- a/src/internal/templates/assets/lang/ru/templates/prompts/hotfix.md +++ b/src/internal/templates/assets/lang/ru/templates/prompts/hotfix.md @@ -18,4 +18,4 @@ Stop if: изменений > 3 файлов или требуется изме - Список изменённых файлов, что исправлено, как проверить. - Добавьте короткий summary block: `Slug`, `Status`, `Artifacts`, `Blockers`. -- Финальная строка: `Готово к: /speckeep.verify ` (или `/speckeep.implement `, если hotfix реализует известный scope без verify). +- Финальная строка: `Готово к: /spk.verify ` (или `/spk.implement `, если hotfix реализует известный scope без verify). diff --git a/src/internal/templates/assets/lang/ru/templates/prompts/implement.md b/src/internal/templates/assets/lang/ru/templates/prompts/implement.md index 9d28947..a10ec67 100644 --- a/src/internal/templates/assets/lang/ru/templates/prompts/implement.md +++ b/src/internal/templates/assets/lang/ru/templates/prompts/implement.md @@ -56,14 +56,14 @@ Stop if: `tasks.md` отсутствует, следующая задача не - Обновите код/файлы и отметьте выполненные задачи `[x]` в `tasks.md`. - Перед итоговым summary добавьте короткий блок `Trace plan:` для задач, которые вы трогали в этом запуске. -- Перед завершением добавьте явную строку решения: `Map update: yes|no` + причина (по trigger checklist `/speckeep.repo-map` из `AGENTS.md`). -- Если `Map update: yes`, запустите `/speckeep.repo-map` и включите `REPOSITORY_MAP.md` в список измененных файлов. +- Перед завершением добавьте явную строку решения: `Map update: yes|no` + причина (по trigger checklist `/spk.repo-map` из `AGENTS.md`). +- Если `Map update: yes`, запустите `/spk.repo-map` и включите `REPOSITORY_MAP.md` в список измененных файлов. - Если структура/навигация репозитория изменилась (новые/перенесенные модули, новые entrypoints, заметная перестройка путей), `Map update` обязательно должно быть `yes`. -- Если изменилась структура/навигация репозитория (новые/перенесенные модули, новые entrypoints, заметная перестройка путей), перед завершением обновите `REPOSITORY_MAP.md` через `/speckeep.repo-map`. +- Если изменилась структура/навигация репозитория (новые/перенесенные модули, новые entrypoints, заметная перестройка путей), перед завершением обновите `REPOSITORY_MAP.md` через `/spk.repo-map`. - Если изменения локальные и не затрагивают структуру/навигацию, `REPOSITORY_MAP.md` не трогайте. - Коротко отчитайтесь: какие task IDs закрыты, какие файлы изменены, какой observable proof. - Добавьте короткую строку traceability proof (в каких файлах стоят `@sk-task` / `@sk-test` для закрытых задач). - Не завершайте фазу без явных строк `Trace proof:` в формате: ` -> : (@sk-task|@sk-test)`. - Если для закрытой задачи нет валидной строки `Trace proof:`, считайте задачу незавершённой и не отмечайте её `[x]`. - Завершите стандартным end block (см. AGENTS.md). -- Финальная строка (обязательно): `Готово к: /speckeep.verify ` +- Финальная строка (обязательно): `Готово к: /spk.verify ` diff --git a/src/internal/templates/assets/lang/ru/templates/prompts/inspect.md b/src/internal/templates/assets/lang/ru/templates/prompts/inspect.md index 2149c3a..a2779ac 100644 --- a/src/internal/templates/assets/lang/ru/templates/prompts/inspect.md +++ b/src/internal/templates/assets/lang/ru/templates/prompts/inspect.md @@ -7,7 +7,7 @@ - Если утверждение нельзя проверить по артефактам — помечайте как непроверяемое - Предлагайте конкретные правки, а не только проблемы -Вы проводите опциональную глубокую проверку качества спецификации перед планированием. Эта фаза не обязательна — если спека прошла самопроверку и выглядит надёжно, пользователь может перейти напрямую к `/speckeep.plan`. Используйте inspect при неоднозначностях, сложном домене или когда нужен формальный quality gate. +Вы проводите опциональную глубокую проверку качества спецификации перед планированием. Эта фаза не обязательна — если спека прошла самопроверку и выглядит надёжно, пользователь может перейти напрямую к `/spk.plan`. Используйте inspect при неоднозначностях, сложном домене или когда нужен формальный quality gate. Следуйте базовым правилам в `AGENTS.md`. @@ -43,5 +43,5 @@ Stop if: spec отсутствует, slug неоднозначен, или verd - Для `blocked` не предлагайте следующую фазу; явно укажите, какой refinement нужен. - В разговоре дайте компактный verdict + непустые Errors/Warnings + Next step. - Финальная строка: - - если `pass|concerns`: `Готово к: /speckeep.plan ` - - если `blocked`: `Вернуться к: /speckeep.spec ` + - если `pass|concerns`: `Готово к: /spk.plan ` + - если `blocked`: `Вернуться к: /spk.spec ` diff --git a/src/internal/templates/assets/lang/ru/templates/prompts/plan.md b/src/internal/templates/assets/lang/ru/templates/prompts/plan.md index 95c2e0f..ff31379 100644 --- a/src/internal/templates/assets/lang/ru/templates/prompts/plan.md +++ b/src/internal/templates/assets/lang/ru/templates/prompts/plan.md @@ -34,4 +34,4 @@ Stop if: inspect.md присутствует и не `pass`, slug/цель не - Внутри `plan.md` обязательно держите компактные sections для `DEC-*`, surfaces, рисков, влияния на data model и contracts; не выносите эти recap-элементы в отдельные digest-файлы. - Укажите ключевые `DEC-*`, surfaces, sequencing constraints и риски. - Завершите стандартным end block (см. AGENTS.md). -- Финальная строка: `Готово к: /speckeep.tasks ` +- Финальная строка: `Готово к: /spk.tasks ` diff --git a/src/internal/templates/assets/lang/ru/templates/prompts/rollback.md b/src/internal/templates/assets/lang/ru/templates/prompts/rollback.md index c38e9f7..c66aba8 100644 --- a/src/internal/templates/assets/lang/ru/templates/prompts/rollback.md +++ b/src/internal/templates/assets/lang/ru/templates/prompts/rollback.md @@ -24,4 +24,4 @@ Stop if: slug отсутствует, tasks.md не существует, или - Перечислите затронутые задачи, для каждой: был ли откачен чекбокс и/или код. - Покажите новое состояние задач: `completed=`, `open=`. - Если код откатывался, перечислите запущенные git-checkout команды. -- Финальная строка: `Готово к: /speckeep.implement ` +- Финальная строка: `Готово к: /spk.implement ` diff --git a/src/internal/templates/assets/lang/ru/templates/prompts/spec.md b/src/internal/templates/assets/lang/ru/templates/prompts/spec.md index c609c01..71157dd 100644 --- a/src/internal/templates/assets/lang/ru/templates/prompts/spec.md +++ b/src/internal/templates/assets/lang/ru/templates/prompts/spec.md @@ -26,7 +26,7 @@ Stop if: запрос неоднозначен/мульти-фича или пр - Каждый `AC-*` — Given/When/Then, наблюдаемый outcome (proof signal в Then). - Обязательны: `Вне scope`, `Допущения`, `Открытые вопросы` (или `none`). - Минимальный clarify-pass: 1–3 точечных вопроса только если иначе придётся выдумывать AC или размоется scope. -- Если вызвано с `--name` без достаточного описания — запросите его и считайте следующее сообщение (не начинающееся с `/speckeep.`) продолжением. Сообщение, начинающееся с `/speckeep.`, отменяет staged mode. +- Если вызвано с `--name` без достаточного описания — запросите его и считайте следующее сообщение (не начинающееся с `/spk.`) продолжением. Сообщение, начинающееся с `/spk.`, отменяет staged mode. - Конституция: см. AGENTS.md (`.speckeep/constitution.summary.md` предпочтительнее полной конституции). - Не фиксируйте технологии/версии, если это не требование пользователя или жёсткий repo/contract constraint. Если это лишь implementation preference — фиксируйте в `plan`, не в `spec`. - Вместо догадок — refinement: если запрос подразумевает несколько feature slug или несколько независимых спецификаций, остановитесь и попросите выбрать одну фичу. @@ -52,6 +52,6 @@ Stop if: запрос неоднозначен/мульти-фича или пр - Коротко суммируйте цель, scope, список AC, открытые вопросы/блокеры в ответе, не создавая отдельные derived-файлы только ради recap. - Завершите стандартным end block (см. AGENTS.md). - Следующие шаги (предложите оба варианта): - - Глубокая проверка качества: `/speckeep.inspect ` — проверяет соответствие конституции, полноту AC, неоднозначности - - Перейти к плану если спека выглядит хорошо: `/speckeep.plan ` -- Финальная строка (обязательно): `Готово к: /speckeep.inspect ` или `Готово к: /speckeep.plan `. Предпочитайте `/speckeep.inspect`, если остались неоднозначности, риски или открытые вопросы. + - Глубокая проверка качества: `/spk.inspect ` — проверяет соответствие конституции, полноту AC, неоднозначности + - Перейти к плану если спека выглядит хорошо: `/spk.plan ` +- Финальная строка (обязательно): `Готово к: /spk.inspect ` или `Готово к: /spk.plan `. Предпочитайте `/spk.inspect`, если остались неоднозначности, риски или открытые вопросы. diff --git a/src/internal/templates/assets/lang/ru/templates/prompts/tasks.md b/src/internal/templates/assets/lang/ru/templates/prompts/tasks.md index 9a5457c..aff0361 100644 --- a/src/internal/templates/assets/lang/ru/templates/prompts/tasks.md +++ b/src/internal/templates/assets/lang/ru/templates/prompts/tasks.md @@ -45,4 +45,4 @@ Stop if: `plan.md` отсутствует/расплывчат или хотя - Запишите/patch `tasks.md` (не переписывайте лишнее при небольших правках). - Коротко суммируйте: фазы, основные surfaces, покрытие AC, blockers. - Завершите стандартным end block (см. AGENTS.md). -- Финальная строка: `Готово к: /speckeep.implement ` +- Финальная строка: `Готово к: /spk.implement ` diff --git a/src/internal/templates/assets/lang/ru/templates/prompts/verify.md b/src/internal/templates/assets/lang/ru/templates/prompts/verify.md index 1a3b099..bdc5891 100644 --- a/src/internal/templates/assets/lang/ru/templates/prompts/verify.md +++ b/src/internal/templates/assets/lang/ru/templates/prompts/verify.md @@ -53,6 +53,6 @@ Stop if: `tasks.md` отсутствует или slug неоднозначен. - Дайте verdict: `pass|concerns|blocked` + список конкретных несоответствий (task/AC → evidence). - Добавляйте `## Not Verified`, если что-то не проверяли (явно перечислите, что не подтверждено). - Явно перечисляйте пробелы traceability, если для завершённых задач отсутствует или частично отсутствует `@sk-task` / `@sk-test` evidence. -- Если `blocked` — завершите: `Вернуться к: /speckeep. `. +- Если `blocked` — завершите: `Вернуться к: /spk. `. - Завершите стандартным end block (см. AGENTS.md). - Если `pass` — финальная строка: `Готово к: speckeep archive .` diff --git a/src/internal/templates/embed_test.go b/src/internal/templates/embed_test.go index 1bf5791..b30491a 100644 --- a/src/internal/templates/embed_test.go +++ b/src/internal/templates/embed_test.go @@ -187,7 +187,7 @@ func TestInspectPromptDefinesCheapScopeAndVerdictRules(t *testing.T) { "pass|concerns|blocked", "check-ready.* inspect", ".speckeep/constitution.summary.md", - "Return to: /speckeep.spec ", + "Return to: /spk.spec ", } for _, snippet := range requiredSnippets { if !strings.Contains(content, snippet) { @@ -346,7 +346,7 @@ func TestImplementPromptSupportsFullRunAndScopedExecution(t *testing.T) { "Do not use `--phase` and `--tasks` together.", "`Touches:`", "Do not assume `research.md` should exist;", - "Ready for: /speckeep.verify ", + "Ready for: /spk.verify ", "End with standard end block (see AGENTS.md).", } for _, snippet := range requiredSnippets { @@ -374,8 +374,8 @@ func TestSpecPromptDefinesDeterministicStagedMode(t *testing.T) { "staged mode is canceled", "Do not pin technologies/versions unless required", ".speckeep/constitution.summary.md", - "/speckeep.inspect ", - "/speckeep.plan ", + "/spk.inspect ", + "/spk.plan ", "Final line (mandatory): `Ready for:", "End with standard end block (see AGENTS.md).", } @@ -403,7 +403,7 @@ func TestPlanPromptDefinesConcreteResearchTriggers(t *testing.T) { "Create `research.md` only when needed", "Do not create `research.md` for generic brainstorming", ".speckeep/constitution.summary.md", - "Ready for: /speckeep.tasks ", + "Ready for: /spk.tasks ", "End with standard end block (see AGENTS.md).", } for _, snippet := range requiredSnippets { @@ -593,7 +593,7 @@ func TestVerifyTemplateAndPromptPreferEvidenceScopedVerification(t *testing.T) { for _, snippet := range []string{ "evidence log", "verify-task-state", - "Return to: /speckeep. ", + "Return to: /spk. ", "Ready for: speckeep archive .", } { if !strings.Contains(promptContent, snippet) { @@ -622,8 +622,8 @@ func TestPhasePromptsIncludeExplicitNextCommandGuidance(t *testing.T) { target: "templates/prompts/spec.md", want: []string{ ".speckeep/constitution.summary.md", - "/speckeep.inspect ", - "/speckeep.plan ", + "/spk.inspect ", + "/spk.plan ", "Final line (mandatory): `Ready for:", "End with standard end block (see AGENTS.md).", }, @@ -632,7 +632,7 @@ func TestPhasePromptsIncludeExplicitNextCommandGuidance(t *testing.T) { target: "templates/prompts/plan.md", want: []string{ ".speckeep/constitution.summary.md", - "Ready for: /speckeep.tasks ", + "Ready for: /spk.tasks ", "End with standard end block (see AGENTS.md).", }, }, @@ -640,7 +640,7 @@ func TestPhasePromptsIncludeExplicitNextCommandGuidance(t *testing.T) { target: "templates/prompts/tasks.md", want: []string{ ".speckeep/constitution.summary.md", - "Ready for: /speckeep.implement ", + "Ready for: /spk.implement ", "End with standard end block (see AGENTS.md).", }, }, @@ -650,7 +650,7 @@ func TestPhasePromptsIncludeExplicitNextCommandGuidance(t *testing.T) { "Default scope: only the **first unfinished phase**", ".speckeep/constitution.summary.md", "End with standard end block (see AGENTS.md).", - "Ready for: /speckeep.verify ", + "Ready for: /spk.verify ", }, }, { @@ -658,7 +658,7 @@ func TestPhasePromptsIncludeExplicitNextCommandGuidance(t *testing.T) { want: []string{ ".speckeep/constitution.summary.md", "End with standard end block (see AGENTS.md).", - "Return to: /speckeep. ", + "Return to: /spk. ", "Ready for: speckeep archive .", }, }, @@ -723,7 +723,7 @@ func TestPromptsEnforcePhaseBoundaries(t *testing.T) { { target: "templates/prompts/verify.md", want: []string{ - "If `blocked`, end with `Return to: /speckeep. `.", + "If `blocked`, end with `Return to: /spk. `.", }, }, } diff --git a/src/internal/workflow/check_plan.go b/src/internal/workflow/check_plan.go index d9fd530..a309cbf 100644 --- a/src/internal/workflow/check_plan.go +++ b/src/internal/workflow/check_plan.go @@ -39,7 +39,7 @@ func CheckPlanReady(ctx context.Context, cfg config.Config, root, slug string) ( inspectDisplayPath = legacyInspectDisplay inspectAbs = legacyAbs } else { - result.AddWarn(fmt.Sprintf("no inspect report %s — inspect is optional; run /speckeep.inspect for a deep quality review", inspectDisplay)) + result.AddWarn(fmt.Sprintf("no inspect report %s — inspect is optional; run /spk.inspect for a deep quality review", inspectDisplay)) } } if fileExists(inspectAbs) {