spets 0.1.9 → 0.1.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.
Files changed (2) hide show
  1. package/dist/index.js +140 -31
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -323,7 +323,13 @@ jobs:
323
323
  - name: Checkout
324
324
  uses: actions/checkout@v4
325
325
  with:
326
- fetch-depth: 0
326
+ fetch-depth: 1
327
+ persist-credentials: false
328
+
329
+ - name: Setup Git
330
+ run: |
331
+ git config user.name "github-actions[bot]"
332
+ git config user.email "github-actions[bot]@users.noreply.github.com"
327
333
 
328
334
  - name: Parse Issue body
329
335
  id: parse
@@ -344,17 +350,33 @@ jobs:
344
350
 
345
351
  - name: Create and checkout branch
346
352
  run: |
353
+ git remote set-url origin https://x-access-token:${gh("secrets.PAT_TOKEN")}@github.com/${gh("github.repository")}.git
347
354
  git checkout -b ${gh("steps.parse.outputs.branch")}
348
355
  git push -u origin ${gh("steps.parse.outputs.branch")}
349
- env:
350
- GH_TOKEN: ${gh("secrets.GITHUB_TOKEN")}
351
356
 
352
357
  - name: Setup Node.js
353
358
  uses: actions/setup-node@v4
354
359
  with:
355
360
  node-version: '20'
361
+ cache: 'npm'
362
+
363
+ - name: Cache global npm packages
364
+ uses: actions/cache@v4
365
+ with:
366
+ path: ~/.npm
367
+ key: ${gh("runner.os")}-npm-global-${gh("hashFiles('package-lock.json')")}
368
+ restore-keys: |
369
+ ${gh("runner.os")}-npm-global-
370
+
371
+ - name: Cache Claude Code
372
+ id: cache-claude
373
+ uses: actions/cache@v4
374
+ with:
375
+ path: /usr/local/lib/node_modules/@anthropic-ai/claude-code
376
+ key: claude-code-${gh("runner.os")}-v1
356
377
 
357
378
  - name: Install Claude Code
379
+ if: steps.cache-claude.outputs.cache-hit != 'true'
358
380
  run: npm install -g @anthropic-ai/claude-code
359
381
 
360
382
  - name: Install dependencies
@@ -370,13 +392,10 @@ jobs:
370
392
 
371
393
  - name: Push changes
372
394
  run: |
373
- git config user.name "github-actions[bot]"
374
- git config user.email "github-actions[bot]@users.noreply.github.com"
395
+ git remote set-url origin https://x-access-token:${gh("secrets.PAT_TOKEN")}@github.com/${gh("github.repository")}.git
375
396
  git add -A
376
397
  git diff --staged --quiet || git commit -m "Spets: Start workflow for #${gh("github.event.issue.number")}"
377
398
  git push
378
- env:
379
- GH_TOKEN: ${gh("secrets.GITHUB_TOKEN")}
380
399
 
381
400
  # Handle commands from Issue/PR comments
382
401
  handle-command:
@@ -389,38 +408,108 @@ jobs:
389
408
  runs-on: ubuntu-latest
390
409
 
391
410
  steps:
392
- - name: Find linked branch
411
+ - name: Find branch from Issue or PR
393
412
  id: branch
413
+ env:
414
+ GH_TOKEN: ${gh("secrets.GITHUB_TOKEN")}
394
415
  run: |
395
- # Try to find branch linked to this issue
396
- BRANCH=$(gh api repos/${gh("github.repository")}/issues/${gh("github.event.issue.number")} --jq '.body' | grep -oP 'spets/\\d+' || echo "")
397
- if [ -z "$BRANCH" ]; then
398
- BRANCH="spets/${gh("github.event.issue.number")}"
416
+ # Check if this is a PR (has pull_request field)
417
+ PR_BRANCH=$(gh api repos/${gh("github.repository")}/issues/${gh("github.event.issue.number")} --jq '.pull_request.url // empty' 2>/dev/null)
418
+
419
+ if [ -n "$PR_BRANCH" ]; then
420
+ # It's a PR - get head branch directly
421
+ BRANCH=$(gh api repos/${gh("github.repository")}/pulls/${gh("github.event.issue.number")} --jq '.head.ref')
422
+ echo "Found PR head branch: $BRANCH"
423
+ else
424
+ # It's an Issue - try to parse branch name from body
425
+ ISSUE_BODY=$(gh api repos/${gh("github.repository")}/issues/${gh("github.event.issue.number")} --jq '.body')
426
+ CUSTOM_BRANCH=$(echo "$ISSUE_BODY" | sed -n '/### Branch Name/,/###/{/###/!p;}' | sed '/^$/d' | head -1)
427
+
428
+ if [ -n "$CUSTOM_BRANCH" ]; then
429
+ BRANCH="$CUSTOM_BRANCH"
430
+ else
431
+ BRANCH="spets/${gh("github.event.issue.number")}"
432
+ fi
433
+ fi
434
+
435
+ echo "Checking for branch: $BRANCH"
436
+
437
+ # Check if branch exists on remote using gh api
438
+ if gh api "repos/${gh("github.repository")}/branches/$BRANCH" --silent 2>/dev/null; then
439
+ echo "name=$BRANCH" >> $GITHUB_OUTPUT
440
+ echo "exists=true" >> $GITHUB_OUTPUT
441
+ echo "Branch $BRANCH found!"
442
+ else
443
+ echo "exists=false" >> $GITHUB_OUTPUT
444
+ echo "expected=$BRANCH" >> $GITHUB_OUTPUT
445
+ echo "::error::Branch $BRANCH not found. Start workflow first by creating an Issue with 'spets' label."
399
446
  fi
