@ngocsangairvds/vsaf 4.0.8 → 4.0.10

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.
@@ -1,105 +0,0 @@
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
@@ -1,113 +0,0 @@
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"
@@ -1,52 +0,0 @@
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
@@ -1,128 +0,0 @@
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
43
- OUT_DIR=".vsaf/docs/features/$FEATURE"
44
-
45
- OUT_JSON="$OUT_DIR/01-discovery-historical.json"
46
- OUT_MD="$OUT_DIR/01-discovery-historical.md"
47
-
48
- if [[ "$DRY_RUN" == "true" ]]; then
49
- SPACE="${VDS_CONFLUENCE_SPACE_DEFAULT:-<VDS_CONFLUENCE_SPACE_DEFAULT>}"
50
- PROJECT="${VDS_JIRA_PROJECT_DEFAULT:-<VDS_JIRA_PROJECT_DEFAULT>}"
51
- CQL="space=$SPACE AND text ~ \"$QUERY\" AND lastmodified > now(\"-${DAYS}d\")"
52
- JQL="project = $PROJECT AND text ~ \"$QUERY\" AND created > -${DAYS}d ORDER BY created DESC"
53
- echo "DRY-RUN — would execute:"
54
- echo " vds-cli confluence search --cql \"$CQL\" --limit $LIMIT --json-only"
55
- echo " vds-cli jira search \"$JQL\" --limit $LIMIT --json-only"
56
- echo " Write to: $OUT_JSON + $OUT_MD"
57
- exit 0
58
- fi
59
-
60
- require_command vds-cli
61
-
62
- # Ensure credentials
63
- ensure_env VDS_CONFLUENCE_TOKEN "Enter VDS Confluence personal access token"
64
- ensure_env VDS_JIRA_TOKEN "Enter VDS Jira personal access token"
65
- ensure_env VDS_CONFLUENCE_SPACE_DEFAULT "Enter default Confluence space key (e.g. ENG)" false
66
- ensure_env VDS_JIRA_PROJECT_DEFAULT "Enter default Jira project key (e.g. NTTC)" false
67
-
68
- # Build CQL + JQL (now using real env vars)
69
- CQL="space=$VDS_CONFLUENCE_SPACE_DEFAULT AND text ~ \"$QUERY\" AND lastmodified > now(\"-${DAYS}d\")"
70
- JQL="project = $VDS_JIRA_PROJECT_DEFAULT AND text ~ \"$QUERY\" AND created > -${DAYS}d ORDER BY created DESC"
71
-
72
- # Create output dir now (after dry-run exits early)
73
- mkdir -p "$OUT_DIR"
74
-
75
- # Execute searches
76
- echo "Searching Confluence (limit $LIMIT, last ${DAYS}d)..."
77
- CONF_RESULTS=$(vds-cli confluence search --cql "$CQL" --limit "$LIMIT" --json-only 2>/dev/null || echo '{"results":[]}')
78
-
79
- echo "Searching Jira (limit $LIMIT, last ${DAYS}d)..."
80
- JIRA_RESULTS=$(vds-cli jira search "$JQL" --limit "$LIMIT" --json-only 2>/dev/null || echo '{"issues":[]}')
81
-
82
- # Combined JSON output + Markdown summary
83
- python3 - "$CONF_RESULTS" "$JIRA_RESULTS" "$OUT_JSON" "$OUT_MD" "$QUERY" "$DAYS" <<'PYEOF'
84
- import json, sys
85
- conf_raw, jira_raw, out_json, out_md, query, days = sys.argv[1:7]
86
- conf = json.loads(conf_raw) if conf_raw.strip() else {"results":[]}
87
- jira = json.loads(jira_raw) if jira_raw.strip() else {"issues":[]}
88
-
89
- combined = {
90
- "query": query,
91
- "days_back": int(days),
92
- "confluence": conf.get("results", []),
93
- "jira": jira.get("issues", []),
94
- }
95
- with open(out_json, "w") as f:
96
- json.dump(combined, f, indent=2, ensure_ascii=False)
97
-
98
- lines = [
99
- f"# Discovery Historical Context — {query}",
100
- f"",
101
- f"> Generated by /vds-skill-search-confluence — searched last {days} days",
102
- f"",
103
- f"## Confluence pages ({len(combined['confluence'])} results)",
104
- f"",
105
- ]
106
- for page in combined["confluence"][:10]:
107
- title = page.get("title", "<no title>")
108
- url = page.get("url", page.get("_links", {}).get("webui", ""))
109
- modified = page.get("lastModified", page.get("version", {}).get("when", "?"))
110
- lines.append(f"- [{title}]({url}) — modified {modified}")
111
-
112
- lines += [
113
- f"",
114
- f"## Jira tickets ({len(combined['jira'])} results)",
115
- f"",
116
- ]
117
- for issue in combined["jira"][:15]:
118
- key = issue.get("key", "?")
119
- summary = issue.get("fields", {}).get("summary", "<no summary>")
120
- status = issue.get("fields", {}).get("status", {}).get("name", "?")
121
- lines.append(f"- **{key}** — {summary} ({status})")
122
-
123
- with open(out_md, "w") as f:
124
- f.write("\n".join(lines) + "\n")
125
-
126
- print(f"Wrote: {out_json}")
127
- print(f"Wrote: {out_md}")
128
- PYEOF