@ngocsangairvds/vsaf 3.1.25 → 3.1.27
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
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ngocsangairvds/vsaf",
|
|
3
|
-
"version": "3.1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "3.1.27",
|
|
4
|
+
"description": "improve confluence format",
|
|
5
5
|
"keywords": ["claude", "claude-code", "ai", "sdlc", "framework", "bmad", "gitnexus", "superpowers"],
|
|
6
6
|
"bin": {
|
|
7
7
|
"vsaf": "./bin/vsaf.js"
|
|
@@ -9,19 +9,22 @@ description: Push PRD document to Confluence. Use after /vsaf-doc-prd or /vsaf-d
|
|
|
9
9
|
Publish the current PRD to Confluence — create a new page if it doesn't exist, or update the existing one. The comment becomes the Confluence version note.
|
|
10
10
|
|
|
11
11
|
## Input
|
|
12
|
+
- `[file]` — optional path to a specific markdown file or directory (defaults to scanning `.vsaf/docs/planning-artifacts/prd-*.md`)
|
|
12
13
|
- `[comment]` — optional version note (e.g. "Initial draft", "Updated scope after stakeholder review")
|
|
13
14
|
|
|
14
15
|
## Prerequisites
|
|
15
16
|
- Confluence MCP must be configured (`vsaf init` sets this up)
|
|
16
|
-
- A PRD file must exist
|
|
17
|
+
- A PRD markdown file must exist
|
|
17
18
|
|
|
18
19
|
## Steps
|
|
19
20
|
|
|
20
|
-
### Step 1 — Find PRD file
|
|
21
|
-
-
|
|
22
|
-
- If
|
|
23
|
-
-
|
|
24
|
-
-
|
|
21
|
+
### Step 1 — Find PRD file(s)
|
|
22
|
+
- If a **directory path** was given (e.g. `@docs/architecture/`): read all `*.md` files in that directory and combine them into a single page body, separated by `<hr/>`. Use the directory name as the page title base.
|
|
23
|
+
- If a **specific file path** was given: use that file directly.
|
|
24
|
+
- Otherwise: list files in `.vsaf/docs/planning-artifacts/` matching `prd-*.md`
|
|
25
|
+
- If multiple found: ask user which one to push
|
|
26
|
+
- If none found: STOP — tell user to run `/vsaf-doc-prd` first
|
|
27
|
+
- Read full file content
|
|
25
28
|
|
|
26
29
|
### Step 2 — Load Confluence config
|
|
27
30
|
Read `.vsaf/_bmad/bmm/config.yaml` and extract:
|
|
@@ -33,37 +36,108 @@ If either field is missing or empty:
|
|
|
33
36
|
- Ask user: "Enter parent page title in Confluence (blank = root of space):"
|
|
34
37
|
- Save answers back to config so the user is not asked again
|
|
35
38
|
|
|
36
|
-
### Step 3 — Determine page title
|
|
37
|
-
|
|
39
|
+
### Step 3 — Determine page title and parent page ID
|
|
40
|
+
- If file is from `prd-*.md`: title = `[PRD] {Feature Name}` (derive from filename: `prd-user-management.md` → `[PRD] User Management`)
|
|
41
|
+
- If input was a directory: title = the numbered section label provided by the user (e.g. `3.4.2.12 VRoute — Architecture Design`)
|
|
42
|
+
- Otherwise: use the first `# Heading` in the file as the page title, or the filename stem if no heading found
|
|
38
43
|
|
|
39
|
-
|
|
40
|
-
Use
|
|
44
|
+
**Resolve parent page ID:**
|
|
45
|
+
Use `confluence_search_pages` to search for the parent page title in the configured space. Extract the `id` field from the result — this is the `parentId` needed for page creation. Do NOT skip this step.
|
|
46
|
+
|
|
47
|
+
### Step 4 — Convert markdown → Confluence storage format
|
|
48
|
+
|
|
49
|
+
**CRITICAL RULES — read before writing a single tag:**
|
|
50
|
+
|
|
51
|
+
1. **Never send raw markdown.** All content must be converted to Confluence Storage Format (XHTML).
|
|
52
|
+
2. **Never wrap the entire body in `<![CDATA[...]]>`.** CDATA is ONLY valid inside `<ac:plain-text-body>` within code macros.
|
|
53
|
+
3. **All Confluence macro attributes MUST use the `ac:` namespace prefix.** The tag is `<ac:parameter ac:name="...">`, never `<parameter name="...">`. Wrong namespace = XML parse error.
|
|
54
|
+
4. **Escape HTML entities in regular text:** `&` → `&`, `<` → `<`, `>` → `>`.
|
|
55
|
+
5. **Every opened tag must be closed.** Confluence's XML parser is strict — an unclosed tag aborts the entire page push.
|
|
56
|
+
|
|
57
|
+
**Block elements:**
|
|
58
|
+
```
|
|
59
|
+
# Heading → <h1>Heading</h1>
|
|
60
|
+
## Heading → <h2>Heading</h2>
|
|
61
|
+
### Heading → <h3>Heading</h3>
|
|
62
|
+
#### Heading → <h4>Heading</h4>
|
|
63
|
+
paragraph text → <p>paragraph text</p>
|
|
64
|
+
--- → <hr/>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**Inline elements:**
|
|
68
|
+
```
|
|
69
|
+
**bold** → <strong>bold</strong>
|
|
70
|
+
*italic* → <em>italic</em>
|
|
71
|
+
`inline code` → <code>inline code</code>
|
|
72
|
+
[text](url) → <a href="url">text</a>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**Lists:**
|
|
76
|
+
```
|
|
77
|
+
- item → <ul><li>item</li></ul>
|
|
78
|
+
1. item → <ol><li>item</li></ol>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**Tables:**
|
|
41
82
|
```
|
|
42
|
-
|
|
83
|
+
| H1 | H2 | → <table><tbody>
|
|
84
|
+
|----|----| → <tr><th>H1</th><th>H2</th></tr>
|
|
85
|
+
| a | b | <tr><td>a</td><td>b</td></tr>
|
|
86
|
+
</tbody></table>
|
|
43
87
|
```
|
|
44
|
-
- **Found** → proceed to Step 5 (update)
|
|
45
|
-
- **Not found** → proceed to Step 6 (create)
|
|
46
88
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
-
|
|
89
|
+
**Code blocks — the ONLY correct place for CDATA:**
|
|
90
|
+
```
|
|
91
|
+
```lang → <ac:structured-macro ac:name="code">
|
|
92
|
+
code here <ac:parameter ac:name="language">lang</ac:parameter>
|
|
93
|
+
``` <ac:plain-text-body><![CDATA[code here]]></ac:plain-text-body>
|
|
94
|
+
</ac:structured-macro>
|
|
95
|
+
```
|
|
96
|
+
⚠️ The attribute is `ac:name` not `name`. Using `<ac:parameter name="language">` will cause an XML parse error.
|
|
97
|
+
|
|
98
|
+
**Info/warning/tip boxes:**
|
|
99
|
+
```
|
|
100
|
+
> [!NOTE] title → <ac:structured-macro ac:name="info">
|
|
101
|
+
> body <ac:parameter ac:name="title">title</ac:parameter>
|
|
102
|
+
<ac:rich-text-body><p>body</p></ac:rich-text-body>
|
|
103
|
+
</ac:structured-macro>
|
|
104
|
+
|
|
105
|
+
> [!WARNING] → ac:name="warning"
|
|
106
|
+
> [!TIP] → ac:name="tip"
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
**Blockquote:**
|
|
110
|
+
```
|
|
111
|
+
> text → <blockquote><p>text</p></blockquote>
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Step 5 — Check if page exists
|
|
115
|
+
Use `confluence_search_pages` to search for a page with that exact title in the configured space.
|
|
116
|
+
- **Found** → proceed to Step 6 (update)
|
|
117
|
+
- **Not found** → proceed to Step 7 (create)
|
|
118
|
+
|
|
119
|
+
### Step 6 — Update existing page
|
|
120
|
+
Call `confluence_update_page` with:
|
|
121
|
+
- `pageId`: the ID from the search result
|
|
122
|
+
- `bodyStorageValue`: the **storage format HTML** converted in Step 4
|
|
123
|
+
- Version comment: the `[comment]` argument (or "Updated via vsaf-push-prd" if blank)
|
|
124
|
+
|
|
125
|
+
Confirm the two-stage update prompt if the MCP requires it.
|
|
126
|
+
|
|
127
|
+
### Step 7 — Create new page
|
|
128
|
+
Call `confluence_create_page` with:
|
|
129
|
+
- `spaceKey`: the space key from config
|
|
130
|
+
- `parentId`: the parent page ID resolved in Step 3
|
|
131
|
+
- `title`: the page title determined in Step 3
|
|
132
|
+
- `bodyStorageValue`: the **storage format HTML** converted in Step 4
|
|
53
133
|
|
|
54
|
-
|
|
55
|
-
- Use the `confluence` MCP create tool with:
|
|
56
|
-
- Space key from config
|
|
57
|
-
- Parent page title from config (find its ID first if needed)
|
|
58
|
-
- Title: `[PRD] {feature-name}`
|
|
59
|
-
- Content: full PRD markdown
|
|
60
|
-
- Version comment: the `[comment]` argument (or "Created via vsaf-push-prd" if blank)
|
|
134
|
+
> The `bodyStorageValue` parameter takes Confluence Storage Format (XHTML) directly — do not add a separate `representation` field.
|
|
61
135
|
|
|
62
|
-
### Step
|
|
136
|
+
### Step 8 — Output to user
|
|
63
137
|
```
|
|
64
138
|
## PRD pushed to Confluence
|
|
65
139
|
|
|
66
|
-
- Page:
|
|
140
|
+
- Page: {page_title}
|
|
67
141
|
- Action: [Created / Updated]
|
|
68
142
|
- Space: {space_key}
|
|
69
143
|
- Comment: {comment}
|
|
@@ -76,4 +150,5 @@ Run /vsaf-push-srs to also publish the SRS, or continue with /vsaf-build
|
|
|
76
150
|
## Notes
|
|
77
151
|
- Never push a PRD that has failed `/vsaf-validate-prd` validation
|
|
78
152
|
- If the Confluence MCP is not configured, tell the user to run `vsaf init` and enter their token
|
|
79
|
-
- Do not modify the local
|
|
153
|
+
- Do not modify the local file during this step
|
|
154
|
+
- The file argument accepts any markdown file path or directory, not just files under `.vsaf/`
|
|
@@ -9,19 +9,22 @@ description: Push SRS document to Confluence. Use after /vsaf-doc-srs or SRS edi
|
|
|
9
9
|
Publish the current SRS to Confluence — create a new page if it doesn't exist, or update the existing one. The comment becomes the Confluence version note.
|
|
10
10
|
|
|
11
11
|
## Input
|
|
12
|
+
- `[file]` — optional path to a specific markdown file or directory (defaults to scanning `.vsaf/docs/srs/*.md`)
|
|
12
13
|
- `[comment]` — optional version note (e.g. "Initial draft", "Revised after tech review")
|
|
13
14
|
|
|
14
15
|
## Prerequisites
|
|
15
16
|
- Confluence MCP must be configured (`vsaf init` sets this up)
|
|
16
|
-
- An SRS file must exist
|
|
17
|
+
- An SRS markdown file must exist
|
|
17
18
|
|
|
18
19
|
## Steps
|
|
19
20
|
|
|
20
|
-
### Step 1 — Find SRS file
|
|
21
|
-
-
|
|
22
|
-
- If
|
|
23
|
-
-
|
|
24
|
-
-
|
|
21
|
+
### Step 1 — Find SRS file(s)
|
|
22
|
+
- If a **directory path** was given (e.g. `@docs/srs/`): read all `*.md` files in that directory (excluding `*-results.md`) and combine them into a single page body, separated by `<hr/>`. Use the directory name as the page title base.
|
|
23
|
+
- If a **specific file path** was given: use that file directly.
|
|
24
|
+
- Otherwise: list files in `.vsaf/docs/srs/` matching `*.md` (exclude `*-results.md`)
|
|
25
|
+
- If multiple found: ask user which one to push
|
|
26
|
+
- If none found: STOP — tell user to run `/vsaf-doc-srs` first
|
|
27
|
+
- Read full file content
|
|
25
28
|
|
|
26
29
|
### Step 2 — Load Confluence config
|
|
27
30
|
Read `.vsaf/_bmad/bmm/config.yaml` and extract:
|
|
@@ -33,46 +36,123 @@ If either field is missing or empty:
|
|
|
33
36
|
- Ask user: "Enter parent page title in Confluence (blank = root of space):"
|
|
34
37
|
- Save answers back to config so the user is not asked again
|
|
35
38
|
|
|
36
|
-
### Step 3 — Determine page title
|
|
37
|
-
|
|
39
|
+
### Step 3 — Determine page title and parent page ID
|
|
40
|
+
- If file is from `srs-*.md` or `SRS-*.md`: title = `[SRS] {Feature Name}` (derive from filename)
|
|
41
|
+
- If input was a directory: title = the numbered section label provided by the user
|
|
42
|
+
- Otherwise: use the first `# Heading` in the file as the page title, or the filename stem if no heading found
|
|
38
43
|
|
|
39
|
-
|
|
40
|
-
Use
|
|
44
|
+
**Resolve parent page ID:**
|
|
45
|
+
Use `confluence_search_pages` to search for the parent page title in the configured space. Extract the `id` field from the result — this is the `parentId` needed for page creation. Do NOT skip this step.
|
|
46
|
+
|
|
47
|
+
### Step 4 — Convert markdown → Confluence storage format
|
|
48
|
+
|
|
49
|
+
**CRITICAL RULES — read before writing a single tag:**
|
|
50
|
+
|
|
51
|
+
1. **Never send raw markdown.** All content must be converted to Confluence Storage Format (XHTML).
|
|
52
|
+
2. **Never wrap the entire body in `<![CDATA[...]]>`.** CDATA is ONLY valid inside `<ac:plain-text-body>` within code macros.
|
|
53
|
+
3. **All Confluence macro attributes MUST use the `ac:` namespace prefix.** The tag is `<ac:parameter ac:name="...">`, never `<parameter name="...">`. Wrong namespace = XML parse error.
|
|
54
|
+
4. **Escape HTML entities in regular text:** `&` → `&`, `<` → `<`, `>` → `>`.
|
|
55
|
+
5. **Every opened tag must be closed.** Confluence's XML parser is strict — an unclosed tag aborts the entire page push.
|
|
56
|
+
|
|
57
|
+
**Block elements:**
|
|
58
|
+
```
|
|
59
|
+
# Heading → <h1>Heading</h1>
|
|
60
|
+
## Heading → <h2>Heading</h2>
|
|
61
|
+
### Heading → <h3>Heading</h3>
|
|
62
|
+
#### Heading → <h4>Heading</h4>
|
|
63
|
+
paragraph text → <p>paragraph text</p>
|
|
64
|
+
--- → <hr/>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**Inline elements:**
|
|
68
|
+
```
|
|
69
|
+
**bold** → <strong>bold</strong>
|
|
70
|
+
*italic* → <em>italic</em>
|
|
71
|
+
`inline code` → <code>inline code</code>
|
|
72
|
+
[text](url) → <a href="url">text</a>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**Lists:**
|
|
76
|
+
```
|
|
77
|
+
- item → <ul><li>item</li></ul>
|
|
78
|
+
1. item → <ol><li>item</li></ol>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**Tables:**
|
|
41
82
|
```
|
|
42
|
-
|
|
83
|
+
| H1 | H2 | → <table><tbody>
|
|
84
|
+
|----|----| → <tr><th>H1</th><th>H2</th></tr>
|
|
85
|
+
| a | b | <tr><td>a</td><td>b</td></tr>
|
|
86
|
+
</tbody></table>
|
|
43
87
|
```
|
|
44
|
-
- **Found** → proceed to Step 5 (update)
|
|
45
|
-
- **Not found** → proceed to Step 6 (create)
|
|
46
88
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
-
|
|
89
|
+
**Code blocks — the ONLY correct place for CDATA:**
|
|
90
|
+
```
|
|
91
|
+
```lang → <ac:structured-macro ac:name="code">
|
|
92
|
+
code here <ac:parameter ac:name="language">lang</ac:parameter>
|
|
93
|
+
``` <ac:plain-text-body><![CDATA[code here]]></ac:plain-text-body>
|
|
94
|
+
</ac:structured-macro>
|
|
95
|
+
```
|
|
96
|
+
⚠️ The attribute is `ac:name` not `name`. Using `<ac:parameter name="language">` will cause an XML parse error.
|
|
97
|
+
|
|
98
|
+
**Info/warning/tip boxes:**
|
|
99
|
+
```
|
|
100
|
+
> [!NOTE] title → <ac:structured-macro ac:name="info">
|
|
101
|
+
> body <ac:parameter ac:name="title">title</ac:parameter>
|
|
102
|
+
<ac:rich-text-body><p>body</p></ac:rich-text-body>
|
|
103
|
+
</ac:structured-macro>
|
|
104
|
+
|
|
105
|
+
> [!WARNING] → ac:name="warning"
|
|
106
|
+
> [!TIP] → ac:name="tip"
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
**Blockquote:**
|
|
110
|
+
```
|
|
111
|
+
> text → <blockquote><p>text</p></blockquote>
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Step 5 — Check if page exists
|
|
115
|
+
Use `confluence_search_pages` to search for a page with that exact title in the configured space.
|
|
116
|
+
- **Found** → proceed to Step 6 (update)
|
|
117
|
+
- **Not found** → proceed to Step 7 (create)
|
|
118
|
+
|
|
119
|
+
### Step 6 — Update existing page
|
|
120
|
+
Call `confluence_update_page` with:
|
|
121
|
+
- `pageId`: the ID from the search result
|
|
122
|
+
- `bodyStorageValue`: the **storage format HTML** converted in Step 4
|
|
123
|
+
- Version comment: the `[comment]` argument (or "Updated via vsaf-push-srs" if blank)
|
|
124
|
+
|
|
125
|
+
Confirm the two-stage update prompt if the MCP requires it.
|
|
126
|
+
|
|
127
|
+
### Step 7 — Create new page
|
|
128
|
+
Call `confluence_create_page` with:
|
|
129
|
+
- `spaceKey`: the space key from config
|
|
130
|
+
- `parentId`: the parent page ID resolved in Step 3
|
|
131
|
+
- `title`: the page title determined in Step 3
|
|
132
|
+
- `bodyStorageValue`: the **storage format HTML** converted in Step 4
|
|
53
133
|
|
|
54
|
-
|
|
55
|
-
- Use the `confluence` MCP create tool with:
|
|
56
|
-
- Space key from config
|
|
57
|
-
- Parent page title from config (find its ID first if needed)
|
|
58
|
-
- Title: `[SRS] {feature-name}`
|
|
59
|
-
- Content: full SRS markdown
|
|
60
|
-
- Version comment: the `[comment]` argument (or "Created via vsaf-push-srs" if blank)
|
|
134
|
+
> The `bodyStorageValue` parameter takes Confluence Storage Format (XHTML) directly — do not add a separate `representation` field.
|
|
61
135
|
|
|
62
|
-
### Step
|
|
136
|
+
### Step 8 — Link SRS page to PRD page (if PRD page exists)
|
|
63
137
|
- Search Confluence for the corresponding `[PRD] {feature-name}` page
|
|
64
|
-
- If found:
|
|
138
|
+
- If found: prepend this block at the top of the SRS content before pushing:
|
|
139
|
+
```xml
|
|
140
|
+
<ac:structured-macro ac:name="info">
|
|
141
|
+
<ac:parameter ac:name="title">Related Documents</ac:parameter>
|
|
142
|
+
<ac:rich-text-body><p><a href="{prd_url}">[PRD] {feature-name}</a></p></ac:rich-text-body>
|
|
143
|
+
</ac:structured-macro>
|
|
144
|
+
```
|
|
65
145
|
- This creates traceability in Confluence
|
|
66
146
|
|
|
67
|
-
### Step
|
|
147
|
+
### Step 9 — Output to user
|
|
68
148
|
```
|
|
69
149
|
## SRS pushed to Confluence
|
|
70
150
|
|
|
71
|
-
- Page:
|
|
72
|
-
- Action:
|
|
73
|
-
- Space:
|
|
74
|
-
- Comment:
|
|
75
|
-
- URL:
|
|
151
|
+
- Page: {page_title}
|
|
152
|
+
- Action: [Created / Updated]
|
|
153
|
+
- Space: {space_key}
|
|
154
|
+
- Comment: {comment}
|
|
155
|
+
- URL: {confluence_page_url}
|
|
76
156
|
- PRD link: [linked / not found]
|
|
77
157
|
|
|
78
158
|
## Next step
|
|
@@ -81,5 +161,6 @@ Run /vsaf-test to generate testcases from this SRS, or /vsaf-build to implement
|
|
|
81
161
|
|
|
82
162
|
## Notes
|
|
83
163
|
- If the Confluence MCP is not configured, tell the user to run `vsaf init` and enter their token
|
|
84
|
-
- Do not modify the local
|
|
164
|
+
- Do not modify the local file during this step
|
|
85
165
|
- SRS result files (`*-results.md`) are test outputs — push those separately if needed
|
|
166
|
+
- The file argument accepts any markdown file path or directory, not just files under `.vsaf/`
|