feat: review Gustavo and Marcos submitted skills
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
#!/usr/bin/env bash
|
||||
# check-mcp-atlassian.sh
|
||||
# Detect whether mcp-atlassian is wired into the active Claude / Cursor client.
|
||||
# Prints PASS / MISSING with the install path that fits the current client.
|
||||
#
|
||||
# Usage: bash scripts/check-mcp-atlassian.sh
|
||||
# Exit: 0 if installed, 1 if missing, 2 if check was inconclusive.
|
||||
|
||||
set -u
|
||||
|
||||
FOUND=0
|
||||
DETAILS=""
|
||||
|
||||
# 1. The MCP server name shows up in the running client's config.
|
||||
CANDIDATE_CONFIGS=(
|
||||
"$HOME/.claude/settings.json"
|
||||
"$HOME/.cursor/mcp.json"
|
||||
"$HOME/.codex/config.yaml"
|
||||
"$HOME/.claude.json"
|
||||
"$(pwd)/.mcp.json"
|
||||
)
|
||||
|
||||
for cfg in "${CANDIDATE_CONFIGS[@]}"; do
|
||||
if [[ -f "$cfg" ]]; then
|
||||
if grep -qiE "mcp-atlassian|sooperset/mcp-atlassian" "$cfg" 2>/dev/null; then
|
||||
FOUND=1
|
||||
DETAILS="$cfg"
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# 2. Active client processes. If the MCP is loaded we usually see a node / uv
|
||||
# process with the server's name in argv.
|
||||
if [[ $FOUND -eq 0 ]]; then
|
||||
if command -v ps >/dev/null 2>&1; then
|
||||
if ps -ef 2>/dev/null | grep -qiE "mcp-atlassian|sooperset.*atlassian"; then
|
||||
FOUND=1
|
||||
DETAILS="(running process)"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# 3. npx cache. If installed globally, it lands here.
|
||||
if [[ $FOUND -eq 0 ]]; then
|
||||
if [[ -d "$HOME/.npm/_npx" ]] && find "$HOME/.npm/_npx" -type d -name "*atlassian*" 2>/dev/null | grep -q .; then
|
||||
FOUND=1
|
||||
DETAILS="(npx cache)"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ $FOUND -eq 1 ]]; then
|
||||
echo "PASS: mcp-atlassian detected in ${DETAILS:-unknown location}"
|
||||
echo
|
||||
echo "Verify the active client can see it:"
|
||||
echo " - Claude Code : restart the session, then list /mcp"
|
||||
echo " - Cursor : Cursor > Settings > MCP, look for 'mcp-atlassian'"
|
||||
echo " - Codex CLI : /mcp list"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
cat <<'EOF'
|
||||
MISSING: mcp-atlassian is not wired into the active Claude / Cursor client.
|
||||
|
||||
The Confluence + Jira tools you need are exposed by this MCP server:
|
||||
https://github.com/sooperset/mcp-atlassian
|
||||
|
||||
Install path depends on the client in use:
|
||||
|
||||
Claude Code
|
||||
claude mcp add atlassian \
|
||||
-e CONFLUENCE_URL=https://bass.netcracker.com \
|
||||
-e CONFLUENCE_USERNAME=<your-username> \
|
||||
-e CONFLUENCE_API_TOKEN=<your-token> \
|
||||
-- npx -y mcp-atlassian
|
||||
# Add JIRA_* envs for Jira access too.
|
||||
|
||||
Cursor (project-level .mcp.json)
|
||||
{
|
||||
"mcpServers": {
|
||||
"atlassian": {
|
||||
"command": "npx",
|
||||
"args": ["-y", "mcp-atlassian"],
|
||||
"env": {
|
||||
"CONFLUENCE_URL": "https://bass.netcracker.com",
|
||||
"CONFLUENCE_USERNAME": "<your-username>",
|
||||
"CONFLUENCE_API_TOKEN": "<your-token>"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Codex CLI
|
||||
Add to ~/.codex/config.yaml:
|
||||
mcp_servers:
|
||||
atlassian:
|
||||
command: npx
|
||||
args: ["-y", "mcp-atlassian"]
|
||||
env:
|
||||
CONFLUENCE_URL: https://bass.netcracker.com
|
||||
CONFLUENCE_USERNAME: <your-username>
|
||||
CONFLUENCE_API_TOKEN: <your-token>
|
||||
|
||||
Approval note: the BASS "Cursor MCPs approval status" page lists mcp-atlassian
|
||||
as "Not approved" by default. Check the current row before relying on it for
|
||||
governed spaces; if governance has not approved it yet, your post will land
|
||||
but the space admin may revert the page.
|
||||
|
||||
After install: restart the client, then re-run this script.
|
||||
EOF
|
||||
exit 1
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
#!/usr/bin/env bash
|
||||
# dry-run-publish.sh
|
||||
# Pre-flight a Confluence storage body before posting. Runs:
|
||||
# - format sanity (storage XHTML, no wiki markup, no markdown fences)
|
||||
# - secret / PII grep (BLOCKER)
|
||||
# - macro sanity (every {code} / {plantuml} / panel is in storage form)
|
||||
# - PlantUML parse (if plantuml on $PATH)
|
||||
# - size sanity (over 300 lines needs justification header)
|
||||
#
|
||||
# Usage:
|
||||
# bash scripts/dry-run-publish.sh <draft.xml>
|
||||
#
|
||||
# Exit codes:
|
||||
# 0 = ready to post
|
||||
# 1 = REVISE (MAJOR or MINOR issues found)
|
||||
# 2 = BLOCK (BLOCKER issues found)
|
||||
|
||||
set -u
|
||||
|
||||
if [[ $# -lt 1 ]]; then
|
||||
echo "Usage: $0 <draft.xml>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
DRAFT="$1"
|
||||
|
||||
if [[ ! -f "$DRAFT" ]]; then
|
||||
echo "Draft not found: $DRAFT" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
BLOCK=0
|
||||
MAJOR=0
|
||||
MINOR=0
|
||||
|
||||
note_block() { echo " [BLOCK] $1"; BLOCK=1; }
|
||||
note_major() { echo " [MAJOR] $1"; MAJOR=1; }
|
||||
note_minor() { echo " [MINOR] $1"; MINOR=1; }
|
||||
|
||||
echo "Pre-flight: $DRAFT"
|
||||
echo "------------------------------------"
|
||||
|
||||
# 1. Format sanity
|
||||
if head -3 "$DRAFT" | grep -q '^---$'; then
|
||||
note_block "Markdown front-matter detected -- storage body must not contain --- fences."
|
||||
fi
|
||||
|
||||
if grep -qE '\{code:' "$DRAFT"; then
|
||||
note_major "Wiki code-block syntax detected. Use <ac:structured-macro ac:name=\"code\">."
|
||||
fi
|
||||
if grep -qE '\{info:' "$DRAFT" || grep -qE '\{note:' "$DRAFT" || grep -qE '\{warning:' "$DRAFT"; then
|
||||
note_major "Wiki panel syntax detected. Use <ac:structured-macro ac:name=\"info|note|warning\">."
|
||||
fi
|
||||
if grep -qE '\{plantuml' "$DRAFT"; then
|
||||
if ! grep -qE '<ac:structured-macro ac:name="plantuml"' "$DRAFT"; then
|
||||
note_major "{plantuml} found but not wrapped in <ac:structured-macro ac:name=\"plantuml\">."
|
||||
fi
|
||||
fi
|
||||
|
||||
if grep -qE '^#{1,6} ' "$DRAFT"; then
|
||||
note_major "Markdown heading detected (# / ## / ###). Use <h1> / <h2> / <h3>."
|
||||
fi
|
||||
if grep -qE '^[[:space:]]*```' "$DRAFT"; then
|
||||
note_major "Markdown code fence (\`\`\`) detected. Use <ac:structured-macro ac:name=\"code\">."
|
||||
fi
|
||||
|
||||
# 2. Secrets / PII
|
||||
SECRET_PATTERNS=(
|
||||
'AKIA[0-9A-Z]{16}'
|
||||
'ghp_[A-Za-z0-9]{30,}'
|
||||
'glpat-[A-Za-z0-9_-]{20,}'
|
||||
'xox[baprs]-[A-Za-z0-9-]{10,}'
|
||||
'sk-[A-Za-z0-9]{40,}'
|
||||
'ATATT[A-Za-z0-9]{30,}'
|
||||
'-----BEGIN [A-Z ]+PRIVATE KEY-----'
|
||||
)
|
||||
|
||||
for pat in "${SECRET_PATTERNS[@]}"; do
|
||||
if grep -qE "$pat" "$DRAFT" 2>/dev/null; then
|
||||
note_block "Secret pattern matched: $pat -- scrub before posting."
|
||||
fi
|
||||
done
|
||||
|
||||
if grep -qE "Netcracker/Projects/NDO/knowledge" "$DRAFT"; then
|
||||
note_block "Body references the local mirror path. Use the public BASS URL."
|
||||
fi
|
||||
|
||||
# 3. Macro sanity
|
||||
PLANTUML_COUNT=$(grep -cE '<ac:structured-macro ac:name="plantuml"' "$DRAFT" || true)
|
||||
PLANTUML_COUNT=$(printf '%d' "${PLANTUML_COUNT:-0}" 2>/dev/null || echo 0)
|
||||
CODE_COUNT=$(grep -cE '<ac:structured-macro ac:name="code"' "$DRAFT" || true)
|
||||
CODE_COUNT=$(printf '%d' "${CODE_COUNT:-0}" 2>/dev/null || echo 0)
|
||||
|
||||
if [[ $PLANTUML_COUNT -gt 0 ]]; then
|
||||
if grep -B2 'ac:name="plantuml"' "$DRAFT" | grep -qE '<ac:structured-macro ac:name="(info|note|warning|tip|code)"'; then
|
||||
note_major "PlantUML macro appears inside a panel or code block. Move to body root."
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ $CODE_COUNT -gt 0 ]]; then
|
||||
if ! grep -q 'ac:parameter ac:name="language"' "$DRAFT"; then
|
||||
note_major "{code} block has no language parameter."
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ $PLANTUML_COUNT -gt 0 ]] && command -v plantuml >/dev/null 2>&1; then
|
||||
TMPDIR_PRE=$(mktemp -d)
|
||||
awk '
|
||||
/<ac:structured-macro ac:name="plantuml"/{flag=1; next}
|
||||
/<\/ac:structured-macro>/{flag=0}
|
||||
flag && /<ac:plain-text-body><!\[CDATA\[/{capture=1; next}
|
||||
flag && capture && /\]\]><\/ac:plain-text-body>/{capture=0; next}
|
||||
flag && capture{print}
|
||||
' "$DRAFT" > "$TMPDIR_PRE/all.puml"
|
||||
if [[ -s "$TMPDIR_PRE/all.puml" ]]; then
|
||||
if ! plantuml -tpng -checkonly -failfast2 "$TMPDIR_PRE/all.puml" >/dev/null 2>&1; then
|
||||
note_major "PlantUML syntax check failed. Run plantuml -tpng locally on the extracted body."
|
||||
fi
|
||||
fi
|
||||
rm -rf "$TMPDIR_PRE"
|
||||
fi
|
||||
|
||||
# 4. Size
|
||||
LINES=$(wc -l < "$DRAFT")
|
||||
if [[ $LINES -gt 300 ]]; then
|
||||
if ! head -5 "$DRAFT" | grep -qiE 'justify|long|expanded'; then
|
||||
note_major "Body is $LINES lines (>300) and no justification header is present."
|
||||
fi
|
||||
fi
|
||||
|
||||
# 5. Image alt text
|
||||
if grep -qE '<ac:image' "$DRAFT"; then
|
||||
if ! grep -q 'ac:alt' "$DRAFT"; then
|
||||
note_major "<ac:image> without ac:alt."
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "------------------------------------"
|
||||
if [[ $BLOCK -eq 1 ]]; then
|
||||
echo "BLOCK -- secret, format, or path issue. Fix and re-run."
|
||||
exit 2
|
||||
elif [[ $MAJOR -eq 1 ]]; then
|
||||
echo "REVISE -- major issues found. Fix and re-run."
|
||||
exit 1
|
||||
elif [[ $MINOR -eq 1 ]]; then
|
||||
echo "PASS (with minor notes) -- ready to post."
|
||||
exit 0
|
||||
else
|
||||
echo "PASS -- ready to post."
|
||||
exit 0
|
||||
fi
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
#!/usr/bin/env bash
|
||||
# new-page.sh
|
||||
# Scaffold a new Confluence page draft from a template into the local drafts
|
||||
# folder. The draft is storage-format XHTML, ready to fill and post.
|
||||
#
|
||||
# Usage:
|
||||
# bash scripts/new-page.sh <space> <title> [template]
|
||||
# space : AVP, BASS, etc. (see confluence-page/references/space-keys.md)
|
||||
# title : Page title; spaces become + in the storage path
|
||||
# template : hub | how-to | rfc | postmortem (default: hub)
|
||||
#
|
||||
# Writes to:
|
||||
# ~/Netcracker/Projects/NDO/knowledge/confluence/drafts/<SPACE>/<slug>.xml
|
||||
#
|
||||
# Exit: 0 on success, 1 on bad args, 2 on missing template.
|
||||
|
||||
set -eu
|
||||
|
||||
if [[ $# -lt 2 ]]; then
|
||||
echo "Usage: $0 <space> <title> [template]" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SPACE="$(echo "$1" | tr '[:lower:]' '[:upper:]')"
|
||||
TITLE="$2"
|
||||
TEMPLATE="${3:-hub}"
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
ROOT="$(dirname "$SCRIPT_DIR")"
|
||||
TEMPLATE_FILE="$ROOT/templates/${TEMPLATE}.md"
|
||||
|
||||
if [[ ! -f "$TEMPLATE_FILE" ]]; then
|
||||
echo "Template not found: $TEMPLATE_FILE" >&2
|
||||
echo "Available templates:" >&2
|
||||
ls "$ROOT/templates" 2>/dev/null | sed 's/\.md$//' | sed 's/^/ - /' >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
DRAFT_ROOT="${DRAFT_ROOT:-$HOME/Netcracker/Projects/NDO/knowledge/confluence/drafts}"
|
||||
DRAFT_DIR="$DRAFT_ROOT/$SPACE"
|
||||
mkdir -p "$DRAFT_DIR"
|
||||
|
||||
SLUG="$(echo "$TITLE" | tr '[:upper:]' '[:lower:]' | tr ' /' '--' | tr -cd 'a-z0-9-_')"
|
||||
DRAFT_FILE="$DRAFT_DIR/${SLUG}.xml"
|
||||
|
||||
{
|
||||
echo '<?xml version="1.0" encoding="UTF-8"?>'
|
||||
echo "<page xmlns:ac=\"http://atlassian.com/content\" xmlns:ri=\"http://atlassian.com/resource/identifier\">"
|
||||
echo " <title>$TITLE</title>"
|
||||
echo " <space>$SPACE</space>"
|
||||
echo " <body>"
|
||||
echo " <h1>$TITLE</h1>"
|
||||
echo " <p><em>Drafted $(date -u +%Y-%m-%d). Edit the body below this line; the title and space are set above.</em></p>"
|
||||
echo ""
|
||||
echo "<!--"
|
||||
cat "$TEMPLATE_FILE"
|
||||
echo ""
|
||||
echo "-->"
|
||||
echo ""
|
||||
echo " <p>Body starts here.</p>"
|
||||
echo ""
|
||||
echo " </body>"
|
||||
echo "</page>"
|
||||
} > "$DRAFT_FILE"
|
||||
|
||||
echo "Draft created: $DRAFT_FILE"
|
||||
echo "Space: $SPACE"
|
||||
echo "Title: $TITLE"
|
||||
echo "Template: $TEMPLATE"
|
||||
echo
|
||||
echo "Next:"
|
||||
echo " 1. Fill the body between <body> and </body> using storage XHTML."
|
||||
echo " 2. Run bash $SCRIPT_DIR/dry-run-publish.sh \"$DRAFT_FILE\""
|
||||
echo " 3. Post via mcp-atlassian: confluence_create_page_from_file."
|
||||
Reference in New Issue
Block a user