@codemcp/ade 0.6.1 → 0.7.0
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/.beads/issues.jsonl +11 -0
- package/.beads/last-touched +1 -1
- package/.kiro/agents/ade.json +10 -2
- package/.kiro/settings/mcp.json +6 -1
- package/.opencode/agents/ade.md +7 -2
- package/.vibe/beads-state-ade-extension-override-skills-d44z9p.json +29 -0
- package/.vibe/development-plan-extension-override-skills.md +110 -0
- package/config.lock.yaml +6 -1
- package/package.json +1 -1
- package/packages/cli/dist/index.js +15 -4
- package/packages/cli/package.json +1 -1
- package/packages/core/package.json +1 -1
- package/packages/core/src/resolver.spec.ts +330 -0
- package/packages/core/src/resolver.ts +16 -0
- package/packages/core/src/types.ts +14 -0
- package/packages/core/src/writers/skills.spec.ts +46 -0
- package/packages/harnesses/package.json +1 -1
- package/packages/harnesses/src/writers/opencode.spec.ts +3 -5
- package/packages/harnesses/src/writers/opencode.ts +3 -4
package/.beads/issues.jsonl
CHANGED
|
@@ -84,3 +84,14 @@
|
|
|
84
84
|
{"id":"ade-8.3","title":"Fix","description":"Implement the solution based on your analysis: - If exists: Follow the design from it - Otherwise: Elaborate design options and present them to the user Before implementing, assess the approach: - How critical is this system? What is the blast radius if the fix causes issues? - Should this be a minimal fix or a more comprehensive solution? Make targeted changes that address the root cause without introducing new issues. Be careful to maintain existing functionality while fixing the bug.","status":"open","priority":3,"issue_type":"task","owner":"github@beimir.net","created_at":"2026-03-20T08:52:50.645347+01:00","created_by":"Oliver Jägle","updated_at":"2026-03-20T08:52:50.645347+01:00","dependencies":[{"issue_id":"ade-8.3","depends_on_id":"ade-8","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"ade-8.3","depends_on_id":"ade-8.2","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
|
|
85
85
|
{"id":"ade-8.4","title":"Verify","description":"Test the fix thoroughly to ensure the original bug is resolved and no new issues were introduced. Run existing tests, create new ones if needed, and verify the solution is robust.","status":"open","priority":3,"issue_type":"task","owner":"github@beimir.net","created_at":"2026-03-20T08:52:50.824002+01:00","created_by":"Oliver Jägle","updated_at":"2026-03-20T08:52:50.824002+01:00","dependencies":[{"issue_id":"ade-8.4","depends_on_id":"ade-8","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"ade-8.4","depends_on_id":"ade-8.3","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
|
|
86
86
|
{"id":"ade-8.5","title":"Finalize","description":"Ensure code quality and documentation accuracy through systematic cleanup and review. **STEP 1: Code Cleanup** Systematically clean up development artifacts: - Remove all temporary debug output statements used during bug investigation (console logging, print statements, debug output functions) - Address each TODO/FIXME comment by either implementing the solution or documenting why it's deferred - Remove completed TODOs and convert remaining ones to proper issue tracking if needed - Remove temporary debugging code, test code blocks, and commented-out code - Ensure proper error handling replaces temporary debug logging **STEP 2: Documentation Review** Review and update documentation to reflect the bug fix: - If exists, update it if design details were refined or changed during the fix - Compare documentation against the actual bug fix implementation - Update only the documentation sections that have functional changes - Remove references to investigation iterations, progress notes, and temporary decisions - Ensure documentation describes the final fixed state, not the debugging process - Ask the user to review document updates **STEP 3: Final Validation** - Run existing tests to ensure cleanup didn't break functionality - Verify documentation accuracy with a final review - Ensure bug fix is ready for production - Update task progress and mark completed work as you finalize the bug fix","status":"open","priority":3,"issue_type":"task","owner":"github@beimir.net","created_at":"2026-03-20T08:52:50.99667+01:00","created_by":"Oliver Jägle","updated_at":"2026-03-20T08:52:50.99667+01:00","dependencies":[{"issue_id":"ade-8.5","depends_on_id":"ade-8","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"ade-8.5","depends_on_id":"ade-8.4","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
|
|
87
|
+
{"id":"ade-9","title":"ade: epcc (development-plan-extension-override-skills.md)","description":"Responsible vibe engineering session using epcc workflow for ade","status":"open","priority":2,"issue_type":"task","owner":"github@beimir.net","created_at":"2026-03-20T11:16:22.460649+01:00","created_by":"Oliver Jägle","updated_at":"2026-03-20T11:16:22.460649+01:00"}
|
|
88
|
+
{"id":"ade-9.1","title":"Explore","description":"Research the codebase to understand existing patterns and gather context about the problem space. - If uncertain about conventions or rules, ask the user about them - Read relevant files and documentation - If exists: Understand and document requirements there - Otherwise: Document requirements in your task management system Focus on understanding without writing code yet. Document your findings and create tasks as needed.","status":"open","priority":3,"issue_type":"task","owner":"github@beimir.net","created_at":"2026-03-20T11:16:22.605996+01:00","created_by":"Oliver Jägle","updated_at":"2026-03-20T11:16:22.605996+01:00","dependencies":[{"issue_id":"ade-9.1","depends_on_id":"ade-9","type":"parent-child","created_at":"0001-01-01T00:00:00Z"}]}
|
|
89
|
+
{"id":"ade-9.2","title":"Plan","description":"Create a detailed implementation strategy based on your exploration: - If exists: Base your strategy on requirements from it - Otherwise: Use existing task context Break down the work into specific, actionable tasks. Consider edge cases, dependencies, and potential challenges. - If architectural changes needed and exists: Document in - Otherwise: Create tasks to track architectural decisions - If exists: Adhere to the design in it - Otherwise: Elaborate design options and present them to the user Document the planning work thoroughly and create implementation tasks as part of the code phase as needed.","status":"open","priority":3,"issue_type":"task","owner":"github@beimir.net","created_at":"2026-03-20T11:16:22.745983+01:00","created_by":"Oliver Jägle","updated_at":"2026-03-20T11:16:22.745983+01:00","dependencies":[{"issue_id":"ade-9.2","depends_on_id":"ade-9","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"ade-9.2","depends_on_id":"ade-9.1","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
|
|
90
|
+
{"id":"ade-9.3","title":"Code","description":"Follow your plan to build the solution: - If exists: Follow the design from it - Otherwise: Elaborate design options and present them to the user - If exists: Build according to the architecture from it - Otherwise: Elaborate architectural options and present them to the user - If exists: Ensure requirements from it are met - Otherwise: Ensure existing requirements are met based on your task context Write clean, well-structured code with proper error handling. Prevent regression by building, linting, and executing existing tests. Stay flexible and adapt the plan as you learn more during implementation. Update task progress and create new tasks as needed.","status":"open","priority":3,"issue_type":"task","owner":"github@beimir.net","created_at":"2026-03-20T11:16:22.881145+01:00","created_by":"Oliver Jägle","updated_at":"2026-03-20T11:16:22.881145+01:00","dependencies":[{"issue_id":"ade-9.3","depends_on_id":"ade-9","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"ade-9.3","depends_on_id":"ade-9.2","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
|
|
91
|
+
{"id":"ade-9.3.1","title":"Add replaces?: string[] to InlineSkill and ExternalSkill in types.ts","status":"closed","priority":1,"issue_type":"task","owner":"github@beimir.net","created_at":"2026-03-20T11:21:56.87809+01:00","created_by":"Oliver Jägle","updated_at":"2026-03-20T11:25:09.682568+01:00","closed_at":"2026-03-20T11:25:09.682568+01:00","close_reason":"Closed","dependencies":[{"issue_id":"ade-9.3.1","depends_on_id":"ade-9.3","type":"parent-child","created_at":"0001-01-01T00:00:00Z"}]}
|
|
92
|
+
{"id":"ade-9.3.2","title":"Post-process skills in resolver: dedup by name + filter replaced names","status":"closed","priority":1,"issue_type":"task","owner":"github@beimir.net","created_at":"2026-03-20T11:21:57.036539+01:00","created_by":"Oliver Jägle","updated_at":"2026-03-20T11:25:26.025057+01:00","closed_at":"2026-03-20T11:25:26.025057+01:00","close_reason":"Closed","dependencies":[{"issue_id":"ade-9.3.2","depends_on_id":"ade-9.3","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"ade-9.3.2","depends_on_id":"ade-9.3.1","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
|
|
93
|
+
{"id":"ade-9.3.3","title":"Write resolver tests: replaces dedup, ordering, no-op when replaces empty","status":"closed","priority":1,"issue_type":"task","owner":"github@beimir.net","created_at":"2026-03-20T11:21:57.182342+01:00","created_by":"Oliver Jägle","updated_at":"2026-03-20T11:26:32.609547+01:00","closed_at":"2026-03-20T11:26:32.609547+01:00","close_reason":"Closed","dependencies":[{"issue_id":"ade-9.3.3","depends_on_id":"ade-9.3","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"ade-9.3.3","depends_on_id":"ade-9.3.2","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
|
|
94
|
+
{"id":"ade-9.3.4","title":"Update skillsWriter spec: pass-through of replaces field","status":"closed","priority":2,"issue_type":"task","owner":"github@beimir.net","created_at":"2026-03-20T11:21:57.338918+01:00","created_by":"Oliver Jägle","updated_at":"2026-03-20T11:27:04.797258+01:00","closed_at":"2026-03-20T11:27:04.797258+01:00","close_reason":"Closed","dependencies":[{"issue_id":"ade-9.3.4","depends_on_id":"ade-9.3","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"ade-9.3.4","depends_on_id":"ade-9.3.1","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
|
|
95
|
+
{"id":"ade-9.3.5","title":"Update writeInlineSkills: ignore replaces field when writing SKILL.md","status":"closed","priority":2,"issue_type":"task","owner":"github@beimir.net","created_at":"2026-03-20T11:21:57.510647+01:00","created_by":"Oliver Jägle","updated_at":"2026-03-20T11:27:13.986652+01:00","closed_at":"2026-03-20T11:27:13.986652+01:00","close_reason":"Closed","dependencies":[{"issue_id":"ade-9.3.5","depends_on_id":"ade-9.3","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"ade-9.3.5","depends_on_id":"ade-9.3.1","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
|
|
96
|
+
{"id":"ade-9.3.6","title":"Update ade.extensions.mjs example with replaces declarations","status":"closed","priority":3,"issue_type":"task","owner":"github@beimir.net","created_at":"2026-03-20T11:21:57.649406+01:00","created_by":"Oliver Jägle","updated_at":"2026-03-20T11:28:51.412822+01:00","closed_at":"2026-03-20T11:28:51.412822+01:00","close_reason":"Closed","dependencies":[{"issue_id":"ade-9.3.6","depends_on_id":"ade-9.3","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"ade-9.3.6","depends_on_id":"ade-9.3.2","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
|
|
97
|
+
{"id":"ade-9.4","title":"Commit","description":"Ensure code quality and documentation accuracy through systematic cleanup and review. **STEP 1: Code Cleanup** Systematically clean up development artifacts: 1. **Remove Debug Output**: Search for and remove all temporary debug output statements used during development. Look for language-specific debug output methods (console logging, print statements, debug output functions). Remove any debugging statements that were added for development purposes. 2. **Review TODO/FIXME Comments**: - Address each TODO/FIXME comment by either implementing the solution or documenting why it's deferred - Remove completed TODOs - Convert remaining TODOs to proper issue tracking if needed 3. **Remove Debugging Code Blocks**: - Remove temporary debugging code, test code blocks, and commented-out code - Clean up any experimental code that's no longer needed - Ensure proper error handling replaces temporary debug logging **STEP 2: Documentation Review** Review and update documentation to reflect final implementation: 1. **Update Long-Term Memory Documents**: Based on what was actually implemented: - If exists: Update it if requirements changed during development - If exists: Update it if architectural impacts were identified - If exists: Update it if design details were refined or changed - Otherwise: Document any changes in the plan file 2. **Compare Against Implementation**: Review documentation against actual implemented functionality 3. **Update Changed Sections**: Only modify documentation sections that have functional changes 4. **Remove Development Progress**: Remove references to development iterations, progress notes, and temporary decisions 5. **Focus on Final State**: Ensure documentation describes the final implemented state, not the development process 6. **Ask User to Review Document Updates** **STEP 3: Final Validation** - Run existing tests to ensure cleanup didn't break functionality - Verify documentation accuracy with a final review - Ensure code is ready for production/delivery Update task progress and mark completed work as you finalize the feature.","status":"open","priority":3,"issue_type":"task","owner":"github@beimir.net","created_at":"2026-03-20T11:16:23.028674+01:00","created_by":"Oliver Jägle","updated_at":"2026-03-20T11:16:23.028674+01:00","dependencies":[{"issue_id":"ade-9.4","depends_on_id":"ade-9","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"ade-9.4","depends_on_id":"ade-9.3","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
|
package/.beads/last-touched
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
ade-
|
|
1
|
+
ade-9.3.6
|
package/.kiro/agents/ade.json
CHANGED
|
@@ -6,7 +6,12 @@
|
|
|
6
6
|
"workflows": {
|
|
7
7
|
"command": "npx",
|
|
8
8
|
"args": ["@codemcp/workflows-server@latest"],
|
|
9
|
-
"autoApprove": [
|
|
9
|
+
"autoApprove": [
|
|
10
|
+
"whats_next",
|
|
11
|
+
"conduct_review",
|
|
12
|
+
"list_workflows",
|
|
13
|
+
"get_tool_info"
|
|
14
|
+
]
|
|
10
15
|
},
|
|
11
16
|
"agentskills": {
|
|
12
17
|
"command": "npx",
|
|
@@ -20,7 +25,10 @@
|
|
|
20
25
|
"write",
|
|
21
26
|
"shell",
|
|
22
27
|
"spec",
|
|
23
|
-
"@workflows
|
|
28
|
+
"@workflows/whats_next",
|
|
29
|
+
"@workflows/conduct_review",
|
|
30
|
+
"@workflows/list_workflows",
|
|
31
|
+
"@workflows/get_tool_info",
|
|
24
32
|
"@agentskills/*"
|
|
25
33
|
],
|
|
26
34
|
"useLegacyMcpJson": true
|
package/.kiro/settings/mcp.json
CHANGED
package/.opencode/agents/ade.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
name: ade
|
|
3
3
|
description: ADE — Agentic Development Environment agent with project conventions and tools
|
|
4
4
|
permission:
|
|
5
|
+
"workflows*": "ask"
|
|
6
|
+
workflows_whats_next: "allow"
|
|
7
|
+
workflows_conduct_review: "allow"
|
|
8
|
+
workflows_list_workflows: "allow"
|
|
9
|
+
workflows_get_tool_info: "allow"
|
|
10
|
+
"agentskills*": "allow"
|
|
5
11
|
read:
|
|
6
12
|
"*": "allow"
|
|
7
13
|
"*.env": "deny"
|
|
@@ -10,7 +16,7 @@ permission:
|
|
|
10
16
|
skill: "deny"
|
|
11
17
|
todoread: "deny"
|
|
12
18
|
todowrite: "deny"
|
|
13
|
-
task: "
|
|
19
|
+
task: "allow"
|
|
14
20
|
lsp: "allow"
|
|
15
21
|
glob: "allow"
|
|
16
22
|
grep: "allow"
|
|
@@ -99,7 +105,6 @@ permission:
|
|
|
99
105
|
"useradd *": "deny"
|
|
100
106
|
"userdel *": "deny"
|
|
101
107
|
"iptables *": "deny"
|
|
102
|
-
doom_loop: "deny"
|
|
103
108
|
---
|
|
104
109
|
|
|
105
110
|
You are an AI assistant that helps users develop software features using the workflows server.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"conversationId": "ade-extension-override-skills-d44z9p",
|
|
3
|
+
"projectPath": "/Users/oliverjaegle/projects/privat/codemcp/ade",
|
|
4
|
+
"epicId": "ade-9",
|
|
5
|
+
"phaseTasks": [
|
|
6
|
+
{
|
|
7
|
+
"phaseId": "explore",
|
|
8
|
+
"phaseName": "Explore",
|
|
9
|
+
"taskId": "ade-9.1"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"phaseId": "plan",
|
|
13
|
+
"phaseName": "Plan",
|
|
14
|
+
"taskId": "ade-9.2"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"phaseId": "code",
|
|
18
|
+
"phaseName": "Code",
|
|
19
|
+
"taskId": "ade-9.3"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"phaseId": "commit",
|
|
23
|
+
"phaseName": "Commit",
|
|
24
|
+
"taskId": "ade-9.4"
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
"createdAt": "2026-03-20T10:16:23.345Z",
|
|
28
|
+
"updatedAt": "2026-03-20T10:16:23.345Z"
|
|
29
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Development Plan: ade (extension-override-skills branch)
|
|
2
|
+
|
|
3
|
+
*Generated on 2026-03-20 by Vibe Feature MCP*
|
|
4
|
+
*Workflow: [epcc](https://mrsimpson.github.io/responsible-vibe-mcp/workflows/epcc)*
|
|
5
|
+
|
|
6
|
+
## Goal
|
|
7
|
+
Allow extension-contributed skills to declare that they replace/supersede generic baseline skills registered by the process option (`codemcp-workflows-skilled`). The resolver should deduplicate the final skills list so that only the effective (non-replaced) skills are shown and installed.
|
|
8
|
+
|
|
9
|
+
## Explore
|
|
10
|
+
<!-- beads-phase-id: ade-9.1 -->
|
|
11
|
+
### Tasks
|
|
12
|
+
- [x] Understand current skill registration flow (process → recipe → skills writer → LogicalConfig)
|
|
13
|
+
- [x] Identify the exact duplication: `codemcp-workflows-skilled` registers 5 generic skills; architecture extensions like `sabdx-frontend` register domain-specific replacements with different names
|
|
14
|
+
- [x] Evaluate solution options (replaces field, baseline priority, excludes at option level)
|
|
15
|
+
- [x] Agree on preferred approach: `replaces?: string[]` on `SkillDefinition`
|
|
16
|
+
|
|
17
|
+
### Phase Entrance Criteria:
|
|
18
|
+
*(initial phase — no prior phase)*
|
|
19
|
+
|
|
20
|
+
## Plan
|
|
21
|
+
<!-- beads-phase-id: ade-9.2 -->
|
|
22
|
+
### Tasks
|
|
23
|
+
|
|
24
|
+
*Tasks managed via `bd` CLI*
|
|
25
|
+
|
|
26
|
+
### Phase Entrance Criteria:
|
|
27
|
+
- [ ] The problem is clearly understood: duplicate generic + domain-specific skills shown at setup
|
|
28
|
+
- [ ] At least two solution alternatives have been evaluated
|
|
29
|
+
- [ ] The preferred approach (`replaces` field on `SkillDefinition`) is agreed upon
|
|
30
|
+
- [ ] Scope is clear: which files are touched
|
|
31
|
+
|
|
32
|
+
## Code
|
|
33
|
+
<!-- beads-phase-id: ade-9.3 -->
|
|
34
|
+
### Tasks
|
|
35
|
+
|
|
36
|
+
*Tasks managed via `bd` CLI*
|
|
37
|
+
|
|
38
|
+
### Phase Entrance Criteria:
|
|
39
|
+
- [ ] Concrete implementation plan is documented (what changes in which file)
|
|
40
|
+
- [ ] Edge cases are identified (ordering, name-collision, TUI display)
|
|
41
|
+
- [ ] Test strategy is defined
|
|
42
|
+
|
|
43
|
+
## Commit
|
|
44
|
+
<!-- beads-phase-id: ade-9.4 -->
|
|
45
|
+
### Tasks
|
|
46
|
+
- [ ] Squash WIP commits: `git reset --soft <first commit of this branch>`. Then, create a conventional commit. In the message, first summarize the intentions and key decisions from the development plan. Then, add a brief summary of the key changes and their side effects and dependencies.
|
|
47
|
+
|
|
48
|
+
*Tasks managed via `bd` CLI*
|
|
49
|
+
|
|
50
|
+
### Phase Entrance Criteria:
|
|
51
|
+
- [ ] All implementation tasks are done and tests pass
|
|
52
|
+
- [ ] The `replaces` field works end-to-end (resolver deduplicates, TUI shows reduced list)
|
|
53
|
+
- [ ] No regressions in existing resolver tests
|
|
54
|
+
|
|
55
|
+
## Key Decisions
|
|
56
|
+
|
|
57
|
+
### KD-1: Add `replaces?: string[]` to `SkillDefinition`
|
|
58
|
+
Both `InlineSkill` and `ExternalSkill` get an optional `replaces` field. Extension authors list the generic skill names they supersede. Deduplication happens as a post-processing step in the resolver (`resolve()` in `resolver.ts`).
|
|
59
|
+
|
|
60
|
+
### KD-2: Deduplication strategy — last-writer-wins + replaces set
|
|
61
|
+
After all provisions are merged, the resolver:
|
|
62
|
+
1. Builds a Set of all names that appear in any skill's `replaces` array.
|
|
63
|
+
2. Deduplicates by name (last occurrence wins, preserving insertion order otherwise) using a Map.
|
|
64
|
+
3. Filters out any skill whose `name` is in the replaced-names Set.
|
|
65
|
+
|
|
66
|
+
This means: if `sabdx-architecture` declares `replaces: ["architecture"]`, the generic `architecture` skill is dropped. The final list contains `sabdx-architecture` only.
|
|
67
|
+
|
|
68
|
+
### KD-3: Skill file names on disk — unchanged
|
|
69
|
+
Skills are written to `.ade/skills/<name>/SKILL.md` by `writeInlineSkills()` in `util.ts`.
|
|
70
|
+
- The generic `architecture` skill → `.ade/skills/architecture/SKILL.md`
|
|
71
|
+
- The replacing `sabdx-architecture` skill → `.ade/skills/sabdx-architecture/SKILL.md`
|
|
72
|
+
|
|
73
|
+
Because `architecture` is filtered out **before** `writeInlineSkills()` is called, **no file is written for `architecture`**. Only `sabdx-architecture/SKILL.md` ends up on disk. The `replaces` field is a resolver-level concern; it does not need to be written to SKILL.md frontmatter.
|
|
74
|
+
|
|
75
|
+
### KD-4: `replaces` field is stripped before writing SKILL.md
|
|
76
|
+
`writeInlineSkills()` uses the skill's `name`, `description`, and `body` for the SKILL.md frontmatter. The `replaces` field is simply ignored during file writing — no changes needed in `util.ts`.
|
|
77
|
+
|
|
78
|
+
### KD-5: `replaces` field is NOT persisted in `config.lock.yaml`
|
|
79
|
+
The lock file records `logical_config`, which is the *post-dedup* skills list. Replaced skills never appear in the lock file.
|
|
80
|
+
|
|
81
|
+
### KD-6: Ordering — extensions should register skills after process
|
|
82
|
+
The resolver processes facets in `sortFacets()` order. The `architecture` facet comes after `process`, so extension skills are appended after the generic ones. The last-writer-wins Map dedup naturally lets extension skills win. But `replaces` is independent of ordering — it is an explicit declaration.
|
|
83
|
+
|
|
84
|
+
## Notes
|
|
85
|
+
|
|
86
|
+
### Full flow for the sadb-frontend scenario
|
|
87
|
+
1. `codemcp-workflows-skilled` recipe runs → appends to `result.skills`: `[starting-project, architecture, application-design, coding, testing]`
|
|
88
|
+
2. `sabdx-frontend` recipe runs → appends: `[sabdx-tasks, sabdx-starting-project{replaces:["starting-project"]}, sabdx-architecture{replaces:["architecture"]}, sabdx-application-design{replaces:["application-design"]}, sabdx-coding{replaces:["coding"]}, sabdx-testing{replaces:["testing"]}, tdd]`
|
|
89
|
+
3. `conventional-commits` recipe runs → appends: `[conventional-commits]`
|
|
90
|
+
4. Raw merged list: 13 skills
|
|
91
|
+
5. Post-dedup (name Map + replaces filter): 8 skills remain — `[sabdx-tasks, sabdx-starting-project, sabdx-architecture, sabdx-application-design, sabdx-coding, sabdx-testing, tdd, conventional-commits]`
|
|
92
|
+
6. `writeInlineSkills()` writes SKILL.md files for the 6 inline sabdx-* skills under `.ade/skills/<name>/`
|
|
93
|
+
7. `installSkills()` installs all 8 into `.agentskills/skills/`
|
|
94
|
+
|
|
95
|
+
### What files exist on disk after setup
|
|
96
|
+
- `.ade/skills/sabdx-tasks/SKILL.md`
|
|
97
|
+
- `.ade/skills/sabdx-starting-project/SKILL.md`
|
|
98
|
+
- `.ade/skills/sabdx-architecture/SKILL.md`
|
|
99
|
+
- `.ade/skills/sabdx-application-design/SKILL.md`
|
|
100
|
+
- `.ade/skills/sabdx-coding/SKILL.md`
|
|
101
|
+
- `.ade/skills/sabdx-testing/SKILL.md`
|
|
102
|
+
- NO `.ade/skills/architecture/SKILL.md` (replaced, never written)
|
|
103
|
+
- NO `.ade/skills/starting-project/SKILL.md` (replaced, never written)
|
|
104
|
+
- etc.
|
|
105
|
+
|
|
106
|
+
### The `tdd` skill from the extension — no `replaces` needed
|
|
107
|
+
`tdd` is an external skill (`source: "mrsimpson/skills-coding"`) and there is no generic `tdd` skill in `codemcp-workflows-skilled`. No clash.
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
*This plan is maintained by the LLM and uses beads CLI for task management. Tool responses provide guidance on which bd commands to use for task management.*
|
package/config.lock.yaml
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
version: 1
|
|
2
|
-
generated_at: 2026-03-
|
|
2
|
+
generated_at: 2026-03-20T08:32:04.912Z
|
|
3
3
|
choices:
|
|
4
4
|
process: codemcp-workflows
|
|
5
5
|
practices:
|
|
@@ -18,6 +18,11 @@ logical_config:
|
|
|
18
18
|
args:
|
|
19
19
|
- "@codemcp/workflows-server@latest"
|
|
20
20
|
env: {}
|
|
21
|
+
allowedTools:
|
|
22
|
+
- whats_next
|
|
23
|
+
- conduct_review
|
|
24
|
+
- list_workflows
|
|
25
|
+
- get_tool_info
|
|
21
26
|
- ref: agentskills
|
|
22
27
|
command: npx
|
|
23
28
|
args:
|
package/package.json
CHANGED
|
@@ -20361,6 +20361,17 @@ async function resolve(userConfig, catalog, registry3) {
|
|
|
20361
20361
|
serversByRef.set(server.ref, server);
|
|
20362
20362
|
}
|
|
20363
20363
|
result.mcp_servers = Array.from(serversByRef.values());
|
|
20364
|
+
const replacedNames = /* @__PURE__ */ new Set();
|
|
20365
|
+
for (const skill of result.skills) {
|
|
20366
|
+
for (const r2 of skill.replaces ?? []) {
|
|
20367
|
+
replacedNames.add(r2);
|
|
20368
|
+
}
|
|
20369
|
+
}
|
|
20370
|
+
const skillsByName = /* @__PURE__ */ new Map();
|
|
20371
|
+
for (const skill of result.skills) {
|
|
20372
|
+
skillsByName.set(skill.name, skill);
|
|
20373
|
+
}
|
|
20374
|
+
result.skills = Array.from(skillsByName.values()).filter((skill) => !replacedNames.has(skill.name));
|
|
20364
20375
|
return result;
|
|
20365
20376
|
}
|
|
20366
20377
|
function getBuiltInProvisionWriter(provision) {
|
|
@@ -43812,9 +43823,10 @@ var APPLICABLE_TO_ALL = {
|
|
|
43812
43823
|
skill: "deny",
|
|
43813
43824
|
//we're using an own skills-mcp
|
|
43814
43825
|
todoread: "deny",
|
|
43815
|
-
//no agent-
|
|
43826
|
+
//no agent-proprietary todo tools
|
|
43816
43827
|
todowrite: "deny",
|
|
43817
|
-
task: "
|
|
43828
|
+
task: "allow",
|
|
43829
|
+
//starts subagents
|
|
43818
43830
|
lsp: "allow",
|
|
43819
43831
|
glob: "allow",
|
|
43820
43832
|
grep: "allow",
|
|
@@ -43915,8 +43927,7 @@ var SENSIBLE_DEFAULTS_RULES = {
|
|
|
43915
43927
|
"useradd *": "deny",
|
|
43916
43928
|
"userdel *": "deny",
|
|
43917
43929
|
"iptables *": "deny"
|
|
43918
|
-
}
|
|
43919
|
-
doom_loop: "deny"
|
|
43930
|
+
}
|
|
43920
43931
|
};
|
|
43921
43932
|
var MAX_AUTONOMY_RULES = {
|
|
43922
43933
|
...APPLICABLE_TO_ALL,
|
|
@@ -246,6 +246,336 @@ describe("resolve", () => {
|
|
|
246
246
|
);
|
|
247
247
|
expect(agentskills).toBeUndefined();
|
|
248
248
|
});
|
|
249
|
+
|
|
250
|
+
it("removes a skill when another skill declares it in replaces", async () => {
|
|
251
|
+
const skillsCatalog: Catalog = {
|
|
252
|
+
facets: [
|
|
253
|
+
{
|
|
254
|
+
id: "process",
|
|
255
|
+
label: "Process",
|
|
256
|
+
description: "Process",
|
|
257
|
+
required: true,
|
|
258
|
+
options: [
|
|
259
|
+
{
|
|
260
|
+
id: "base",
|
|
261
|
+
label: "Base",
|
|
262
|
+
description: "Base process",
|
|
263
|
+
recipe: [
|
|
264
|
+
{
|
|
265
|
+
writer: "skills",
|
|
266
|
+
config: {
|
|
267
|
+
skills: [
|
|
268
|
+
{
|
|
269
|
+
name: "architecture",
|
|
270
|
+
description: "Generic architecture skill",
|
|
271
|
+
body: "Generic architecture content."
|
|
272
|
+
}
|
|
273
|
+
]
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
]
|
|
277
|
+
}
|
|
278
|
+
]
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
id: "architecture",
|
|
282
|
+
label: "Architecture",
|
|
283
|
+
description: "Stack",
|
|
284
|
+
required: false,
|
|
285
|
+
options: [
|
|
286
|
+
{
|
|
287
|
+
id: "sabdx",
|
|
288
|
+
label: "SABDX",
|
|
289
|
+
description: "SABDX frontend",
|
|
290
|
+
recipe: [
|
|
291
|
+
{
|
|
292
|
+
writer: "skills",
|
|
293
|
+
config: {
|
|
294
|
+
skills: [
|
|
295
|
+
{
|
|
296
|
+
name: "sabdx-architecture",
|
|
297
|
+
description: "SABDX architecture skill",
|
|
298
|
+
body: "SABDX architecture content.",
|
|
299
|
+
replaces: ["architecture"]
|
|
300
|
+
}
|
|
301
|
+
]
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
]
|
|
305
|
+
}
|
|
306
|
+
]
|
|
307
|
+
}
|
|
308
|
+
]
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
const userConfig: UserConfig = {
|
|
312
|
+
choices: { process: "base", architecture: "sabdx" }
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
const result = await resolve(userConfig, skillsCatalog, registry);
|
|
316
|
+
|
|
317
|
+
expect(result.skills).toHaveLength(1);
|
|
318
|
+
expect(result.skills[0].name).toBe("sabdx-architecture");
|
|
319
|
+
expect(
|
|
320
|
+
result.skills.find((s) => s.name === "architecture")
|
|
321
|
+
).toBeUndefined();
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
it("removes multiple skills when a single skill declares several replaces entries", async () => {
|
|
325
|
+
const skillsCatalog: Catalog = {
|
|
326
|
+
facets: [
|
|
327
|
+
{
|
|
328
|
+
id: "process",
|
|
329
|
+
label: "Process",
|
|
330
|
+
description: "Process",
|
|
331
|
+
required: true,
|
|
332
|
+
options: [
|
|
333
|
+
{
|
|
334
|
+
id: "base",
|
|
335
|
+
label: "Base",
|
|
336
|
+
description: "Base",
|
|
337
|
+
recipe: [
|
|
338
|
+
{
|
|
339
|
+
writer: "skills",
|
|
340
|
+
config: {
|
|
341
|
+
skills: [
|
|
342
|
+
{
|
|
343
|
+
name: "coding",
|
|
344
|
+
description: "Generic coding",
|
|
345
|
+
body: "Generic coding."
|
|
346
|
+
},
|
|
347
|
+
{
|
|
348
|
+
name: "testing",
|
|
349
|
+
description: "Generic testing",
|
|
350
|
+
body: "Generic testing."
|
|
351
|
+
}
|
|
352
|
+
]
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
]
|
|
356
|
+
}
|
|
357
|
+
]
|
|
358
|
+
},
|
|
359
|
+
{
|
|
360
|
+
id: "architecture",
|
|
361
|
+
label: "Architecture",
|
|
362
|
+
description: "Stack",
|
|
363
|
+
required: false,
|
|
364
|
+
options: [
|
|
365
|
+
{
|
|
366
|
+
id: "ext",
|
|
367
|
+
label: "Extension",
|
|
368
|
+
description: "Extension",
|
|
369
|
+
recipe: [
|
|
370
|
+
{
|
|
371
|
+
writer: "skills",
|
|
372
|
+
config: {
|
|
373
|
+
skills: [
|
|
374
|
+
{
|
|
375
|
+
name: "ext-all",
|
|
376
|
+
description: "Replaces both",
|
|
377
|
+
body: "Extension content.",
|
|
378
|
+
replaces: ["coding", "testing"]
|
|
379
|
+
}
|
|
380
|
+
]
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
]
|
|
384
|
+
}
|
|
385
|
+
]
|
|
386
|
+
}
|
|
387
|
+
]
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
const userConfig: UserConfig = {
|
|
391
|
+
choices: { process: "base", architecture: "ext" }
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
const result = await resolve(userConfig, skillsCatalog, registry);
|
|
395
|
+
|
|
396
|
+
expect(result.skills).toHaveLength(1);
|
|
397
|
+
expect(result.skills[0].name).toBe("ext-all");
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
it("keeps all skills when no replaces are declared", async () => {
|
|
401
|
+
const skillsCatalog: Catalog = {
|
|
402
|
+
facets: [
|
|
403
|
+
{
|
|
404
|
+
id: "process",
|
|
405
|
+
label: "Process",
|
|
406
|
+
description: "Process",
|
|
407
|
+
required: true,
|
|
408
|
+
options: [
|
|
409
|
+
{
|
|
410
|
+
id: "base",
|
|
411
|
+
label: "Base",
|
|
412
|
+
description: "Base",
|
|
413
|
+
recipe: [
|
|
414
|
+
{
|
|
415
|
+
writer: "skills",
|
|
416
|
+
config: {
|
|
417
|
+
skills: [
|
|
418
|
+
{ name: "skill-a", description: "A", body: "Body A." },
|
|
419
|
+
{ name: "skill-b", description: "B", body: "Body B." }
|
|
420
|
+
]
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
]
|
|
424
|
+
}
|
|
425
|
+
]
|
|
426
|
+
}
|
|
427
|
+
]
|
|
428
|
+
};
|
|
429
|
+
|
|
430
|
+
const userConfig: UserConfig = { choices: { process: "base" } };
|
|
431
|
+
const result = await resolve(userConfig, skillsCatalog, registry);
|
|
432
|
+
|
|
433
|
+
expect(result.skills).toHaveLength(2);
|
|
434
|
+
expect(result.skills.map((s) => s.name)).toEqual(["skill-a", "skill-b"]);
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
it("deduplicates skills by name — last writer wins", async () => {
|
|
438
|
+
const skillsCatalog: Catalog = {
|
|
439
|
+
facets: [
|
|
440
|
+
{
|
|
441
|
+
id: "process",
|
|
442
|
+
label: "Process",
|
|
443
|
+
description: "Process",
|
|
444
|
+
required: true,
|
|
445
|
+
options: [
|
|
446
|
+
{
|
|
447
|
+
id: "base",
|
|
448
|
+
label: "Base",
|
|
449
|
+
description: "Base",
|
|
450
|
+
recipe: [
|
|
451
|
+
{
|
|
452
|
+
writer: "skills",
|
|
453
|
+
config: {
|
|
454
|
+
skills: [
|
|
455
|
+
{
|
|
456
|
+
name: "shared-skill",
|
|
457
|
+
description: "First",
|
|
458
|
+
body: "First body."
|
|
459
|
+
}
|
|
460
|
+
]
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
]
|
|
464
|
+
}
|
|
465
|
+
]
|
|
466
|
+
},
|
|
467
|
+
{
|
|
468
|
+
id: "architecture",
|
|
469
|
+
label: "Architecture",
|
|
470
|
+
description: "Stack",
|
|
471
|
+
required: false,
|
|
472
|
+
options: [
|
|
473
|
+
{
|
|
474
|
+
id: "ext",
|
|
475
|
+
label: "Extension",
|
|
476
|
+
description: "Extension",
|
|
477
|
+
recipe: [
|
|
478
|
+
{
|
|
479
|
+
writer: "skills",
|
|
480
|
+
config: {
|
|
481
|
+
skills: [
|
|
482
|
+
{
|
|
483
|
+
name: "shared-skill",
|
|
484
|
+
description: "Second",
|
|
485
|
+
body: "Second body."
|
|
486
|
+
}
|
|
487
|
+
]
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
]
|
|
491
|
+
}
|
|
492
|
+
]
|
|
493
|
+
}
|
|
494
|
+
]
|
|
495
|
+
};
|
|
496
|
+
|
|
497
|
+
const userConfig: UserConfig = {
|
|
498
|
+
choices: { process: "base", architecture: "ext" }
|
|
499
|
+
};
|
|
500
|
+
|
|
501
|
+
const result = await resolve(userConfig, skillsCatalog, registry);
|
|
502
|
+
|
|
503
|
+
expect(result.skills).toHaveLength(1);
|
|
504
|
+
expect(result.skills[0]).toMatchObject({
|
|
505
|
+
name: "shared-skill",
|
|
506
|
+
body: "Second body."
|
|
507
|
+
});
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
it("works with external skills that declare replaces", async () => {
|
|
511
|
+
const skillsCatalog: Catalog = {
|
|
512
|
+
facets: [
|
|
513
|
+
{
|
|
514
|
+
id: "process",
|
|
515
|
+
label: "Process",
|
|
516
|
+
description: "Process",
|
|
517
|
+
required: true,
|
|
518
|
+
options: [
|
|
519
|
+
{
|
|
520
|
+
id: "base",
|
|
521
|
+
label: "Base",
|
|
522
|
+
description: "Base",
|
|
523
|
+
recipe: [
|
|
524
|
+
{
|
|
525
|
+
writer: "skills",
|
|
526
|
+
config: {
|
|
527
|
+
skills: [
|
|
528
|
+
{
|
|
529
|
+
name: "tdd",
|
|
530
|
+
description: "Generic TDD",
|
|
531
|
+
body: "Generic TDD."
|
|
532
|
+
}
|
|
533
|
+
]
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
]
|
|
537
|
+
}
|
|
538
|
+
]
|
|
539
|
+
},
|
|
540
|
+
{
|
|
541
|
+
id: "architecture",
|
|
542
|
+
label: "Architecture",
|
|
543
|
+
description: "Stack",
|
|
544
|
+
required: false,
|
|
545
|
+
options: [
|
|
546
|
+
{
|
|
547
|
+
id: "ext",
|
|
548
|
+
label: "Extension",
|
|
549
|
+
description: "Extension",
|
|
550
|
+
recipe: [
|
|
551
|
+
{
|
|
552
|
+
writer: "skills",
|
|
553
|
+
config: {
|
|
554
|
+
skills: [
|
|
555
|
+
{
|
|
556
|
+
name: "ext-tdd",
|
|
557
|
+
source: "org/repo/skills/ext-tdd",
|
|
558
|
+
replaces: ["tdd"]
|
|
559
|
+
}
|
|
560
|
+
]
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
]
|
|
564
|
+
}
|
|
565
|
+
]
|
|
566
|
+
}
|
|
567
|
+
]
|
|
568
|
+
};
|
|
569
|
+
|
|
570
|
+
const userConfig: UserConfig = {
|
|
571
|
+
choices: { process: "base", architecture: "ext" }
|
|
572
|
+
};
|
|
573
|
+
|
|
574
|
+
const result = await resolve(userConfig, skillsCatalog, registry);
|
|
575
|
+
|
|
576
|
+
expect(result.skills).toHaveLength(1);
|
|
577
|
+
expect(result.skills[0].name).toBe("ext-tdd");
|
|
578
|
+
});
|
|
249
579
|
});
|
|
250
580
|
|
|
251
581
|
describe("setup_notes merging", () => {
|
|
@@ -125,6 +125,22 @@ export async function resolve(
|
|
|
125
125
|
}
|
|
126
126
|
result.mcp_servers = Array.from(serversByRef.values());
|
|
127
127
|
|
|
128
|
+
// Dedup skills: collect all names declared as replaced, dedup by name
|
|
129
|
+
// (last-writer-wins), then filter out replaced ones.
|
|
130
|
+
const replacedNames = new Set<string>();
|
|
131
|
+
for (const skill of result.skills) {
|
|
132
|
+
for (const r of skill.replaces ?? []) {
|
|
133
|
+
replacedNames.add(r);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
const skillsByName = new Map<string, (typeof result.skills)[number]>();
|
|
137
|
+
for (const skill of result.skills) {
|
|
138
|
+
skillsByName.set(skill.name, skill);
|
|
139
|
+
}
|
|
140
|
+
result.skills = Array.from(skillsByName.values()).filter(
|
|
141
|
+
(skill) => !replacedNames.has(skill.name)
|
|
142
|
+
);
|
|
143
|
+
|
|
128
144
|
return result;
|
|
129
145
|
}
|
|
130
146
|
|
|
@@ -54,11 +54,25 @@ export interface InlineSkill {
|
|
|
54
54
|
name: string;
|
|
55
55
|
description: string;
|
|
56
56
|
body: string;
|
|
57
|
+
/**
|
|
58
|
+
* Names of other skills that this skill supersedes.
|
|
59
|
+
* Any skill whose `name` appears here will be removed from the final
|
|
60
|
+
* resolved skills list. Used by extension-contributed skills to suppress
|
|
61
|
+
* the generic baseline skills registered by the process option.
|
|
62
|
+
*/
|
|
63
|
+
replaces?: string[];
|
|
57
64
|
}
|
|
58
65
|
|
|
59
66
|
export interface ExternalSkill {
|
|
60
67
|
name: string;
|
|
61
68
|
source: string;
|
|
69
|
+
/**
|
|
70
|
+
* Names of other skills that this skill supersedes.
|
|
71
|
+
* Any skill whose `name` appears here will be removed from the final
|
|
72
|
+
* resolved skills list. Used by extension-contributed skills to suppress
|
|
73
|
+
* the generic baseline skills registered by the process option.
|
|
74
|
+
*/
|
|
75
|
+
replaces?: string[];
|
|
62
76
|
}
|
|
63
77
|
|
|
64
78
|
export type SkillDefinition = InlineSkill | ExternalSkill;
|
|
@@ -85,6 +85,52 @@ describe("skillsWriter", () => {
|
|
|
85
85
|
});
|
|
86
86
|
});
|
|
87
87
|
|
|
88
|
+
it("passes through replaces field on inline skills", async () => {
|
|
89
|
+
const result = await skillsWriter.write(
|
|
90
|
+
{
|
|
91
|
+
skills: [
|
|
92
|
+
{
|
|
93
|
+
name: "ext-architecture",
|
|
94
|
+
description: "Extension architecture",
|
|
95
|
+
body: "Extension body.",
|
|
96
|
+
replaces: ["architecture"]
|
|
97
|
+
}
|
|
98
|
+
]
|
|
99
|
+
},
|
|
100
|
+
emptyContext
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
expect(result.skills).toHaveLength(1);
|
|
104
|
+
expect(result.skills![0]).toEqual({
|
|
105
|
+
name: "ext-architecture",
|
|
106
|
+
description: "Extension architecture",
|
|
107
|
+
body: "Extension body.",
|
|
108
|
+
replaces: ["architecture"]
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("passes through replaces field on external skills", async () => {
|
|
113
|
+
const result = await skillsWriter.write(
|
|
114
|
+
{
|
|
115
|
+
skills: [
|
|
116
|
+
{
|
|
117
|
+
name: "ext-tdd",
|
|
118
|
+
source: "org/repo/skills/ext-tdd",
|
|
119
|
+
replaces: ["tdd"]
|
|
120
|
+
}
|
|
121
|
+
]
|
|
122
|
+
},
|
|
123
|
+
emptyContext
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
expect(result.skills).toHaveLength(1);
|
|
127
|
+
expect(result.skills![0]).toEqual({
|
|
128
|
+
name: "ext-tdd",
|
|
129
|
+
source: "org/repo/skills/ext-tdd",
|
|
130
|
+
replaces: ["tdd"]
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
|
|
88
134
|
it("handles mixed inline and external skills", async () => {
|
|
89
135
|
const result = await skillsWriter.write(
|
|
90
136
|
{
|
|
@@ -102,7 +102,7 @@ describe("opencodeWriter", () => {
|
|
|
102
102
|
expect(defaultsAgent).toContain('grep: "allow"');
|
|
103
103
|
expect(defaultsAgent).toContain('list: "allow"');
|
|
104
104
|
expect(defaultsAgent).toContain('lsp: "allow"');
|
|
105
|
-
expect(defaultsAgent).toContain('task: "
|
|
105
|
+
expect(defaultsAgent).toContain('task: "allow"');
|
|
106
106
|
expect(defaultsAgent).toContain('skill: "deny"');
|
|
107
107
|
expect(defaultsAgent).toContain('todoread: "deny"');
|
|
108
108
|
expect(defaultsAgent).toContain('todowrite: "deny"');
|
|
@@ -110,7 +110,6 @@ describe("opencodeWriter", () => {
|
|
|
110
110
|
expect(defaultsAgent).toContain('websearch: "ask"');
|
|
111
111
|
expect(defaultsAgent).toContain('codesearch: "ask"');
|
|
112
112
|
expect(defaultsAgent).toContain('external_directory: "ask"');
|
|
113
|
-
expect(defaultsAgent).toContain('doom_loop: "deny"');
|
|
114
113
|
expect(defaultsAgent).toContain('"grep *": "allow"');
|
|
115
114
|
expect(defaultsAgent).toContain('"rm *": "deny"');
|
|
116
115
|
expect(defaultsFrontmatter.permission).toMatchObject({
|
|
@@ -119,15 +118,14 @@ describe("opencodeWriter", () => {
|
|
|
119
118
|
grep: "allow",
|
|
120
119
|
list: "allow",
|
|
121
120
|
lsp: "allow",
|
|
122
|
-
task: "
|
|
121
|
+
task: "allow",
|
|
123
122
|
skill: "deny",
|
|
124
123
|
todoread: "deny",
|
|
125
124
|
todowrite: "deny",
|
|
126
125
|
webfetch: "ask",
|
|
127
126
|
websearch: "ask",
|
|
128
127
|
codesearch: "ask",
|
|
129
|
-
external_directory: "ask"
|
|
130
|
-
doom_loop: "deny"
|
|
128
|
+
external_directory: "ask"
|
|
131
129
|
});
|
|
132
130
|
const defaultsPermission = defaultsFrontmatter.permission as {
|
|
133
131
|
bash: Record<string, string>;
|
|
@@ -24,9 +24,9 @@ const APPLICABLE_TO_ALL: Record<string, PermissionRule> = {
|
|
|
24
24
|
"*.env.example": "allow"
|
|
25
25
|
},
|
|
26
26
|
skill: "deny", //we're using an own skills-mcp
|
|
27
|
-
todoread: "deny", //no agent-
|
|
27
|
+
todoread: "deny", //no agent-proprietary todo tools
|
|
28
28
|
todowrite: "deny",
|
|
29
|
-
task: "
|
|
29
|
+
task: "allow", //starts subagents
|
|
30
30
|
lsp: "allow",
|
|
31
31
|
glob: "allow",
|
|
32
32
|
grep: "allow",
|
|
@@ -129,8 +129,7 @@ const SENSIBLE_DEFAULTS_RULES: Record<string, PermissionRule> = {
|
|
|
129
129
|
"useradd *": "deny",
|
|
130
130
|
"userdel *": "deny",
|
|
131
131
|
"iptables *": "deny"
|
|
132
|
-
}
|
|
133
|
-
doom_loop: "deny"
|
|
132
|
+
}
|
|
134
133
|
};
|
|
135
134
|
|
|
136
135
|
const MAX_AUTONOMY_RULES: Record<string, PermissionRule> = {
|