@ngocsangairvds/vsaf 4.0.1 → 4.0.2
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/package.json +1 -1
- package/packages/cli/dist/commands/install.d.ts.map +1 -1
- package/packages/cli/dist/commands/install.js +13 -0
- package/packages/cli/dist/commands/install.js.map +1 -1
- package/skills/sdlc/discovery/SKILL.md +20 -5
- package/skills/sdlc/implement/SKILL.md +47 -14
- package/skills/sdlc/pack.yaml +1 -1
- package/skills/vds-skill/_shared/credentials.sh +79 -0
- package/skills/vds-skill/create-bitbucket-pr/SKILL.md +47 -0
- package/skills/vds-skill/create-bitbucket-pr/scripts/create-pr.sh +107 -0
- package/skills/vds-skill/create-jira-epic/SKILL.md +46 -0
- package/skills/vds-skill/create-jira-epic/scripts/create-epic.sh +113 -0
- package/skills/vds-skill/pack.yaml +24 -0
- package/skills/vds-skill/pull/SKILL.md +38 -0
- package/skills/vds-skill/pull/scripts/pull.sh +52 -0
- package/skills/vds-skill/push-prd/SKILL.md +218 -0
- package/skills/vds-skill/push-srs/SKILL.md +108 -0
- package/skills/vds-skill/search-confluence/SKILL.md +44 -0
- package/skills/vds-skill/search-confluence/scripts/search.sh +137 -0
- package/skills/vds-skill/vds-scripts-skill/.openskills.json +6 -0
- package/skills/vds-skill/vds-scripts-skill/QUALITY.md +44 -0
- package/skills/vds-skill/vds-scripts-skill/SKILL.md +127 -0
- package/skills/vds-skill/vds-scripts-skill/references/audit-commands.md +171 -0
- package/skills/vds-skill/vds-scripts-skill/references/capability-index.md +34 -0
- package/skills/vds-skill/vds-scripts-skill/references/development-commands.md +12 -0
- package/skills/vds-skill/vds-scripts-skill/references/google-sheets.md +71 -0
- package/skills/vds-skill/vds-scripts-skill/references/integration-commands.md +17 -0
- package/skills/vds-skill/vds-scripts-skill/references/platform-bootstrap.md +31 -0
- package/skills/vds-skill/vds-scripts-skill/references/specialist-routing.md +14 -0
- package/skills/vds-skill/vds-scripts-skill/references/validation-commands.md +15 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
name: vds-skill
|
|
2
|
+
version: 1.0.0
|
|
3
|
+
description: Viettel VDS automation skills — opt-in pack wrapping vds-cli for Confluence/Jira/Bitbucket integration with SDLC flow
|
|
4
|
+
author: "@ngocsangairvds/vsaf"
|
|
5
|
+
|
|
6
|
+
# Skills deployed WITH prefix: /vds-skill-<name>
|
|
7
|
+
skills:
|
|
8
|
+
# Knowledge sync
|
|
9
|
+
- pull # /vds-skill-pull — git pull + stale index detection
|
|
10
|
+
|
|
11
|
+
# Discovery enrichment (helper for Phase 1)
|
|
12
|
+
- search-confluence # /vds-skill-search-confluence — search Confluence + Jira for historical context
|
|
13
|
+
|
|
14
|
+
# PRD/SRS publication (helper for Phase 2/4)
|
|
15
|
+
- push-prd # /vds-skill-push-prd — push PRD to Confluence via vds-cli
|
|
16
|
+
- push-srs # /vds-skill-push-srs — push SRS to Confluence via vds-cli + link PRD
|
|
17
|
+
|
|
18
|
+
# Epic/PR creation (helper for Phase 2/9)
|
|
19
|
+
- create-jira-epic # /vds-skill-create-jira-epic — create Jira Epic from PRD
|
|
20
|
+
- create-bitbucket-pr # /vds-skill-create-bitbucket-pr — create Bitbucket PR after ship
|
|
21
|
+
|
|
22
|
+
# Bundled external skills — deployed WITHOUT prefix (as-is)
|
|
23
|
+
bundled:
|
|
24
|
+
- vds-scripts-skill # /vds-scripts-skill — platform-routing skill (imported from /Downloads/vds-scripts/)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: vds-skill-pull
|
|
3
|
+
description: Pull latest code via `git pull` then detect stale local knowledge index (`.gitnexus/`, `graphify-out/graph.json`) by comparing mtime with `.git/FETCH_HEAD`. Suggest `/sdlc-onboard-code` if stale. Use instead of bare `git pull` for projects using SDLC pack.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /vds-skill-pull
|
|
7
|
+
|
|
8
|
+
Wrapper for `git pull` that detects stale local knowledge index after pull and suggests rebuild.
|
|
9
|
+
|
|
10
|
+
## Usage
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
/vds-skill-pull # equivalent to `git pull`
|
|
14
|
+
/vds-skill-pull --rebase # forwards args to git pull
|
|
15
|
+
/vds-skill-pull origin main # also forwards
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Behavior
|
|
19
|
+
|
|
20
|
+
1. Run `git pull` with all passed args
|
|
21
|
+
2. If pull succeeds, check `.gitnexus/` and `graphify-out/graph.json` mtime vs `.git/FETCH_HEAD`
|
|
22
|
+
3. If any stale → print suggestion to run `/sdlc-onboard-code`
|
|
23
|
+
4. Exit 0 (advisory, does not block workflow)
|
|
24
|
+
|
|
25
|
+
## Implementation
|
|
26
|
+
|
|
27
|
+
Invoke the bundled script:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
bash ~/.claude/skills/vds-skill-pull/scripts/pull.sh "$@"
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Notes
|
|
34
|
+
|
|
35
|
+
- Works for both Viettel and non-Viettel projects (no vds-cli dependency).
|
|
36
|
+
- If `.gitnexus/` or `graphify-out/` does not exist, that's OK — only flagged if present-but-stale.
|
|
37
|
+
- Skill exits 0 even when knowledge is stale (advisory only — user decides whether to onboard now or later).
|
|
38
|
+
- `.gitnexus/` staleness uses directory mtime — this catches new files but may miss in-place edits. If GitNexus rewrites files without re-creating them, the check could give a false "fresh" reading. Acceptable for advisory mode.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# vds-skill-pull: git pull + detect stale local knowledge index
|
|
3
|
+
# Exit codes: forwards `git pull` exit code (0 on success even if knowledge stale)
|
|
4
|
+
|
|
5
|
+
# Run git pull, forwarding all args. Capture exit code for explicit forwarding.
|
|
6
|
+
# (No `set -e` — we want full control of the exit-code path for the advisory stale check.)
|
|
7
|
+
git pull "$@"
|
|
8
|
+
EXIT=$?
|
|
9
|
+
|
|
10
|
+
if [[ $EXIT -ne 0 ]]; then
|
|
11
|
+
exit $EXIT
|
|
12
|
+
fi
|
|
13
|
+
|
|
14
|
+
# Skip stale check if not a fetch-based pull (e.g., --no-rebase --quiet might skip FETCH_HEAD)
|
|
15
|
+
if [[ ! -f .git/FETCH_HEAD ]]; then
|
|
16
|
+
exit 0
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
FETCH_HEAD_MTIME=$(stat -c %Y .git/FETCH_HEAD 2>/dev/null || stat -f %m .git/FETCH_HEAD 2>/dev/null || echo 0)
|
|
20
|
+
STALE_REASONS=()
|
|
21
|
+
|
|
22
|
+
# Check .gitnexus/
|
|
23
|
+
if [[ -d .gitnexus ]]; then
|
|
24
|
+
GITNEXUS_MTIME=$(stat -c %Y .gitnexus 2>/dev/null || stat -f %m .gitnexus 2>/dev/null || echo 0)
|
|
25
|
+
if [[ $GITNEXUS_MTIME -lt $FETCH_HEAD_MTIME ]]; then
|
|
26
|
+
STALE_REASONS+=(".gitnexus/ index older than fetched commits")
|
|
27
|
+
fi
|
|
28
|
+
fi
|
|
29
|
+
# Note: .gitnexus missing is OK (project may not use GitNexus)
|
|
30
|
+
|
|
31
|
+
# Check graphify-out/graph.json
|
|
32
|
+
if [[ -f graphify-out/graph.json ]]; then
|
|
33
|
+
GRAPH_MTIME=$(stat -c %Y graphify-out/graph.json 2>/dev/null || stat -f %m graphify-out/graph.json 2>/dev/null || echo 0)
|
|
34
|
+
if [[ $GRAPH_MTIME -lt $FETCH_HEAD_MTIME ]]; then
|
|
35
|
+
STALE_REASONS+=("graphify-out/graph.json older than fetched commits")
|
|
36
|
+
fi
|
|
37
|
+
fi
|
|
38
|
+
# Note: graphify-out missing is OK
|
|
39
|
+
|
|
40
|
+
# Print suggestion if anything stale
|
|
41
|
+
if [[ ${#STALE_REASONS[@]} -gt 0 ]]; then
|
|
42
|
+
echo ""
|
|
43
|
+
echo "⚠️ Knowledge index có thể stale sau pull:"
|
|
44
|
+
for reason in "${STALE_REASONS[@]}"; do
|
|
45
|
+
echo " - $reason"
|
|
46
|
+
done
|
|
47
|
+
echo ""
|
|
48
|
+
echo " Khuyến nghị: chạy /sdlc-onboard-code để rebuild GitNexus + Graphify locally."
|
|
49
|
+
echo ""
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
exit 0
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: vds-skill-push-prd
|
|
3
|
+
description: Push PRD markdown to Viettel Confluence via vds-cli. Converts markdown → Confluence Storage Format (XHTML), searches for existing page, creates or updates. Use after /sdlc-prd has produced 02-prd.md. Viettel-only (requires vds-cli).
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /vds-skill-push-prd
|
|
7
|
+
|
|
8
|
+
Publish the current PRD to Viettel Confluence via `vds-cli` — create a new page if it doesn't exist, or update the existing one. The optional `[comment]` becomes the Confluence version note.
|
|
9
|
+
|
|
10
|
+
## Input
|
|
11
|
+
|
|
12
|
+
- `[file]` — optional path to a specific markdown file. Default: scan `.vsaf/docs/features/*/02-prd.md`
|
|
13
|
+
- `[comment]` — optional version note (e.g., "Initial draft", "Updated after stakeholder review")
|
|
14
|
+
|
|
15
|
+
## Prerequisites
|
|
16
|
+
|
|
17
|
+
- `vds-cli` installed (`command -v vds-cli`)
|
|
18
|
+
- A PRD markdown file must exist
|
|
19
|
+
- `VDS_CONFLUENCE_TOKEN` set OR will be lazy-prompted (via `source ~/.claude/skills/_shared/vds-skill/credentials.sh; ensure_env`)
|
|
20
|
+
- Confluence space + parent page configured in `.vsaf/config.yaml` (or lazy-prompted)
|
|
21
|
+
|
|
22
|
+
## Steps
|
|
23
|
+
|
|
24
|
+
### Step 1 — Find PRD file
|
|
25
|
+
|
|
26
|
+
- If `[file]` given: use directly
|
|
27
|
+
- Otherwise: list `.vsaf/docs/features/*/02-prd.md`
|
|
28
|
+
- Multiple: ask user which one
|
|
29
|
+
- None: STOP — tell user to run `/sdlc-prd` first
|
|
30
|
+
- Read full file content
|
|
31
|
+
|
|
32
|
+
### Step 2 — Load Confluence config
|
|
33
|
+
|
|
34
|
+
Read `.vsaf/config.yaml` (or `.vsaf/_bmad/bmm/config.yaml`) and extract:
|
|
35
|
+
- `confluence_space_key`
|
|
36
|
+
- `confluence_parent_page`
|
|
37
|
+
|
|
38
|
+
If missing: lazy-prompt + persist via `_shared/credentials.sh ensure_env`.
|
|
39
|
+
|
|
40
|
+
### Step 3 — Determine page title
|
|
41
|
+
|
|
42
|
+
- For `02-prd.md` under `features/{feature-name}/`: title = `[PRD] {Feature Name}` (derived from folder name)
|
|
43
|
+
- Otherwise: use first `# Heading` in file, or filename stem
|
|
44
|
+
|
|
45
|
+
### Step 4 — Convert markdown → Confluence storage format (XHTML)
|
|
46
|
+
|
|
47
|
+
**CRITICAL RULES:**
|
|
48
|
+
|
|
49
|
+
1. **Never send raw markdown.** All content must be converted to Confluence Storage Format (XHTML).
|
|
50
|
+
2. **Never wrap entire body in `<![CDATA[...]]>`.** CDATA is ONLY valid inside `<ac:plain-text-body>` within code macros.
|
|
51
|
+
3. **All Confluence macro attributes MUST use `ac:` namespace prefix.** The tag is `<ac:parameter ac:name="...">`, never `<parameter name="...">`.
|
|
52
|
+
4. **Escape HTML entities in regular text:** `&` → `&`, `<` → `<`, `>` → `>`.
|
|
53
|
+
5. **Every opened tag must be closed.** Confluence XML parser is strict.
|
|
54
|
+
|
|
55
|
+
**Block elements:**
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
# Heading → <h1>Heading</h1>
|
|
59
|
+
## Heading → <h2>Heading</h2>
|
|
60
|
+
### Heading → <h3>Heading</h3>
|
|
61
|
+
#### Heading → <h4>Heading</h4>
|
|
62
|
+
paragraph → <p>paragraph</p>
|
|
63
|
+
--- → <hr/>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**Inline elements:**
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
**bold** → <strong>bold</strong>
|
|
70
|
+
*italic* → <em>italic</em>
|
|
71
|
+
`code` → <code>code</code>
|
|
72
|
+
[text](url) → <a href="url">text</a>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**Lists:**
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
- item → <ul><li>item</li></ul>
|
|
79
|
+
1. item → <ol><li>item</li></ol>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**Tables:**
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
| H1 | H2 | → <table><tbody>
|
|
86
|
+
|----|----| <tr><th>H1</th><th>H2</th></tr>
|
|
87
|
+
| a | b | <tr><td>a</td><td>b</td></tr>
|
|
88
|
+
</tbody></table>
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**Code blocks (ONLY place for CDATA):**
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
```lang → <ac:structured-macro ac:name="code">
|
|
95
|
+
code here <ac:parameter ac:name="language">lang</ac:parameter>
|
|
96
|
+
``` <ac:plain-text-body><![CDATA[code here]]></ac:plain-text-body>
|
|
97
|
+
</ac:structured-macro>
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**Info/warning/tip boxes:**
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
> [!NOTE] → <ac:structured-macro ac:name="info">
|
|
104
|
+
> body <ac:parameter ac:name="title">title</ac:parameter>
|
|
105
|
+
<ac:rich-text-body><p>body</p></ac:rich-text-body>
|
|
106
|
+
</ac:structured-macro>
|
|
107
|
+
|
|
108
|
+
> [!WARNING] → ac:name="warning"
|
|
109
|
+
> [!TIP] → ac:name="tip"
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**Blockquote:**
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
> text → <blockquote><p>text</p></blockquote>
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Save converted XHTML to a temp file: `BODY_FILE=$(mktemp --suffix=.html)`.
|
|
119
|
+
|
|
120
|
+
### Step 5 — Search for existing page
|
|
121
|
+
|
|
122
|
+
Use Bash tool to run:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
source ~/.claude/skills/_shared/vds-skill/credentials.sh
|
|
126
|
+
ensure_env VDS_CONFLUENCE_TOKEN "Enter VDS Confluence personal access token"
|
|
127
|
+
|
|
128
|
+
SPACE_KEY="<from config>"
|
|
129
|
+
PAGE_TITLE="<title from Step 3>"
|
|
130
|
+
|
|
131
|
+
SEARCH_RESULT=$(vds-cli confluence search \
|
|
132
|
+
--cql "space=$SPACE_KEY AND title = \"$PAGE_TITLE\"" \
|
|
133
|
+
--limit 1 --json-only)
|
|
134
|
+
|
|
135
|
+
EXISTING_PAGE_ID=$(echo "$SEARCH_RESULT" | python3 -c \
|
|
136
|
+
'import json,sys; d=json.load(sys.stdin); print(d["results"][0]["id"] if d.get("results") else "")')
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
If `$EXISTING_PAGE_ID` non-empty → Step 6 (update). Otherwise → Step 7 (create).
|
|
140
|
+
|
|
141
|
+
### Step 6 — Update existing page (via vds-cli)
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
EXISTING_VERSION=$(echo "$SEARCH_RESULT" | python3 -c \
|
|
145
|
+
'import json,sys; d=json.load(sys.stdin); print(d["results"][0].get("version",{}).get("number",1))')
|
|
146
|
+
|
|
147
|
+
VERSION_COMMENT="${COMMENT:-Updated via vds-skill-push-prd}"
|
|
148
|
+
|
|
149
|
+
vds-cli confluence content update \
|
|
150
|
+
--page-id "$EXISTING_PAGE_ID" \
|
|
151
|
+
--body-file "$BODY_FILE" \
|
|
152
|
+
--version $((EXISTING_VERSION + 1)) \
|
|
153
|
+
--version-comment "$VERSION_COMMENT" \
|
|
154
|
+
--json-only
|
|
155
|
+
|
|
156
|
+
rm -f "$BODY_FILE"
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Conflict handling:** if `vds-cli` returns version mismatch error, retry once with fresh version:
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
LATEST_VERSION=$(vds-cli confluence content page "$EXISTING_PAGE_ID" --json-only \
|
|
163
|
+
| python3 -c 'import json,sys; print(json.load(sys.stdin)["version"]["number"])')
|
|
164
|
+
|
|
165
|
+
vds-cli confluence content update \
|
|
166
|
+
--page-id "$EXISTING_PAGE_ID" \
|
|
167
|
+
--body-file "$BODY_FILE" \
|
|
168
|
+
--version $((LATEST_VERSION + 1)) \
|
|
169
|
+
--version-comment "$VERSION_COMMENT" \
|
|
170
|
+
--json-only
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Step 7 — Create new page (via vds-cli)
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
# Resolve parent page ID via search
|
|
177
|
+
PARENT_ID=""
|
|
178
|
+
if [[ -n "$CONFLUENCE_PARENT_PAGE" ]]; then
|
|
179
|
+
PARENT_ID=$(vds-cli confluence search \
|
|
180
|
+
--cql "space=$SPACE_KEY AND title = \"$CONFLUENCE_PARENT_PAGE\"" \
|
|
181
|
+
--limit 1 --json-only \
|
|
182
|
+
| python3 -c 'import json,sys; d=json.load(sys.stdin); print(d["results"][0]["id"] if d.get("results") else "")')
|
|
183
|
+
fi
|
|
184
|
+
|
|
185
|
+
CREATE_ARGS=(vds-cli confluence content create-page
|
|
186
|
+
--space "$SPACE_KEY"
|
|
187
|
+
--title "$PAGE_TITLE"
|
|
188
|
+
--body-file "$BODY_FILE"
|
|
189
|
+
--version-comment "${COMMENT:-Initial PRD push via vds-skill-push-prd}"
|
|
190
|
+
--json-only)
|
|
191
|
+
[[ -n "$PARENT_ID" ]] && CREATE_ARGS+=(--parent-id "$PARENT_ID")
|
|
192
|
+
|
|
193
|
+
"${CREATE_ARGS[@]}"
|
|
194
|
+
rm -f "$BODY_FILE"
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Step 8 — Output to user
|
|
198
|
+
|
|
199
|
+
```
|
|
200
|
+
## PRD pushed to Confluence
|
|
201
|
+
|
|
202
|
+
- Page: {page_title}
|
|
203
|
+
- Action: [Created / Updated]
|
|
204
|
+
- Space: {space_key}
|
|
205
|
+
- Comment: {comment}
|
|
206
|
+
- URL: {confluence_page_url}
|
|
207
|
+
|
|
208
|
+
## Next step
|
|
209
|
+
Optionally run /vds-skill-create-jira-epic to create a Jira epic from this PRD,
|
|
210
|
+
or continue with /sdlc-architecture (Phase 3).
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## Notes
|
|
214
|
+
|
|
215
|
+
- Never push a PRD that has failed validation
|
|
216
|
+
- If `vds-cli` is not installed, tell user to install vds-scripts first
|
|
217
|
+
- Do not modify the local file during this step
|
|
218
|
+
- Conflict handling: version mismatch → auto-retry once with fresh version number
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: vds-skill-push-srs
|
|
3
|
+
description: Push SRS markdown to Viettel Confluence via vds-cli. Same flow as push-prd plus link to the corresponding PRD page. Use after /sdlc-srs has produced 05-srs.md. Viettel-only (requires vds-cli).
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /vds-skill-push-srs
|
|
7
|
+
|
|
8
|
+
Publish the current SRS to Viettel Confluence via `vds-cli` — create or update the page, and link to the corresponding PRD page if it exists.
|
|
9
|
+
|
|
10
|
+
## Input
|
|
11
|
+
|
|
12
|
+
- `[file]` — optional path to a specific markdown file. Default: scan `.vsaf/docs/features/*/05-srs.md`
|
|
13
|
+
- `[comment]` — optional version note
|
|
14
|
+
|
|
15
|
+
## Prerequisites
|
|
16
|
+
|
|
17
|
+
- `vds-cli` installed
|
|
18
|
+
- An SRS markdown file must exist
|
|
19
|
+
- `VDS_CONFLUENCE_TOKEN` set OR lazy-prompted
|
|
20
|
+
- Confluence space + parent page in config or lazy-prompted
|
|
21
|
+
|
|
22
|
+
## Steps
|
|
23
|
+
|
|
24
|
+
### Step 1 — Find SRS file
|
|
25
|
+
|
|
26
|
+
- If `[file]` given: use directly
|
|
27
|
+
- Otherwise: list `.vsaf/docs/features/*/05-srs.md` (exclude `*-results.md`)
|
|
28
|
+
- Multiple: ask user
|
|
29
|
+
- None: STOP — tell user to run `/sdlc-srs` first
|
|
30
|
+
- Read full content
|
|
31
|
+
|
|
32
|
+
### Step 2 — Load Confluence config
|
|
33
|
+
|
|
34
|
+
Same as `/vds-skill-push-prd` Step 2.
|
|
35
|
+
|
|
36
|
+
### Step 3 — Determine page title
|
|
37
|
+
|
|
38
|
+
- For `05-srs.md` under `features/{feature-name}/`: title = `[SRS] {Feature Name}` (derived from folder name)
|
|
39
|
+
- Otherwise: first `# Heading` or filename stem
|
|
40
|
+
|
|
41
|
+
### Step 4 — Convert markdown → Confluence storage format (XHTML)
|
|
42
|
+
|
|
43
|
+
Same conversion rules as `/vds-skill-push-prd` Step 4 (see that skill for full reference). Save converted body to `$BODY_FILE`.
|
|
44
|
+
|
|
45
|
+
### Step 5 — Search for existing page
|
|
46
|
+
|
|
47
|
+
Same as `/vds-skill-push-prd` Step 5 — search for `[SRS] {Feature Name}` page in the space, store `EXISTING_PAGE_ID` and `SEARCH_RESULT`.
|
|
48
|
+
|
|
49
|
+
### Step 6 — Update existing page (via vds-cli)
|
|
50
|
+
|
|
51
|
+
Same as `/vds-skill-push-prd` Step 6 (with auto-retry on conflict). Use `Updated via vds-skill-push-srs` as default version comment.
|
|
52
|
+
|
|
53
|
+
### Step 7 — Create new page (via vds-cli)
|
|
54
|
+
|
|
55
|
+
Same as `/vds-skill-push-prd` Step 7. Use `Initial SRS push via vds-skill-push-srs` as default version comment.
|
|
56
|
+
|
|
57
|
+
### Step 8 — Link SRS page to PRD page (if PRD exists)
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
source ~/.claude/skills/_shared/vds-skill/credentials.sh
|
|
61
|
+
ensure_env VDS_CONFLUENCE_TOKEN "Enter VDS Confluence personal access token"
|
|
62
|
+
|
|
63
|
+
# Derive PRD page title from feature name
|
|
64
|
+
FEATURE_NAME="<from folder>"
|
|
65
|
+
PRD_TITLE="[PRD] $FEATURE_NAME"
|
|
66
|
+
|
|
67
|
+
PRD_PAGE=$(vds-cli confluence search \
|
|
68
|
+
--cql "space=$SPACE_KEY AND title = \"$PRD_TITLE\"" \
|
|
69
|
+
--limit 1 --json-only)
|
|
70
|
+
|
|
71
|
+
PRD_URL=$(echo "$PRD_PAGE" | python3 -c \
|
|
72
|
+
'import json,sys; d=json.load(sys.stdin); r=d.get("results"); print(r[0].get("url","") if r else "")')
|
|
73
|
+
|
|
74
|
+
if [[ -n "$PRD_URL" ]]; then
|
|
75
|
+
# Prepend "Related Documents" macro to SRS body BEFORE push (modify $BODY_FILE)
|
|
76
|
+
RELATED_BLOCK='<ac:structured-macro ac:name="info"><ac:parameter ac:name="title">Related Documents</ac:parameter><ac:rich-text-body><p><a href="'"$PRD_URL"'">'"$PRD_TITLE"'</a></p></ac:rich-text-body></ac:structured-macro>'
|
|
77
|
+
|
|
78
|
+
NEW_BODY=$(mktemp --suffix=.html)
|
|
79
|
+
{ echo "$RELATED_BLOCK"; cat "$BODY_FILE"; } > "$NEW_BODY"
|
|
80
|
+
mv "$NEW_BODY" "$BODY_FILE"
|
|
81
|
+
fi
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
This block runs BEFORE Step 6/7 actually executes the create/update — i.e., the Related Documents banner is part of the body content pushed to Confluence.
|
|
85
|
+
|
|
86
|
+
### Step 9 — Output to user
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
## SRS pushed to Confluence
|
|
90
|
+
|
|
91
|
+
- Page: {page_title}
|
|
92
|
+
- Action: [Created / Updated]
|
|
93
|
+
- Space: {space_key}
|
|
94
|
+
- Comment: {comment}
|
|
95
|
+
- URL: {confluence_page_url}
|
|
96
|
+
- PRD link: [linked / not found]
|
|
97
|
+
|
|
98
|
+
## Next step
|
|
99
|
+
Continue to Phase 5: /sdlc-test-design
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Notes
|
|
103
|
+
|
|
104
|
+
- If `vds-cli` is not installed, tell user to install vds-scripts first
|
|
105
|
+
- Do not modify the local file during this step
|
|
106
|
+
- SRS result files (`*-results.md`) are test outputs — push those separately if needed
|
|
107
|
+
- Conflict handling: version mismatch → auto-retry once with fresh version number
|
|
108
|
+
- PRD link is best-effort — if PRD page doesn't exist in Confluence yet, SRS pushes without the link
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: vds-skill-search-confluence
|
|
3
|
+
description: Search Viettel Confluence + Jira for historical context related to a feature, write index to .vsaf/docs/features/{name}/01-discovery-historical.{md,json}. Run BEFORE /sdlc-discovery to enrich grill session context. Viettel-only (requires vds-cli).
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /vds-skill-search-confluence
|
|
7
|
+
|
|
8
|
+
Search Viettel Confluence + Jira for pages/tickets related to a feature, then write a Markdown + JSON index into the feature folder. Output is consumed by `/sdlc-discovery` (Phase 1) to enrich the grill session.
|
|
9
|
+
|
|
10
|
+
## Prerequisites
|
|
11
|
+
|
|
12
|
+
- `vds-cli` installed
|
|
13
|
+
- `python3` installed
|
|
14
|
+
- Inside a project root with `.vsaf/docs/features/` or `.synapse/docs/features/`
|
|
15
|
+
- Credentials lazy-prompted: `VDS_CONFLUENCE_TOKEN`, `VDS_JIRA_TOKEN`, `VDS_CONFLUENCE_SPACE_DEFAULT`, `VDS_JIRA_PROJECT_DEFAULT`
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
/vds-skill-search-confluence --feature user-management --query "auth jwt"
|
|
21
|
+
/vds-skill-search-confluence --feature payment --query "payment flow" --days 90 --limit 50
|
|
22
|
+
/vds-skill-search-confluence --feature billing --query "billing" --dry-run
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Behavior
|
|
26
|
+
|
|
27
|
+
1. Build CQL: `space=<DEFAULT> AND text ~ "<QUERY>" AND lastmodified > now("-Nd")`
|
|
28
|
+
2. Build JQL: `project = <DEFAULT> AND text ~ "<QUERY>" AND created > -Nd ORDER BY created DESC`
|
|
29
|
+
3. Execute `vds-cli confluence search` + `vds-cli jira search` (sequential)
|
|
30
|
+
4. Combine into JSON at `<feature-dir>/01-discovery-historical.json`
|
|
31
|
+
5. Generate Markdown summary at `<feature-dir>/01-discovery-historical.md` (top 10 Confluence + top 15 Jira)
|
|
32
|
+
|
|
33
|
+
## Implementation
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
bash ~/.claude/skills/vds-skill-search-confluence/scripts/search.sh "$@"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Notes
|
|
40
|
+
|
|
41
|
+
- Run BEFORE `/sdlc-discovery` to enrich grill session.
|
|
42
|
+
- Default `--days 180`, `--limit 30`.
|
|
43
|
+
- Empty results are OK — Markdown still generated, sdlc-discovery proceeds normally.
|
|
44
|
+
- Dry-run skips `vds-cli` invocation — preview mode works without `vds-cli` installed.
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# vds-skill-search-confluence: search Confluence + Jira for feature discovery context
|
|
3
|
+
# Usage: search.sh --feature NAME --query KEYWORDS [--dry-run] [--days N] [--limit N]
|
|
4
|
+
|
|
5
|
+
# NOTE: No `set -e` — we want full control of the exit-code path.
|
|
6
|
+
|
|
7
|
+
# Source credentials helper (deployed path: ~/.claude/skills/_shared/vds-skill/credentials.sh)
|
|
8
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
9
|
+
# shellcheck source=/dev/null
|
|
10
|
+
source "$SCRIPT_DIR/../../_shared/vds-skill/credentials.sh"
|
|
11
|
+
|
|
12
|
+
require_command python3
|
|
13
|
+
# Note: require_command vds-cli moved AFTER dry-run check so --dry-run
|
|
14
|
+
# works without vds-cli installed (preview mode).
|
|
15
|
+
|
|
16
|
+
FEATURE=""
|
|
17
|
+
QUERY=""
|
|
18
|
+
DAYS=180
|
|
19
|
+
LIMIT=30
|
|
20
|
+
DRY_RUN=false
|
|
21
|
+
|
|
22
|
+
while [[ $# -gt 0 ]]; do
|
|
23
|
+
case "$1" in
|
|
24
|
+
--feature) FEATURE="$2"; shift 2 ;;
|
|
25
|
+
--query) QUERY="$2"; shift 2 ;;
|
|
26
|
+
--days) DAYS="$2"; shift 2 ;;
|
|
27
|
+
--limit) LIMIT="$2"; shift 2 ;;
|
|
28
|
+
--dry-run) DRY_RUN=true; shift ;;
|
|
29
|
+
*) echo "Unknown arg: $1" >&2; exit 2 ;;
|
|
30
|
+
esac
|
|
31
|
+
done
|
|
32
|
+
|
|
33
|
+
if [[ -z "$FEATURE" ]]; then
|
|
34
|
+
echo "ERROR: --feature is required" >&2
|
|
35
|
+
exit 2
|
|
36
|
+
fi
|
|
37
|
+
if [[ -z "$QUERY" ]]; then
|
|
38
|
+
echo "ERROR: --query (search keywords) is required" >&2
|
|
39
|
+
exit 2
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
# Determine output dir — prefer .vsaf/, fallback to .synapse/
|
|
43
|
+
OUT_DIR=""
|
|
44
|
+
for path in ".vsaf/docs/features/$FEATURE" ".synapse/docs/features/$FEATURE"; do
|
|
45
|
+
if [[ -d "$path" ]]; then
|
|
46
|
+
OUT_DIR="$path"
|
|
47
|
+
break
|
|
48
|
+
fi
|
|
49
|
+
done
|
|
50
|
+
if [[ -z "$OUT_DIR" ]]; then
|
|
51
|
+
OUT_DIR=".vsaf/docs/features/$FEATURE"
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
OUT_JSON="$OUT_DIR/01-discovery-historical.json"
|
|
55
|
+
OUT_MD="$OUT_DIR/01-discovery-historical.md"
|
|
56
|
+
|
|
57
|
+
if [[ "$DRY_RUN" == "true" ]]; then
|
|
58
|
+
SPACE="${VDS_CONFLUENCE_SPACE_DEFAULT:-<VDS_CONFLUENCE_SPACE_DEFAULT>}"
|
|
59
|
+
PROJECT="${VDS_JIRA_PROJECT_DEFAULT:-<VDS_JIRA_PROJECT_DEFAULT>}"
|
|
60
|
+
CQL="space=$SPACE AND text ~ \"$QUERY\" AND lastmodified > now(\"-${DAYS}d\")"
|
|
61
|
+
JQL="project = $PROJECT AND text ~ \"$QUERY\" AND created > -${DAYS}d ORDER BY created DESC"
|
|
62
|
+
echo "DRY-RUN — would execute:"
|
|
63
|
+
echo " vds-cli confluence search --cql \"$CQL\" --limit $LIMIT --json-only"
|
|
64
|
+
echo " vds-cli jira search \"$JQL\" --limit $LIMIT --json-only"
|
|
65
|
+
echo " Write to: $OUT_JSON + $OUT_MD"
|
|
66
|
+
exit 0
|
|
67
|
+
fi
|
|
68
|
+
|
|
69
|
+
require_command vds-cli
|
|
70
|
+
|
|
71
|
+
# Ensure credentials
|
|
72
|
+
ensure_env VDS_CONFLUENCE_TOKEN "Enter VDS Confluence personal access token"
|
|
73
|
+
ensure_env VDS_JIRA_TOKEN "Enter VDS Jira personal access token"
|
|
74
|
+
ensure_env VDS_CONFLUENCE_SPACE_DEFAULT "Enter default Confluence space key (e.g. ENG)" false
|
|
75
|
+
ensure_env VDS_JIRA_PROJECT_DEFAULT "Enter default Jira project key (e.g. NTTC)" false
|
|
76
|
+
|
|
77
|
+
# Build CQL + JQL (now using real env vars)
|
|
78
|
+
CQL="space=$VDS_CONFLUENCE_SPACE_DEFAULT AND text ~ \"$QUERY\" AND lastmodified > now(\"-${DAYS}d\")"
|
|
79
|
+
JQL="project = $VDS_JIRA_PROJECT_DEFAULT AND text ~ \"$QUERY\" AND created > -${DAYS}d ORDER BY created DESC"
|
|
80
|
+
|
|
81
|
+
# Create output dir now (after dry-run exits early)
|
|
82
|
+
mkdir -p "$OUT_DIR"
|
|
83
|
+
|
|
84
|
+
# Execute searches
|
|
85
|
+
echo "Searching Confluence (limit $LIMIT, last ${DAYS}d)..."
|
|
86
|
+
CONF_RESULTS=$(vds-cli confluence search --cql "$CQL" --limit "$LIMIT" --json-only 2>/dev/null || echo '{"results":[]}')
|
|
87
|
+
|
|
88
|
+
echo "Searching Jira (limit $LIMIT, last ${DAYS}d)..."
|
|
89
|
+
JIRA_RESULTS=$(vds-cli jira search "$JQL" --limit "$LIMIT" --json-only 2>/dev/null || echo '{"issues":[]}')
|
|
90
|
+
|
|
91
|
+
# Combined JSON output + Markdown summary
|
|
92
|
+
python3 - "$CONF_RESULTS" "$JIRA_RESULTS" "$OUT_JSON" "$OUT_MD" "$QUERY" "$DAYS" <<'PYEOF'
|
|
93
|
+
import json, sys
|
|
94
|
+
conf_raw, jira_raw, out_json, out_md, query, days = sys.argv[1:7]
|
|
95
|
+
conf = json.loads(conf_raw) if conf_raw.strip() else {"results":[]}
|
|
96
|
+
jira = json.loads(jira_raw) if jira_raw.strip() else {"issues":[]}
|
|
97
|
+
|
|
98
|
+
combined = {
|
|
99
|
+
"query": query,
|
|
100
|
+
"days_back": int(days),
|
|
101
|
+
"confluence": conf.get("results", []),
|
|
102
|
+
"jira": jira.get("issues", []),
|
|
103
|
+
}
|
|
104
|
+
with open(out_json, "w") as f:
|
|
105
|
+
json.dump(combined, f, indent=2, ensure_ascii=False)
|
|
106
|
+
|
|
107
|
+
lines = [
|
|
108
|
+
f"# Discovery Historical Context — {query}",
|
|
109
|
+
f"",
|
|
110
|
+
f"> Generated by /vds-skill-search-confluence — searched last {days} days",
|
|
111
|
+
f"",
|
|
112
|
+
f"## Confluence pages ({len(combined['confluence'])} results)",
|
|
113
|
+
f"",
|
|
114
|
+
]
|
|
115
|
+
for page in combined["confluence"][:10]:
|
|
116
|
+
title = page.get("title", "<no title>")
|
|
117
|
+
url = page.get("url", page.get("_links", {}).get("webui", ""))
|
|
118
|
+
modified = page.get("lastModified", page.get("version", {}).get("when", "?"))
|
|
119
|
+
lines.append(f"- [{title}]({url}) — modified {modified}")
|
|
120
|
+
|
|
121
|
+
lines += [
|
|
122
|
+
f"",
|
|
123
|
+
f"## Jira tickets ({len(combined['jira'])} results)",
|
|
124
|
+
f"",
|
|
125
|
+
]
|
|
126
|
+
for issue in combined["jira"][:15]:
|
|
127
|
+
key = issue.get("key", "?")
|
|
128
|
+
summary = issue.get("fields", {}).get("summary", "<no summary>")
|
|
129
|
+
status = issue.get("fields", {}).get("status", {}).get("name", "?")
|
|
130
|
+
lines.append(f"- **{key}** — {summary} ({status})")
|
|
131
|
+
|
|
132
|
+
with open(out_md, "w") as f:
|
|
133
|
+
f.write("\n".join(lines) + "\n")
|
|
134
|
+
|
|
135
|
+
print(f"Wrote: {out_json}")
|
|
136
|
+
print(f"Wrote: {out_md}")
|
|
137
|
+
PYEOF
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Quality Baseline — vds-scripts-skill
|
|
2
|
+
|
|
3
|
+
## Version History
|
|
4
|
+
|
|
5
|
+
| Version | Date | Score | Evaluator | Notes |
|
|
6
|
+
|---------|------|-------|-----------|-------|
|
|
7
|
+
| 1.0.0 | 2026-03-19 | 3.6/5 | Manual | Initial baseline - needs split |
|
|
8
|
+
| 1.1.0 | 2026-03-23 | pending | Manual | Repositioned as platform-routing skill; pending post-refactor review |
|
|
9
|
+
|
|
10
|
+
## Evaluation Criteria
|
|
11
|
+
|
|
12
|
+
| Criterion | Weight | Type | Description |
|
|
13
|
+
|-----------|--------|------|-------------|
|
|
14
|
+
| Accuracy | 40% | Scored 1-5 | Commands and routing guidance are correct |
|
|
15
|
+
| Completeness | 25% | Scored 1-5 | Current WHO capabilities are represented through skill text, references, or routing aids |
|
|
16
|
+
| Actionability | 20% | Scored 1-5 | Users can quickly choose the correct command family or specialist skill |
|
|
17
|
+
| Token Efficiency | 10% | Scored 1-5 | Main skill stays concise and relies on progressive disclosure |
|
|
18
|
+
| Schema Validity | 5% | Binary | Skill follows AgentSkills/OpenSkills structure and metadata |
|
|
19
|
+
|
|
20
|
+
## Current Role
|
|
21
|
+
|
|
22
|
+
`vds-scripts-skill` is the platform-routing skill for the WHO scripts ecosystem.
|
|
23
|
+
It is not the deep specialist runbook for audit workflows or other specialist domains.
|
|
24
|
+
|
|
25
|
+
## Known Issues
|
|
26
|
+
|
|
27
|
+
- Post-refactor scoring still needs a fresh baseline run.
|
|
28
|
+
- Capability coverage should be validated against the current WHO workspace inventory.
|
|
29
|
+
- Generated/root agent surfaces must be synced after the final skill/doc changes land.
|
|
30
|
+
|
|
31
|
+
## Validation Checklist
|
|
32
|
+
|
|
33
|
+
- [ ] `SKILL.md` remains concise and activation-oriented
|
|
34
|
+
- [ ] references/ covers the broader capability map
|
|
35
|
+
- [ ] routing matrix maps common intents to the right skill/command family
|
|
36
|
+
- [ ] registry metadata matches the updated role
|
|
37
|
+
- [ ] scripts docs and skills docs tell the same ownership story
|
|
38
|
+
|
|
39
|
+
## Quality Hypotheses
|
|
40
|
+
|
|
41
|
+
| Date | Hypothesis | Expected | Actual | Score Change |
|
|
42
|
+
|------|------------|----------|--------|--------------|
|
|
43
|
+
| 2026-03-23 | Shift from command dump to platform-routing + references | Token Efficiency up, Completeness up, clearer routing | pending | pending |
|
|
44
|
+
| 2026-03-23 | Add capability index and routing matrix | Completeness 3.5→4.2 | pending | pending |
|