@elalfner/relevo 0.7.0 → 0.9.0

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 (45) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.es.md +1 -0
  3. package/README.md +1 -0
  4. package/package.json +1 -1
  5. package/scripts/doctor.mjs +5 -4
  6. package/scripts/init.mjs +25 -4
  7. package/scripts/lib/can-edit-issue.mjs +4 -1
  8. package/scripts/lib/cli.mjs +6 -4
  9. package/scripts/lib/config.mjs +19 -1
  10. package/scripts/lib/doctor.mjs +264 -25
  11. package/scripts/lib/github.mjs +15 -5
  12. package/scripts/lib/init.mjs +89 -6
  13. package/scripts/lib/labels.mjs +4 -0
  14. package/scripts/lib/messages.mjs +109 -0
  15. package/scripts/lib/next-step.mjs +12 -0
  16. package/scripts/lib/plan.mjs +29 -6
  17. package/scripts/lib/preflight.mjs +1 -1
  18. package/scripts/lib/review-events.mjs +6 -3
  19. package/scripts/lib/ship-github.mjs +87 -0
  20. package/scripts/lib/ship-unattended.mjs +271 -0
  21. package/scripts/lib/ship.mjs +15 -3
  22. package/scripts/lib/toolchain-check.mjs +6 -0
  23. package/scripts/lib/web-preflight.mjs +50 -4
  24. package/scripts/lib/workflow-upgrade.mjs +198 -0
  25. package/scripts/review-event.mjs +10 -1
  26. package/scripts/ship-check.mjs +6 -4
  27. package/scripts/ship-unattended.mjs +45 -0
  28. package/scripts/toolchain-check.mjs +3 -3
  29. package/scripts/web-hook.mjs +28 -0
  30. package/scripts/web-preflight.mjs +6 -5
  31. package/scripts/web-review.mjs +1 -1
  32. package/skills/doctor/SKILL.md +6 -5
  33. package/skills/go/SKILL.md +4 -2
  34. package/skills/init/SKILL.md +10 -4
  35. package/skills/review/SKILL.md +4 -3
  36. package/skills/ship/SKILL.md +3 -1
  37. package/stacks/vue.md +2 -2
  38. package/templates/agents/antigravity-step.yml +8 -5
  39. package/templates/relevo.yml +4 -0
  40. package/templates/workflows/relevo-digest.yml +11 -1
  41. package/templates/workflows/relevo-go.yml +33 -14
  42. package/templates/workflows/relevo-queue.yml +11 -1
  43. package/templates/workflows/relevo-review.yml +11 -1
  44. package/templates/workflows/relevo-ship.yml +136 -0
  45. package/templates/workflows/relevo-sla.yml +11 -1
