@ngocsangairvds/vsaf 4.0.1 → 4.0.3

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.
Files changed (39) hide show
  1. package/package.json +1 -1
  2. package/packages/cli/dist/commands/install.d.ts.map +1 -1
  3. package/packages/cli/dist/commands/install.js +15 -2
  4. package/packages/cli/dist/commands/install.js.map +1 -1
  5. package/packages/cli/dist/commands/skill.d.ts.map +1 -1
  6. package/packages/cli/dist/commands/skill.js +1 -9
  7. package/packages/cli/dist/commands/skill.js.map +1 -1
  8. package/packages/cli/dist/index.js +1 -1
  9. package/packages/cli/dist/index.js.map +1 -1
  10. package/skills/sdlc/discovery/SKILL.md +20 -5
  11. package/skills/sdlc/hotfix-analyze/SKILL.md +41 -17
  12. package/skills/sdlc/implement/SKILL.md +47 -14
  13. package/skills/sdlc/install-deps.mjs +7 -1
  14. package/skills/sdlc/pack.yaml +1 -1
  15. package/skills/sdlc/sdlc-health/SKILL.md +36 -36
  16. package/skills/vds-skill/_shared/credentials.sh +79 -0
  17. package/skills/vds-skill/create-bitbucket-pr/SKILL.md +65 -0
  18. package/skills/vds-skill/create-bitbucket-pr/scripts/create-pr.sh +105 -0
  19. package/skills/vds-skill/create-jira-epic/SKILL.md +65 -0
  20. package/skills/vds-skill/create-jira-epic/scripts/create-epic.sh +113 -0
  21. package/skills/vds-skill/install-deps.mjs +157 -0
  22. package/skills/vds-skill/pack.yaml +24 -0
  23. package/skills/vds-skill/pull/SKILL.md +38 -0
  24. package/skills/vds-skill/pull/scripts/pull.sh +52 -0
  25. package/skills/vds-skill/push-prd/SKILL.md +238 -0
  26. package/skills/vds-skill/push-srs/SKILL.md +128 -0
  27. package/skills/vds-skill/search-confluence/SKILL.md +66 -0
  28. package/skills/vds-skill/search-confluence/scripts/search.sh +128 -0
  29. package/skills/vds-skill/vds-scripts-skill/.openskills.json +6 -0
  30. package/skills/vds-skill/vds-scripts-skill/QUALITY.md +44 -0
  31. package/skills/vds-skill/vds-scripts-skill/SKILL.md +127 -0
  32. package/skills/vds-skill/vds-scripts-skill/references/audit-commands.md +171 -0
  33. package/skills/vds-skill/vds-scripts-skill/references/capability-index.md +34 -0
  34. package/skills/vds-skill/vds-scripts-skill/references/development-commands.md +12 -0
  35. package/skills/vds-skill/vds-scripts-skill/references/google-sheets.md +71 -0
  36. package/skills/vds-skill/vds-scripts-skill/references/integration-commands.md +17 -0
  37. package/skills/vds-skill/vds-scripts-skill/references/platform-bootstrap.md +31 -0
  38. package/skills/vds-skill/vds-scripts-skill/references/specialist-routing.md +14 -0
  39. package/skills/vds-skill/vds-scripts-skill/references/validation-commands.md +15 -0
@@ -18,22 +18,22 @@ Execute ALL checks below in order, then print the summary table.
18
18
  Use the Read tool to check each of these 16 skill files (sdlc-health is excluded — if you're running this, it's installed). If the file exists, mark ✓. If Read returns an error, mark ✗.
19
19
 
20
20
  ```
21
- ~/.claude/skills/sdlc-init/SKILL.md
22
- ~/.claude/skills/sdlc-onboard-docs/SKILL.md
23
- ~/.claude/skills/sdlc-onboard-code/SKILL.md
24
- ~/.claude/skills/sdlc-discovery/SKILL.md
25
- ~/.claude/skills/sdlc-prd/SKILL.md
26
- ~/.claude/skills/sdlc-architecture/SKILL.md
27
- ~/.claude/skills/sdlc-srs/SKILL.md
28
- ~/.claude/skills/sdlc-test-design/SKILL.md
29
- ~/.claude/skills/sdlc-implement/SKILL.md
30
- ~/.claude/skills/sdlc-review/SKILL.md
31
- ~/.claude/skills/sdlc-feature-complete/SKILL.md
32
- ~/.claude/skills/sdlc-ship/SKILL.md
33
- ~/.claude/skills/sdlc-hotfix-analyze/SKILL.md
34
- ~/.claude/skills/sdlc-hotfix-red/SKILL.md
35
- ~/.claude/skills/sdlc-hotfix-green/SKILL.md
36
- ~/.claude/skills/sdlc-hotfix-review/SKILL.md
21
+ .claude/skills/sdlc-init/SKILL.md
22
+ .claude/skills/sdlc-onboard-docs/SKILL.md
23
+ .claude/skills/sdlc-onboard-code/SKILL.md
24
+ .claude/skills/sdlc-discovery/SKILL.md
25
+ .claude/skills/sdlc-prd/SKILL.md
26
+ .claude/skills/sdlc-architecture/SKILL.md
27
+ .claude/skills/sdlc-srs/SKILL.md
28
+ .claude/skills/sdlc-test-design/SKILL.md
29
+ .claude/skills/sdlc-implement/SKILL.md
30
+ .claude/skills/sdlc-review/SKILL.md
31
+ .claude/skills/sdlc-feature-complete/SKILL.md
32
+ .claude/skills/sdlc-ship/SKILL.md
33
+ .claude/skills/sdlc-hotfix-analyze/SKILL.md
34
+ .claude/skills/sdlc-hotfix-red/SKILL.md
35
+ .claude/skills/sdlc-hotfix-green/SKILL.md
36
+ .claude/skills/sdlc-hotfix-review/SKILL.md
37
37
  ```