400
- echo "name=$BRANCH" >> $GITHUB_OUTPUT
447
+
448
+ - name: Post error comment
449
+ if: steps.branch.outputs.exists == 'false'
450
+ run: |
451
+ gh issue comment ${gh("github.event.issue.number")} \\
452
+ -R "${gh("github.repository")}" \\
453
+ --body "\u274C **Spets Error**: Branch \\\`${gh("steps.branch.outputs.expected")}\\\` not found.
454
+
455
+ Please make sure the workflow was started properly. You can:
456
+ 1. Add the \\\`spets\\\` label to this issue to trigger the start workflow
457
+ 2. Or manually create the branch and run \\\`spets start\\\`"
401
458
  env:
402
459
  GH_TOKEN: ${gh("secrets.GITHUB_TOKEN")}
403
460
 
461
+ - name: Exit if branch not found
462
+ if: steps.branch.outputs.exists == 'false'
463
+ run: exit 1
464
+
404
465
  - name: Checkout
405
466
  uses: actions/checkout@v4
406
467
  with:
407
468
  ref: ${gh("steps.branch.outputs.name")}
408
- fetch-depth: 0
469
+ fetch-depth: 1
470
+ persist-credentials: false
471
+
472
+ - name: Setup Git
473
+ run: |
474
+ git config user.name "github-actions[bot]"
475
+ git config user.email "github-actions[bot]@users.noreply.github.com"
409
476
 
410
477
  - name: Setup Node.js
411
478
  uses: actions/setup-node@v4
412
479
  with:
413
480
  node-version: '20'
481
+ cache: 'npm'
482
+
483
+ - name: Cache global npm packages
484
+ uses: actions/cache@v4
485
+ with:
486
+ path: ~/.npm
487
+ key: ${gh("runner.os")}-npm-global-${gh("hashFiles('package-lock.json')")}
488
+ restore-keys: |
489
+ ${gh("runner.os")}-npm-global-
490
+
491
+ - name: Cache Claude Code
492
+ id: cache-claude
493
+ uses: actions/cache@v4
494
+ with:
495
+ path: /usr/local/lib/node_modules/@anthropic-ai/claude-code
496
+ key: claude-code-${gh("runner.os")}-v1
414
497
 
415
498
  - name: Install Claude Code
499
+ if: steps.cache-claude.outputs.cache-hit != 'true'
416
500
  run: npm install -g @anthropic-ai/claude-code
417
501
 
418
502
  - name: Install dependencies
419
503
  run: npm ci
420
504
 
421
505
  - name: Run Spets command
506
+ id: spets
422
507
  run: |
423
508
  npx spets github --issue ${gh("github.event.issue.number")} --comment "$COMMENT"
509
+ # Check if PR should be created
510
+ if [[ "$COMMENT" == "/approve --pr"* ]]; then
511
+ echo "create_pr=true" >> $GITHUB_OUTPUT
512
+ fi
424
513
  env:
425
514
  COMMENT: ${gh("github.event.comment.body")}
426
515
  CLAUDE_CODE_OAUTH_TOKEN: ${gh("secrets.CLAUDE_CODE_OAUTH_TOKEN")}
@@ -428,13 +517,33 @@ jobs:
428
517
 
429
518
  - name: Push changes
430
519
  run: |
431
- git config user.name "github-actions[bot]"
432
- git config user.email "github-actions[bot]@users.noreply.github.com"
520
+ git remote set-url origin https://x-access-token:${gh("secrets.PAT_TOKEN")}@github.com/${gh("github.repository")}.git
433
521
  git add -A
434
522
  git diff --staged --quiet || git commit -m "Spets: Update from #${gh("github.event.issue.number")}"
435
523
  git push
524
+
525
+ - name: Create PR
526
+ if: steps.spets.outputs.create_pr == 'true'
527
+ run: |
528
+ PR_BODY="Closes #${gh("github.event.issue.number")}
529
+
530
+ ---
531
+
532
+ ## Spets Commands
533
+
534
+ | Command | Description |
535
+ |---------|-------------|
536
+ | \\\`/approve\\\` | Approve current step and continue |
537
+ | \\\`/approve --pr\\\` | Approve and create PR |
538
+ | \\\`/revise <feedback>\\\` | Request changes with feedback |
539
+ | \\\`/reject\\\` | Reject and stop workflow |"
540
+
541
+ gh pr create \\
542
+ --title "Spets: Issue #${gh("github.event.issue.number")}" \\
543
+ --body "$PR_BODY" \\
544
+ --repo ${gh("github.repository")}
436
545
  env:
437
- GH_TOKEN: ${gh("secrets.GITHUB_TOKEN")}
546
+ GH_TOKEN: ${gh("secrets.PAT_TOKEN")}
438
547
  `;
