@nano-step/skill-manager 5.0.0 → 5.1.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/dist/utils.d.ts +1 -1
- package/dist/utils.js +1 -1
- package/package.json +3 -1
- package/skills/rri-t-testing/SKILL.md +76 -0
- package/skills/rri-t-testing/assets/rri-t-coverage-dashboard.md +101 -0
- package/skills/rri-t-testing/assets/rri-t-persona-interview.md +226 -0
- package/skills/rri-t-testing/assets/rri-t-stress-matrix.md +100 -0
- package/skills/rri-t-testing/assets/rri-t-test-case.md +155 -0
- package/skills/rri-t-testing/skill.json +9 -0
- package/skills/skill-management/assets/tools-template.json +1 -1
- package/skills/skill-management/assets/workflow-schema.json +1 -1
- package/skills/skill-management/references/error-handling.md +7 -7
- package/skills/skill-management/references/tool-categories.md +4 -4
- package/skills/skill-management/references/tool-execution.md +7 -7
- package/skills/skill-management/references/workflows.md +9 -9
- package/dist/install.d.ts +0 -1
- package/dist/install.js +0 -35
- package/dist/remove.d.ts +0 -1
- package/dist/remove.js +0 -32
- package/dist/update.d.ts +0 -1
- package/dist/update.js +0 -53
package/dist/utils.d.ts
CHANGED
package/dist/utils.js
CHANGED
|
@@ -13,7 +13,7 @@ exports.writeText = writeText;
|
|
|
13
13
|
const path_1 = __importDefault(require("path"));
|
|
14
14
|
const os_1 = __importDefault(require("os"));
|
|
15
15
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
16
|
-
exports.MANAGER_VERSION = "5.
|
|
16
|
+
exports.MANAGER_VERSION = "5.1.0";
|
|
17
17
|
async function detectOpenCodePaths() {
|
|
18
18
|
const homeConfig = path_1.default.join(os_1.default.homedir(), ".config", "opencode");
|
|
19
19
|
const cwd = process.cwd();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nano-step/skill-manager",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.1.0",
|
|
4
4
|
"description": "CLI tool that installs and manages AI agent skills, MCP tool routing, and workflow configurations.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -19,6 +19,8 @@
|
|
|
19
19
|
"keywords": [
|
|
20
20
|
"nano-step",
|
|
21
21
|
"opencode",
|
|
22
|
+
"skill",
|
|
23
|
+
"skill-manager",
|
|
22
24
|
"mcp",
|
|
23
25
|
"model-context-protocol",
|
|
24
26
|
"ai",
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rri-t-testing
|
|
3
|
+
description: RRI-T QA methodology skill. Execute 5-phase testing: PREPARE, DISCOVER, STRUCTURE, EXECUTE, ANALYZE. Use before release, creating test cases, or QA review.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# RRI-T Testing Skill
|
|
7
|
+
|
|
8
|
+
Execute comprehensive QA testing using Reverse Requirements Interview - Testing methodology.
|
|
9
|
+
|
|
10
|
+
## When to Use
|
|
11
|
+
|
|
12
|
+
- Testing any feature before release
|
|
13
|
+
- Creating test cases for new features
|
|
14
|
+
- Performing thorough QA review
|
|
15
|
+
- Running stress tests and edge case analysis
|
|
16
|
+
|
|
17
|
+
## Input
|
|
18
|
+
|
|
19
|
+
| Param | Req | Description |
|
|
20
|
+
|-------|-----|-------------|
|
|
21
|
+
| feature | Yes | Feature name in kebab-case |
|
|
22
|
+
| phase | No | `prepare`, `discover`, `structure`, `execute`, `analyze` |
|
|
23
|
+
| dimensions | No | `ui-ux,api,performance,security,data,infra,edge-cases` |
|
|
24
|
+
|
|
25
|
+
## 5 Phases
|
|
26
|
+
|
|
27
|
+
1. **PREPARE** — Read specs, setup output dir
|
|
28
|
+
2. **DISCOVER** — Interview 5 personas for test scenarios
|
|
29
|
+
3. **STRUCTURE** — Format as Q-A-R-P-T test cases
|
|
30
|
+
4. **EXECUTE** — Run tests, capture screenshots
|
|
31
|
+
5. **ANALYZE** — Calculate coverage, apply release gates
|
|
32
|
+
|
|
33
|
+
## Output
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
/ai/test-case/rri-t/{feature-name}/
|
|
37
|
+
├── 01-prepare.md
|
|
38
|
+
├── 02-discover.md
|
|
39
|
+
├── 03-structure.md
|
|
40
|
+
├── 04-execute.md
|
|
41
|
+
├── 05-analyze.md
|
|
42
|
+
└── summary.md
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Templates
|
|
46
|
+
|
|
47
|
+
Use templates bundled in `assets/` directory of this skill:
|
|
48
|
+
- `rri-t-persona-interview.md` — Persona interviews
|
|
49
|
+
- `rri-t-test-case.md` — Q-A-R-P-T format
|
|
50
|
+
- `rri-t-coverage-dashboard.md` — 7-dimension tracking
|
|
51
|
+
- `rri-t-stress-matrix.md` — 8-axis stress testing
|
|
52
|
+
|
|
53
|
+
## 7 Dimensions
|
|
54
|
+
|
|
55
|
+
UI/UX | API | Performance | Security | Data Integrity | Infrastructure | Edge Cases
|
|
56
|
+
|
|
57
|
+
## 5 Personas
|
|
58
|
+
|
|
59
|
+
End User | Business Analyst | QA Destroyer | DevOps Tester | Security Auditor
|
|
60
|
+
|
|
61
|
+
## Release Gates
|
|
62
|
+
|
|
63
|
+
| GO | NO-GO |
|
|
64
|
+
|----|-------|
|
|
65
|
+
| All 7 dims >= 70% | Any dim < 50% |
|
|
66
|
+
| 5/7 >= 85% | >2 P0 FAILs |
|
|
67
|
+
| Zero P0 FAIL | Critical MISSING |
|
|
68
|
+
|
|
69
|
+
## Guardrails
|
|
70
|
+
|
|
71
|
+
1. Test all 7 dimensions
|
|
72
|
+
2. Use all 5 personas
|
|
73
|
+
3. Document everything
|
|
74
|
+
4. PAINFUL is valid (not failure)
|
|
75
|
+
5. Follow release gates
|
|
76
|
+
6. Test Vietnamese locale
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# RRI-T Coverage Dashboard — {feature_name}
|
|
2
|
+
|
|
3
|
+
Feature: {feature_name}
|
|
4
|
+
Date: {date}
|
|
5
|
+
Release Gate Status: {release_gate_status}
|
|
6
|
+
Release Version: {release_version}
|
|
7
|
+
Owner: {owner}
|
|
8
|
+
Prepared By: {prepared_by}
|
|
9
|
+
|
|
10
|
+
## Release Gate Criteria
|
|
11
|
+
|
|
12
|
+
| Rule | Criteria | Status |
|
|
13
|
+
| --- | --- | --- |
|
|
14
|
+
| RG-1 | All 7 dimensions >= 70% coverage | {rg1_status} |
|
|
15
|
+
| RG-2 | At least 5/7 dimensions >= 85% coverage | {rg2_status} |
|
|
16
|
+
| RG-3 | Zero P0 items in FAIL state | {rg3_status} |
|
|
17
|
+
|
|
18
|
+
## Dimension Coverage
|
|
19
|
+
|
|
20
|
+
| Dimension | Total | PASS | FAIL | PAINFUL | MISSING | Coverage % | Gate |
|
|
21
|
+
| --- | --- | --- | --- | --- | --- | --- | --- |
|
|
22
|
+
| D1: UI/UX | {d1_total} | {d1_pass} | {d1_fail} | {d1_painful} | {d1_missing} | {d1_coverage} | {d1_gate} |
|
|
23
|
+
| D2: API | {d2_total} | {d2_pass} | {d2_fail} | {d2_painful} | {d2_missing} | {d2_coverage} | {d2_gate} |
|
|
24
|
+
| D3: Performance | {d3_total} | {d3_pass} | {d3_fail} | {d3_painful} | {d3_missing} | {d3_coverage} | {d3_gate} |
|
|
25
|
+
| D4: Security | {d4_total} | {d4_pass} | {d4_fail} | {d4_painful} | {d4_missing} | {d4_coverage} | {d4_gate} |
|
|
26
|
+
| D5: Data Integrity | {d5_total} | {d5_pass} | {d5_fail} | {d5_painful} | {d5_missing} | {d5_coverage} | {d5_gate} |
|
|
27
|
+
| D6: Infrastructure | {d6_total} | {d6_pass} | {d6_fail} | {d6_painful} | {d6_missing} | {d6_coverage} | {d6_gate} |
|
|
28
|
+
| D7: Edge Cases | {d7_total} | {d7_pass} | {d7_fail} | {d7_painful} | {d7_missing} | {d7_coverage} | {d7_gate} |
|
|
29
|
+
|
|
30
|
+
Legend: ✅ PASS | ❌ FAIL | ⚠️ PAINFUL | ☐ MISSING
|
|
31
|
+
|
|
32
|
+
## Priority Breakdown
|
|
33
|
+
|
|
34
|
+
| Priority | Total | PASS | FAIL | PAINFUL | MISSING | Coverage % | Gate |
|
|
35
|
+
| --- | --- | --- | --- | --- | --- | --- | --- |
|
|
36
|
+
| P0 | {p0_total} | {p0_pass} | {p0_fail} | {p0_painful} | {p0_missing} | {p0_coverage} | {p0_gate} |
|
|
37
|
+
| P1 | {p1_total} | {p1_pass} | {p1_fail} | {p1_painful} | {p1_missing} | {p1_coverage} | {p1_gate} |
|
|
38
|
+
| P2 | {p2_total} | {p2_pass} | {p2_fail} | {p2_painful} | {p2_missing} | {p2_coverage} | {p2_gate} |
|
|
39
|
+
| P3 | {p3_total} | {p3_pass} | {p3_fail} | {p3_painful} | {p3_missing} | {p3_coverage} | {p3_gate} |
|
|
40
|
+
|
|
41
|
+
## Summary Metrics
|
|
42
|
+
|
|
43
|
+
- Total Test Cases: {total_tc}
|
|
44
|
+
- Overall Coverage %: {overall_coverage}
|
|
45
|
+
- Dimensions Passing Gate: {dimensions_passing_gate}
|
|
46
|
+
- P0 FAIL Count: {p0_fail_count}
|
|
47
|
+
- P0 PAINFUL Count: {p0_painful_count}
|
|
48
|
+
- MISSING Count: {missing_count}
|
|
49
|
+
- Latest Update: {latest_update}
|
|
50
|
+
- Notes: {summary_notes}
|
|
51
|
+
- Risks: {summary_risks}
|
|
52
|
+
|
|
53
|
+
## FAIL Items
|
|
54
|
+
|
|
55
|
+
| TC ID | Priority | Dimension | Description | Assigned To |
|
|
56
|
+
| --- | --- | --- | --- | --- |
|
|
57
|
+
| {fail_tc_id_1} | {fail_priority_1} | {fail_dimension_1} | {fail_description_1} | {fail_assigned_to_1} |
|
|
58
|
+
| {fail_tc_id_2} | {fail_priority_2} | {fail_dimension_2} | {fail_description_2} | {fail_assigned_to_2} |
|
|
59
|
+
| {fail_tc_id_3} | {fail_priority_3} | {fail_dimension_3} | {fail_description_3} | {fail_assigned_to_3} |
|
|
60
|
+
| {fail_tc_id_4} | {fail_priority_4} | {fail_dimension_4} | {fail_description_4} | {fail_assigned_to_4} |
|
|
61
|
+
| {fail_tc_id_5} | {fail_priority_5} | {fail_dimension_5} | {fail_description_5} | {fail_assigned_to_5} |
|
|
62
|
+
|
|
63
|
+
## PAINFUL Items
|
|
64
|
+
|
|
65
|
+
| TC ID | Priority | Dimension | Description | UX Impact |
|
|
66
|
+
| --- | --- | --- | --- | --- |
|
|
67
|
+
| {painful_tc_id_1} | {painful_priority_1} | {painful_dimension_1} | {painful_description_1} | {painful_ux_impact_1} |
|
|
68
|
+
| {painful_tc_id_2} | {painful_priority_2} | {painful_dimension_2} | {painful_description_2} | {painful_ux_impact_2} |
|
|
69
|
+
| {painful_tc_id_3} | {painful_priority_3} | {painful_dimension_3} | {painful_description_3} | {painful_ux_impact_3} |
|
|
70
|
+
| {painful_tc_id_4} | {painful_priority_4} | {painful_dimension_4} | {painful_description_4} | {painful_ux_impact_4} |
|
|
71
|
+
| {painful_tc_id_5} | {painful_priority_5} | {painful_dimension_5} | {painful_description_5} | {painful_ux_impact_5} |
|
|
72
|
+
|
|
73
|
+
## MISSING Items
|
|
74
|
+
|
|
75
|
+
| TC ID | Priority | Dimension | Description | User Need |
|
|
76
|
+
| --- | --- | --- | --- | --- |
|
|
77
|
+
| {missing_tc_id_1} | {missing_priority_1} | {missing_dimension_1} | {missing_description_1} | {missing_user_need_1} |
|
|
78
|
+
| {missing_tc_id_2} | {missing_priority_2} | {missing_dimension_2} | {missing_description_2} | {missing_user_need_2} |
|
|
79
|
+
| {missing_tc_id_3} | {missing_priority_3} | {missing_dimension_3} | {missing_description_3} | {missing_user_need_3} |
|
|
80
|
+
| {missing_tc_id_4} | {missing_priority_4} | {missing_dimension_4} | {missing_description_4} | {missing_user_need_4} |
|
|
81
|
+
| {missing_tc_id_5} | {missing_priority_5} | {missing_dimension_5} | {missing_description_5} | {missing_user_need_5} |
|
|
82
|
+
|
|
83
|
+
## Regression Test List
|
|
84
|
+
|
|
85
|
+
| Test ID | Title | Dimension | Priority | Status |
|
|
86
|
+
| --- | --- | --- | --- | --- |
|
|
87
|
+
| {regression_id_1} | {regression_title_1} | {regression_dimension_1} | {regression_priority_1} | {regression_status_1} |
|
|
88
|
+
| {regression_id_2} | {regression_title_2} | {regression_dimension_2} | {regression_priority_2} | {regression_status_2} |
|
|
89
|
+
| {regression_id_3} | {regression_title_3} | {regression_dimension_3} | {regression_priority_3} | {regression_status_3} |
|
|
90
|
+
| {regression_id_4} | {regression_title_4} | {regression_dimension_4} | {regression_priority_4} | {regression_status_4} |
|
|
91
|
+
| {regression_id_5} | {regression_title_5} | {regression_dimension_5} | {regression_priority_5} | {regression_status_5} |
|
|
92
|
+
|
|
93
|
+
## Sign-off
|
|
94
|
+
|
|
95
|
+
| Role | Name | Decision | Notes |
|
|
96
|
+
| --- | --- | --- | --- |
|
|
97
|
+
| QA Lead | {qa_lead_name} | {qa_lead_decision} | {qa_lead_notes} |
|
|
98
|
+
| Dev Lead | {dev_lead_name} | {dev_lead_decision} | {dev_lead_notes} |
|
|
99
|
+
| Product | {product_name} | {product_decision} | {product_notes} |
|
|
100
|
+
|
|
101
|
+
Decision Legend: {approve_label}/{reject_label}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
# RRI-T Persona Interview — {Feature Name}
|
|
2
|
+
|
|
3
|
+
**Feature:** {feature-name}
|
|
4
|
+
**Date:** {YYYY-MM-DD}
|
|
5
|
+
**Interviewer:** {agent/person}
|
|
6
|
+
|
|
7
|
+
## Interview Summary
|
|
8
|
+
| Persona | Questions Generated | Key Concerns |
|
|
9
|
+
|---------|-------------------|--------------|
|
|
10
|
+
| End User | 0/25 | |
|
|
11
|
+
| Business Analyst | 0/25 | |
|
|
12
|
+
| QA Destroyer | 0/25 | |
|
|
13
|
+
| DevOps Tester | 0/25 | |
|
|
14
|
+
| Security Auditor | 0/25 | |
|
|
15
|
+
| **Total** | **0/125** | |
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Persona 1: End User (Người dùng cuối)
|
|
20
|
+
|
|
21
|
+
### Context
|
|
22
|
+
As a household member using {feature-name} daily to manage my family's shared resources, I need the feature to work reliably across different devices, network conditions, and usage patterns. I care about speed, clarity, and not losing my work.
|
|
23
|
+
|
|
24
|
+
### Questions
|
|
25
|
+
1. What happens when I add an inventory item while my phone has weak 3G signal?
|
|
26
|
+
2. What happens when I start editing a shopping list on mobile, then switch to desktop mid-task?
|
|
27
|
+
3. What happens when I search for "nguyen" but the item name is "Nguyễn Văn A"?
|
|
28
|
+
4. What happens when I accidentally navigate away from a half-filled form?
|
|
29
|
+
5. What happens when I try to delete an item that another household member is currently editing?
|
|
30
|
+
6. What happens when I upload a photo of a receipt and the file is 10MB?
|
|
31
|
+
7. What happens when I filter 500+ inventory items by expiration date on a mid-range phone?
|
|
32
|
+
8. What happens when I receive a phone call while recording a voice note for a meal plan?
|
|
33
|
+
9. What happens when the app shows "1,000,000đ" instead of "1.000.000đ" for Vietnamese currency?
|
|
34
|
+
10. What happens when I'm offline for 2 days and then reconnect with 50 pending changes?
|
|
35
|
+
11.
|
|
36
|
+
12.
|
|
37
|
+
13.
|
|
38
|
+
14.
|
|
39
|
+
15.
|
|
40
|
+
16.
|
|
41
|
+
17.
|
|
42
|
+
18.
|
|
43
|
+
19.
|
|
44
|
+
20.
|
|
45
|
+
21.
|
|
46
|
+
22.
|
|
47
|
+
23.
|
|
48
|
+
24.
|
|
49
|
+
25.
|
|
50
|
+
|
|
51
|
+
### Key Concerns
|
|
52
|
+
- {list concerns discovered}
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Persona 2: Business Analyst (Phân tích nghiệp vụ)
|
|
57
|
+
|
|
58
|
+
### Context
|
|
59
|
+
As someone responsible for ensuring business rules are correctly implemented, I need to verify that household permissions, data ownership, financial calculations, and multi-household scenarios work as specified. I care about data consistency and rule enforcement.
|
|
60
|
+
|
|
61
|
+
### Questions
|
|
62
|
+
1. What happens when a household member with "viewer" role tries to delete an inventory item?
|
|
63
|
+
2. What happens when a user belongs to 3 households and switches between them rapidly?
|
|
64
|
+
3. What happens when two members simultaneously mark the same shopping list item as "purchased"?
|
|
65
|
+
4. What happens when a household admin removes a member who has pending edits?
|
|
66
|
+
5. What happens when the total expense calculation includes items in different currencies (VND and USD)?
|
|
67
|
+
6. What happens when a recurring meal plan conflicts with a one-time event on the same date?
|
|
68
|
+
7. What happens when a user tries to share an inventory item with a household they don't belong to?
|
|
69
|
+
8. What happens when the system calculates "items expiring in 3 days" across different timezones?
|
|
70
|
+
9. What happens when a household reaches the maximum allowed inventory items (if there's a limit)?
|
|
71
|
+
10. What happens when a deleted household still has active shopping lists in other members' offline caches?
|
|
72
|
+
11.
|
|
73
|
+
12.
|
|
74
|
+
13.
|
|
75
|
+
14.
|
|
76
|
+
15.
|
|
77
|
+
16.
|
|
78
|
+
17.
|
|
79
|
+
18.
|
|
80
|
+
19.
|
|
81
|
+
20.
|
|
82
|
+
21.
|
|
83
|
+
22.
|
|
84
|
+
23.
|
|
85
|
+
24.
|
|
86
|
+
25.
|
|
87
|
+
|
|
88
|
+
### Key Concerns
|
|
89
|
+
- {list concerns discovered}
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Persona 3: QA Destroyer (Phá hoại viên QA)
|
|
94
|
+
|
|
95
|
+
### Context
|
|
96
|
+
As someone whose job is to break things, I need to find every edge case, race condition, and unexpected input that could crash the system or corrupt data. I care about boundary conditions, malformed inputs, and timing attacks.
|
|
97
|
+
|
|
98
|
+
### Questions
|
|
99
|
+
1. What happens when I paste 50,000 characters into the "item name" field?
|
|
100
|
+
2. What happens when I rapidly click "save" 20 times in 1 second?
|
|
101
|
+
3. What happens when I set my device date to 2099 and create an inventory item?
|
|
102
|
+
4. What happens when I upload a file named `"; DROP TABLE inventory; --"` as an item photo?
|
|
103
|
+
5. What happens when I create an item with expiration date "yesterday" and quantity "-5"?
|
|
104
|
+
6. What happens when I open the app in 10 browser tabs and edit the same item in all of them?
|
|
105
|
+
7. What happens when I force-kill the app during a GraphQL mutation?
|
|
106
|
+
8. What happens when I inject `<script>alert('xss')</script>` into a meal plan description?
|
|
107
|
+
9. What happens when I create a circular dependency (Item A requires Item B, Item B requires Item A)?
|
|
108
|
+
10. What happens when I change my device timezone mid-session and create a timestamped event?
|
|
109
|
+
11.
|
|
110
|
+
12.
|
|
111
|
+
13.
|
|
112
|
+
14.
|
|
113
|
+
15.
|
|
114
|
+
16.
|
|
115
|
+
17.
|
|
116
|
+
18.
|
|
117
|
+
19.
|
|
118
|
+
20.
|
|
119
|
+
21.
|
|
120
|
+
22.
|
|
121
|
+
23.
|
|
122
|
+
24.
|
|
123
|
+
25.
|
|
124
|
+
|
|
125
|
+
### Key Concerns
|
|
126
|
+
- {list concerns discovered}
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Persona 4: DevOps Tester (Kiểm thử hạ tầng)
|
|
131
|
+
|
|
132
|
+
### Context
|
|
133
|
+
As someone responsible for deployment, monitoring, and infrastructure reliability, I need to verify that the feature works under load, handles server restarts gracefully, and doesn't leak resources. I care about scalability, observability, and recovery.
|
|
134
|
+
|
|
135
|
+
### Questions
|
|
136
|
+
1. What happens when the GraphQL server restarts while a user is mid-sync?
|
|
137
|
+
2. What happens when 100 users simultaneously bulk-import 500 inventory items each?
|
|
138
|
+
3. What happens when the database connection pool is exhausted during peak usage?
|
|
139
|
+
4. What happens when the CDN serving item photos goes down?
|
|
140
|
+
5. What happens when a GraphQL query takes longer than the 30-second timeout?
|
|
141
|
+
6. What happens when the Redis cache is cleared while users have active sessions?
|
|
142
|
+
7. What happens when a deployment rolls out a new schema version while old clients are still connected?
|
|
143
|
+
8. What happens when disk space runs out during a photo upload?
|
|
144
|
+
9. What happens when the monitoring system detects 500 errors but the app still appears functional?
|
|
145
|
+
10. What happens when a user's offline queue grows to 1000+ pending mutations?
|
|
146
|
+
11.
|
|
147
|
+
12.
|
|
148
|
+
13.
|
|
149
|
+
14.
|
|
150
|
+
15.
|
|
151
|
+
16.
|
|
152
|
+
17.
|
|
153
|
+
18.
|
|
154
|
+
19.
|
|
155
|
+
20.
|
|
156
|
+
21.
|
|
157
|
+
22.
|
|
158
|
+
23.
|
|
159
|
+
24.
|
|
160
|
+
25.
|
|
161
|
+
|
|
162
|
+
### Key Concerns
|
|
163
|
+
- {list concerns discovered}
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## Persona 5: Security Auditor (Kiểm toán bảo mật)
|
|
168
|
+
|
|
169
|
+
### Context
|
|
170
|
+
As someone responsible for security compliance, I need to verify that authentication, authorization, data exposure, and audit trails are properly implemented. I care about access control, data leakage, and attack surface.
|
|
171
|
+
|
|
172
|
+
### Questions
|
|
173
|
+
1. What happens when a user's JWT token expires mid-session?
|
|
174
|
+
2. What happens when a user tries to access another household's data by guessing the household ID?
|
|
175
|
+
3. What happens when a removed household member still has cached data on their device?
|
|
176
|
+
4. What happens when someone intercepts the GraphQL request and replays it with modified variables?
|
|
177
|
+
5. What happens when a user tries to upload a malicious file disguised as an image?
|
|
178
|
+
6. What happens when the audit log shows who deleted an item, but the user claims they didn't?
|
|
179
|
+
7. What happens when a user shares their session token with someone outside the household?
|
|
180
|
+
8. What happens when someone uses SQL injection in a search query (even though it's GraphQL)?
|
|
181
|
+
9. What happens when a user's password is compromised and they don't realize it for 3 days?
|
|
182
|
+
10. What happens when the system logs sensitive data (like financial amounts) in plain text?
|
|
183
|
+
11.
|
|
184
|
+
12.
|
|
185
|
+
13.
|
|
186
|
+
14.
|
|
187
|
+
15.
|
|
188
|
+
16.
|
|
189
|
+
17.
|
|
190
|
+
18.
|
|
191
|
+
19.
|
|
192
|
+
20.
|
|
193
|
+
21.
|
|
194
|
+
22.
|
|
195
|
+
23.
|
|
196
|
+
24.
|
|
197
|
+
25.
|
|
198
|
+
|
|
199
|
+
### Key Concerns
|
|
200
|
+
- {list concerns discovered}
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## Raw Test Ideas (Consolidated)
|
|
205
|
+
| # | Idea | Source Persona | Potential Dimension | Priority Estimate |
|
|
206
|
+
|---|------|---------------|--------------------|--------------------|
|
|
207
|
+
| 1 | | | | |
|
|
208
|
+
| 2 | | | | |
|
|
209
|
+
| 3 | | | | |
|
|
210
|
+
| 4 | | | | |
|
|
211
|
+
| 5 | | | | |
|
|
212
|
+
| 6 | | | | |
|
|
213
|
+
| 7 | | | | |
|
|
214
|
+
| 8 | | | | |
|
|
215
|
+
| 9 | | | | |
|
|
216
|
+
| 10 | | | | |
|
|
217
|
+
| 11 | | | | |
|
|
218
|
+
| 12 | | | | |
|
|
219
|
+
| 13 | | | | |
|
|
220
|
+
| 14 | | | | |
|
|
221
|
+
| 15 | | | | |
|
|
222
|
+
| 16 | | | | |
|
|
223
|
+
| 17 | | | | |
|
|
224
|
+
| 18 | | | | |
|
|
225
|
+
| 19 | | | | |
|
|
226
|
+
| 20 | | | | |
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# RRI-T Stress Matrix Template
|
|
2
|
+
|
|
3
|
+
## Feature
|
|
4
|
+
- Name: <feature-name>
|
|
5
|
+
- Owner: <owner>
|
|
6
|
+
- Date: <yyyy-mm-dd>
|
|
7
|
+
- Build/Release: <build-id>
|
|
8
|
+
- Environment: <dev/staging/prod>
|
|
9
|
+
|
|
10
|
+
## Summary
|
|
11
|
+
This template covers RRI-T 8-axis stress testing for a household management app
|
|
12
|
+
(inventory, meal planning, shopping lists, finances).
|
|
13
|
+
|
|
14
|
+
## Stress Axes Summary
|
|
15
|
+
| Axis | Name | Focus | Notes |
|
|
16
|
+
| --- | --- | --- | --- |
|
|
17
|
+
| 1 | TIME | Deadlines, bulk ops, timeouts | Burst actions, long-running jobs |
|
|
18
|
+
| 2 | DATA | 1000+ rows, search/filter speed | Large inventory, long history |
|
|
19
|
+
| 3 | ERROR | Undo/redo, auto-save recovery, messages | Resilience, recoverability |
|
|
20
|
+
| 4 | COLLAB | Concurrent editing, conflicts, multi-user | Household members overlap |
|
|
21
|
+
| 5 | EMERGENCY | Interruptions, crash recovery | Browser/device failures |
|
|
22
|
+
| 6 | SECURITY | Access revocation, audit logs, session expiry | Role changes, expiring auth |
|
|
23
|
+
| 7 | INFRA | Server crash, RTO<15m, RPO<5m, offline | Service resilience |
|
|
24
|
+
| 8 | LOCALE | Vietnamese diacritics, VND, GMT+7, overflow | Local UX correctness |
|
|
25
|
+
|
|
26
|
+
## Axis Combination Matrix (Test Where X)
|
|
27
|
+
| Axis | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|
|
28
|
+
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
|
29
|
+
| 1 TIME | - | X | X | X | X | X | X | X |
|
|
30
|
+
| 2 DATA | X | - | X | X | | X | X | X |
|
|
31
|
+
| 3 ERROR | X | X | - | X | X | | X | X |
|
|
32
|
+
| 4 COLLAB | X | X | X | - | | X | | X |
|
|
33
|
+
| 5 EMERGENCY | X | | X | | - | X | X | |
|
|
34
|
+
| 6 SECURITY | X | X | | X | X | - | X | X |
|
|
35
|
+
| 7 INFRA | X | X | X | | X | X | - | X |
|
|
36
|
+
| 8 LOCALE | X | X | X | X | | X | X | - |
|
|
37
|
+
|
|
38
|
+
## Stress Scenarios
|
|
39
|
+
|
|
40
|
+
### Axis 1: TIME
|
|
41
|
+
| # | Scenario | Steps | Expected | Priority |
|
|
42
|
+
| --- | --- | --- | --- | --- |
|
|
43
|
+
| S-TIME-001 | Bulk add 500 pantry items before dinner | Start timer 2 min, import CSV of pantry items | Import completes, progress visible, no timeout | P1 |
|
|
44
|
+
| S-TIME-002 | Rapid meal plan edits during 10-min window | Update 10 meals in 60s, save each | Saves succeed, no stale data, UI responsive | P1 |
|
|
45
|
+
| S-TIME-003 | Shopping list sync under poor network | Add 30 items quickly, toggle offline/online | Sync resolves within 60s, no duplicates | P2 |
|
|
46
|
+
| S-TIME-004 | Finance entry auto-save timeout | Create expense, wait 45s idle, resume edit | Auto-save persists, no data loss | P2 |
|
|
47
|
+
|
|
48
|
+
### Axis 2: DATA
|
|
49
|
+
| # | Scenario | Steps | Expected | Priority |
|
|
50
|
+
| S-DATA-001 | Inventory list 1000+ items | Load inventory with 1200 items | Scroll, search, filter remain under 2s | P1 |
|
|
51
|
+
| S-DATA-002 | Shopping history filter speed | Filter 800 past purchases by category | Results appear under 2s, no UI freeze | P2 |
|
|
52
|
+
| S-DATA-003 | Meal plan calendar 6 months | Open 6-month plan view with 180 entries | Render within 3s, no layout shift | P2 |
|
|
53
|
+
| S-DATA-004 | Finance ledger export 2000 rows | Export 2k ledger rows to CSV | Export completes, file accurate | P2 |
|
|
54
|
+
|
|
55
|
+
### Axis 3: ERROR
|
|
56
|
+
| # | Scenario | Steps | Expected | Priority |
|
|
57
|
+
| S-ERROR-001 | Undo/redo inventory quantity changes | Change item qty 5 times, undo 5, redo 5 | Exact state restored each step | P1 |
|
|
58
|
+
| S-ERROR-002 | Auto-save recovery after crash | Edit meal notes, force close tab, reopen | Draft restored with last autosave | P1 |
|
|
59
|
+
| S-ERROR-003 | Validation error messages | Add expense with negative value | Clear inline error, no save | P2 |
|
|
60
|
+
| S-ERROR-004 | Failed bulk import rollback | Import malformed CSV for pantry | No partial data, error list shown | P1 |
|
|
61
|
+
|
|
62
|
+
### Axis 4: COLLAB
|
|
63
|
+
| # | Scenario | Steps | Expected | Priority |
|
|
64
|
+
| S-COLLAB-001 | Two users edit shopping list | User A adds 5 items, User B deletes 2 | Conflict warning, final list consistent | P1 |
|
|
65
|
+
| S-COLLAB-002 | Concurrent budget updates | Two users change monthly budget | Latest change prompts merge dialog | P2 |
|
|
66
|
+
| S-COLLAB-003 | Shared meal plan edit | User A updates recipe, User B updates servings | Both changes applied without loss | P2 |
|
|
67
|
+
| S-COLLAB-004 | New member joins household | Invite new user during active edits | New user sees updated list | P3 |
|
|
68
|
+
|
|
69
|
+
### Axis 5: EMERGENCY
|
|
70
|
+
| # | Scenario | Steps | Expected | Priority |
|
|
71
|
+
| S-EMERGENCY-001 | Browser crash while editing | Edit grocery item notes, kill browser | Reopen, draft restored | P1 |
|
|
72
|
+
| S-EMERGENCY-002 | Power loss during bulk update | Start bulk pantry update, go offline | Partial changes queued or rolled back | P1 |
|
|
73
|
+
| S-EMERGENCY-003 | Device sleep mid-sync | Start sync, close laptop lid | Resume sync without duplication | P2 |
|
|
74
|
+
| S-EMERGENCY-004 | App reload mid-transaction | Save expense, hit refresh instantly | No double charge, one entry saved | P2 |
|
|
75
|
+
|
|
76
|
+
### Axis 6: SECURITY
|
|
77
|
+
| # | Scenario | Steps | Expected | Priority |
|
|
78
|
+
| S-SECURITY-001 | Access revoked during edit | Admin removes user role mid-edit | User warned, changes blocked, data safe | P1 |
|
|
79
|
+
| S-SECURITY-002 | Session expiry while shopping | Session expires, user adds item | Redirect to login, item queued | P1 |
|
|
80
|
+
| S-SECURITY-003 | Audit log for finance edits | Edit expense amount | Audit entry with user, time, change | P2 |
|
|
81
|
+
| S-SECURITY-004 | Private list access attempt | Non-member tries to open list | Access denied, no data leak | P1 |
|
|
82
|
+
|
|
83
|
+
### Axis 7: INFRA
|
|
84
|
+
| # | Scenario | Steps | Expected | Priority |
|
|
85
|
+
| S-INFRA-001 | Server crash during sync | Trigger sync, kill server | Retry logic, no data loss | P1 |
|
|
86
|
+
| S-INFRA-002 | RTO < 15m recovery | Simulate outage, restore service | Service back within 15m, status updated | P1 |
|
|
87
|
+
| S-INFRA-003 | RPO < 5m data recovery | Create 3 entries, failover | Max 5m data loss, latest persists | P1 |
|
|
88
|
+
| S-INFRA-004 | Offline mode for shopping list | Go offline, add 10 items | Local cache used, sync on reconnect | P2 |
|
|
89
|
+
|
|
90
|
+
### Axis 8: LOCALE
|
|
91
|
+
| # | Scenario | Steps | Expected | Priority |
|
|
92
|
+
| S-LOCALE-001 | Diacritic-insensitive search | Search "nguyen" in household members | Finds "Nguyễn" matches | P1 |
|
|
93
|
+
| S-LOCALE-002 | VND currency formatting | View finance summary | Shows "1.000.000đ" not "1,000,000" | P1 |
|
|
94
|
+
| S-LOCALE-003 | Vietnamese text overflow | Open long Vietnamese recipe names | No overflow, wraps cleanly | P2 |
|
|
95
|
+
| S-LOCALE-004 | Date format DD/MM/YYYY | View meal plan date header | Displays DD/MM/YYYY | P1 |
|
|
96
|
+
|
|
97
|
+
## Notes
|
|
98
|
+
- Attach logs, screenshots, and timings for any P1 or P2 failures.
|
|
99
|
+
- Capture device, OS, browser, and network conditions.
|
|
100
|
+
- Link to any incident or bug IDs created from results.
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# RRI-T Test Cases — {Feature Name}
|
|
2
|
+
|
|
3
|
+
**Feature:** {feature-name}
|
|
4
|
+
**Generated from:** Persona Interview ({date})
|
|
5
|
+
**Total Test Cases:** {count}
|
|
6
|
+
|
|
7
|
+
## Priority Distribution
|
|
8
|
+
| Priority | Count | Description |
|
|
9
|
+
|----------|-------|-------------|
|
|
10
|
+
| P0 | 0 | Critical — blocks release |
|
|
11
|
+
| P1 | 0 | Major — fix before release |
|
|
12
|
+
| P2 | 0 | Minor — next sprint |
|
|
13
|
+
| P3 | 0 | Trivial — backlog |
|
|
14
|
+
|
|
15
|
+
## Dimension Distribution
|
|
16
|
+
| Dimension | Count | Target Coverage |
|
|
17
|
+
|-----------|-------|----------------|
|
|
18
|
+
| D1: UI/UX | 0 | >= 85% |
|
|
19
|
+
| D2: API | 0 | >= 85% |
|
|
20
|
+
| D3: Performance | 0 | >= 70% |
|
|
21
|
+
| D4: Security | 0 | >= 85% |
|
|
22
|
+
| D5: Data Integrity | 0 | >= 85% |
|
|
23
|
+
| D6: Infrastructure | 0 | >= 70% |
|
|
24
|
+
| D7: Edge Cases | 0 | >= 85% |
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Test Cases
|
|
29
|
+
|
|
30
|
+
### TC-RRI-{FEATURE}-001
|
|
31
|
+
- **Q (Question):** As an end user, what happens when I add an inventory item while on a weak 3G connection?
|
|
32
|
+
- **A (Answer):** The item should be saved locally immediately, show a "syncing" indicator, and sync to the server when connection improves. No data loss should occur.
|
|
33
|
+
- **R (Requirement):** REQ-OFFLINE-001: App must support offline-first operations with automatic sync
|
|
34
|
+
- **P (Priority):** P0
|
|
35
|
+
- **T (Test Case):**
|
|
36
|
+
- **Preconditions:**
|
|
37
|
+
- User logged in to household
|
|
38
|
+
- Device has weak 3G connection (simulated: 500ms latency, 50% packet loss)
|
|
39
|
+
- At least 1 existing inventory item for comparison
|
|
40
|
+
- **Steps:**
|
|
41
|
+
1. Navigate to Inventory screen
|
|
42
|
+
2. Tap "Add Item" button
|
|
43
|
+
3. Fill in: Name "Gạo ST25", Quantity "5", Unit "kg", Expiration "2026-03-15"
|
|
44
|
+
4. Tap "Save"
|
|
45
|
+
5. Observe UI feedback
|
|
46
|
+
6. Wait 30 seconds
|
|
47
|
+
7. Check item appears in inventory list
|
|
48
|
+
8. Restore normal network connection
|
|
49
|
+
9. Wait for sync indicator to complete
|
|
50
|
+
10. Verify item exists on server (check from another device)
|
|
51
|
+
- **Expected Result:**
|
|
52
|
+
- Item appears in list immediately with "syncing" badge
|
|
53
|
+
- No error message shown
|
|
54
|
+
- After network restores, item syncs successfully
|
|
55
|
+
- Item visible from other devices within 5 seconds of sync
|
|
56
|
+
- **Dimension:** D3: Performance
|
|
57
|
+
- **Stress Axis:** TIME, INFRA
|
|
58
|
+
- **Source Persona:** End User
|
|
59
|
+
- **Result:** ✅ PASS
|
|
60
|
+
- **Notes:** Tested on iPhone 12 with Network Link Conditioner. Sync completed in 3.2s after network restored.
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
### TC-RRI-{FEATURE}-002
|
|
65
|
+
- **Q (Question):** As a business analyst, what happens when a household member with "viewer" role tries to delete an inventory item?
|
|
66
|
+
- **A (Answer):** The delete button should be hidden or disabled for viewers. If they somehow trigger a delete (via API manipulation), the server should reject it with a 403 Forbidden error.
|
|
67
|
+
- **R (Requirement):** REQ-RBAC-003: Viewers can only read data, not modify or delete
|
|
68
|
+
- **P (Priority):** P1
|
|
69
|
+
- **T (Test Case):**
|
|
70
|
+
- **Preconditions:**
|
|
71
|
+
- User "viewer@example.com" has "viewer" role in household "Test Family"
|
|
72
|
+
- Household has inventory item "Sữa tươi" (ID: inv_123)
|
|
73
|
+
- User logged in on mobile app
|
|
74
|
+
- **Steps:**
|
|
75
|
+
1. Login as viewer@example.com
|
|
76
|
+
2. Navigate to Inventory screen
|
|
77
|
+
3. Tap on "Sữa tươi" item to view details
|
|
78
|
+
4. Look for delete button/option
|
|
79
|
+
5. (If delete button exists) Attempt to tap it
|
|
80
|
+
6. (Alternative) Use GraphQL client to send deleteInventoryItem mutation directly
|
|
81
|
+
- **Expected Result:**
|
|
82
|
+
- Delete button should not be visible in UI
|
|
83
|
+
- If mutation sent directly, server returns error: `{"errors": [{"message": "Forbidden: insufficient permissions", "extensions": {"code": "FORBIDDEN"}}]}`
|
|
84
|
+
- Item remains in database unchanged
|
|
85
|
+
- **Dimension:** D4: Security
|
|
86
|
+
- **Stress Axis:** SECURITY
|
|
87
|
+
- **Source Persona:** Business Analyst
|
|
88
|
+
- **Result:** ⚠️ PAINFUL
|
|
89
|
+
- **Notes:** Delete button is correctly hidden, but when mutation sent via GraphQL Playground, error message is generic "Unauthorized" instead of specific "Forbidden: insufficient permissions". UX improvement: add clearer error messages for debugging. Item was NOT deleted (security works), but error clarity needs improvement.
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
### TC-RRI-{FEATURE}-003
|
|
94
|
+
- **Q (Question):** As a QA destroyer, what happens when I paste 50,000 characters into the "item name" field?
|
|
95
|
+
- **A (Answer):** The field should enforce a maximum length (e.g., 200 characters), truncate or reject input gracefully, and show a validation error. The app should not crash or freeze.
|
|
96
|
+
- **R (Requirement):** REQ-VALIDATION-005: All text inputs must have reasonable length limits
|
|
97
|
+
- **P (Priority):** P1
|
|
98
|
+
- **T (Test Case):**
|
|
99
|
+
- **Preconditions:**
|
|
100
|
+
- User logged in
|
|
101
|
+
- On "Add Inventory Item" screen
|
|
102
|
+
- Clipboard contains 50,000-character string
|
|
103
|
+
- **Steps:**
|
|
104
|
+
1. Tap into "Item Name" field
|
|
105
|
+
2. Paste 50,000-character string
|
|
106
|
+
3. Observe UI behavior
|
|
107
|
+
4. Attempt to save the form
|
|
108
|
+
- **Expected Result:**
|
|
109
|
+
- Field truncates input to max length (200 chars) OR shows validation error
|
|
110
|
+
- UI remains responsive (no freeze)
|
|
111
|
+
- Save button disabled or shows error: "Item name too long (max 200 characters)"
|
|
112
|
+
- No crash or GraphQL error
|
|
113
|
+
- **Dimension:** D7: Edge Cases
|
|
114
|
+
- **Stress Axis:** DATA, ERROR
|
|
115
|
+
- **Source Persona:** QA Destroyer
|
|
116
|
+
- **Result:** ☐ MISSING
|
|
117
|
+
- **Notes:** Feature not yet implemented. Current behavior: field accepts all 50,000 characters, UI freezes for 2-3 seconds, GraphQL mutation fails with "Payload too large" error. Need to add client-side validation and maxLength attribute.
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
### TC-RRI-{FEATURE}-004
|
|
122
|
+
- **Q (Question):** {From persona's perspective — what are they trying to do/verify?}
|
|
123
|
+
- **A (Answer):** {Expected behavior — what SHOULD happen}
|
|
124
|
+
- **R (Requirement):** {Requirement ID or description}
|
|
125
|
+
- **P (Priority):** P0 | P1 | P2 | P3
|
|
126
|
+
- **T (Test Case):**
|
|
127
|
+
- **Preconditions:** {required state}
|
|
128
|
+
- **Steps:**
|
|
129
|
+
1. {step 1}
|
|
130
|
+
2. {step 2}
|
|
131
|
+
- **Expected Result:** {specific, measurable outcome}
|
|
132
|
+
- **Dimension:** D{n}: {name}
|
|
133
|
+
- **Stress Axis:** {axis name} (if applicable)
|
|
134
|
+
- **Source Persona:** {persona name}
|
|
135
|
+
- **Result:** ✅ PASS | ❌ FAIL | ⚠️ PAINFUL | ☐ MISSING
|
|
136
|
+
- **Notes:** {observations, screenshots, bug IDs}
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
### TC-RRI-{FEATURE}-005
|
|
141
|
+
- **Q (Question):** {From persona's perspective — what are they trying to do/verify?}
|
|
142
|
+
- **A (Answer):** {Expected behavior — what SHOULD happen}
|
|
143
|
+
- **R (Requirement):** {Requirement ID or description}
|
|
144
|
+
- **P (Priority):** P0 | P1 | P2 | P3
|
|
145
|
+
- **T (Test Case):**
|
|
146
|
+
- **Preconditions:** {required state}
|
|
147
|
+
- **Steps:**
|
|
148
|
+
1. {step 1}
|
|
149
|
+
2. {step 2}
|
|
150
|
+
- **Expected Result:** {specific, measurable outcome}
|
|
151
|
+
- **Dimension:** D{n}: {name}
|
|
152
|
+
- **Stress Axis:** {axis name} (if applicable)
|
|
153
|
+
- **Source Persona:** {persona name}
|
|
154
|
+
- **Result:** ✅ PASS | ❌ FAIL | ⚠️ PAINFUL | ☐ MISSING
|
|
155
|
+
- **Notes:** {observations, screenshots, bug IDs}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "rri-t-testing",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "RRI-T QA methodology — 5-phase testing (PREPARE, DISCOVER, STRUCTURE, EXECUTE, ANALYZE) with 7 dimensions, 5 personas, and release gates",
|
|
5
|
+
"compatibility": "OpenCode",
|
|
6
|
+
"agent": null,
|
|
7
|
+
"commands": [],
|
|
8
|
+
"tags": ["testing", "qa", "rri-t", "release-gates", "test-cases"]
|
|
9
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
3
|
"title": "Agent Skill Tools Cache v2.0.0",
|
|
4
|
-
"description": "Cache file for
|
|
4
|
+
"description": "Cache file for tool routing. Generated by /skill-refresh command using semantic AI categorization.",
|
|
5
5
|
"type": "object",
|
|
6
6
|
"properties": {
|
|
7
7
|
"version": {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
3
|
"title": "Agent Skill Workflow Definition",
|
|
4
|
-
"description": "Schema for defining prerequisite workflows in
|
|
4
|
+
"description": "Schema for defining prerequisite workflows in Skill Manager",
|
|
5
5
|
"type": "object",
|
|
6
6
|
"properties": {
|
|
7
7
|
"enabled": {
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
## Automatic Retry Mechanism
|
|
14
14
|
|
|
15
|
-
The
|
|
15
|
+
The skill-manager automatically retries failed tool executions before returning errors.
|
|
16
16
|
|
|
17
17
|
### Retry Configuration
|
|
18
18
|
- Maximum attempts: 3
|
|
@@ -67,7 +67,7 @@ Template:
|
|
|
67
67
|
```
|
|
68
68
|
Error: Tool not found: <tool-id>
|
|
69
69
|
Suggestions: <tool-a>, <tool-b>, <tool-c>
|
|
70
|
-
Next: confirm the intended tool or run /
|
|
70
|
+
Next: confirm the intended tool or run /skill-refresh.
|
|
71
71
|
```
|
|
72
72
|
|
|
73
73
|
## Execution Failure Handling
|
|
@@ -113,18 +113,18 @@ Next: confirm retry with new parameters
|
|
|
113
113
|
|
|
114
114
|
## Cache Missing Recovery
|
|
115
115
|
Symptoms:
|
|
116
|
-
- `.opencode/
|
|
116
|
+
- `.opencode/skill-tools.json` missing.
|
|
117
117
|
- Cache file invalid or unreadable.
|
|
118
118
|
|
|
119
119
|
Recovery steps:
|
|
120
120
|
1. Inform that cache is missing or invalid.
|
|
121
|
-
2. Recommend /
|
|
121
|
+
2. Recommend /skill-refresh to regenerate.
|
|
122
122
|
3. Proceed with dynamic tool discovery if possible.
|
|
123
123
|
|
|
124
124
|
Template:
|
|
125
125
|
```
|
|
126
|
-
Cache missing or invalid at .opencode/
|
|
127
|
-
Suggestion: run /
|
|
126
|
+
Cache missing or invalid at .opencode/skill-tools.json
|
|
127
|
+
Suggestion: run /skill-refresh
|
|
128
128
|
Fallback: dynamic discovery enabled
|
|
129
129
|
```
|
|
130
130
|
|
|
@@ -247,7 +247,7 @@ Decision tree (text form):
|
|
|
247
247
|
- Yes -> request corrected params.
|
|
248
248
|
- No -> continue.
|
|
249
249
|
5. Is cache missing?
|
|
250
|
-
- Yes -> recommend /
|
|
250
|
+
- Yes -> recommend /skill-refresh and use dynamic discovery.
|
|
251
251
|
- No -> continue.
|
|
252
252
|
6. Unknown failure
|
|
253
253
|
- Provide generic error template and ask for clarification.
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
This skill uses **semantic categorization**:
|
|
8
8
|
|
|
9
|
-
1. **Tool discovery** - `/
|
|
9
|
+
1. **Tool discovery** - `/skill-refresh` enumerates all tools available to the agent
|
|
10
10
|
2. **Semantic analysis** - the AI reads each tool's **name + description**
|
|
11
11
|
3. **Dynamic grouping** - tools are grouped into categories based on what they do
|
|
12
12
|
|
|
@@ -31,12 +31,12 @@ categories are **labels**, not fixed contracts, and can evolve with the tool set
|
|
|
31
31
|
|
|
32
32
|
- Categories are **not hard-coded**
|
|
33
33
|
- Category names are **derived from the tools** at refresh time
|
|
34
|
-
- Custom
|
|
35
|
-
- The system works with any
|
|
34
|
+
- Custom tool servers are handled automatically
|
|
35
|
+
- The system works with any tool configuration (MetaMCP, standalone, or custom)
|
|
36
36
|
|
|
37
37
|
## Cache File (v2.0.0) - How to Read It
|
|
38
38
|
|
|
39
|
-
The `/
|
|
39
|
+
The `/skill-refresh` command writes a cache file using the v2.0.0 schema. This
|
|
40
40
|
file is the **source of truth** for the current categorization state.
|
|
41
41
|
|
|
42
42
|
### Schema Overview
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
# Do not include category catalogs, result summarization, or error templates here.
|
|
4
4
|
|
|
5
5
|
## Cache Access and Reading
|
|
6
|
-
Cache location: .opencode/
|
|
7
|
-
Purpose: fast tool routing without reloading full
|
|
6
|
+
Cache location: .opencode/skill-tools.json
|
|
7
|
+
Purpose: fast tool routing without reloading full tool schemas.
|
|
8
8
|
|
|
9
9
|
How to read the cache:
|
|
10
|
-
1. Check if file exists at project root `.opencode/
|
|
10
|
+
1. Check if file exists at project root `.opencode/skill-tools.json`.
|
|
11
11
|
2. Parse JSON into a structured object.
|
|
12
12
|
3. Validate minimal fields: version, refreshed_at, tool_count, categories.
|
|
13
13
|
4. If missing or malformed, fall back to dynamic discovery.
|
|
@@ -18,10 +18,10 @@ Cache staleness heuristic:
|
|
|
18
18
|
|
|
19
19
|
## Cache Schema (TypeScript Interface)
|
|
20
20
|
```ts
|
|
21
|
-
interface
|
|
21
|
+
interface SkillToolCache {
|
|
22
22
|
version: string;
|
|
23
23
|
refreshed_at: string; // ISO string
|
|
24
|
-
|
|
24
|
+
tool_sources: string[];
|
|
25
25
|
tool_count: number;
|
|
26
26
|
categories: {
|
|
27
27
|
[name: string]: {
|
|
@@ -156,7 +156,7 @@ params: { fullPage: true }
|
|
|
156
156
|
## When to Avoid Cache
|
|
157
157
|
- During tool upgrades or when discrepancies are reported.
|
|
158
158
|
- When a tool id from cache fails execution.
|
|
159
|
-
- When the user references a new
|
|
159
|
+
- When the user references a new tool server prefix.
|
|
160
160
|
|
|
161
161
|
## Execution Prerequisites
|
|
162
162
|
- Ensure selected tool exists in cache or registry.
|
|
@@ -234,7 +234,7 @@ Tool: sequentialthinking { thought: "...", thoughtNumber: 1, totalThoughts: 4, n
|
|
|
234
234
|
## Cache Refresh Recommendation Text
|
|
235
235
|
Recommended message:
|
|
236
236
|
```
|
|
237
|
-
Cache appears stale or missing. Run /
|
|
237
|
+
Cache appears stale or missing. Run /skill-refresh to rebuild tool metadata.
|
|
238
238
|
```
|
|
239
239
|
|
|
240
240
|
## Execution Output Metadata (Internal)
|
|
@@ -70,7 +70,7 @@ Each prerequisite step has:
|
|
|
70
70
|
|
|
71
71
|
## Session State
|
|
72
72
|
|
|
73
|
-
Completed prerequisites are tracked in `.opencode/.
|
|
73
|
+
Completed prerequisites are tracked in `.opencode/.skill-session.json`:
|
|
74
74
|
|
|
75
75
|
```json
|
|
76
76
|
{
|
|
@@ -202,26 +202,26 @@ Also matched: 'custom-db-workflow'
|
|
|
202
202
|
|
|
203
203
|
## Managing Workflows
|
|
204
204
|
|
|
205
|
-
Use `/
|
|
205
|
+
Use `/skill-workflow` command:
|
|
206
206
|
|
|
207
207
|
```bash
|
|
208
208
|
# List all workflows
|
|
209
|
-
/
|
|
209
|
+
/skill-workflow list
|
|
210
210
|
|
|
211
211
|
# Add from template
|
|
212
|
-
/
|
|
212
|
+
/skill-workflow add --template database
|
|
213
213
|
|
|
214
214
|
# Add custom workflow
|
|
215
|
-
/
|
|
215
|
+
/skill-workflow add my-workflow
|
|
216
216
|
|
|
217
217
|
# Edit existing
|
|
218
|
-
/
|
|
218
|
+
/skill-workflow edit my-workflow
|
|
219
219
|
|
|
220
220
|
# Disable temporarily
|
|
221
|
-
/
|
|
221
|
+
/skill-workflow disable my-workflow
|
|
222
222
|
|
|
223
223
|
# Remove
|
|
224
|
-
/
|
|
224
|
+
/skill-workflow remove my-workflow
|
|
225
225
|
```
|
|
226
226
|
|
|
227
227
|
## Best Practices
|
|
@@ -230,4 +230,4 @@ Use `/agent-skill-workflow` command:
|
|
|
230
230
|
2. **Use enforce sparingly** - Only for critical safety workflows
|
|
231
231
|
3. **Keep prerequisites minimal** - Each step adds latency
|
|
232
232
|
4. **Mark optional steps** - Use `required: false` for nice-to-have steps
|
|
233
|
-
5. **Review session state** - Check `.
|
|
233
|
+
5. **Review session state** - Check `.skill-session.json` if prerequisites seem stuck
|
package/dist/install.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function install(): Promise<void>;
|
package/dist/install.js
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.install = install;
|
|
7
|
-
const path_1 = __importDefault(require("path"));
|
|
8
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
-
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
10
|
-
const utils_1 = require("./utils");
|
|
11
|
-
async function install() {
|
|
12
|
-
const paths = await (0, utils_1.detectOpenCodePaths)();
|
|
13
|
-
await (0, utils_1.ensureDirExists)(paths.commandDir);
|
|
14
|
-
await (0, utils_1.ensureDirExists)(paths.skillsDir);
|
|
15
|
-
const skillTargetDir = path_1.default.join(paths.skillsDir, utils_1.SKILL_DIR_NAME);
|
|
16
|
-
const commandTargetPath = path_1.default.join(paths.commandDir, "agent-skill-refresh.md");
|
|
17
|
-
await fs_extra_1.default.copy(paths.templateSkillDir, skillTargetDir, { overwrite: true });
|
|
18
|
-
const commandTemplate = await (0, utils_1.readText)(paths.templateCommandPath);
|
|
19
|
-
await (0, utils_1.writeText)(commandTargetPath, commandTemplate);
|
|
20
|
-
const agentTemplate = await (0, utils_1.readJsonFile)(paths.templateAgentPath, {});
|
|
21
|
-
const agentConfig = await (0, utils_1.readJsonFile)(paths.agentConfigPath, {});
|
|
22
|
-
const agents = (agentConfig.agents || {});
|
|
23
|
-
const templateAgents = (agentTemplate.agents || agentTemplate);
|
|
24
|
-
agentConfig.agents = { ...agents, ...templateAgents };
|
|
25
|
-
await (0, utils_1.writeJsonFile)(paths.agentConfigPath, agentConfig);
|
|
26
|
-
await (0, utils_1.writeJsonFile)(paths.versionFilePath, { version: utils_1.PACKAGE_VERSION, installedAt: new Date().toISOString() });
|
|
27
|
-
const state = await (0, utils_1.getInstallationState)(paths);
|
|
28
|
-
if (!state.skillInstalled || !state.commandInstalled || !state.agentInstalled) {
|
|
29
|
-
throw new Error("Installation verification failed. Some files were not installed.");
|
|
30
|
-
}
|
|
31
|
-
if (Object.keys(agentConfig).length > 0 && Object.prototype.hasOwnProperty.call(agentConfig, utils_1.AGENT_ID)) {
|
|
32
|
-
console.log(chalk_1.default.yellow("agent-skill-manager agent already existed; configuration was updated."));
|
|
33
|
-
}
|
|
34
|
-
console.log(chalk_1.default.green("Agent skill manager installed successfully."));
|
|
35
|
-
}
|
package/dist/remove.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function remove(): Promise<void>;
|
package/dist/remove.js
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.remove = remove;
|
|
7
|
-
const path_1 = __importDefault(require("path"));
|
|
8
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
-
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
10
|
-
const utils_1 = require("./utils");
|
|
11
|
-
async function remove() {
|
|
12
|
-
const paths = await (0, utils_1.detectOpenCodePaths)();
|
|
13
|
-
const skillTargetDir = path_1.default.join(paths.skillsDir, utils_1.SKILL_DIR_NAME);
|
|
14
|
-
const commandTargetPath = path_1.default.join(paths.commandDir, "agent-skill-refresh.md");
|
|
15
|
-
if (await fs_extra_1.default.pathExists(skillTargetDir)) {
|
|
16
|
-
await fs_extra_1.default.remove(skillTargetDir);
|
|
17
|
-
}
|
|
18
|
-
if (await fs_extra_1.default.pathExists(commandTargetPath)) {
|
|
19
|
-
await fs_extra_1.default.remove(commandTargetPath);
|
|
20
|
-
}
|
|
21
|
-
const agentConfig = await (0, utils_1.readJsonFile)(paths.agentConfigPath, {});
|
|
22
|
-
const agents = (agentConfig.agents || {});
|
|
23
|
-
if (Object.prototype.hasOwnProperty.call(agents, utils_1.AGENT_ID)) {
|
|
24
|
-
delete agents[utils_1.AGENT_ID];
|
|
25
|
-
agentConfig.agents = agents;
|
|
26
|
-
await (0, utils_1.writeJsonFile)(paths.agentConfigPath, agentConfig);
|
|
27
|
-
}
|
|
28
|
-
if (await fs_extra_1.default.pathExists(paths.versionFilePath)) {
|
|
29
|
-
await fs_extra_1.default.remove(paths.versionFilePath);
|
|
30
|
-
}
|
|
31
|
-
console.log(chalk_1.default.green("Agent skill manager removed successfully."));
|
|
32
|
-
}
|
package/dist/update.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function update(): Promise<void>;
|
package/dist/update.js
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.update = update;
|
|
7
|
-
const path_1 = __importDefault(require("path"));
|
|
8
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
-
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
10
|
-
const utils_1 = require("./utils");
|
|
11
|
-
async function update() {
|
|
12
|
-
const paths = await (0, utils_1.detectOpenCodePaths)();
|
|
13
|
-
await (0, utils_1.ensureDirExists)(paths.commandDir);
|
|
14
|
-
await (0, utils_1.ensureDirExists)(paths.skillsDir);
|
|
15
|
-
const skillTargetDir = path_1.default.join(paths.skillsDir, utils_1.SKILL_DIR_NAME);
|
|
16
|
-
const commandTargetPath = path_1.default.join(paths.commandDir, "agent-skill-refresh.md");
|
|
17
|
-
await (0, utils_1.ensureDirExists)(skillTargetDir);
|
|
18
|
-
const state = await (0, utils_1.getInstallationState)(paths);
|
|
19
|
-
if (state.installedVersion === utils_1.PACKAGE_VERSION) {
|
|
20
|
-
console.log(chalk_1.default.green("Agent skill manager is already up to date."));
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
const [skillCustomized, commandCustomized] = await Promise.all([
|
|
24
|
-
(0, utils_1.directoryDiffersFromTemplate)(skillTargetDir, paths.templateSkillDir),
|
|
25
|
-
(0, utils_1.fileDiffersFromTemplate)(commandTargetPath, paths.templateCommandPath),
|
|
26
|
-
]);
|
|
27
|
-
if (skillCustomized || commandCustomized) {
|
|
28
|
-
console.log(chalk_1.default.yellow("Detected customized files. Backups will be created before update."));
|
|
29
|
-
}
|
|
30
|
-
if (await fs_extra_1.default.pathExists(skillTargetDir)) {
|
|
31
|
-
console.log(chalk_1.default.yellow("Backing up existing skill directory before update."));
|
|
32
|
-
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
33
|
-
const backupDir = `${skillTargetDir}.backup-${timestamp}.bak`;
|
|
34
|
-
await fs_extra_1.default.copy(skillTargetDir, backupDir, { overwrite: true });
|
|
35
|
-
}
|
|
36
|
-
if (await fs_extra_1.default.pathExists(commandTargetPath)) {
|
|
37
|
-
await (0, utils_1.backupFile)(commandTargetPath, "backup");
|
|
38
|
-
}
|
|
39
|
-
if (await fs_extra_1.default.pathExists(paths.agentConfigPath)) {
|
|
40
|
-
await (0, utils_1.backupFile)(paths.agentConfigPath, "backup");
|
|
41
|
-
}
|
|
42
|
-
await fs_extra_1.default.copy(paths.templateSkillDir, skillTargetDir, { overwrite: true });
|
|
43
|
-
const commandTemplate = await fs_extra_1.default.readFile(paths.templateCommandPath, "utf8");
|
|
44
|
-
await fs_extra_1.default.writeFile(commandTargetPath, commandTemplate, "utf8");
|
|
45
|
-
const agentTemplate = await (0, utils_1.readJsonFile)(paths.templateAgentPath, {});
|
|
46
|
-
const agentConfig = await (0, utils_1.readJsonFile)(paths.agentConfigPath, {});
|
|
47
|
-
const agents = (agentConfig.agents || {});
|
|
48
|
-
const templateAgents = (agentTemplate.agents || agentTemplate);
|
|
49
|
-
agentConfig.agents = { ...agents, ...templateAgents };
|
|
50
|
-
await (0, utils_1.writeJsonFile)(paths.agentConfigPath, agentConfig);
|
|
51
|
-
await (0, utils_1.writeJsonFile)(paths.versionFilePath, { version: utils_1.PACKAGE_VERSION, updatedAt: new Date().toISOString() });
|
|
52
|
-
console.log(chalk_1.default.green("Agent skill manager updated successfully."));
|
|
53
|
-
}
|