@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.
- package/dist/cli.js +71 -4
- package/openspec/changes/archive/2026-02-07-fix-skill-yaml-frontmatter/.openspec.yaml +2 -0
- package/openspec/changes/archive/2026-02-07-fix-skill-yaml-frontmatter/design.md +69 -0
- package/openspec/changes/archive/2026-02-07-fix-skill-yaml-frontmatter/proposal.md +25 -0
- package/openspec/changes/archive/2026-02-07-fix-skill-yaml-frontmatter/specs/skill-directory-structure/spec.md +29 -0
- package/openspec/changes/archive/2026-02-07-fix-skill-yaml-frontmatter/specs/skill-yaml-frontmatter/spec.md +61 -0
- package/openspec/changes/archive/2026-02-07-fix-skill-yaml-frontmatter/tasks.md +14 -0
- package/openspec/changes/handle-kit-deleted-items/.openspec.yaml +2 -0
- package/openspec/changes/handle-kit-deleted-items/design.md +78 -0
- package/openspec/changes/handle-kit-deleted-items/proposal.md +26 -0
- package/openspec/changes/handle-kit-deleted-items/specs/kit-deleted-items/spec.md +115 -0
- package/openspec/changes/handle-kit-deleted-items/tasks.md +36 -0
- package/openspec/specs/kit-deleted-items/spec.md +110 -0
- package/openspec/specs/skill-directory-structure/spec.md +16 -4
- package/openspec/specs/skill-yaml-frontmatter/spec.md +61 -0
- package/package.json +2 -2
- package/.augment/commands/compact.md +0 -73
- package/.augment/skills/compact/SKILL.md +0 -73
- package/.claude/commands/opsx/apply.md +0 -152
- package/.claude/commands/opsx/archive.md +0 -157
- package/.claude/commands/opsx/bulk-archive.md +0 -242
- package/.claude/commands/opsx/continue.md +0 -114
- package/.claude/commands/opsx/explore.md +0 -174
- package/.claude/commands/opsx/ff.md +0 -94
- package/.claude/commands/opsx/new.md +0 -69
- package/.claude/commands/opsx/onboard.md +0 -525
- package/.claude/commands/opsx/sync.md +0 -134
- package/.claude/commands/opsx/verify.md +0 -164
- package/.claude/skills/openspec-apply-change/SKILL.md +0 -156
- package/.claude/skills/openspec-archive-change/SKILL.md +0 -114
- package/.claude/skills/openspec-bulk-archive-change/SKILL.md +0 -246
- package/.claude/skills/openspec-continue-change/SKILL.md +0 -118
- package/.claude/skills/openspec-explore/SKILL.md +0 -290
- package/.claude/skills/openspec-ff-change/SKILL.md +0 -101
- package/.claude/skills/openspec-new-change/SKILL.md +0 -74
- package/.claude/skills/openspec-onboard/SKILL.md +0 -529
- package/.claude/skills/openspec-sync-specs/SKILL.md +0 -138
- package/.claude/skills/openspec-verify-change/SKILL.md +0 -168
- /package/openspec/changes/{add-dual-prompt-save → archive/2026-02-05-add-dual-prompt-save}/.openspec.yaml +0 -0
- /package/openspec/changes/{add-dual-prompt-save → archive/2026-02-05-add-dual-prompt-save}/design.md +0 -0
- /package/openspec/changes/{add-dual-prompt-save → archive/2026-02-05-add-dual-prompt-save}/proposal.md +0 -0
- /package/openspec/changes/{add-dual-prompt-save → archive/2026-02-05-add-dual-prompt-save}/specs/dual-prompt-save/spec.md +0 -0
- /package/openspec/changes/{add-dual-prompt-save → archive/2026-02-05-add-dual-prompt-save}/specs/skill-directory-structure/spec.md +0 -0
- /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
|
-
|
|
3547
|
-
|
|
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
|
|
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=
|
|
4209
|
+
//# debugId=706C0DF49CFC16E464756E2164756E21
|
|
@@ -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,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
|