38
38
 
39
39
  ### Check 2: BMAD Skills (filesystem)
@@ -41,21 +41,21 @@ Use the Read tool to check each of these 16 skill files (sdlc-health is excluded
41
41
  Check these 15 BMAD skills — required by discovery, prd, architecture, srs, test-design, review:
42
42
 
43
43
  ```
44
- ~/.claude/skills/bmad-advanced-elicitation/SKILL.md
45
- ~/.claude/skills/bmad-brainstorming/SKILL.md
46
- ~/.claude/skills/bmad-domain-research/SKILL.md
47
- ~/.claude/skills/bmad-prfaq/SKILL.md
48
- ~/.claude/skills/bmad-create-prd/SKILL.md
49
- ~/.claude/skills/bmad-validate-prd/SKILL.md
50
- ~/.claude/skills/bmad-review-adversarial-general/SKILL.md
51
- ~/.claude/skills/bmad-create-architecture/SKILL.md
52
- ~/.claude/skills/bmad-create-epics-and-stories/SKILL.md
53
- ~/.claude/skills/bmad-check-implementation-readiness/SKILL.md
54
- ~/.claude/skills/bmad-agent-analyst/SKILL.md
55
- ~/.claude/skills/bmad-review-edge-case-hunter/SKILL.md
56
- ~/.claude/skills/bmad-code-review/SKILL.md
57
- ~/.claude/skills/bmad-party-mode/SKILL.md
58
- ~/.claude/skills/bmad-qa-generate-e2e-tests/SKILL.md
44
+ .claude/skills/bmad-advanced-elicitation/SKILL.md
45
+ .claude/skills/bmad-brainstorming/SKILL.md
46
+ .claude/skills/bmad-domain-research/SKILL.md
47
+ .claude/skills/bmad-prfaq/SKILL.md
48
+ .claude/skills/bmad-create-prd/SKILL.md
49
+ .claude/skills/bmad-validate-prd/SKILL.md
50
+ .claude/skills/bmad-review-adversarial-general/SKILL.md
51
+ .claude/skills/bmad-create-architecture/SKILL.md
52
+ .claude/skills/bmad-create-epics-and-stories/SKILL.md
53
+ .claude/skills/bmad-check-implementation-readiness/SKILL.md
54
+ .claude/skills/bmad-agent-analyst/SKILL.md
55
+ .claude/skills/bmad-review-edge-case-hunter/SKILL.md
56
+ .claude/skills/bmad-code-review/SKILL.md
57
+ .claude/skills/bmad-party-mode/SKILL.md
58
+ .claude/skills/bmad-qa-generate-e2e-tests/SKILL.md
59
59
  ```
60
60
 
61
61
  ### Check 3: mattpocock Skills (filesystem)
@@ -63,11 +63,11 @@ Check these 15 BMAD skills — required by discovery, prd, architecture, srs, te
63
63
  Check these 5 skills — lean alternative for bugfix/known-domain flows:
64
64
 
65
65
  ```
66
- ~/.claude/skills/grill-me/SKILL.md
67
- ~/.claude/skills/diagnose/SKILL.md
68
- ~/.claude/skills/zoom-out/SKILL.md
69
- ~/.claude/skills/tdd/SKILL.md
70
- ~/.claude/skills/improve-codebase-architecture/SKILL.md
66
+ .claude/skills/grill-me/SKILL.md
67
+ .claude/skills/diagnose/SKILL.md
68
+ .claude/skills/zoom-out/SKILL.md
69
+ .claude/skills/tdd/SKILL.md
70
+ .claude/skills/improve-codebase-architecture/SKILL.md
71
71
  ```
72
72
 
73
73
  ### Check 4: Plugins (Claude-only)
@@ -0,0 +1,79 @@
1
+ #!/bin/bash
2
+ # Shared credential helper for vds-skill-* skills.
3
+ # Sourced by skill scripts to lazy-prompt + persist credentials.
4
+ # Config file: ~/.vds/sdlc-config.env (chmod 600)
5
+ #
6
+ # Portable across bash and zsh (uses eval for indirect expansion).
7
+
8
+ VSAF_CONFIG_FILE="${VSAF_CONFIG_FILE:-$HOME/.vds/sdlc-config.env}"
9
+ readonly VSAF_CONFIG_FILE
10
+
11
+ # Load existing config if present
12
+ if [[ -f "$VSAF_CONFIG_FILE" ]]; then
13
+ # shellcheck source=/dev/null
14
+ source "$VSAF_CONFIG_FILE"
15
+ fi
16
+
17
+ # Also load vds-cli's own env if present (for token reuse)
18
+ if [[ -f "$HOME/.vds/.env" ]]; then
19
+ set -a
20
+ # shellcheck source=/dev/null
21
+ source "$HOME/.vds/.env"
22
+ set +a
23
+ fi
24
+
25
+ # ensure_env VAR_NAME "Prompt message" [is_secret]
26
+ # Prompts user if VAR is empty, persists to config file.
27
+ # Re-persists if VAR is pre-set (supports token rotation).
28
+ ensure_env() {
29
+ local var="$1"
30
+ local prompt="${2:-Enter $var}"
31
+ local is_secret="${3:-true}"
32
+
33
+ # Portable indirect expansion (works in both bash and zsh)
34
+ local value
35
+ eval "value=\${$var:-}"
36
+
37
+ if [[ -z "$value" ]]; then
38
+ # Prompt user
39
+ if [[ "$is_secret" == "true" ]]; then
40
+ read -rsp "$prompt: " value
41
+ echo "" >&2
42
+ else
43
+ read -rp "$prompt: " value
44
+ fi
45
+
46
+ if [[ -z "$value" ]]; then
47
+ echo "ERROR: $var is required" >&2
48
+ return 1
49
+ fi
50
+
51
+ export "$var=$value"
52
+ fi
53
+
54
+ # Persist to config file (idempotent — replace existing entry or append)
55
+ mkdir -p "$(dirname "$VSAF_CONFIG_FILE")" || { echo "ERROR: Cannot create config dir $(dirname "$VSAF_CONFIG_FILE")" >&2; return 1; }
56
+
57
+ if grep -q "^${var}=" "$VSAF_CONFIG_FILE" 2>/dev/null; then
58
+ # Update in place (BSD/GNU sed compatible via tmp file)
59
+ local tmp
60
+ tmp=$(mktemp) || { echo "ERROR: mktemp failed" >&2; return 1; }
61
+ trap 'rm -f "$tmp"' EXIT INT TERM
62
+ grep -v "^${var}=" "$VSAF_CONFIG_FILE" > "$tmp"
63
+ printf '%s=%q\n' "$var" "$value" >> "$tmp"
64
+ mv "$tmp" "$VSAF_CONFIG_FILE"
65
+ trap - EXIT INT TERM
66
+ else
67
+ printf '%s=%q\n' "$var" "$value" >> "$VSAF_CONFIG_FILE"
68
+ fi
69
+ chmod 600 "$VSAF_CONFIG_FILE" || echo "WARN: Could not set chmod 600 on $VSAF_CONFIG_FILE" >&2
70
+ }
71
+
72
+ # require_command COMMAND_NAME — exits 127 if missing
73
+ require_command() {
74
+ if ! command -v "$1" >/dev/null 2>&1; then
75
+ echo "ERROR: Required command '$1' not found in PATH" >&2
76
+ echo " Install it before running this skill." >&2
77
+ return 127
78
+ fi
79
+ }
@@ -0,0 +1,65 @@
1
+ ---
2
+ name: vds-skill-create-bitbucket-pr
3
+ description: Create a Bitbucket PR via `vds-cli bitbucket pr create`. Auto-extracts PROJECT/REPO from `git remote get-url origin`. Viettel-only — for GitHub use `gh pr create`. Run after /sdlc-ship when remote is bitbucket.digital.vn.
4
+ ---
5
+
6
+ # /vds-skill-create-bitbucket-pr
7
+
8
+ Create a Bitbucket PR on Viettel internal Bitbucket via `vds-cli`.
9
+
10
+ ## Config Check (run FIRST)
11
+
12
+ Before doing anything, run this check via Bash tool:
13
+
14
+ ```bash
15
+ source .claude/skills/_shared/vds-skill/credentials.sh 2>/dev/null
16
+ MISSING=""
17
+ [[ -z "${VDS_BITBUCKET_TOKEN:-}" ]] && MISSING="$MISSING VDS_BITBUCKET_TOKEN"
18
+ if [[ -n "$MISSING" ]]; then
19
+ echo "BLOCKED — missing:$MISSING"
20
+ echo "Fix: edit ~/.vds/sdlc-config.env (or run: vsaf install vds-skill)"
21
+ else
22
+ echo "OK"
23
+ fi
24
+ ```
25
+
26
+ If BLOCKED: tell the user exactly what's missing and how to fix, then STOP. Do NOT fabricate output. `--dry-run` mode skips credential + vds-cli checks.
27
+
28
+ ## Prerequisites
29
+
30
+ - `vds-cli` installed (for non-dry-run)
31
+ - Inside a git repo with remote pointing to `bitbucket.digital.vn`
32
+ - On a named branch (not detached HEAD)
33
+ - `VDS_BITBUCKET_TOKEN` in `~/.vds/sdlc-config.env`
34
+
35
+ ## Usage
36
+
37
+ ```bash
38
+ /vds-skill-create-bitbucket-pr # interactive, target=master
39
+ /vds-skill-create-bitbucket-pr --target develop # different target
40
+ /vds-skill-create-bitbucket-pr --dry-run # preview without executing
41
+ /vds-skill-create-bitbucket-pr --description-file FILE # custom description
42
+ /vds-skill-create-bitbucket-pr --title "Custom title"
43
+ ```
44
+
45
+ ## Behavior
46
+
47
+ 1. Verify remote URL matches `bitbucket.digital.vn` — abort if not
48
+ 2. Extract PROJECT/REPO from remote URL
49
+ 3. Determine source branch (current) + target (default `master`)
50
+ 4. Auto-detect description from `.vsaf/docs/features/*/09-ship.md` or `.vsaf/docs/hotfixes/*/03-ship.md`
51
+ 5. Lazy-prompt `VDS_BITBUCKET_TOKEN` if not set
52
+ 6. Confirm with user before executing
53
+ 7. Run `vds-cli bitbucket pr create $PROJECT/$REPO --source ... --target ... --title ... --description-file ... --yes --json-only`
54
+
55
+ ## Implementation
56
+
57
+ ```bash
58
+ bash .claude/skills/vds-skill-create-bitbucket-pr/scripts/create-pr.sh "$@"
59
+ ```
60
+
61
+ ## Notes
62
+
63
+ - For GitHub repos: use `gh pr create` instead (already standard in `/sdlc-ship`).
64
+ - PR description defaults to the latest ship report from `.vsaf/docs/`.
65
+ - Dry-run works without `vds-cli` installed (preview mode).
@@ -0,0 +1,105 @@
1
+ #!/bin/bash
2
+ # vds-skill-create-bitbucket-pr: create Bitbucket PR via vds-cli
3
+ # Usage: create-pr.sh [--dry-run] [--target BRANCH] [--description-file FILE] [--title TITLE]
4
+ # Auto-extracts project/repo from `git remote get-url origin`.
5
+
6
+ # NOTE: No `set -e` — we want full control of the exit-code path.
7
+
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 git
13
+ # Note: require_command vds-cli moved AFTER dry-run check.
14
+
15
+ DRY_RUN=false
16
+ TARGET_BRANCH="master"
17
+ DESC_FILE=""
18
+ TITLE=""
19
+
20
+ while [[ $# -gt 0 ]]; do
21
+ case "$1" in
22
+ --dry-run) DRY_RUN=true; shift ;;
23
+ --target) TARGET_BRANCH="$2"; shift 2 ;;
24
+ --description-file) DESC_FILE="$2"; shift 2 ;;
25
+ --title) TITLE="$2"; shift 2 ;;
26
+ *) echo "Unknown arg: $1" >&2; exit 2 ;;
27
+ esac
28
+ done
29
+
30
+ REMOTE_URL=$(git remote get-url origin 2>/dev/null || true)
31
+ if [[ -z "$REMOTE_URL" ]]; then
32
+ echo "ERROR: No git remote 'origin' configured" >&2
33
+ exit 1
34
+ fi
35
+
36
+ if [[ ! "$REMOTE_URL" =~ bitbucket\.digital\.vn ]]; then
37
+ echo "WARNING: Remote URL does not match bitbucket.digital.vn pattern:" >&2
38
+ echo " $REMOTE_URL" >&2
39
+ echo " This skill is for Viettel Bitbucket. For GitHub, use 'gh pr create'." >&2
40
+ exit 1
41
+ fi
42
+
43
+ # Extract PROJECT/REPO from URL
44
+ # Handles:
45
+ # ssh://git@bitbucket.digital.vn/PROJECT/repo.git
46
+ # ssh://git@bitbucket.digital.vn:7999/PROJECT/repo.git
47
+ # https://bitbucket.digital.vn/scm/PROJECT/repo.git
48
+ if [[ "$REMOTE_URL" =~ /scm/([^/]+)/([^/]+)\.git$ ]]; then
49
+ PROJECT="${BASH_REMATCH[1]}"
50
+ REPO="${BASH_REMATCH[2]}"
51
+ elif [[ "$REMOTE_URL" =~ /([^/]+)/([^/]+)\.git$ ]]; then
52
+ PROJECT="${BASH_REMATCH[1]}"
53
+ REPO="${BASH_REMATCH[2]}"
54
+ else
55
+ echo "ERROR: Cannot parse PROJECT/REPO from remote URL: $REMOTE_URL" >&2
56
+ exit 1
57
+ fi
58
+
59
+ SOURCE_BRANCH=$(git rev-parse --abbrev-ref HEAD)
60
+ if [[ -z "$SOURCE_BRANCH" ]] || [[ "$SOURCE_BRANCH" == "HEAD" ]]; then
61
+ echo "ERROR: Not on a named branch" >&2
62
+ exit 1
63
+ fi
64
+
65
+ if [[ -z "$TITLE" ]]; then
66
+ TITLE=$(git log -1 --pretty=%s)
67
+ fi
68
+
69
+ if [[ -z "$DESC_FILE" ]]; then
70
+ DESC_FILE=$(find .vsaf/docs/features -name '09-ship.md' 2>/dev/null | head -1)
71
+ [[ -z "$DESC_FILE" ]] && DESC_FILE=$(find .vsaf/docs/hotfixes -name '03-ship.md' 2>/dev/null | head -1)
72
+ fi
73
+
74
+ CMD=(vds-cli bitbucket pr create "$PROJECT/$REPO"
75
+ --source "$SOURCE_BRANCH"
76
+ --target "$TARGET_BRANCH"
77
+ --title "$TITLE")
78
+ [[ -n "$DESC_FILE" ]] && [[ -f "$DESC_FILE" ]] && CMD+=(--description-file "$DESC_FILE")
79
+
80
+ if [[ "$DRY_RUN" == "true" ]]; then
81
+ echo "DRY-RUN — would execute:"
82
+ printf ' %q' "${CMD[@]}"
83
+ echo ""
84
+ echo " + --yes --json-only"
85
+ exit 0
86
+ fi
87
+
88
+ require_command vds-cli
89
+
90
+ ensure_env VDS_BITBUCKET_TOKEN "Enter VDS Bitbucket personal access token"
91
+
92
+ echo "About to create PR:"
93
+ echo " Project/Repo: $PROJECT/$REPO"
94
+ echo " Source: $SOURCE_BRANCH"
95
+ echo " Target: $TARGET_BRANCH"
96
+ echo " Title: $TITLE"
97
+ echo " Description: ${DESC_FILE:-<empty>}"
98
+ echo ""
99
+ read -rp "Proceed? [y/N]: " confirm
100
+ if [[ "$confirm" != "y" ]] && [[ "$confirm" != "Y" ]]; then
101
+ echo "Aborted"
102
+ exit 1
103
+ fi
104
+
105
+ "${CMD[@]}" --yes --json-only
@@ -0,0 +1,65 @@
1
+ ---
2
+ name: vds-skill-create-jira-epic
3
+ description: Create a Jira Epic via `vds-cli jira create --issuetype Epic` from a PRD file. Use after /sdlc-prd has produced 02-prd.md. Auto-detects PRD location, lazy-prompts credentials. Viettel-only (requires vds-cli).
4
+ ---
5
+
6
+ # /vds-skill-create-jira-epic
7
+
8
+ Create a Jira Epic on Viettel Jira based on a PRD markdown file.
9
+
10
+ ## Config Check (run FIRST)
11
+
12
+ Before doing anything, run this check via Bash tool:
13
+
14
+ ```bash
15
+ source .claude/skills/_shared/vds-skill/credentials.sh 2>/dev/null
16
+ MISSING=""
17
+ [[ -z "${VDS_JIRA_TOKEN:-}" ]] && MISSING="$MISSING VDS_JIRA_TOKEN"
18
+ [[ -z "${VDS_JIRA_PROJECT_DEFAULT:-}" ]] && MISSING="$MISSING VDS_JIRA_PROJECT_DEFAULT"
19
+ if [[ -n "$MISSING" ]]; then
20
+ echo "BLOCKED — missing:$MISSING"
21
+ echo "Fix: edit ~/.vds/sdlc-config.env (or run: vsaf install vds-skill)"
22
+ else
23
+ echo "OK"
24
+ fi
25
+ ```
26
+
27
+ If BLOCKED: tell the user exactly what's missing and how to fix, then STOP. Do NOT fabricate output. `--dry-run` mode skips credential + vds-cli checks.
28
+
29
+ ## Prerequisites
30
+
31
+ - `vds-cli` installed (for non-dry-run)
32
+ - `python3` installed
33
+ - A PRD file exists at `.vsaf/docs/features/{feature}/02-prd.md`
34
+ - `VDS_JIRA_TOKEN` + `VDS_JIRA_PROJECT_DEFAULT` in `~/.vds/sdlc-config.env`
35
+
36
+ ## Usage
37
+
38
+ ```bash
39
+ /vds-skill-create-jira-epic # auto-detect latest PRD
40
+ /vds-skill-create-jira-epic --feature user-management # specific feature folder
41
+ /vds-skill-create-jira-epic --project NTTC # override project key
42
+ /vds-skill-create-jira-epic --dry-run # preview
43
+ /vds-skill-create-jira-epic --description-file path/to.md # custom description source
44
+ ```
45
+
46
+ ## Behavior
47
+
48
+ 1. Locate PRD file (or use `--description-file`)
49
+ 2. Extract summary from PRD's first H1 heading
50
+ 3. Lazy-prompt `VDS_JIRA_TOKEN` + `VDS_JIRA_PROJECT_DEFAULT` if missing
51
+ 4. Confirm with user
52
+ 5. Run `vds-cli jira create --project KEY --issuetype Epic --summary ... --description-file ... --yes --json-only`
53
+ 6. Save returned epic key to `<feature-dir>/jira-epic-key.txt`
54
+
55
+ ## Implementation
56
+
57
+ ```bash
58
+ bash .claude/skills/vds-skill-create-jira-epic/scripts/create-epic.sh "$@"
59
+ ```
60
+
61
+ ## Notes
62
+
63
+ - Dry-run prints constructed `vds-cli` command without executing
64
+ - Dry-run skips `vds-cli` availability check — works on machines without vds-cli installed
65
+ - Epic key written to `<feature-dir>/jira-epic-key.txt` for later cross-reference
@@ -0,0 +1,113 @@
1
+ #!/bin/bash
2
+ # vds-skill-create-jira-epic: create a Jira Epic via vds-cli
3
+ # Usage: create-epic.sh [--dry-run] [--project KEY] [--description-file FILE] [--feature NAME]
4
+
5
+ # NOTE: No `set -e` — we want full control of the exit-code path.
6
+
7
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
8
+ # shellcheck source=/dev/null
9
+ source "$SCRIPT_DIR/../../_shared/vds-skill/credentials.sh"
10
+
11
+ require_command python3
12
+ # Note: require_command vds-cli moved AFTER dry-run check so --dry-run
13
+ # works without vds-cli installed (preview mode).
14
+
15
+ DRY_RUN=false
16
+ PROJECT_KEY=""
17
+ DESC_FILE=""
18
+ FEATURE_NAME=""
19
+
20
+ while [[ $# -gt 0 ]]; do
21
+ case "$1" in
22
+ --dry-run) DRY_RUN=true; shift ;;
23
+ --project) PROJECT_KEY="$2"; shift 2 ;;
24
+ --description-file) DESC_FILE="$2"; shift 2 ;;
25
+ --feature) FEATURE_NAME="$2"; shift 2 ;;
26
+ *) echo "Unknown arg: $1" >&2; exit 2 ;;
27
+ esac
28
+ done
29
+
30
+ # Determine PRD file path
31
+ if [[ -z "$DESC_FILE" ]]; then
32
+ if [[ -n "$FEATURE_NAME" ]]; then
33
+ for path in ".vsaf/docs/features/$FEATURE_NAME/02-prd.md"; do
34
+ [[ -f "$path" ]] && DESC_FILE="$path" && break
35
+ done
36
+ fi
37
+
38
+ # Fallback: most recent 02-prd.md
39
+ if [[ -z "$DESC_FILE" ]]; then
40
+ DESC_FILE=$(find .vsaf/docs/features -name '02-prd.md' 2>/dev/null \
41
+ | xargs -I{} ls -t {} 2>/dev/null | head -1)
42
+ fi
43
+ fi
44
+
45
+ if [[ -z "$DESC_FILE" ]] || [[ ! -f "$DESC_FILE" ]]; then
46
+ echo "ERROR: PRD file not found. Run /sdlc-prd first or specify --description-file" >&2
47
+ exit 1
48
+ fi
49
+
50
+ # Derive feature name from PRD path if not given
51
+ if [[ -z "$FEATURE_NAME" ]]; then
52
+ FEATURE_NAME=$(basename "$(dirname "$DESC_FILE")")
53
+ fi
54
+
55
+ # Extract summary from PRD (first H1)
56
+ SUMMARY=$(grep -m1 '^# ' "$DESC_FILE" | sed 's/^# //' || true)
57
+ [[ -z "$SUMMARY" ]] && SUMMARY="$FEATURE_NAME"
58
+
59
+ if [[ "$DRY_RUN" == "true" ]]; then
60
+ DISPLAY_PROJECT="${PROJECT_KEY:-${VDS_JIRA_PROJECT_DEFAULT:-<VDS_JIRA_PROJECT_DEFAULT>}}"
61
+ CMD_DRY=(vds-cli jira create
62
+ --project "$DISPLAY_PROJECT"
63
+ --issuetype Epic
64
+ --summary "$SUMMARY"
65
+ --description-file "$DESC_FILE")
66
+ echo "DRY-RUN — would execute:"
67
+ printf ' %q' "${CMD_DRY[@]}"
68
+ echo ""
69
+ echo " + --yes --json-only"
70
+ exit 0
71
+ fi
72
+
73
+ require_command vds-cli
74
+
75
+ # Ensure credentials
76
+ ensure_env VDS_JIRA_TOKEN "Enter VDS Jira personal access token"
77
+ ensure_env VDS_JIRA_PROJECT_DEFAULT "Enter default Jira project key (e.g. NTTC)" false
78
+
79
+ PROJECT_KEY="${PROJECT_KEY:-$VDS_JIRA_PROJECT_DEFAULT}"
80
+
81
+ CMD=(vds-cli jira create
82
+ --project "$PROJECT_KEY"
83
+ --issuetype Epic
84
+ --summary "$SUMMARY"
85
+ --description-file "$DESC_FILE")
86
+
87
+ echo "About to create Jira Epic:"
88
+ echo " Project: $PROJECT_KEY"
89
+ echo " Summary: $SUMMARY"
90
+ echo " Description: $DESC_FILE"
91
+ echo " Feature: $FEATURE_NAME"
92
+ echo ""
93
+ read -rp "Proceed? [y/N]: " confirm
94
+ if [[ "$confirm" != "y" ]] && [[ "$confirm" != "Y" ]]; then
95
+ echo "Aborted"
96
+ exit 1
97
+ fi
98
+
99
+ RESULT=$("${CMD[@]}" --yes --json-only)
100
+ EPIC_KEY=$(echo "$RESULT" | python3 -c 'import json,sys; print(json.load(sys.stdin).get("key",""))')
101
+
102
+ if [[ -z "$EPIC_KEY" ]]; then
103
+ echo "ERROR: Failed to extract epic key from vds-cli response" >&2
104
+ echo "Response: $RESULT" >&2
105
+ exit 1
106
+ fi
107
+
108
+ EPIC_KEY_FILE="$(dirname "$DESC_FILE")/jira-epic-key.txt"
109
+ echo "$EPIC_KEY" > "$EPIC_KEY_FILE"
110
+
111
+ echo ""
112
+ echo "✓ Created Jira Epic: $EPIC_KEY"
113
+ echo " Saved key to: $EPIC_KEY_FILE"
@@ -0,0 +1,157 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * VDS Skill Pack — credential & config setup
5
+ *
6
+ * Creates ~/.vds/sdlc-config.env template with all required
7
+ * environment variables for vds-skill-* skills.
8
+ *
9
+ * Usage:
10
+ * node install-deps.mjs [projectPath]
11
+ */
12
+
13
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
14
+ import { join } from 'path';
15
+ import { homedir } from 'os';
16
+
17
+ const projectPath = process.argv[2] || process.cwd();
18
+
19
+ // ── Config ──
20
+
21
+ const VDS_DIR = join(homedir(), '.vds');
22
+ const CONFIG_FILE = join(VDS_DIR, 'sdlc-config.env');
23
+
24
+ const REQUIRED_VARS = [
25
+ { name: 'VDS_CONFLUENCE_TOKEN', desc: 'Confluence personal access token', skills: 'push-prd, push-srs, search-confluence' },
26
+ { name: 'VDS_JIRA_TOKEN', desc: 'Jira personal access token', skills: 'create-jira-epic, search-confluence' },
27
+ { name: 'VDS_BITBUCKET_TOKEN', desc: 'Bitbucket personal access token', skills: 'create-bitbucket-pr' },
28
+ { name: 'VDS_CONFLUENCE_SPACE_DEFAULT', desc: 'Default Confluence space key (e.g. CEP)', skills: 'push-prd, push-srs, search-confluence' },
29
+ { name: 'VDS_JIRA_PROJECT_DEFAULT', desc: 'Default Jira project key (e.g. NTTC)', skills: 'create-jira-epic, search-confluence' },
30
+ ];
31
+
32
+ // ── Helpers ──
33
+
34
+ function log(icon, msg) {
35
+ console.log(` ${icon} ${msg}`);
36
+ }
37
+
38
+ function parseExistingConfig(filePath) {
39
+ if (!existsSync(filePath)) return {};
40
+ const vars = {};
41
+ for (const line of readFileSync(filePath, 'utf-8').split('\n')) {
42
+ const trimmed = line.trim();
43
+ if (!trimmed || trimmed.startsWith('#')) continue;
44
+ const eq = trimmed.indexOf('=');
45
+ if (eq > 0) {
46
+ const key = trimmed.slice(0, eq);
47
+ const val = trimmed.slice(eq + 1).replace(/^['"]|['"]$/g, '');
48
+ if (val) vars[key] = val;
49
+ }
50
+ }
51
+ return vars;
52
+ }
53
+
54
+ // ── Step 1: Ensure ~/.vds/ directory ──
55
+
56
+ console.log('\n[vds-skill] Setting up VDS credentials...\n');
57
+
58
+ mkdirSync(VDS_DIR, { recursive: true });
59
+
60
+ // ── Step 2: Create or merge config template ──
61
+
62
+ const existing = parseExistingConfig(CONFIG_FILE);
63
+ const missing = [];
64
+ const filled = [];
65
+
66
+ for (const v of REQUIRED_VARS) {
67
+ if (existing[v.name]) {
68
+ filled.push(v);
69
+ } else {
70
+ missing.push(v);
71
+ }
72
+ }
73
+
74
+ if (!existsSync(CONFIG_FILE)) {
75
+ // Create fresh template
76
+ const lines = [
77
+ '# VDS Skill Pack — credential config',
78
+ '# File: ~/.vds/sdlc-config.env',
79
+ '# Permissions: 600 (auto-set by credentials.sh)',
80
+ '#',
81
+ '# Fill in the values below. Skills will use these automatically.',
82
+ '# To rotate a token: update the value here, skills pick it up next run.',
83
+ '',
84
+ ];
85
+
86
+ for (const v of REQUIRED_VARS) {
87
+ lines.push(`# ${v.desc}`);
88
+ lines.push(`# Used by: ${v.skills}`);
89
+ lines.push(`${v.name}=`);
90
+ lines.push('');
91
+ }
92
+
93
+ writeFileSync(CONFIG_FILE, lines.join('\n'), { mode: 0o600 });
94
+ log('✅', `Config created: ${CONFIG_FILE}`);
95
+ } else if (missing.length > 0) {
96
+ // Append missing vars to existing config
97
+ const appendLines = ['\n# --- Added by vds-skill install ---\n'];
98
+ for (const v of missing) {
99
+ if (!readFileSync(CONFIG_FILE, 'utf-8').includes(v.name)) {
100
+ appendLines.push(`# ${v.desc}`);
101
+ appendLines.push(`# Used by: ${v.skills}`);
102
+ appendLines.push(`${v.name}=`);
103
+ appendLines.push('');
104
+ }
105
+ }
106
+ if (appendLines.length > 1) {
107
+ writeFileSync(CONFIG_FILE, readFileSync(CONFIG_FILE, 'utf-8') + appendLines.join('\n'), { mode: 0o600 });
108
+ log('✅', `Config updated: ${CONFIG_FILE}`);
109
+ }
110
+ } else {
111
+ log('✅', `Config already complete: ${CONFIG_FILE}`);
112
+ }
113
+
114
+ // ── Step 3: Print status ──
115
+
116
+ console.log('');
117
+ if (filled.length > 0) {
118
+ log('✅', `${filled.length} credential(s) already configured:`);
119
+ for (const v of filled) {
120
+ log(' ', `${v.name} — ${v.desc}`);
121
+ }
122
+ }
123
+
124
+ if (missing.length > 0) {
125
+ console.log('');
126
+ log('⚠️', `${missing.length} credential(s) need to be filled:`);
127
+ console.log('');
128
+ console.log(' ┌────────────────────────────────────┬──────────────────────────────────────────────┐');
129
+ console.log(' │ Variable │ Description │');
130
+ console.log(' ├────────────────────────────────────┼──────────────────────────────────────────────┤');
131
+ for (const v of missing) {
132
+ const name = v.name.padEnd(36);
133
+ const desc = v.desc.padEnd(44);
134
+ console.log(` │ ${name}│ ${desc}│`);
135
+ }
136
+ console.log(' └────────────────────────────────────┴──────────────────────────────────────────────┘');
137
+ console.log('');
138
+ log('📝', `Edit config file:`);
139
+ console.log(` ${CONFIG_FILE}`);
140
+ console.log('');
141
+ log('💡', 'Skills will also lazy-prompt at runtime if values are empty.');
142
+ }
143
+
144
+ // ── Step 4: Check vds-cli ──
145
+
146
+ console.log('');
147
+ try {
148
+ const { execSync } = await import('child_process');
149
+ const version = execSync('vds-cli --version', { stdio: 'pipe', encoding: 'utf-8' }).trim();
150
+ log('✅', `vds-cli ${version}`);
151
+ } catch {
152
+ log('⚠️', 'vds-cli not found — required for non-dry-run execution');
153
+ log(' ', 'Install vds-scripts from Viettel internal repo, then verify:');
154
+ log(' ', ' command -v vds-cli && vds-cli --version');
155
+ }
156
+
157
+ console.log('\n[vds-skill] Setup complete ✅\n');