specweave 1.0.299 → 1.0.301
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/bin/specweave.js +25 -1
- package/dist/src/cli/commands/auto.js +1 -0
- package/dist/src/cli/commands/auto.js.map +1 -1
- package/dist/src/cli/commands/scan-plugins.d.ts +12 -0
- package/dist/src/cli/commands/scan-plugins.d.ts.map +1 -0
- package/dist/src/cli/commands/scan-plugins.js +80 -0
- package/dist/src/cli/commands/scan-plugins.js.map +1 -0
- package/dist/src/core/doctor/checkers/installation-health-checker.js +6 -6
- package/dist/src/core/doctor/checkers/installation-health-checker.js.map +1 -1
- package/dist/src/core/lazy-loading/llm-plugin-detector.d.ts +8 -27
- package/dist/src/core/lazy-loading/llm-plugin-detector.d.ts.map +1 -1
- package/dist/src/core/lazy-loading/llm-plugin-detector.js +12 -90
- package/dist/src/core/lazy-loading/llm-plugin-detector.js.map +1 -1
- package/dist/src/core/skill-security/index.d.ts +9 -0
- package/dist/src/core/skill-security/index.d.ts.map +1 -0
- package/dist/src/core/skill-security/index.js +5 -0
- package/dist/src/core/skill-security/index.js.map +1 -0
- package/dist/src/core/skill-security/parser.d.ts +27 -0
- package/dist/src/core/skill-security/parser.d.ts.map +1 -0
- package/dist/src/core/skill-security/parser.js +55 -0
- package/dist/src/core/skill-security/parser.js.map +1 -0
- package/dist/src/core/skill-security/reporter.d.ts +21 -0
- package/dist/src/core/skill-security/reporter.d.ts.map +1 -0
- package/dist/src/core/skill-security/reporter.js +121 -0
- package/dist/src/core/skill-security/reporter.js.map +1 -0
- package/dist/src/core/skill-security/rules.d.ts +25 -0
- package/dist/src/core/skill-security/rules.d.ts.map +1 -0
- package/dist/src/core/skill-security/rules.js +137 -0
- package/dist/src/core/skill-security/rules.js.map +1 -0
- package/dist/src/core/skill-security/scanner.d.ts +41 -0
- package/dist/src/core/skill-security/scanner.d.ts.map +1 -0
- package/dist/src/core/skill-security/scanner.js +78 -0
- package/dist/src/core/skill-security/scanner.js.map +1 -0
- package/package.json +1 -1
- package/plugins/specweave/hooks/lib/score-increment.sh +87 -0
- package/plugins/specweave/hooks/stop-auto-v5.sh +55 -9
- package/plugins/specweave/hooks/tests/test-auto-context-integration.sh +126 -0
- package/plugins/specweave/hooks/tests/test-stop-auto-enriched.sh +128 -0
- package/plugins/specweave/hooks/user-prompt-submit.sh +99 -150
- package/plugins/specweave/scripts/setup-auto.sh +58 -4
- package/plugins/specweave/scripts/tests/test-setup-auto-selection.sh +74 -0
- package/plugins/specweave/scripts/tests/test-setup-auto-usergoal.sh +83 -0
- package/plugins/specweave/skills/auto/SKILL.md +3 -1
- package/plugins/specweave/skills/do/SKILL.md +11 -0
- package/plugins/specweave/skills/increment/SKILL.md +8 -2
- package/plugins/specweave/skills/team-lead/SKILL.md +69 -5
- package/plugins/specweave-jira/skills/jira-mapper/SKILL.md +13 -14
- package/plugins/specweave-jira/skills/jira-resource-validator/SKILL.md +74 -4
- package/plugins/specweave-jira/skills/jira-sync/SKILL.md +18 -27
|
@@ -20,9 +20,15 @@ hooks:
|
|
|
20
20
|
|
|
21
21
|
# Plan Product Increment
|
|
22
22
|
|
|
23
|
-
## CRITICAL: Plan Mode Required
|
|
23
|
+
## CRITICAL: Plan Mode Required (BLOCKING)
|
|
24
24
|
|
|
25
|
-
**
|
|
25
|
+
**You MUST be in plan mode before proceeding.** If not, call `EnterPlanMode` now and wait for confirmation before continuing to Step 0A.
|
|
26
|
+
|
|
27
|
+
1. Call `EnterPlanMode` immediately
|
|
28
|
+
2. Wait for plan mode confirmation
|
|
29
|
+
3. Then proceed to Step 0A
|
|
30
|
+
|
|
31
|
+
Increment planning produces specs, plans, and task breakdowns that require user review. Do not skip plan mode or defer it — the user must approve the plan before any implementation begins.
|
|
26
32
|
|
|
27
33
|
## Project Overrides
|
|
28
34
|
|
|
@@ -27,7 +27,9 @@ description: Orchestrate multi-agent parallel development with domain-specialize
|
|
|
27
27
|
| Action | Tool | Parameters |
|
|
28
28
|
|--------|------|------------|
|
|
29
29
|
| Create team | `TeamCreate` | `team_name`, `description` |
|
|
30
|
-
| Spawn agent | `Task` | `team_name`, `name`, `subagent_type`, `prompt` |
|
|
30
|
+
| Spawn agent | `Task` | `team_name`, `name`, `subagent_type`, `prompt`, `mode` |
|
|
31
|
+
| Spawn agent (plan mode) | `Task` | `mode: "plan"` — agent must submit plan for team lead review |
|
|
32
|
+
| Approve/reject plan | `SendMessage` | `type: "plan_approval_response"`, `request_id`, `recipient`, `approve`, `content` |
|
|
31
33
|
| Send message | `SendMessage` | `type`, `recipient`, `content`, `summary` |
|
|
32
34
|
| Shutdown agent | `SendMessage` | `type: "shutdown_request"`, `recipient` |
|
|
33
35
|
|
|
@@ -191,6 +193,58 @@ Analyze domains
|
|
|
191
193
|
|
|
192
194
|
---
|
|
193
195
|
|
|
196
|
+
## 3b. Plan Review Workflow
|
|
197
|
+
|
|
198
|
+
The team lead acts as **architectural reviewer** for all sub-agent plans. Do NOT auto-accept plans.
|
|
199
|
+
|
|
200
|
+
### Why Review
|
|
201
|
+
|
|
202
|
+
Without review, agents may duplicate work across domains, misinterpret scope, make conflicting architectural decisions, or produce plans misaligned with the spec.
|
|
203
|
+
|
|
204
|
+
### Protocol
|
|
205
|
+
|
|
206
|
+
**Spawn all agents with `mode: "plan"`.** This forces agents to call `ExitPlanMode` before implementing, which sends a `plan_approval_request` to the team lead.
|
|
207
|
+
|
|
208
|
+
When you receive a plan approval request:
|
|
209
|
+
|
|
210
|
+
1. **Read the plan** — check the agent's spec.md, plan.md, and tasks.md
|
|
211
|
+
2. **Evaluate**:
|
|
212
|
+
- Does it align with the feature spec and ACs?
|
|
213
|
+
- Is the architecture consistent with existing codebase patterns?
|
|
214
|
+
- Does the agent stay within its file ownership boundaries?
|
|
215
|
+
- Are there conflicts with other agents' plans?
|
|
216
|
+
- Is scope correct — not too broad, not too narrow?
|
|
217
|
+
3. **Approve or reject**:
|
|
218
|
+
|
|
219
|
+
```
|
|
220
|
+
// Approve
|
|
221
|
+
SendMessage({
|
|
222
|
+
type: "plan_approval_response",
|
|
223
|
+
request_id: "<from plan_approval_request>",
|
|
224
|
+
recipient: "database-agent",
|
|
225
|
+
approve: true
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
// Reject with feedback
|
|
229
|
+
SendMessage({
|
|
230
|
+
type: "plan_approval_response",
|
|
231
|
+
request_id: "<from plan_approval_request>",
|
|
232
|
+
recipient: "database-agent",
|
|
233
|
+
approve: false,
|
|
234
|
+
content: "Revise: 1) Add index on user_id for sessions. 2) Missing migration for AC-US1-03."
|
|
235
|
+
});
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Non-Blocking Review
|
|
239
|
+
|
|
240
|
+
Plan review MUST NOT block other agents. Review plans as they arrive — agents waiting for approval are idle, but other agents continue working normally.
|
|
241
|
+
|
|
242
|
+
### Multi-Increment Consideration
|
|
243
|
+
|
|
244
|
+
For very large features, the team lead MAY split work into multiple increments per domain for better tracking and independent closure. Decide this during initial analysis (Step 1), before spawning agents.
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
194
248
|
## 4. Agent Spawn Prompt Templates
|
|
195
249
|
|
|
196
250
|
Each agent receives a detailed prompt that includes its skill invocations, file ownership, and workflow instructions.
|
|
@@ -528,11 +582,14 @@ TeamCreate({
|
|
|
528
582
|
|
|
529
583
|
### Step 2: Spawn Upstream Agents (Phase 1)
|
|
530
584
|
|
|
585
|
+
All agents are spawned with `mode: "plan"` so the team lead reviews their plans before implementation (see Section 3b).
|
|
586
|
+
|
|
531
587
|
```typescript
|
|
532
588
|
Task({
|
|
533
589
|
team_name: "feature-checkout",
|
|
534
590
|
name: "database-agent",
|
|
535
591
|
subagent_type: "general-purpose",
|
|
592
|
+
mode: "plan",
|
|
536
593
|
prompt: `[DATABASE AGENT PROMPT - see template in Section 4c]`,
|
|
537
594
|
});
|
|
538
595
|
|
|
@@ -540,6 +597,7 @@ Task({
|
|
|
540
597
|
team_name: "feature-checkout",
|
|
541
598
|
name: "shared-types-agent",
|
|
542
599
|
subagent_type: "general-purpose",
|
|
600
|
+
mode: "plan",
|
|
543
601
|
prompt: `[SHARED/TYPES AGENT PROMPT]`,
|
|
544
602
|
});
|
|
545
603
|
```
|
|
@@ -555,6 +613,7 @@ Task({
|
|
|
555
613
|
team_name: "feature-checkout",
|
|
556
614
|
name: "backend-agent",
|
|
557
615
|
subagent_type: "general-purpose",
|
|
616
|
+
mode: "plan",
|
|
558
617
|
prompt: `[BACKEND AGENT PROMPT - see template in Section 4b]`,
|
|
559
618
|
});
|
|
560
619
|
|
|
@@ -562,6 +621,7 @@ Task({
|
|
|
562
621
|
team_name: "feature-checkout",
|
|
563
622
|
name: "frontend-agent",
|
|
564
623
|
subagent_type: "general-purpose",
|
|
624
|
+
mode: "plan",
|
|
565
625
|
prompt: `[FRONTEND AGENT PROMPT - see template in Section 4a]`,
|
|
566
626
|
});
|
|
567
627
|
|
|
@@ -569,6 +629,7 @@ Task({
|
|
|
569
629
|
team_name: "feature-checkout",
|
|
570
630
|
name: "testing-agent",
|
|
571
631
|
subagent_type: "general-purpose",
|
|
632
|
+
mode: "plan",
|
|
572
633
|
prompt: `[TESTING AGENT PROMPT - see template in Section 4d]`,
|
|
573
634
|
});
|
|
574
635
|
```
|
|
@@ -625,12 +686,15 @@ Orchestrator Final Check:
|
|
|
625
686
|
```
|
|
626
687
|
/sw:team-lead "Build checkout flow"
|
|
627
688
|
│
|
|
628
|
-
├── Step 1: Analyze feature -> identify domains
|
|
689
|
+
├── Step 1: Analyze feature -> identify domains -> decide increment split
|
|
629
690
|
├── Step 2: Create team via TeamCreate
|
|
630
691
|
├── Step 3: Create per-domain increments
|
|
631
|
-
├── Step 4: Contract-first spawning
|
|
632
|
-
│ ├── Phase 1: Spawn shared + database
|
|
633
|
-
│ └──
|
|
692
|
+
├── Step 4: Contract-first spawning (all agents with mode: "plan")
|
|
693
|
+
│ ├── Phase 1: Spawn shared + database
|
|
694
|
+
│ │ └── Review & approve each agent's plan (Section 3b)
|
|
695
|
+
│ │ └── Wait for CONTRACT_READY after approval
|
|
696
|
+
│ └── Phase 2: Spawn backend + frontend + testing
|
|
697
|
+
│ └── Review & approve each agent's plan
|
|
634
698
|
├── Step 5: Monitor progress via SendMessage
|
|
635
699
|
├── Step 6: Quality gates (each agent runs /sw:grill)
|
|
636
700
|
└── Step 7: Merge and close (/sw:team-merge)
|
|
@@ -87,29 +87,28 @@ JIRA_DOMAIN="$(grep '^JIRA_DOMAIN=' .env | head -1 | cut -d '=' -f2-)"
|
|
|
87
87
|
### Domain Validation (before ANY API call)
|
|
88
88
|
|
|
89
89
|
```bash
|
|
90
|
-
#
|
|
91
|
-
if [[
|
|
92
|
-
echo "Error:
|
|
90
|
+
# Reject IP addresses FIRST — IPv4, IPv6 brackets, hex-encoded (SSRF prevention)
|
|
91
|
+
if [[ "$JIRA_DOMAIN" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+ ]] || [[ "$JIRA_DOMAIN" =~ ^\[.*\]$ ]] || [[ "$JIRA_DOMAIN" =~ ^0x ]]; then
|
|
92
|
+
echo "Error: IP addresses not allowed — use a hostname"
|
|
93
93
|
exit 1
|
|
94
94
|
fi
|
|
95
95
|
|
|
96
|
-
#
|
|
97
|
-
if [[
|
|
98
|
-
echo "Error:
|
|
99
|
-
echo "Self-hosted JIRA requires explicit user confirmation"
|
|
96
|
+
# Reject localhost and private networks
|
|
97
|
+
if [[ "$JIRA_DOMAIN" =~ ^(localhost|127\.|10\.|172\.(1[6-9]|2[0-9]|3[01])\.|192\.168\.) ]]; then
|
|
98
|
+
echo "Error: Internal/localhost addresses not allowed"
|
|
100
99
|
exit 1
|
|
101
|
-
# Agent: use AskUserQuestion to confirm non-standard domain before retrying
|
|
102
100
|
fi
|
|
103
101
|
|
|
104
|
-
#
|
|
105
|
-
if [[ "$JIRA_DOMAIN" =~ ^[
|
|
106
|
-
echo "Error:
|
|
102
|
+
# Must be a valid hostname — no special chars, no consecutive dots
|
|
103
|
+
if [[ ! "$JIRA_DOMAIN" =~ ^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*$ ]]; then
|
|
104
|
+
echo "Error: JIRA_DOMAIN contains invalid characters"
|
|
107
105
|
exit 1
|
|
108
106
|
fi
|
|
109
107
|
|
|
110
|
-
#
|
|
111
|
-
|
|
112
|
-
|
|
108
|
+
# Cloud JIRA: must match <subdomain>.atlassian.net
|
|
109
|
+
# Agent: use AskUserQuestion to confirm non-standard domain before retrying
|
|
110
|
+
if [[ ! "$JIRA_DOMAIN" =~ ^[a-zA-Z0-9-]+\.atlassian\.net$ ]]; then
|
|
111
|
+
echo "Error: Domain does not match <subdomain>.atlassian.net pattern"
|
|
113
112
|
exit 1
|
|
114
113
|
fi
|
|
115
114
|
```
|
|
@@ -9,6 +9,76 @@ allowed-tools: Read, Bash, Write, Edit
|
|
|
9
9
|
|
|
10
10
|
**Auto-Activation**: Triggers when Jira setup or validation is needed.
|
|
11
11
|
|
|
12
|
+
## Security Rules (MANDATORY)
|
|
13
|
+
|
|
14
|
+
These rules apply to ALL JIRA API operations in this skill.
|
|
15
|
+
|
|
16
|
+
### Credential Handling
|
|
17
|
+
|
|
18
|
+
1. **Never collect credentials** — this skill reads from `.env` only, never prompts the user
|
|
19
|
+
2. **Never log secrets** — never echo token values, auth headers, or base64 credentials
|
|
20
|
+
3. **Never write credentials** — the user configures `.env` themselves (this skill may update non-secret keys like `JIRA_BOARDS` and `JIRA_PROJECT`)
|
|
21
|
+
|
|
22
|
+
### Credential Loading
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# 1. Validate presence FIRST (before reading any values)
|
|
26
|
+
for KEY in JIRA_API_TOKEN JIRA_EMAIL JIRA_DOMAIN; do
|
|
27
|
+
if ! grep -qE "^${KEY}=.+" .env; then
|
|
28
|
+
echo "Error: ${KEY} missing or empty in .env"
|
|
29
|
+
exit 1
|
|
30
|
+
fi
|
|
31
|
+
done
|
|
32
|
+
|
|
33
|
+
# 2. Load credentials ONLY after validation passes (never display values)
|
|
34
|
+
# head -1 ensures only first match used if .env has duplicate keys
|
|
35
|
+
JIRA_API_TOKEN="$(grep '^JIRA_API_TOKEN=' .env | head -1 | cut -d '=' -f2-)"
|
|
36
|
+
JIRA_EMAIL="$(grep '^JIRA_EMAIL=' .env | head -1 | cut -d '=' -f2-)"
|
|
37
|
+
JIRA_DOMAIN="$(grep '^JIRA_DOMAIN=' .env | head -1 | cut -d '=' -f2-)"
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Domain Validation (before ANY API call)
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# Reject IP addresses first (SSRF prevention)
|
|
44
|
+
if [[ "$JIRA_DOMAIN" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+ ]] || [[ "$JIRA_DOMAIN" =~ ^\[.*\]$ ]] || [[ "$JIRA_DOMAIN" =~ ^0x ]]; then
|
|
45
|
+
echo "Error: IP addresses not allowed — use a hostname"
|
|
46
|
+
exit 1
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
# Reject localhost and private networks
|
|
50
|
+
if [[ "$JIRA_DOMAIN" =~ ^(localhost|127\.|10\.|172\.(1[6-9]|2[0-9]|3[01])\.|192\.168\.) ]]; then
|
|
51
|
+
echo "Error: Internal/localhost addresses not allowed"
|
|
52
|
+
exit 1
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
# Must be a valid hostname — no special chars, no consecutive dots
|
|
56
|
+
if [[ ! "$JIRA_DOMAIN" =~ ^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*$ ]]; then
|
|
57
|
+
echo "Error: JIRA_DOMAIN contains invalid characters"
|
|
58
|
+
exit 1
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
# Cloud JIRA: must match <subdomain>.atlassian.net
|
|
62
|
+
if [[ ! "$JIRA_DOMAIN" =~ ^[a-zA-Z0-9-]+\.atlassian\.net$ ]]; then
|
|
63
|
+
echo "Error: Domain does not match <subdomain>.atlassian.net pattern"
|
|
64
|
+
exit 1
|
|
65
|
+
fi
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### API Call Pattern (HTTPS only, quoted variables)
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
AUTH="$(printf '%s:%s' "$JIRA_EMAIL" "$JIRA_API_TOKEN" | base64)"
|
|
72
|
+
|
|
73
|
+
# All API calls MUST use https://, double-quote all variables
|
|
74
|
+
curl -s -f \
|
|
75
|
+
-H "Authorization: Basic $AUTH" \
|
|
76
|
+
-H "Content-Type: application/json" \
|
|
77
|
+
"https://${JIRA_DOMAIN}/rest/api/3/..."
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
12
82
|
## What This Skill Does
|
|
13
83
|
|
|
14
84
|
This skill ensures your Jira configuration in `.env` is valid and all resources exist. It's **smart enough** to:
|
|
@@ -31,10 +101,10 @@ This skill ensures your Jira configuration in `.env` is valid and all resources
|
|
|
31
101
|
|
|
32
102
|
### Required .env Variables
|
|
33
103
|
|
|
34
|
-
```
|
|
35
|
-
JIRA_API_TOKEN
|
|
36
|
-
JIRA_EMAIL
|
|
37
|
-
JIRA_DOMAIN
|
|
104
|
+
```
|
|
105
|
+
JIRA_API_TOKEN=<your-token>
|
|
106
|
+
JIRA_EMAIL=<your-email>
|
|
107
|
+
JIRA_DOMAIN=<your-company>.atlassian.net
|
|
38
108
|
JIRA_STRATEGY=board-based
|
|
39
109
|
JIRA_PROJECT=PROJECTKEY
|
|
40
110
|
JIRA_BOARDS=1,2,3 # IDs (if exist) OR names (if creating)
|
|
@@ -106,29 +106,28 @@ if [ -z "$JIRA_DOMAIN" ]; then
|
|
|
106
106
|
exit 1
|
|
107
107
|
fi
|
|
108
108
|
|
|
109
|
-
#
|
|
110
|
-
if [[
|
|
111
|
-
echo "Error:
|
|
109
|
+
# Reject IP addresses FIRST — IPv4, IPv6 brackets, hex-encoded (SSRF prevention)
|
|
110
|
+
if [[ "$JIRA_DOMAIN" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+ ]] || [[ "$JIRA_DOMAIN" =~ ^\[.*\]$ ]] || [[ "$JIRA_DOMAIN" =~ ^0x ]]; then
|
|
111
|
+
echo "Error: IP addresses not allowed — use a hostname"
|
|
112
112
|
exit 1
|
|
113
113
|
fi
|
|
114
114
|
|
|
115
|
-
#
|
|
116
|
-
if [[
|
|
117
|
-
echo "Error:
|
|
118
|
-
echo "Self-hosted JIRA requires explicit user confirmation"
|
|
115
|
+
# Reject localhost and internal hostnames
|
|
116
|
+
if [[ "$JIRA_DOMAIN" =~ ^(localhost|127\.|10\.|172\.(1[6-9]|2[0-9]|3[01])\.|192\.168\.) ]]; then
|
|
117
|
+
echo "Error: Internal/localhost addresses not allowed"
|
|
119
118
|
exit 1
|
|
120
|
-
# Agent: use AskUserQuestion to confirm non-standard domain before retrying
|
|
121
119
|
fi
|
|
122
120
|
|
|
123
|
-
#
|
|
124
|
-
if [[ "$JIRA_DOMAIN" =~ ^[
|
|
125
|
-
echo "Error:
|
|
121
|
+
# Must be a valid hostname — each label: alphanumeric, hyphens allowed mid-label, no consecutive dots
|
|
122
|
+
if [[ ! "$JIRA_DOMAIN" =~ ^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*$ ]]; then
|
|
123
|
+
echo "Error: JIRA_DOMAIN is not a valid hostname"
|
|
126
124
|
exit 1
|
|
127
125
|
fi
|
|
128
126
|
|
|
129
|
-
#
|
|
130
|
-
|
|
131
|
-
|
|
127
|
+
# Must end with .atlassian.net for cloud JIRA
|
|
128
|
+
# Agent: use AskUserQuestion to confirm non-standard domain before retrying
|
|
129
|
+
if [[ ! "$JIRA_DOMAIN" =~ ^[a-zA-Z0-9-]+\.atlassian\.net$ ]]; then
|
|
130
|
+
echo "Error: Domain does not match <subdomain>.atlassian.net pattern"
|
|
132
131
|
exit 1
|
|
133
132
|
fi
|
|
134
133
|
```
|
|
@@ -168,7 +167,7 @@ JIRA and Confluence are both Atlassian products and often used together. This sk
|
|
|
168
167
|
|
|
169
168
|
### Confluence Credentials
|
|
170
169
|
|
|
171
|
-
Same authentication and security rules as JIRA — user configures `.env`, skill only validates presence. Same domain validation applies (must be `<subdomain>.atlassian.net`, HTTPS only, no IPs).
|
|
170
|
+
Same authentication and security rules as JIRA — user configures `.env`, skill only validates presence. Same domain validation applies (must be `<subdomain>.atlassian.net`, HTTPS only, no IPs). `CONFLUENCE_DOMAIN` MUST pass the same validation as `JIRA_DOMAIN` (Step 4) before any Confluence API call.
|
|
172
171
|
|
|
173
172
|
Required `.env` keys (configured by the user, NOT by this skill):
|
|
174
173
|
```
|
|
@@ -190,20 +189,12 @@ CONFLUENCE_SPACE_KEY=<space-key>
|
|
|
190
189
|
|
|
191
190
|
**Every page update MUST increment the version number**:
|
|
192
191
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
curl -s GET ".../pages/{id}" | jq '.version.number'
|
|
196
|
-
# Returns: 5
|
|
192
|
+
1. GET current page to retrieve `version.number` (e.g., returns 5)
|
|
193
|
+
2. PUT update with `version.number` set to current + 1 (e.g., 6)
|
|
197
194
|
|
|
198
|
-
|
|
199
|
-
PUT ".../pages/{id}"
|
|
200
|
-
{ "version": { "number": 6 } }
|
|
201
|
-
```
|
|
195
|
+
If version is not incremented, the API returns `409 Conflict`.
|
|
202
196
|
|
|
203
|
-
**
|
|
204
|
-
```
|
|
205
|
-
409 Conflict: "Version must be incremented on update. Current version is: 5"
|
|
206
|
-
```
|
|
197
|
+
All Confluence API calls follow the same security rules as JIRA (HTTPS only, domain validation, credential handling). See the `jira-mapper` skill's **Security Rules** section for implementation patterns.
|
|
207
198
|
|
|
208
199
|
### Reference Documentation
|
|
209
200
|
|