@@ -0,0 +1,136 @@
1
+ # relevo-template: 0.9.0
2
+ # Relevo: ships an issue when a person applies the `relevo:ship` label to it.
3
+ # Copy to .github/workflows/relevo-ship.yml. If you renamed the ship label in relevo.yml, change it below too.
4
+ #
5
+ # It runs the steps of /relevo:ship with the same rules, and no model: it needs no model credential. The person who
6
+ # applied the label is the one judged (they must be the one who ships under review.merger), and the label is their
7
+ # written confirmation. It archives the specification on the branch, squash-merges the pull request, closes the issue
8
+ # and removes its labels. When anything stops it, it comments why on the issue and removes the label. Nothing from the
9
+ # pull request's branch is run: the scripts come from the published package and relevo.yml from the base branch.
10
+ #
11
+ # Checks: a push with the workflow token starts no workflows, so the archive commit gets no checks of its own. The
12
+ # checks of the approved head count for it, because it changes only openspec/. If the base branch REQUIRES status
13
+ # checks, GitHub refuses that merge: create a GitHub App for this repository (contents, pull requests and issues:
14
+ # read and write), store its id as the secret RELEVO_SHIP_APP_ID and its private key as RELEVO_SHIP_APP_KEY. The run
15
+ # then pushes, merges and closes with the App's token, so your CI runs on the archive commit, and waits for it. The App
16
+ # is also worth it when you rely on workflows that run on pushes to the base branch. Never add it to a bypass list.
17
+ #
18
+ # The repository variable RELEVO_CLOUD_SHIP set to `off` pauses it: the label then does nothing.
19
+ # This workflow runs from the default branch; it works only once it is there.
20
+
21
+ # Runner: `runs-on` comes from `runner.labels` in relevo.yml (`/relevo:init` writes it into this file, `/relevo:doctor` checks it).
22
+ # The runner needs git, gh and jq; Node and the tools of the job are installed per job. A self-hosted runner is assumed to
23
+ # persist between jobs, so the job puts its tools under $RUNNER_TEMP and removes what it adds to the workspace.
24
+
25
+ name: relevo-ship
26
+
27
+ # The version of @elalfner/relevo whose scripts this workflow runs. The plugin's templates carry the version they
28
+ # were released with, and `/relevo:init` reports this file as different when it is older; change it by hand to update.
29
+ env:
30
+ RELEVO_VERSION: '0.9.0'
31
+ # The version of OpenSpec that the job installs for itself.
32
+ OPENSPEC_VERSION: '1.14.3'
33
+
34
+ on:
35
+ issues:
36
+ types: [labeled]
37
+
38
+ # One ship per issue: a second label event waits for the first run and then finds the label gone or the issue closed.
39
+ concurrency:
40
+ group: relevo-ship-${{ github.event.issue.number }}
41
+ cancel-in-progress: false
42
+
43
+ permissions:
44
+ contents: write
45
+ issues: write
46
+ pull-requests: write
47
+ # To start the queue (relevo-queue.yml) after the close, which the workflow token's close does not start by itself.
48
+ actions: write
49
+
50
+ jobs:
51
+ ship:
52
+ # Any sender: a label applied by a bot is removed by the script without shipping anything.
53
+ if: vars.RELEVO_CLOUD_SHIP != 'off' && github.event.label.name == 'relevo:ship' && !github.event.issue.pull_request
54
+ runs-on: ubuntu-latest
55
+ # The run may wait up to 30 minutes for the checks of the archive commit.
56
+ timeout-minutes: 45
57
+ env:
58
+ HAS_APP: ${{ secrets.RELEVO_SHIP_APP_ID != '' && secrets.RELEVO_SHIP_APP_KEY != '' }}
59
+ steps:
60
+ # Only with the App: a token for this repository, used to push, merge and close.
61
+ - name: App token
62
+ id: app
63
+ if: env.HAS_APP == 'true'
64
+ uses: actions/create-github-app-token@v1
65
+ with:
66
+ app-id: ${{ secrets.RELEVO_SHIP_APP_ID }}
67
+ private-key: ${{ secrets.RELEVO_SHIP_APP_KEY }}
68
+
69
+ # The default branch, which holds this workflow and names the base branch. The script switches to the feature
70
+ # branch in this checkout only to run git and OpenSpec on it; it never installs or runs anything from it.
71
+ - uses: actions/checkout@v4
72
+ with:
73
+ path: work
74
+ fetch-depth: 0
75
+ token: ${{ steps.app.outputs.token || github.token }}
76
+
77
+ - uses: actions/setup-node@v4
78
+ with:
79
+ node-version: 22
80
+
81
+ - name: Install the Relevo scripts
82
+ # The published package at the version pinned above, unpacked outside the checkout so that the archive sees
83
+ # a clean working tree. A package without a script this job runs stops the run here, before anything changes.
84
+ run: |
85
+ mkdir -p "$RUNNER_TEMP/relevo"
86
+ npm pack "@elalfner/relevo@$RELEVO_VERSION" --silent --pack-destination "$RUNNER_TEMP" > /dev/null
87
+ tar -xzf "$RUNNER_TEMP"/elalfner-relevo-*.tgz --strip-components=1 -C "$RUNNER_TEMP/relevo"
88
+ for f in scripts/ship-unattended.mjs scripts/scan-diff.mjs scripts/check-archive.mjs scripts/stage.mjs scripts/fix-tasks.mjs scripts/conflict-scope.mjs scripts/render-message.mjs; do
89
+ [ -f "$RUNNER_TEMP/relevo/$f" ] || { echo "::error::The Relevo package $RELEVO_VERSION lacks $f"; exit 1; }
90
+ done
91
+
92
+ - name: Install OpenSpec
93
+ # Under the temporary folder of the job, at the pinned version: nothing global is left on a runner that persists.
94
+ run: |
95
+ npm install --prefix "$RUNNER_TEMP/openspec" "@fission-ai/openspec@$OPENSPEC_VERSION" --no-fund --no-audit
96
+ echo "$RUNNER_TEMP/openspec/node_modules/.bin" >> "$GITHUB_PATH"
97
+ env:
98
+ OPENSPEC_TELEMETRY: '0'
99
+
100
+ - name: Ship
101
+ working-directory: work
102
+ env:
103
+ GH_TOKEN: ${{ github.token }}
104
+ GH_PUSH_TOKEN: ${{ steps.app.outputs.token || github.token }}
105
+ OPENSPEC_TELEMETRY: '0'
106
+ GITHUB_REPOSITORY: ${{ github.repository }}
107
+ ISSUE: ${{ github.event.issue.number }}
108
+ ACTOR: ${{ github.event.sender.login }}
109
+ ACTOR_TYPE: ${{ github.event.sender.type }}
110
+ run: |
111
+ git config user.name 'github-actions[bot]'
112
+ git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
113
+ node "$RUNNER_TEMP/relevo/scripts/ship-unattended.mjs" --repo "$GITHUB_REPOSITORY" --issue "$ISSUE" --actor "$ACTOR" --actor-type "$ACTOR_TYPE" --work .
114
+
115
+ # A run that fails before it could comment (the package cannot be installed, a git or GitHub error) leaves the
116
+ # label on the issue with nobody told. If the label is still there, remove it and say so.
117
+ # If you renamed the ship label in relevo.yml, change the name below too.
118
+ - name: Report a run that ended without an outcome
119
+ if: always()
120
+ env:
121
+ GH_TOKEN: ${{ github.token }}
122
+ ISSUE: ${{ github.event.issue.number }}
123
+ ACTOR: ${{ github.event.sender.login }}
124
+ RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
125
+ run: |
126
+ labels=$(gh issue view "$ISSUE" --json labels --jq '.labels[].name')
127
+ if ! printf '%s\n' "$labels" | grep -qx 'relevo:ship'; then
128
+ exit 0
129
+ fi
130
+ gh issue edit "$ISSUE" --remove-label relevo:ship
131
+ body=""
132
+ if [ -f "$RUNNER_TEMP/relevo/scripts/render-message.mjs" ]; then
133
+ body=$(jq -n --arg issue "$ISSUE" --arg run "$RUN_URL" --arg actor "$ACTOR" '{issue: $issue, run: $run, actor: $actor}' | node "$RUNNER_TEMP/relevo/scripts/render-message.mjs" ship_failed --config work/relevo.yml) || body=""
134
+ fi
135
+ [ -n "$body" ] || body="@$ACTOR #$ISSUE was not shipped: the run ended without an outcome. Read the log to see why: $RUN_URL"
136
+ gh issue comment "$ISSUE" --body "$body"
@@ -1,14 +1,19 @@
1
+ # relevo-template: 0.9.0
1
2
  # Relevo: reminds the reviewer when a pull request waits longer than limits.review_sla_hours, and escalates
