@dccxx/auggiegw 1.0.28 → 1.0.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/cli.js +71 -4
  2. package/openspec/changes/archive/2026-02-07-fix-skill-yaml-frontmatter/.openspec.yaml +2 -0
  3. package/openspec/changes/archive/2026-02-07-fix-skill-yaml-frontmatter/design.md +69 -0
  4. package/openspec/changes/archive/2026-02-07-fix-skill-yaml-frontmatter/proposal.md +25 -0
  5. package/openspec/changes/archive/2026-02-07-fix-skill-yaml-frontmatter/specs/skill-directory-structure/spec.md +29 -0
  6. package/openspec/changes/archive/2026-02-07-fix-skill-yaml-frontmatter/specs/skill-yaml-frontmatter/spec.md +61 -0
  7. package/openspec/changes/archive/2026-02-07-fix-skill-yaml-frontmatter/tasks.md +14 -0
  8. package/openspec/changes/handle-kit-deleted-items/.openspec.yaml +2 -0
  9. package/openspec/changes/handle-kit-deleted-items/design.md +78 -0
  10. package/openspec/changes/handle-kit-deleted-items/proposal.md +26 -0
  11. package/openspec/changes/handle-kit-deleted-items/specs/kit-deleted-items/spec.md +115 -0
  12. package/openspec/changes/handle-kit-deleted-items/tasks.md +36 -0
  13. package/openspec/specs/kit-deleted-items/spec.md +110 -0
  14. package/openspec/specs/skill-directory-structure/spec.md +16 -4
  15. package/openspec/specs/skill-yaml-frontmatter/spec.md +61 -0
  16. package/package.json +2 -2
  17. package/.augment/commands/compact.md +0 -73
  18. package/.augment/skills/compact/SKILL.md +0 -73
  19. package/.claude/commands/opsx/apply.md +0 -152
  20. package/.claude/commands/opsx/archive.md +0 -157
  21. package/.claude/commands/opsx/bulk-archive.md +0 -242
  22. package/.claude/commands/opsx/continue.md +0 -114
  23. package/.claude/commands/opsx/explore.md +0 -174
  24. package/.claude/commands/opsx/ff.md +0 -94
  25. package/.claude/commands/opsx/new.md +0 -69
  26. package/.claude/commands/opsx/onboard.md +0 -525
  27. package/.claude/commands/opsx/sync.md +0 -134
  28. package/.claude/commands/opsx/verify.md +0 -164
  29. package/.claude/skills/openspec-apply-change/SKILL.md +0 -156
  30. package/.claude/skills/openspec-archive-change/SKILL.md +0 -114
  31. package/.claude/skills/openspec-bulk-archive-change/SKILL.md +0 -246
  32. package/.claude/skills/openspec-continue-change/SKILL.md +0 -118
  33. package/.claude/skills/openspec-explore/SKILL.md +0 -290
  34. package/.claude/skills/openspec-ff-change/SKILL.md +0 -101
  35. package/.claude/skills/openspec-new-change/SKILL.md +0 -74
  36. package/.claude/skills/openspec-onboard/SKILL.md +0 -529
  37. package/.claude/skills/openspec-sync-specs/SKILL.md +0 -138
  38. package/.claude/skills/openspec-verify-change/SKILL.md +0 -168
  39. /package/openspec/changes/{add-dual-prompt-save → archive/2026-02-05-add-dual-prompt-save}/.openspec.yaml +0 -0
  40. /package/openspec/changes/{add-dual-prompt-save → archive/2026-02-05-add-dual-prompt-save}/design.md +0 -0
  41. /package/openspec/changes/{add-dual-prompt-save → archive/2026-02-05-add-dual-prompt-save}/proposal.md +0 -0
  42. /package/openspec/changes/{add-dual-prompt-save → archive/2026-02-05-add-dual-prompt-save}/specs/dual-prompt-save/spec.md +0 -0
  43. /package/openspec/changes/{add-dual-prompt-save → archive/2026-02-05-add-dual-prompt-save}/specs/skill-directory-structure/spec.md +0 -0
  44. /package/openspec/changes/{add-dual-prompt-save → archive/2026-02-05-add-dual-prompt-save}/tasks.md +0 -0
package/dist/cli.js CHANGED
@@ -3543,8 +3543,8 @@ function resolveInstallPaths(target, scope) {
3543
3543
  }