439
548
  }
440
549
 
@@ -1514,28 +1623,28 @@ function installClaudePlugin() {
1514
1623
  const claudeDir = join3(homedir(), ".claude");
1515
1624
  const commandsDir = join3(claudeDir, "commands");
1516
1625
  mkdirSync2(commandsDir, { recursive: true });
1517
- const skillPath = join3(commandsDir, "sdd-do.md");
1626
+ const skillPath = join3(commandsDir, "spets.md");
1518
1627
  writeFileSync2(skillPath, getClaudeSkillContent());
1519
1628
  console.log("Installed Claude Code plugin.");
1520
1629
  console.log(`Location: ${skillPath}`);
1521
1630
  console.log("");
1522
1631
  console.log("Usage in Claude Code:");
1523
- console.log(' /sdd-do "your task description"');
1632
+ console.log(' /spets "your task description"');
1524
1633
  console.log("");
1525
1634
  console.log("This skill runs deterministically within your Claude Code session.");
1526
1635
  console.log("No additional Claude processes are spawned.");
1527
1636
  }
1528
1637
  async function uninstallPlugin(name) {
1529
1638
  if (name === "claude") {
1530
- const oldSkillPath = join3(homedir(), ".claude", "commands", "spets.md");
1531
- const newSkillPath = join3(homedir(), ".claude", "commands", "sdd-do.md");
1639
+ const skillPath = join3(homedir(), ".claude", "commands", "spets.md");
1640
+ const legacySkillPath = join3(homedir(), ".claude", "commands", "sdd-do.md");
1532
1641
  let uninstalled = false;
1533
- if (existsSync3(oldSkillPath)) {
1534
- rmSync(oldSkillPath);
1642
+ if (existsSync3(skillPath)) {
1643
+ rmSync(skillPath);
1535
1644
  uninstalled = true;
1536
1645
  }
1537
- if (existsSync3(newSkillPath)) {
1538
- rmSync(newSkillPath);
1646
+ if (existsSync3(legacySkillPath)) {
1647
+ rmSync(legacySkillPath);
1539
1648
  uninstalled = true;
1540
1649
  }
1541
1650
  if (uninstalled) {
@@ -1551,11 +1660,11 @@ async function uninstallPlugin(name) {
1551
1660
  async function listPlugins() {
1552
1661
  console.log("Available plugins:");
1553
1662
  console.log("");
1554
- console.log(" claude - Claude Code /sdd-do skill");
1663
+ console.log(" claude - Claude Code /spets skill");
1555
1664
  console.log("");
1556
- const oldSkillPath = join3(homedir(), ".claude", "commands", "spets.md");
1557
- const newSkillPath = join3(homedir(), ".claude", "commands", "sdd-do.md");
1558
- const claudeInstalled = existsSync3(oldSkillPath) || existsSync3(newSkillPath);
1665
+ const skillPath = join3(homedir(), ".claude", "commands", "spets.md");
1666
+ const legacySkillPath = join3(homedir(), ".claude", "commands", "sdd-do.md");
1667
+ const claudeInstalled = existsSync3(skillPath) || existsSync3(legacySkillPath);
1559
1668
  console.log("Installed:");
1560
1669
  if (claudeInstalled) {
1561
1670
  console.log(" - claude");
@@ -1564,7 +1673,7 @@ async function listPlugins() {
1564
1673
  }
1565
1674
  }
1566
1675
  function getClaudeSkillContent() {
1567
- return `# SDD-Do Skill
1676
+ return `# Spets - Spec Driven Development
1568
1677
 
1569
1678
  Spec-Driven Development workflow execution skill for Claude Code.
1570
1679
 
@@ -1573,7 +1682,7 @@ Spec-Driven Development workflow execution skill for Claude Code.
1573
1682
  ## When to Use This Skill
1574
1683
 
1575
1684
  Automatically invoked when user uses:
1576
- - \`/sdd-do\` - Run SDD workflow
1685
+ - \`/spets\` - Run Spets workflow
1577
1686
 
1578
1687
  ---
1579
1688
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spets",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "description": "Spec Driven Development Execution Framework",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",