2
3
  # to the spec writer (adding the needs-reviewer label) after the same time again.
3
4
  # Copy to .github/workflows/relevo-sla.yml. Needs a relevo.yml at the repository root.
4
5
  # The scripts come from the published package @elalfner/relevo, at the version pinned in RELEVO_VERSION.
5
6
 
7
+ # Runner: `runs-on` comes from `runner.labels` in relevo.yml (`/relevo:init` writes it into this file, `/relevo:doctor` checks it).
8
+ # The runner needs git, gh and jq; Node and the tools of the job are installed per job. A self-hosted runner is assumed to
9
+ # persist between jobs, so the job puts its tools under $RUNNER_TEMP and removes what it adds to the workspace.
10
+
6
11
  name: relevo-sla
7
12
 
8
13
  # The version of @elalfner/relevo whose scripts this workflow runs. The plugin's templates carry the version they
9
14
  # were released with, and `/relevo:init` reports this file as different when it is older; change it by hand to update.
10
15
  env:
11
- RELEVO_VERSION: '0.7.0'
16
+ RELEVO_VERSION: '0.9.0'
12
17
 
13
18
  on:
14
19
  schedule:
@@ -51,3 +56,8 @@ jobs:
51
56
  GH_TOKEN: ${{ github.token }}
52
57
  GITHUB_REPOSITORY: ${{ github.repository }}
53
58
  run: node .relevo-plugin/scripts/review-sla.mjs --repo "$GITHUB_REPOSITORY"
59
+
60
+ # A runner may keep its workspace between jobs (a self-hosted one does): remove what this job added to it.
61
+ - name: Remove what this job added
62
+ if: always()
63
+ run: rm -rf .relevo-plugin