3544
3544
  async function savePromptToPath(prompt, skillsDir, commandsDir) {
3545
3545
  const markdownContent = `---
3546
- description: ${prompt.name}
3547
- type: "manual"
3546
+ name: ${prompt.name}
3547
+ description: ${prompt.description ?? prompt.name}
3548
3548
  ---
3549
3549
 
3550
3550
  ${prompt.content}`;
@@ -3650,6 +3650,66 @@ function resolveMultipleTargetPaths(targets, scope) {
3650
3650
  paths
3651
3651
  };
3652
3652
  }
3653
+ function resolveDeletePaths(installConfig) {
3654
+ const deletePaths = [];
3655
+ const homeDir = os.homedir();
3656
+ const projectDir = process.cwd();
3657
+ const selectedTargets = Object.keys(installConfig.paths);
3658
+ for (const target of selectedTargets) {
3659
+ if (target === "augment") {
3660
+ deletePaths.push({
3661
+ commands: path.join(homeDir, ".augment", "skills"),
3662
+ commandsLegacy: path.join(homeDir, ".augment", "commands"),
3663
+ agents: path.join(homeDir, ".augment", "agents")
3664
+ });
3665
+ deletePaths.push({
3666
+ commands: path.join(projectDir, ".augment", "skills"),
3667
+ commandsLegacy: path.join(projectDir, ".augment", "commands"),
3668
+ agents: path.join(projectDir, ".augment", "agents")
3669
+ });
3670
+ } else if (target === "claude") {
3671
+ deletePaths.push({
3672
+ commands: path.join(homeDir, ".claude", "skills"),
3673
+ commandsLegacy: path.join(homeDir, ".claude", "commands"),
3674
+ agents: path.join(homeDir, ".claude", "agents")
3675
+ });
3676
+ deletePaths.push({
3677
+ commands: path.join(projectDir, ".claude", "skills"),
3678
+ commandsLegacy: path.join(projectDir, ".claude", "commands"),
3679
+ agents: path.join(projectDir, ".claude", "agents")
3680
+ });
3681
+ } else if (target === "opencode") {
3682
+ deletePaths.push({
3683
+ commands: path.join(homeDir, ".config", "opencode", "skills"),
3684
+ commandsLegacy: path.join(homeDir, ".config", "opencode", "commands"),
3685
+ agents: path.join(homeDir, ".config", "opencode", "agents")
3686
+ });
3687
+ deletePaths.push({
3688
+ commands: path.join(projectDir, ".opencode", "skills"),
3689
+ commandsLegacy: path.join(projectDir, ".opencode", "commands"),
3690
+ agents: path.join(projectDir, ".opencode", "agents")
3691
+ });
3692
+ }
3693
+ }
3694
+ return deletePaths;
3695
+ }
3696
+ async function deleteKitItems(deletedItems, deletePaths) {
3697
+ let deletedCount = 0;
3698
+ for (const name of deletedItems.prompts) {
3699
+ for (const pathSet of deletePaths) {
3700
+ await fs.rm(path.join(pathSet.commands, name), { recursive: true, force: true });
3701
+ await fs.rm(path.join(pathSet.commandsLegacy, `${name}.md`), { force: true });
3702
+ }
3703
+ deletedCount++;
3704
+ }
3705
+ for (const name of deletedItems.subagents) {
3706
+ for (const pathSet of deletePaths) {
3707
+ await fs.rm(path.join(pathSet.agents, `${name}.md`), { force: true });
3708
+ }
3709
+ deletedCount++;
3710
+ }
3711
+ return deletedCount;
3712
+ }
3653
3713
  async function promptInput(question, hidden = false) {
3654
3714
  const rl = readline.createInterface({
3655
3715
  input: process.stdin,
@@ -4087,7 +4147,14 @@ async function handleKit(kitId, options = {}) {
4087
4147
  subagentsCount++;
4088
4148
  }
4089
4149
  }
4090
- let successMessage = `Successfully installed kit "${kit.name}": ${promptsCount} prompts, ${subagentsCount} subagents
4150
+ let deletedCount = 0;
4151
+ if (kit.deleted_items && (kit.deleted_items.prompts.length > 0 || kit.deleted_items.subagents.length > 0)) {
4152
+ spinner.text = "Cleaning up deleted items...";
4153
+ const deletePaths = resolveDeletePaths(installConfig);
4154
+ deletedCount = await deleteKitItems(kit.deleted_items, deletePaths);
4155
+ }
4156
+ const deletedSuffix = deletedCount > 0 ? `, ${deletedCount} removed` : "";
4157
+ let successMessage = `Successfully installed kit "${kit.name}": ${promptsCount} prompts, ${subagentsCount} subagents${deletedSuffix}
4091
4158
 
4092
4159
  Installed to:`;
4093
4160
  if (installConfig.paths.augment) {
@@ -4139,4 +4206,4 @@ program2.command("kit <kit-id>").description("Fetch and install a kit (prompts a
4139
4206
  });
4140
4207
  program2.parse();
4141
4208
 
4142
- //# debugId=24CCB949527CC51D64756E2164756E21
4209
+ //# debugId=706C0DF49CFC16E464756E2164756E21
@@ -0,0 +1,2 @@
1
+ schema: spec-driven
2
+ created: 2026-02-07
@@ -0,0 +1,69 @@
1
+ ## Context
2
+
3
+ The CLI tool (`auggie`) fetches prompts from an API and saves them as Markdown files with YAML frontmatter. The current `savePromptToPath()` function writes incorrect frontmatter:
4
+
5
+ ```yaml
6
+ ---
7
+ description: spec-apply # ← This is actually the name, not a description
8
+ type: "manual" # ← Hardcoded, unnecessary
9
+ ---
10
+ ```
11
+
12
+ The `PromptData` interface has three fields: `name`, `command`, `content`. There is no `description` field. The API response is cast directly to `PromptData` without transformation.
13
+
14
+ Subagents (`saveSubagentToPath()`) already use the correct format with both `name` and `description` fields.
15
+
16
+ ## Goals / Non-Goals
17
+
18
+ **Goals:**
19
+ - Emit correct YAML frontmatter with `name` field for skill files
20
+ - Include `description` field in frontmatter when available
21
+ - Remove the hardcoded `type: "manual"` field
22
+ - Align prompt frontmatter style with subagent frontmatter style
23
+
24
+ **Non-Goals:**
25
+ - Migrating existing saved skill files to the new format (they'll update on next fetch/install)
26
+ - Changing the API response structure
27
+ - Changing subagent frontmatter (already correct)
28
+
29
+ ## Decisions
30
+
31
+ ### Decision 1: Add optional `description` field to `PromptData`
32
+
33
+ **Choice:** Add `description?: string` to the `PromptData` interface.
34
+
35
+ **Rationale:** The API may already return a `description` field that gets silently dropped by the current TypeScript interface (since `as` casts don't strip extra fields, the data is there at runtime but not typed). Adding it as optional ensures:
36
+ - If the API provides it, it gets used
37
+ - If the API doesn't provide it, we fall back gracefully
38
+
39
+ **Alternative considered:** Making `description` required — rejected because we can't control the API response and don't want to break if it's absent.
40
+
41
+ ### Decision 2: Frontmatter template format
42
+
43
+ **Choice:** New format:
44
+ ```yaml
45
+ ---
46
+ name: <prompt.name>
47
+ description: <prompt.description or prompt.name>
48
+ ---
49
+ ```
50
+
51
+ **Rationale:**
52
+ - `name` field is the primary identifier — must be present
53
+ - `description` falls back to `name` if not available from API, ensuring the field is never empty
54
+ - `type: "manual"` removed — it serves no purpose and isn't used by any consumer
55
+ - Matches the pattern used by `saveSubagentToPath()` for consistency
56
+
57
+ **Alternative considered:** Omitting `description` entirely when not available — rejected because having a consistent set of frontmatter fields is better for consumers.
58
+
59
+ ### Decision 3: Single function change, no structural refactor
60
+
61
+ **Choice:** Modify `savePromptToPath()` in place. No new functions or abstractions.
62
+
63
+ **Rationale:** This is a ~5 line fix. The function structure is fine; only the template string and interface need updating.
64
+
65
+ ## Risks / Trade-offs
66
+
67
+ - **[Existing files have old format]** → Acceptable. Files update on next `fetch` or `kit` install. No migration needed.
68
+ - **[API might not return description]** → Mitigated by making field optional and falling back to `name`.
69
+
@@ -0,0 +1,25 @@
1
+ ## Why
2
+
3
+ The `savePromptToPath()` function writes incorrect YAML frontmatter when saving skill files. The prompt's `name` is written into the `description` field, the `name` field is missing entirely, and a hardcoded `type: "manual"` field is included unnecessarily. This means skills are saved without a proper `name` identifier and lack a real description.
4
+
5
+ ## What Changes
6
+
7
+ - Fix YAML frontmatter in saved skill files to include a `name` field
8
+ - Add `description` field to `PromptData` interface (if API provides it) or derive it from `name`
9
+ - Remove the hardcoded `type: "manual"` field from frontmatter
10
+ - Update the existing spec that codified the old (incorrect) format
11
+
12
+ ## Capabilities
13
+
14
+ ### New Capabilities
15
+ - `skill-yaml-frontmatter`: Correct YAML frontmatter format for saved skill files, ensuring `name` and `description` fields are present and `type` is removed
16
+
17
+ ### Modified Capabilities
18
+ - `skill-directory-structure`: The "Preserve file content format" requirement currently specifies the old buggy format (`description: <name>`, `type: "manual"`). This needs to be updated to reflect the corrected frontmatter format.
19
+
20
+ ## Impact
21
+
22
+ - **Code**: `src/cli.ts` — `savePromptToPath()` function (~line 556-580), `PromptData` interface (~line 68-72)
23
+ - **Saved files**: All skill files (`SKILL.md`) written by `auggie fetch`, `auggie fetch --refresh-commands`, and `auggie kit` commands will have the new frontmatter format
24
+ - **Existing skills**: Previously saved skill files will retain the old format until re-fetched/re-installed
25
+
@@ -0,0 +1,29 @@
1
+ ## MODIFIED Requirements
2
+
3
+ ### Requirement: Preserve file content format
4
+ The system SHALL write skill files with YAML frontmatter containing `name` and `description` fields when saving to the directory structure.
5
+
6
+ #### Scenario: File content format
7
+ - **WHEN** saving a prompt with name "Test Prompt", description "A test prompt", and content "Hello world"
8
+ - **THEN** `SKILL.md` contains:
9
+ ```
10
+ ---
11
+ name: Test Prompt
12
+ description: A test prompt
13
+ ---
14
+
15
+ Hello world
16
+ ```
17
+
18
+ #### Scenario: File content format without description
19
+ - **WHEN** saving a prompt with name "Test Prompt", no description, and content "Hello world"
20
+ - **THEN** `SKILL.md` contains:
21
+ ```
22
+ ---
23
+ name: Test Prompt
24
+ description: Test Prompt
25
+ ---
26
+
27
+ Hello world
28
+ ```
29
+
@@ -0,0 +1,61 @@
1
+ ## ADDED Requirements
2
+
3
+ ### Requirement: Skill files SHALL include name in YAML frontmatter
4
+ The system SHALL write a `name` field in the YAML frontmatter of saved skill files, using the prompt's name value.
5
+
6
+ #### Scenario: Skill file includes name field
7
+ - **WHEN** saving a prompt with name "spec-apply"
8
+ - **THEN** the SKILL.md frontmatter SHALL contain `name: spec-apply`
9
+
10
+ ### Requirement: Skill files SHALL include description in YAML frontmatter
11
+ The system SHALL write a `description` field in the YAML frontmatter of saved skill files. If the prompt has a description, that value SHALL be used. If no description is available, the prompt's name SHALL be used as fallback.
12
+
13
+ #### Scenario: Skill file with description from API
14
+ - **WHEN** saving a prompt with name "spec-apply" and description "Apply spec changes to codebase"
15
+ - **THEN** the SKILL.md frontmatter SHALL contain `description: Apply spec changes to codebase`
16
+
17
+ #### Scenario: Skill file without description falls back to name
18
+ - **WHEN** saving a prompt with name "spec-apply" and no description
19
+ - **THEN** the SKILL.md frontmatter SHALL contain `description: spec-apply`
20
+
21
+ ### Requirement: Skill files SHALL NOT include type field
22
+ The system SHALL NOT write a `type` field in the YAML frontmatter of saved skill files.
23
+
24
+ #### Scenario: No type field in frontmatter
25
+ - **WHEN** saving any prompt
26
+ - **THEN** the SKILL.md frontmatter SHALL NOT contain a `type` field
27
+
28
+ ### Requirement: Complete frontmatter format
29
+ The system SHALL write skill file frontmatter in the following format with name and description fields only.
30
+
31
+ #### Scenario: Full frontmatter output
32
+ - **WHEN** saving a prompt with name "My Skill" and description "Does something useful"
33
+ - **THEN** `SKILL.md` SHALL contain:
34
+ ```
35
+ ---
36
+ name: My Skill
37
+ description: Does something useful
38
+ ---
39
+ ```
40
+
41
+ #### Scenario: Full frontmatter output without description
42
+ - **WHEN** saving a prompt with name "My Skill" and no description
43
+ - **THEN** `SKILL.md` SHALL contain:
44
+ ```
45
+ ---
46
+ name: My Skill
47
+ description: My Skill
48
+ ---
49
+ ```
50
+
51
+ ### Requirement: PromptData SHALL support optional description
52
+ The `PromptData` interface SHALL include an optional `description` field of type string to capture prompt descriptions from the API.
53
+
54
+ #### Scenario: API returns description
55
+ - **WHEN** the API response includes a `description` field for a prompt
56
+ - **THEN** the value SHALL be available in `PromptData.description`
57
+
58
+ #### Scenario: API does not return description
59
+ - **WHEN** the API response does not include a `description` field for a prompt
60
+ - **THEN** `PromptData.description` SHALL be `undefined`
61
+
@@ -0,0 +1,14 @@
1
+ ## 1. Update PromptData Interface
2
+
3
+ - [x] 1.1 Add optional `description` field to `PromptData` interface in `src/cli.ts` (~line 68-72)
4
+
5
+ ## 2. Fix Frontmatter Template
6
+
7
+ - [x] 2.1 Update `savePromptToPath()` in `src/cli.ts` (~line 556-580) to write `name` field using `prompt.name`
8
+ - [x] 2.2 Update `savePromptToPath()` to write `description` field using `prompt.description ?? prompt.name`
9
+ - [x] 2.3 Remove `type: "manual"` from the frontmatter template
10
+
11
+ ## 3. Update Existing Spec
12
+
13
+ - [x] 3.1 Update `openspec/specs/skill-directory-structure/spec.md` "Preserve file content format" requirement to reflect the new frontmatter format (name + description, no type)
14
+
@@ -0,0 +1,2 @@
1
+ schema: spec-driven
2
+ created: 2026-02-09
@@ -0,0 +1,78 @@
1
+ ## Context
2
+
3
+ The `kit` command in `src/cli.ts` fetches a kit from the API and saves prompts and subagents to local directories. The API now returns a `deleted_items` field:
4
+
5
+ ```json
6
+ {
7
+ "deleted_items": {
8
+ "prompts": ["openspec-ff"],
9
+ "subagents": ["aaa"],
10
+ "rules": []
11
+ }
12
+ }
13
+ ```
14
+
15
+ These represent items that were deleted server-side and should be cleaned up locally. The current `handleKit()` function supports multiple AI targets (claude, augment, opencode) and two scopes (user `~/`, project `./`). Path resolution is handled by `resolveInstallPaths()` and `resolveMultipleTargetPaths()`.
16
+
17
+ File locations per target:
18
+ - **Prompts (new)**: `{base}/.{target}/skills/{name}/SKILL.md` (directory)
19
+ - **Prompts (legacy)**: `{base}/.{target}/commands/{name}.md` (file)
20
+ - **Subagents**: `{base}/.{target}/agents/{name}.md` (file)
21
+
22
+ Where `{base}` is `~/` for user scope or `./` for project scope, and `{target}` is `augment`, `claude`, or `config/opencode` (user) / `opencode` (project).
23
+
24
+ ## Goals / Non-Goals
25
+
26
+ **Goals:**
27
+ - Delete locally stored prompts and subagents that appear in `deleted_items`
28
+ - Delete from **selected targets** only (matching user's `--target` choice)
29
+ - Delete from **both scopes** always (user + project), regardless of install scope selection
30
+ - Handle missing files silently (no errors if file doesn't exist)
31
+ - Show deletion count in success message
32
+ - Skip `deleted_items.rules` entirely (no rules storage exists)
33
+
34
+ **Non-Goals:**
35
+ - Implementing rules storage or deletion
36
+ - Deleting from targets the user didn't select
37
+ - Scanning other project directories beyond `./` and `~/`
38
+ - Adding a `--no-delete` flag to skip deletion
39
+ - Prompting user for confirmation before deleting
40
+
41
+ ## Decisions
42
+
43
+ ### Decision 1: Delete from both scopes, always
44
+ **Rationale**: If the server says an item is deleted, it should be removed everywhere the user might have it. Limiting deletion to only the selected scope would leave stale files in the other scope.
45
+
46
+ **Trade-off**: We can only clean `~/` (user) and `./` (current project). Other projects that installed the same kit won't be cleaned. This is an acceptable limitation.
47
+
48
+ ### Decision 2: Delete from selected targets only
49
+ **Rationale**: If a user chose `--target claude`, they're managing their Claude setup. We shouldn't touch their Augment or OpenCode directories without being asked.
50
+
51
+ ### Decision 3: Resolve delete paths separately from install paths
52
+ **Rationale**: Install paths use the user's selected scope. Delete paths need both scopes. Rather than modifying `resolveInstallPaths()`, we build delete paths independently by calling the path resolution for both scopes and merging the results.
53
+
54
+ **Approach**: Create a helper `resolveDeletePaths()` that takes the selected targets and returns paths for both user and project scopes. This keeps the existing install path logic untouched.
55
+
56
+ ### Decision 4: Delete after saving (not before)
57
+ **Rationale**: If a prompt name appears in both `prompts` (to save) and `deleted_items.prompts` (to delete), the save should win — this would be a server-side data inconsistency, but saving is the safer default. However, in practice the server should never include the same name in both arrays.
58
+
59
+ ### Decision 5: Use fs.rm with force option for silent failure
60
+ **Rationale**: Using `fs.rm(path, { force: true })` and `fs.rm(dir, { recursive: true, force: true })` handles the "file doesn't exist" case without try/catch. Clean and idiomatic.
61
+
62
+ ## Risks / Trade-offs
63
+
64
+ **[Risk] Accidental deletion of user-created files** → Mitigation: We only delete files whose names match `deleted_items` entries. If a user manually created a skill with the same name as a deleted kit item, it would be removed. This is acceptable — the name collision means it was likely from the kit originally.
65
+
66
+ **[Risk] Race condition with concurrent kit installs** → Mitigation: Extremely unlikely for a CLI tool. No mitigation needed.
67
+
68
+ **[Risk] `deleted_items` field missing from older API versions** → Mitigation: Field is optional (`deleted_items?`). If missing, no deletion occurs. Full backward compatibility.
69
+
70
+ ## Migration Plan
71
+
72
+ No migration needed. This is purely additive behavior:
73
+ 1. Update `KitData` interface
74
+ 2. Add `deleteKitItems()` function
75
+ 3. Call it from `handleKit()` after saving
76
+ 4. Update success message
77
+
78
+ Existing kits without `deleted_items` work exactly as before.
@@ -0,0 +1,26 @@
1
+ ## Why
2
+
3
+ The kit API now returns a `deleted_items` field containing arrays of prompt names, subagent names, and rule names that were deleted server-side. Currently, the `kit` command only adds/overwrites items — it never removes anything. When a kit author deletes a prompt or subagent from their kit, users who re-install the kit still have the stale files locally. This creates confusion and potential conflicts.
4
+
5
+ ## What Changes
6
+
7
+ - Update `KitData` interface to include the optional `deleted_items` field from the API response
8
+ - Add deletion logic to `handleKit()` that processes `deleted_items.prompts` and `deleted_items.subagents`
9
+ - Deletions apply to **selected targets** (claude/augment/opencode) but always across **both scopes** (user + project), regardless of which scope was chosen for installation
10
+ - Rules are excluded from this change (no rules storage exists yet)
11
+ - Files that don't exist are silently skipped (no errors)
12
+
13
+ ## Capabilities
14
+
15
+ ### New Capabilities
16
+ - `kit-deleted-items`: Process `deleted_items` from kit API response to clean up locally deleted prompts and subagents
17
+
18
+ ### Modified Capabilities
19
+ - `kit-command`: Existing kit command gains deletion behavior after saving new items
20
+
21
+ ## Impact
22
+
23
+ - **Code**: `src/cli.ts` — `KitData` interface update, new `deleteKitItems()` function, `handleKit()` updated to call deletion logic
24
+ - **Dependencies**: None
25
+ - **Breaking Change**: None — deletion is additive behavior. Kits without `deleted_items` work exactly as before (field is optional)
26
+ - **User Experience**: Users see a summary of deleted items in the success message. Stale files are automatically cleaned up on kit re-install
@@ -0,0 +1,115 @@
1
+ ## NEW Requirements
2
+
3
+ ### Requirement: Deleted Items Type Definition
4
+ WHEN the kit API returns a response, THE SYSTEM SHALL support an optional `deleted_items` field in the `KitData` interface containing arrays of names for prompts, subagents, and rules to delete.
5
+
6
+ #### Scenario: API response includes deleted_items
7
+ - **WHEN** the API response contains a `deleted_items` object
8
+ - **THEN** the system parses `deleted_items.prompts` as `string[]`
9
+ - **AND** parses `deleted_items.subagents` as `string[]`
10
+ - **AND** parses `deleted_items.rules` as `string[]`
11
+
12
+ #### Scenario: API response without deleted_items
13
+ - **WHEN** the API response does not contain a `deleted_items` field
14
+ - **THEN** the system proceeds normally without any deletion (backward compatible)
15
+
16
+ ### Requirement: Delete Prompts from Local Storage
17
+ WHEN `deleted_items.prompts` contains prompt names, THE SYSTEM SHALL delete the corresponding prompt files from the selected targets across both user and project scopes.
18
+
19
+ #### Scenario: Delete prompt from skills directory (new format)
20
+ - **WHEN** `deleted_items.prompts` contains `"openspec-ff"`
21
+ - **AND** user selected target "claude"
22
+ - **THEN** system deletes directory `~/.claude/skills/openspec-ff/` recursively (if exists)
23
+ - **AND** deletes directory `./.claude/skills/openspec-ff/` recursively (if exists)
24
+
25
+ #### Scenario: Delete prompt from commands directory (legacy format)
26
+ - **WHEN** `deleted_items.prompts` contains `"openspec-ff"`
27
+ - **AND** user selected target "claude"
28
+ - **THEN** system deletes file `~/.claude/commands/openspec-ff.md` (if exists)
29
+ - **AND** deletes file `./.claude/commands/openspec-ff.md` (if exists)
30
+
31
+ #### Scenario: Delete prompt from multiple selected targets
32
+ - **WHEN** `deleted_items.prompts` contains `"openspec-ff"`
33
+ - **AND** user selected target "both" (augment + claude)
34
+ - **THEN** system deletes from both augment and claude directories
35
+ - **AND** deletes from both user (`~/`) and project (`./`) scopes for each target
36
+
37
+ #### Scenario: Delete prompt file does not exist
38
+ - **WHEN** `deleted_items.prompts` contains a name that has no corresponding local file
39
+ - **THEN** system silently skips the deletion (no error)
40
+
41
+ ### Requirement: Delete Subagents from Local Storage
42
+ WHEN `deleted_items.subagents` contains subagent names, THE SYSTEM SHALL delete the corresponding subagent files from the selected targets across both user and project scopes.
43
+
44
+ #### Scenario: Delete subagent file
45
+ - **WHEN** `deleted_items.subagents` contains `"aaa"`
46
+ - **AND** user selected target "claude"
47
+ - **THEN** system deletes file `~/.claude/agents/aaa.md` (if exists)
48
+ - **AND** deletes file `./.claude/agents/aaa.md` (if exists)
49
+
50
+ #### Scenario: Delete subagent from multiple selected targets
51
+ - **WHEN** `deleted_items.subagents` contains `"aaa"`
52
+ - **AND** user selected target "both" (augment + claude)
53
+ - **THEN** system deletes from both augment and claude agent directories
54
+ - **AND** deletes from both user (`~/`) and project (`./`) scopes for each target
55
+
56
+ #### Scenario: Delete subagent file does not exist
57
+ - **WHEN** `deleted_items.subagents` contains a name that has no corresponding local file
58
+ - **THEN** system silently skips the deletion (no error)
59
+
60
+ ### Requirement: Rules Deletion Excluded
61
+ THE SYSTEM SHALL NOT process `deleted_items.rules` in this change.
62
+
63
+ #### Scenario: Rules array present but ignored
64
+ - **WHEN** `deleted_items.rules` contains rule names
65
+ - **THEN** system ignores the rules array entirely (no action taken)
66
+
67
+ ### Requirement: Deletion Scope Always Both
68
+ REGARDLESS of the user's selected installation scope, THE SYSTEM SHALL always attempt deletion from both user-level (`~/`) and project-level (`./`) directories.
69
+
70
+ #### Scenario: User selects project scope for install
71
+ - **WHEN** user selects scope "project" for installation
72
+ - **THEN** new items are installed to project scope only (`./`)
73
+ - **BUT** deleted items are removed from both project (`./`) AND user (`~/`) scopes
74
+
75
+ #### Scenario: User selects user scope for install
76
+ - **WHEN** user selects scope "user" for installation
77
+ - **THEN** new items are installed to user scope only (`~/`)
78
+ - **BUT** deleted items are removed from both user (`~/`) AND project (`./`) scopes
79
+
80
+ ### Requirement: Deletion Targets Match Selected Targets
81
+ THE SYSTEM SHALL only delete from the AI tool targets that the user selected for installation.
82
+
83
+ #### Scenario: User selects only claude target
84
+ - **WHEN** user selects target "claude"
85
+ - **THEN** deleted items are removed only from claude directories (not augment or opencode)
86
+
87
+ #### Scenario: User selects both targets
88
+ - **WHEN** user selects target "both"
89
+ - **THEN** deleted items are removed from both augment and claude directories
90
+
91
+ ### Requirement: Deletion Timing
92
+ THE SYSTEM SHALL process deletions AFTER saving new/updated items.
93
+
94
+ #### Scenario: Save then delete
95
+ - **WHEN** kit contains both new prompts and deleted_items
96
+ - **THEN** system saves all new prompts and subagents first
97
+ - **THEN** system processes deleted_items
98
+
99
+ ## MODIFIED Requirements
100
+
101
+ ### Requirement: User Feedback (updated)
102
+ WHILE fetching and installing the kit, THE SYSTEM SHALL display progress information including deletion counts.
103
+
104
+ #### Scenario: Display deletion progress
105
+ - **WHEN** processing deleted items
106
+ - **THEN** system updates the spinner text to "Cleaning up deleted items..."
107
+
108
+ #### Scenario: Display success message with deletions
109
+ - **WHEN** installation completes with deletions
110
+ - **THEN** system displays "Successfully installed kit \"{name}\": {promptsCount} prompts, {subagentsCount} subagents, {deletedCount} removed"
111
+ - **AND** displays exact installation paths
112
+
113
+ #### Scenario: Display success message without deletions
114
+ - **WHEN** installation completes with no deleted_items (or empty arrays)
115
+ - **THEN** system displays the existing success message format without deletion count
@@ -0,0 +1,36 @@
1
+ ## 1. Update KitData Interface
2
+
3
+ - [x] 1.1 Add optional `deleted_items` field to `KitData` interface in `src/cli.ts` (around line 107):
4
+ ```typescript
5
+ deleted_items?: {
6
+ prompts: string[];
7
+ subagents: string[];
8
+ rules: string[];
9
+ };
10
+ ```
11
+
12
+ ## 2. Create Delete Path Resolution Helper
13
+
14
+ - [x] 2.1 Create `resolveDeletePaths()` function in `src/cli.ts` that takes selected targets (`KitInstallConfig`) and returns an array of path sets for BOTH scopes (user + project). It should:
15
+ - Extract which targets are selected from `installConfig.paths` (augment/claude/opencode)
16
+ - For each selected target, resolve paths for both `user` scope (`os.homedir()`) and `project` scope (`process.cwd()`)
17
+ - Return an array of `{ commands: string; commandsLegacy: string; agents: string }` objects representing all directories to delete from
18
+ - Handle opencode's special user-level path (`~/.config/opencode/`) vs project-level path (`./.opencode/`)
19
+
20
+ ## 3. Create deleteKitItems Function
21
+
22
+ - [x] 3.1 Create `deleteKitItems()` async function
23
+ - [x] 3.2 Implement prompt deletion logic
24
+ - [x] 3.3 Implement subagent deletion logic
25
+ - [x] 3.4 Skip `deleted_items.rules` entirely (no processing)
26
+ - [x] 3.5 Return a count of deletion operations attempted
27
+
28
+ ## 4. Update handleKit Function
29
+
30
+ - [x] 4.1 After the existing save prompts and save subagents blocks, add deleted_items processing
31
+ - [x] 4.2 Update the success message to include deletion count when deletions occurred
32
+
33
+ ## 5. Quality Assurance
34
+
35
+ - [x] 5.1 Run `bun run lint` and fix any issues (no `--unsafe` flag)
36
+ - [x] 5.2 Run `bun run build` and verify it succeeds