@slamb2k/mad-skills 2.0.26 → 2.0.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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mad-skills",
3
3
  "description": "AI-assisted planning, development and governance tools",
4
- "version": "2.0.26",
4
+ "version": "2.0.27",
5
5
  "author": {
6
6
  "name": "slamb2k",
7
7
  "url": "https://github.com/slamb2k"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@slamb2k/mad-skills",
3
- "version": "2.0.26",
3
+ "version": "2.0.27",
4
4
  "description": "Claude Code skills collection — full lifecycle development tools",
5
5
  "type": "module",
6
6
  "repository": {
@@ -273,13 +273,24 @@ Parse VERIFY_REPORT. Present the final summary using the format in
273
273
 
274
274
  **Only if the project is a git repo** (from SCAN_REPORT `git_initialized`).
275
275
 
276
- Check if the default branch (main or master) has branch protection:
276
+ Detect the default branch and hosting platform:
277
277
 
278
278
  ```bash
279
279
  default_branch=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's@^refs/remotes/origin/@@' || echo "main")
280
+
281
+ REMOTE_URL=$(git remote get-url origin 2>/dev/null)
282
+ if echo "$REMOTE_URL" | grep -qiE 'dev\.azure\.com|visualstudio\.com'; then
283
+ PLATFORM="azdo"
284
+ elif echo "$REMOTE_URL" | grep -qi 'github\.com'; then
285
+ PLATFORM="github"
286
+ else
287
+ PLATFORM="unknown"
288
+ fi
280
289
  ```
281
290
 
282
- If a GitHub remote is detected (`git remote get-url origin` matches github.com):
291
+ ### GitHub
292
+
293
+ If `PLATFORM == github`:
283
294
  1. Check for existing branch protection via `gh api repos/{owner}/{repo}/branches/{default_branch}/protection` (404 = unprotected)
284
295
  2. If unprotected, ask via AskUserQuestion:
285
296
 
@@ -299,6 +310,108 @@ If a GitHub remote is detected (`git remote get-url origin` matches github.com):
299
310
  -F allow_deletions=false
300
311
  ```
301
312
 
313
+ ### Azure DevOps
314
+
315
+ If `PLATFORM == azdo`:
316
+
317
+ Extract org and project from the remote URL (same pattern as `/ship`):
318
+ ```bash
319
+ if echo "$REMOTE_URL" | grep -q 'dev\.azure\.com'; then
320
+ AZDO_ORG=$(echo "$REMOTE_URL" | sed -n 's|.*dev\.azure\.com/\([^/]*\)/.*|\1|p')
321
+ AZDO_PROJECT=$(echo "$REMOTE_URL" | sed -n 's|.*dev\.azure\.com/[^/]*/\([^/]*\)/.*|\1|p')
322
+ AZDO_ORG_URL="https://dev.azure.com/$AZDO_ORG"
323
+ elif echo "$REMOTE_URL" | grep -q 'vs-ssh\.visualstudio\.com'; then
324
+ AZDO_ORG=$(echo "$REMOTE_URL" | sed -n 's|.*vs-ssh\.visualstudio\.com:v3/\([^/]*\)/.*|\1|p')
325
+ AZDO_PROJECT=$(echo "$REMOTE_URL" | sed -n 's|.*vs-ssh\.visualstudio\.com:v3/[^/]*/\([^/]*\)/.*|\1|p')
326
+ AZDO_ORG_URL="https://dev.azure.com/$AZDO_ORG"
327
+ elif echo "$REMOTE_URL" | grep -q 'visualstudio\.com'; then
328
+ AZDO_ORG=$(echo "$REMOTE_URL" | sed -n 's|.*//\([^.]*\)\.visualstudio\.com.*|\1|p')
329
+ AZDO_PROJECT=$(echo "$REMOTE_URL" | sed -n 's|.*/\([^/]*\)/_git/.*|\1|p')
330
+ AZDO_ORG_URL="https://dev.azure.com/$AZDO_ORG"
331
+ fi
332
+ REPO_NAME=$(basename -s .git "$REMOTE_URL")
333
+ ```
334
+
335
+ If org/project extraction fails, report ⚠️ and skip branch policies.
336
+
337
+ 1. Check for existing branch policies. Use `az repos` CLI if available,
338
+ otherwise fall back to REST API:
339
+
340
+ **CLI:**
341
+ ```bash
342
+ az repos policy list \
343
+ --org "$AZDO_ORG_URL" --project "$AZDO_PROJECT" \
344
+ --repository-id "$REPO_NAME" --branch "$default_branch" \
345
+ --query "[].type.displayName" -o tsv
346
+ ```
347
+
348
+ **REST fallback:**
349
+ ```bash
350
+ AUTH="Authorization: Basic $(echo -n ":$PAT" | base64)"
351
+ # Get repository ID first
352
+ REPO_ID=$(curl -s -H "$AUTH" \
353
+ "$AZDO_ORG_URL/$AZDO_PROJECT/_apis/git/repositories/$REPO_NAME?api-version=7.0" \
354
+ | jq -r '.id')
355
+ # List branch policies
356
+ curl -s -H "$AUTH" \
357
+ "$AZDO_ORG_URL/$AZDO_PROJECT/_apis/policy/configurations?api-version=7.0" \
358
+ | jq "[.value[] | select(.settings.scope[]?.refName == \"refs/heads/$default_branch\" and .settings.scope[]?.repositoryId == \"$REPO_ID\")]"
359
+ ```
360
+
361
+ 2. If no "Minimum number of reviewers" policy exists, ask via AskUserQuestion:
362
+
363
+ Question: "Default branch `{default_branch}` has no minimum reviewer policy. Add it?"
364
+ Options:
365
+ - "Yes, require PR reviews (Recommended)" — require 1 approval, block direct push
366
+ - "Skip" — leave unprotected
367
+
368
+ 3. If user accepts, create the policy:
369
+
370
+ **CLI:**
371
+ ```bash
372
+ REPO_ID=$(az repos show --repository "$REPO_NAME" \
373
+ --org "$AZDO_ORG_URL" --project "$AZDO_PROJECT" \
374
+ --query 'id' -o tsv)
375
+
376
+ az repos policy approver-count create \
377
+ --org "$AZDO_ORG_URL" --project "$AZDO_PROJECT" \
378
+ --repository-id "$REPO_ID" --branch "$default_branch" \
379
+ --minimum-approver-count 1 \
380
+ --creator-vote-counts false \
381
+ --allow-downvotes false \
382
+ --reset-on-source-push true \
383
+ --blocking true --enabled true
384
+ ```
385
+
386
+ **REST fallback:**
387
+ ```bash
388
+ curl -s -X POST -H "$AUTH" -H "Content-Type: application/json" \
389
+ "$AZDO_ORG_URL/$AZDO_PROJECT/_apis/policy/configurations?api-version=7.0" \
390
+ -d "{
391
+ \"isEnabled\": true,
392
+ \"isBlocking\": true,
393
+ \"type\": {\"id\": \"fa4e907d-c16b-4a4c-9dfa-4906e5d171dd\"},
394
+ \"settings\": {
395
+ \"minimumApproverCount\": 1,
396
+ \"creatorVoteCounts\": false,
397
+ \"allowDownvotes\": false,
398
+ \"resetOnSourcePush\": true,
399
+ \"scope\": [{
400
+ \"repositoryId\": \"$REPO_ID\",
401
+ \"refName\": \"refs/heads/$default_branch\",
402
+ \"matchKind\": \"exact\"
403
+ }]
404
+ }
405
+ }"
406
+ ```
407
+
408
+ ### Unknown Platform
409
+
410
+ If `PLATFORM == unknown`, skip branch protection and report:
411
+ ```
412
+ ⏭️ Branch protection — skipped (unrecognized remote, not GitHub or Azure DevOps)
413
+ ```
414
+
302
415
  Include result in the final report under a "🔒 Branch protection" section.
303
416
 
304
417
  ---
@@ -1,12 +1,12 @@
1
1
  {
2
- "generated": "2026-03-12T03:25:58.495Z",
2
+ "generated": "2026-03-12T10:15:46.290Z",
3
3
  "count": 10,
4
4
  "skills": [
5
5
  {
6
6
  "name": "brace",
7
7
  "directory": "brace",
8
8
  "description": "'Initialize any project directory with a standard scaffold for AI-assisted development. Creates specs/ and context/ directories, a project CLAUDE.md with development workflow and guardrails, .gitignore, and branch protection. Recommends claude-mem for persistent memory. Idempotent — safe to run on existing projects. Triggers: \"init project\", \"setup brace\", \"brace\", \"initialize\", \"bootstrap\", \"scaffold\".'",
9
- "lines": 328,
9
+ "lines": 441,
10
10
  "hasScripts": false,
11
11
  "hasReferences": true,
12
12
  "hasAssets": true,