@codyswann/lisa 4.74.2 → 4.74.3

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 (61) hide show
  1. package/cdk/create-only/.github/workflows/deploy.yml +58 -1
  2. package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
  3. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  4. package/dist/core/upstream-evidence-manifest.js +8 -6
  5. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  6. package/expo/create-only/.github/workflows/deploy.yml +106 -3
  7. package/harper-fabric/create-only/.github/workflows/deploy.yml +97 -0
  8. package/nestjs/create-only/.github/workflows/deploy.yml +135 -2
  9. package/package.json +4 -4
  10. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  11. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  12. package/plugins/lisa-agy/plugin.json +1 -1
  13. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  14. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  15. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  16. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  17. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  18. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  19. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  20. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  21. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  22. package/plugins/lisa-expo-agy/plugin.json +1 -1
  23. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  24. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  25. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  26. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  27. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  28. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  29. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  30. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  31. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  32. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  33. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  34. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  35. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  36. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  37. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  38. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  39. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  40. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  41. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  42. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  43. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  44. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  45. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  46. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  47. package/plugins/lisa-rails-agy/plugin.json +1 -1
  48. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  49. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  50. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  51. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  52. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  53. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  54. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  55. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  56. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  57. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  58. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  59. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  60. package/rails/create-only/.github/workflows/deploy.yml +97 -2
  61. package/scripts/two-channel-couplings.json +1 -1
@@ -22,6 +22,16 @@ on:
22
22
  - dev
23
23
  workflow_dispatch:
24
24
  inputs:
25
+ rollback_commit:
26
+ description: 'Commit SHA to deploy for a deliberate rollback; leave empty for the run commit'
27
+ required: false
28
+ default: ''
29
+ type: string
30
+ force_stale_deploy:
31
+ description: "Allow a deliberate rollback to this run's old commit (may overwrite a newer deployment)"
32
+ required: false
33
+ default: false
34
+ type: boolean
25
35
  environment:
26
36
  description: 'Environment to deploy to'
27
37
  required: true
@@ -43,6 +53,53 @@ concurrency:
43
53
  cancel-in-progress: true
44
54
 
45
55
  jobs:
56
+ # Re-runs retain their original SHA. Refuse an old run before release or deployment.
57
+ validate_deploy_commit:
58
+ name: 🚦 Validate Deployment Commit
59
+ runs-on: ubuntu-latest
60
+ timeout-minutes: 5
61
+ permissions:
62
+ contents: read
63
+ steps:
64
+ - uses: actions/checkout@v6
65
+ with:
66
+ ref: ${{ github.event_name == 'workflow_dispatch' && inputs.rollback_commit || github.sha }}
67
+ # Check the actual checkout again on job-only retries; earlier jobs may not rerun.
68
+ - name: 🚦 Refuse stale deployment
69
+ shell: bash
70
+ env:
71
+ DEPLOY_BRANCH: ${{ github.event_name == 'workflow_dispatch' && inputs.environment || github.ref_name }}
72
+ DEPLOY_EVENT: ${{ github.event_name }}
73
+ FORCE_STALE_DEPLOY: ${{ github.event_name == 'workflow_dispatch' && inputs.force_stale_deploy == true }}
74
+ run: |
75
+ set -euo pipefail
76
+ DEPLOY_SHA=$(git rev-parse HEAD)
77
+ TARGET_REF="refs/heads/$DEPLOY_BRANCH"
78
+ if ! git check-ref-format "$TARGET_REF"; then
79
+ echo "::error::Invalid deployment branch: $DEPLOY_BRANCH. Choose an existing branch."
80
+ exit 1
81
+ fi
82
+ if ! REMOTE=$(git ls-remote --exit-code --heads origin "$TARGET_REF"); then
83
+ echo "::error::Cannot read the current tip of $DEPLOY_BRANCH. Nothing will be deployed. Check repository access and the branch name, then retry."
84
+ exit 1
85
+ fi
86
+ read -r TIP RESOLVED_REF <<< "$REMOTE"
87
+ if [[ ! "$TIP" =~ ^[0-9a-f]{40}$ ]] || [ "$RESOLVED_REF" != "$TARGET_REF" ]; then
88
+ echo "::error::Could not verify the current tip of $DEPLOY_BRANCH. Nothing will be deployed."
89
+ exit 1
90
+ fi
91
+ if [ "$DEPLOY_SHA" = "$TIP" ]; then
92
+ echo "✅ Deployment commit $DEPLOY_SHA is the current tip of $DEPLOY_BRANCH."
93
+ exit 0
94
+ fi
95
+ if [ "$DEPLOY_EVENT" = "workflow_dispatch" ] && [ "$FORCE_STALE_DEPLOY" = "true" ]; then
96
+ echo "::warning title=Deliberate stale deployment::Deploying non-tip commit $DEPLOY_SHA to $DEPLOY_BRANCH; the current branch tip is $TIP. force_stale_deploy was explicitly enabled."
97
+ echo "### ⚠️ Deliberate rollback: deploying $DEPLOY_SHA to $DEPLOY_BRANCH instead of current tip $TIP." >> "${GITHUB_STEP_SUMMARY:-/dev/stdout}"
98
+ exit 0
99
+ fi
100
+ echo "::error title=Stale deployment refused::This run would deploy $DEPLOY_SHA, but $DEPLOY_BRANCH is now at $TIP. This is probably a re-run of an old run and would roll the environment back. Re-run the latest deploy run for this branch, or start workflow_dispatch on the branch tip. For a deliberate rollback only, explicitly enable force_stale_deploy in a manual run."
101
+ exit 1
102
+
46
103
  # Environment setup
47
104
  determine_environment:
48
105
  name: 🌍 Determine Environment
@@ -104,7 +161,7 @@ jobs:
104
161
  pre_deploy_gates:
105
162
  name: 🚦 Pre-Deploy Gates
106
163
  uses: CodySwannGT/lisa/.github/workflows/gates.yml@main
107
- needs: [determine_environment]
164
+ needs: [determine_environment, validate_deploy_commit]
108
165
  with:
109
166
  # Travels with the `uses:` line above — the two are one unit. Lisa's
110
167
  # reusable workflows are tracked at `@main`, so that file changes under
@@ -238,7 +295,14 @@ jobs:
238
295
  # Trigger EAS Build if needed (only runs if app config changed)
239
296
  trigger_eas_build:
240
297
  name: Trigger EAS Build
241
- needs: [determine_environment, check_eas_setup, check_app_config_changes]
298
+ needs:
299
+ [
300
+ determine_environment,
301
+ check_eas_setup,
302
+ check_app_config_changes,
303
+ validate_deploy_commit,
304
+ release,
305
+ ]
242
306
  if: needs.check_eas_setup.outputs.has_eas_setup == 'true' && (needs.check_app_config_changes.outputs.app_config_changed == 'true' || inputs.force_build == true)
243
307
  uses: CodySwannGT/lisa/.github/workflows/build.yml@main
244
308
  permissions:
@@ -252,6 +316,9 @@ jobs:
252
316
  # (CodySwannGT/lisa#3698).
253
317
  expected_workflow_contract_major: '1'
254
318
  environment: ${{ needs.determine_environment.outputs.environment }}
319
+ deployment_branch: ${{ needs.determine_environment.outputs.environment }}
320
+ source_ref: ${{ inputs.force_stale_deploy == true && (inputs.rollback_commit || github.sha) || needs.release.outputs.release_commit || github.sha }}
321
+ force_stale_deploy: ${{ github.event_name == 'workflow_dispatch' && inputs.force_stale_deploy == true }}
255
322
  secrets:
256
323
  EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }}
257
324
  LISA_SECRETS_BOOTSTRAP: ${{ secrets.BWS_ACCESS_TOKEN }}
@@ -325,7 +392,43 @@ jobs:
325
392
  - name: Checkout repository
326
393
  uses: actions/checkout@v6
327
394
  with:
328
- ref: ${{ github.ref }} # Use branch HEAD to include version bump from release job
395
+ ref: ${{ inputs.force_stale_deploy == true && (inputs.rollback_commit || github.sha) || needs.release.outputs.release_commit || github.sha }}
396
+ # Check the actual checkout again on job-only retries; earlier jobs may not rerun.
397
+ - name: 🚦 Refuse stale deployment
398
+ shell: bash
399
+ env:
400
+ DEPLOY_BRANCH: ${{ github.event_name == 'workflow_dispatch' && inputs.environment || github.ref_name }}
401
+ DEPLOY_EVENT: ${{ github.event_name }}
402
+ FORCE_STALE_DEPLOY: ${{ github.event_name == 'workflow_dispatch' && inputs.force_stale_deploy == true }}
403
+ run: |
404
+ set -euo pipefail
405
+ DEPLOY_SHA=$(git rev-parse HEAD)
406
+ TARGET_REF="refs/heads/$DEPLOY_BRANCH"
407
+ if ! git check-ref-format "$TARGET_REF"; then
408
+ echo "::error::Invalid deployment branch: $DEPLOY_BRANCH. Choose an existing branch."
409
+ exit 1
410
+ fi
411
+ if ! REMOTE=$(git ls-remote --exit-code --heads origin "$TARGET_REF"); then
412
+ echo "::error::Cannot read the current tip of $DEPLOY_BRANCH. Nothing will be deployed. Check repository access and the branch name, then retry."
413
+ exit 1
414
+ fi
415
+ read -r TIP RESOLVED_REF <<< "$REMOTE"
416
+ if [[ ! "$TIP" =~ ^[0-9a-f]{40}$ ]] || [ "$RESOLVED_REF" != "$TARGET_REF" ]; then
417
+ echo "::error::Could not verify the current tip of $DEPLOY_BRANCH. Nothing will be deployed."
418
+ exit 1
419
+ fi
420
+ if [ "$DEPLOY_SHA" = "$TIP" ]; then
421
+ echo "✅ Deployment commit $DEPLOY_SHA is the current tip of $DEPLOY_BRANCH."
422
+ exit 0
423
+ fi
424
+ if [ "$DEPLOY_EVENT" = "workflow_dispatch" ] && [ "$FORCE_STALE_DEPLOY" = "true" ]; then
425
+ echo "::warning title=Deliberate stale deployment::Deploying non-tip commit $DEPLOY_SHA to $DEPLOY_BRANCH; the current branch tip is $TIP. force_stale_deploy was explicitly enabled."
426
+ echo "### ⚠️ Deliberate rollback: deploying $DEPLOY_SHA to $DEPLOY_BRANCH instead of current tip $TIP." >> "${GITHUB_STEP_SUMMARY:-/dev/stdout}"
427
+ exit 0
428
+ fi
429
+ echo "::error title=Stale deployment refused::This run would deploy $DEPLOY_SHA, but $DEPLOY_BRANCH is now at $TIP. This is probably a re-run of an old run and would roll the environment back. Re-run the latest deploy run for this branch, or start workflow_dispatch on the branch tip. For a deliberate rollback only, explicitly enable force_stale_deploy in a manual run."
430
+ exit 1
431
+
329
432
  - name: 🔧 Setup Node.js
330
433
  uses: actions/setup-node@v6
331
434
  with:
@@ -11,12 +11,70 @@ on:
11
11
  branches:
12
12
  - main
13
13
  workflow_dispatch:
14
+ inputs:
15
+ rollback_commit:
16
+ description: 'Commit SHA to deploy for a deliberate rollback; leave empty for the run commit'
17
+ required: false
18
+ default: ''
19
+ type: string
20
+ force_stale_deploy:
21
+ description: "Allow a deliberate rollback to this run's old commit (may overwrite a newer deployment)"
22
+ required: false
23
+ default: false
24
+ type: boolean
14
25
 
15
26
  concurrency:
16
27
  group: harper-fabric-deploy-${{ github.ref }}
17
28
  cancel-in-progress: true
18
29
 
19
30
  jobs:
31
+ # Re-runs retain their original SHA. Refuse an old run before release or deployment.
32
+ validate_deploy_commit:
33
+ name: 🚦 Validate Deployment Commit
34
+ runs-on: ubuntu-latest
35
+ timeout-minutes: 5
36
+ permissions:
37
+ contents: read
38
+ steps:
39
+ - uses: actions/checkout@v6
40
+ with:
41
+ ref: ${{ github.event_name == 'workflow_dispatch' && inputs.rollback_commit || github.sha }}
42
+ # Check the actual checkout again on job-only retries; earlier jobs may not rerun.
43
+ - name: 🚦 Refuse stale deployment
44
+ shell: bash
45
+ env:
46
+ DEPLOY_BRANCH: ${{ github.event_name == 'workflow_dispatch' && inputs.environment || github.ref_name }}
47
+ DEPLOY_EVENT: ${{ github.event_name }}
48
+ FORCE_STALE_DEPLOY: ${{ github.event_name == 'workflow_dispatch' && inputs.force_stale_deploy == true }}
49
+ run: |
50
+ set -euo pipefail
51
+ DEPLOY_SHA=$(git rev-parse HEAD)
52
+ TARGET_REF="refs/heads/$DEPLOY_BRANCH"
53
+ if ! git check-ref-format "$TARGET_REF"; then
54
+ echo "::error::Invalid deployment branch: $DEPLOY_BRANCH. Choose an existing branch."
55
+ exit 1
56
+ fi
57
+ if ! REMOTE=$(git ls-remote --exit-code --heads origin "$TARGET_REF"); then
58
+ echo "::error::Cannot read the current tip of $DEPLOY_BRANCH. Nothing will be deployed. Check repository access and the branch name, then retry."
59
+ exit 1
60
+ fi
61
+ read -r TIP RESOLVED_REF <<< "$REMOTE"
62
+ if [[ ! "$TIP" =~ ^[0-9a-f]{40}$ ]] || [ "$RESOLVED_REF" != "$TARGET_REF" ]; then
63
+ echo "::error::Could not verify the current tip of $DEPLOY_BRANCH. Nothing will be deployed."
64
+ exit 1
65
+ fi
66
+ if [ "$DEPLOY_SHA" = "$TIP" ]; then
67
+ echo "✅ Deployment commit $DEPLOY_SHA is the current tip of $DEPLOY_BRANCH."
68
+ exit 0
69
+ fi
70
+ if [ "$DEPLOY_EVENT" = "workflow_dispatch" ] && [ "$FORCE_STALE_DEPLOY" = "true" ]; then
71
+ echo "::warning title=Deliberate stale deployment::Deploying non-tip commit $DEPLOY_SHA to $DEPLOY_BRANCH; the current branch tip is $TIP. force_stale_deploy was explicitly enabled."
72
+ echo "### ⚠️ Deliberate rollback: deploying $DEPLOY_SHA to $DEPLOY_BRANCH instead of current tip $TIP." >> "${GITHUB_STEP_SUMMARY:-/dev/stdout}"
73
+ exit 0
74
+ fi
75
+ echo "::error title=Stale deployment refused::This run would deploy $DEPLOY_SHA, but $DEPLOY_BRANCH is now at $TIP. This is probably a re-run of an old run and would roll the environment back. Re-run the latest deploy run for this branch, or start workflow_dispatch on the branch tip. For a deliberate rollback only, explicitly enable force_stale_deploy in a manual run."
76
+ exit 1
77
+
20
78
  # ── Pre-deploy gates ──────────────────────────────────────────────────────
21
79
  # Resolves `pre-deploy:<branch>` from the `gates` block of .lisa.config.json
22
80
  # and runs whatever is declared there, BEFORE the deploy job.
@@ -30,6 +88,7 @@ jobs:
30
88
  # nothing is deployed. A gate job running BESIDE the deploy would go red after
31
89
  # the thing had already shipped, which is a report.
32
90
  pre_deploy_gates:
91
+ needs: [validate_deploy_commit]
33
92
  name: 🚦 Pre-Deploy Gates
34
93
  uses: CodySwannGT/lisa/.github/workflows/gates.yml@main
35
94
  with:
@@ -60,6 +119,44 @@ jobs:
60
119
  steps:
61
120
  - name: Checkout
62
121
  uses: actions/checkout@v6
122
+ with:
123
+ ref: ${{ inputs.force_stale_deploy == true && (inputs.rollback_commit || github.sha) || github.sha }}
124
+
125
+ # Check the actual checkout again on job-only retries; earlier jobs may not rerun.
126
+ - name: 🚦 Refuse stale deployment
127
+ shell: bash
128
+ env:
129
+ DEPLOY_BRANCH: ${{ github.event_name == 'workflow_dispatch' && inputs.environment || github.ref_name }}
130
+ DEPLOY_EVENT: ${{ github.event_name }}
131
+ FORCE_STALE_DEPLOY: ${{ github.event_name == 'workflow_dispatch' && inputs.force_stale_deploy == true }}
132
+ run: |
133
+ set -euo pipefail
134
+ DEPLOY_SHA=$(git rev-parse HEAD)
135
+ TARGET_REF="refs/heads/$DEPLOY_BRANCH"
136
+ if ! git check-ref-format "$TARGET_REF"; then
137
+ echo "::error::Invalid deployment branch: $DEPLOY_BRANCH. Choose an existing branch."
138
+ exit 1
139
+ fi
140
+ if ! REMOTE=$(git ls-remote --exit-code --heads origin "$TARGET_REF"); then
141
+ echo "::error::Cannot read the current tip of $DEPLOY_BRANCH. Nothing will be deployed. Check repository access and the branch name, then retry."
142
+ exit 1
143
+ fi
144
+ read -r TIP RESOLVED_REF <<< "$REMOTE"
145
+ if [[ ! "$TIP" =~ ^[0-9a-f]{40}$ ]] || [ "$RESOLVED_REF" != "$TARGET_REF" ]; then
146
+ echo "::error::Could not verify the current tip of $DEPLOY_BRANCH. Nothing will be deployed."
147
+ exit 1
148
+ fi
149
+ if [ "$DEPLOY_SHA" = "$TIP" ]; then
150
+ echo "✅ Deployment commit $DEPLOY_SHA is the current tip of $DEPLOY_BRANCH."
151
+ exit 0
152
+ fi
153
+ if [ "$DEPLOY_EVENT" = "workflow_dispatch" ] && [ "$FORCE_STALE_DEPLOY" = "true" ]; then
154
+ echo "::warning title=Deliberate stale deployment::Deploying non-tip commit $DEPLOY_SHA to $DEPLOY_BRANCH; the current branch tip is $TIP. force_stale_deploy was explicitly enabled."
155
+ echo "### ⚠️ Deliberate rollback: deploying $DEPLOY_SHA to $DEPLOY_BRANCH instead of current tip $TIP." >> "${GITHUB_STEP_SUMMARY:-/dev/stdout}"
156
+ exit 0
157
+ fi
158
+ echo "::error title=Stale deployment refused::This run would deploy $DEPLOY_SHA, but $DEPLOY_BRANCH is now at $TIP. This is probably a re-run of an old run and would roll the environment back. Re-run the latest deploy run for this branch, or start workflow_dispatch on the branch tip. For a deliberate rollback only, explicitly enable force_stale_deploy in a manual run."
159
+ exit 1
63
160
 
64
161
  - name: Setup Node.js
65
162
  uses: actions/setup-node@v6
@@ -22,6 +22,16 @@ on:
22
22
  - dev
23
23
  workflow_dispatch:
24
24
  inputs:
25
+ rollback_commit:
26
+ description: 'Commit SHA to deploy for a deliberate rollback; leave empty for the run commit'
27
+ required: false
28
+ default: ''
29
+ type: string
30
+ force_stale_deploy:
31
+ description: "Allow a deliberate rollback to this run's old commit (may overwrite a newer deployment)"
32
+ required: false
33
+ default: false
34
+ type: boolean
25
35
  environment:
26
36
  description: 'Environment to deploy to'
27
37
  required: true
@@ -38,6 +48,53 @@ concurrency:
38
48
  cancel-in-progress: true
39
49
 
40
50
  jobs:
51
+ # Re-runs retain their original SHA. Refuse an old run before release or deployment.
52
+ validate_deploy_commit:
53
+ name: 🚦 Validate Deployment Commit
54
+ runs-on: ubuntu-latest
55
+ timeout-minutes: 5
56
+ permissions:
57
+ contents: read
58
+ steps:
59
+ - uses: actions/checkout@v6
60
+ with:
61
+ ref: ${{ github.event_name == 'workflow_dispatch' && inputs.rollback_commit || github.sha }}
62
+ # Check the actual checkout again on job-only retries; earlier jobs may not rerun.
63
+ - name: 🚦 Refuse stale deployment
64
+ shell: bash
65
+ env:
66
+ DEPLOY_BRANCH: ${{ github.event_name == 'workflow_dispatch' && inputs.environment || github.ref_name }}
67
+ DEPLOY_EVENT: ${{ github.event_name }}
68
+ FORCE_STALE_DEPLOY: ${{ github.event_name == 'workflow_dispatch' && inputs.force_stale_deploy == true }}
69
+ run: |
70
+ set -euo pipefail
71
+ DEPLOY_SHA=$(git rev-parse HEAD)
72
+ TARGET_REF="refs/heads/$DEPLOY_BRANCH"
73
+ if ! git check-ref-format "$TARGET_REF"; then
74
+ echo "::error::Invalid deployment branch: $DEPLOY_BRANCH. Choose an existing branch."
75
+ exit 1
76
+ fi
77
+ if ! REMOTE=$(git ls-remote --exit-code --heads origin "$TARGET_REF"); then
78
+ echo "::error::Cannot read the current tip of $DEPLOY_BRANCH. Nothing will be deployed. Check repository access and the branch name, then retry."
79
+ exit 1
80
+ fi
81
+ read -r TIP RESOLVED_REF <<< "$REMOTE"
82
+ if [[ ! "$TIP" =~ ^[0-9a-f]{40}$ ]] || [ "$RESOLVED_REF" != "$TARGET_REF" ]; then
83
+ echo "::error::Could not verify the current tip of $DEPLOY_BRANCH. Nothing will be deployed."
84
+ exit 1
85
+ fi
86
+ if [ "$DEPLOY_SHA" = "$TIP" ]; then
87
+ echo "✅ Deployment commit $DEPLOY_SHA is the current tip of $DEPLOY_BRANCH."
88
+ exit 0
89
+ fi
90
+ if [ "$DEPLOY_EVENT" = "workflow_dispatch" ] && [ "$FORCE_STALE_DEPLOY" = "true" ]; then
91
+ echo "::warning title=Deliberate stale deployment::Deploying non-tip commit $DEPLOY_SHA to $DEPLOY_BRANCH; the current branch tip is $TIP. force_stale_deploy was explicitly enabled."
92
+ echo "### ⚠️ Deliberate rollback: deploying $DEPLOY_SHA to $DEPLOY_BRANCH instead of current tip $TIP." >> "${GITHUB_STEP_SUMMARY:-/dev/stdout}"
93
+ exit 0
94
+ fi
95
+ echo "::error title=Stale deployment refused::This run would deploy $DEPLOY_SHA, but $DEPLOY_BRANCH is now at $TIP. This is probably a re-run of an old run and would roll the environment back. Re-run the latest deploy run for this branch, or start workflow_dispatch on the branch tip. For a deliberate rollback only, explicitly enable force_stale_deploy in a manual run."
96
+ exit 1
97
+
41
98
  # Environment setup
42
99
  determine_environment:
43
100
  name: 🌍 Determine Environment
@@ -100,7 +157,7 @@ jobs:
100
157
  pre_deploy_gates:
101
158
  name: 🚦 Pre-Deploy Gates
102
159
  uses: CodySwannGT/lisa/.github/workflows/gates.yml@main
103
- needs: [determine_environment]
160
+ needs: [determine_environment, validate_deploy_commit]
104
161
  with:
105
162
  # Travels with the `uses:` line above — the two are one unit. Lisa's
106
163
  # reusable workflows are tracked at `@main`, so that file changes under
@@ -235,13 +292,51 @@ jobs:
235
292
  migrate:
236
293
  name: Schema Migrations
237
294
  runs-on: ubuntu-latest
238
- needs: verify_vpn
295
+ needs: [verify_vpn, release]
239
296
  if: always() && needs.verify_vpn.outputs.has_vpn_setup == 'true'
240
297
  permissions:
241
298
  id-token: write # needed to interact with GitHub's OIDC Token endpoint.
242
299
  contents: read
243
300
  steps:
244
301
  - uses: actions/checkout@v6
302
+ with:
303
+ ref: ${{ inputs.force_stale_deploy == true && (inputs.rollback_commit || github.sha) || needs.release.outputs.release_commit || github.sha }}
304
+ # Check the actual checkout again on job-only retries; earlier jobs may not rerun.
305
+ - name: 🚦 Refuse stale deployment
306
+ shell: bash
307
+ env:
308
+ DEPLOY_BRANCH: ${{ github.event_name == 'workflow_dispatch' && inputs.environment || github.ref_name }}
309
+ DEPLOY_EVENT: ${{ github.event_name }}
310
+ FORCE_STALE_DEPLOY: ${{ github.event_name == 'workflow_dispatch' && inputs.force_stale_deploy == true }}
311
+ run: |
312
+ set -euo pipefail
313
+ DEPLOY_SHA=$(git rev-parse HEAD)
314
+ TARGET_REF="refs/heads/$DEPLOY_BRANCH"
315
+ if ! git check-ref-format "$TARGET_REF"; then
316
+ echo "::error::Invalid deployment branch: $DEPLOY_BRANCH. Choose an existing branch."
317
+ exit 1
318
+ fi
319
+ if ! REMOTE=$(git ls-remote --exit-code --heads origin "$TARGET_REF"); then
320
+ echo "::error::Cannot read the current tip of $DEPLOY_BRANCH. Nothing will be deployed. Check repository access and the branch name, then retry."
321
+ exit 1
322
+ fi
323
+ read -r TIP RESOLVED_REF <<< "$REMOTE"
324
+ if [[ ! "$TIP" =~ ^[0-9a-f]{40}$ ]] || [ "$RESOLVED_REF" != "$TARGET_REF" ]; then
325
+ echo "::error::Could not verify the current tip of $DEPLOY_BRANCH. Nothing will be deployed."
326
+ exit 1
327
+ fi
328
+ if [ "$DEPLOY_SHA" = "$TIP" ]; then
329
+ echo "✅ Deployment commit $DEPLOY_SHA is the current tip of $DEPLOY_BRANCH."
330
+ exit 0
331
+ fi
332
+ if [ "$DEPLOY_EVENT" = "workflow_dispatch" ] && [ "$FORCE_STALE_DEPLOY" = "true" ]; then
333
+ echo "::warning title=Deliberate stale deployment::Deploying non-tip commit $DEPLOY_SHA to $DEPLOY_BRANCH; the current branch tip is $TIP. force_stale_deploy was explicitly enabled."
334
+ echo "### ⚠️ Deliberate rollback: deploying $DEPLOY_SHA to $DEPLOY_BRANCH instead of current tip $TIP." >> "${GITHUB_STEP_SUMMARY:-/dev/stdout}"
335
+ exit 0
336
+ fi
337
+ echo "::error title=Stale deployment refused::This run would deploy $DEPLOY_SHA, but $DEPLOY_BRANCH is now at $TIP. This is probably a re-run of an old run and would roll the environment back. Re-run the latest deploy run for this branch, or start workflow_dispatch on the branch tip. For a deliberate rollback only, explicitly enable force_stale_deploy in a manual run."
338
+ exit 1
339
+
245
340
  - uses: noliran/branch-based-secrets@ef9182f16f118c7c3d05c36973546ebc990b8c69 # v1 (2020-10-09, no semver tag)
246
341
  with:
247
342
  secrets: AWS_ACCOUNT_ID
@@ -306,6 +401,44 @@ jobs:
306
401
  contents: read
307
402
  steps:
308
403
  - uses: actions/checkout@v6
404
+ with:
405
+ ref: ${{ inputs.force_stale_deploy == true && (inputs.rollback_commit || github.sha) || needs.release.outputs.release_commit || github.sha }}
406
+ # Check the actual checkout again on job-only retries; earlier jobs may not rerun.
407
+ - name: 🚦 Refuse stale deployment
408
+ shell: bash
409
+ env:
410
+ DEPLOY_BRANCH: ${{ github.event_name == 'workflow_dispatch' && inputs.environment || github.ref_name }}
411
+ DEPLOY_EVENT: ${{ github.event_name }}
412
+ FORCE_STALE_DEPLOY: ${{ github.event_name == 'workflow_dispatch' && inputs.force_stale_deploy == true }}
413
+ run: |
414
+ set -euo pipefail
415
+ DEPLOY_SHA=$(git rev-parse HEAD)
416
+ TARGET_REF="refs/heads/$DEPLOY_BRANCH"
417
+ if ! git check-ref-format "$TARGET_REF"; then
418
+ echo "::error::Invalid deployment branch: $DEPLOY_BRANCH. Choose an existing branch."
419
+ exit 1
420
+ fi
421
+ if ! REMOTE=$(git ls-remote --exit-code --heads origin "$TARGET_REF"); then
422
+ echo "::error::Cannot read the current tip of $DEPLOY_BRANCH. Nothing will be deployed. Check repository access and the branch name, then retry."
423
+ exit 1
424
+ fi
425
+ read -r TIP RESOLVED_REF <<< "$REMOTE"
426
+ if [[ ! "$TIP" =~ ^[0-9a-f]{40}$ ]] || [ "$RESOLVED_REF" != "$TARGET_REF" ]; then
427
+ echo "::error::Could not verify the current tip of $DEPLOY_BRANCH. Nothing will be deployed."
428
+ exit 1
429
+ fi
430
+ if [ "$DEPLOY_SHA" = "$TIP" ]; then
431
+ echo "✅ Deployment commit $DEPLOY_SHA is the current tip of $DEPLOY_BRANCH."
432
+ exit 0
433
+ fi
434
+ if [ "$DEPLOY_EVENT" = "workflow_dispatch" ] && [ "$FORCE_STALE_DEPLOY" = "true" ]; then
435
+ echo "::warning title=Deliberate stale deployment::Deploying non-tip commit $DEPLOY_SHA to $DEPLOY_BRANCH; the current branch tip is $TIP. force_stale_deploy was explicitly enabled."
436
+ echo "### ⚠️ Deliberate rollback: deploying $DEPLOY_SHA to $DEPLOY_BRANCH instead of current tip $TIP." >> "${GITHUB_STEP_SUMMARY:-/dev/stdout}"
437
+ exit 0
438
+ fi
439
+ echo "::error title=Stale deployment refused::This run would deploy $DEPLOY_SHA, but $DEPLOY_BRANCH is now at $TIP. This is probably a re-run of an old run and would roll the environment back. Re-run the latest deploy run for this branch, or start workflow_dispatch on the branch tip. For a deliberate rollback only, explicitly enable force_stale_deploy in a manual run."
440
+ exit 1
441
+
309
442
  - name: Use Node.js 24.21.0
310
443
  uses: actions/setup-node@v6
311
444
  with:
package/package.json CHANGED
@@ -189,7 +189,7 @@
189
189
  "qs": "^6.16.0"
190
190
  },
191
191
  "name": "@codyswann/lisa",
192
- "version": "4.74.2",
192
+ "version": "4.74.3",
193
193
  "description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
194
194
  "main": "dist/index.js",
195
195
  "exports": {
@@ -345,7 +345,7 @@
345
345
  "test": "tests"
346
346
  },
347
347
  "types": "./dist/index.d.ts",
348
- "lisaReleaseCommit": "49bcce1aacaea1aba5ff900d13d3c6231fa54ca7",
349
- "gitHead": "49bcce1aacaea1aba5ff900d13d3c6231fa54ca7",
350
- "lisaReleaseTag": "v4.74.2"
348
+ "lisaReleaseCommit": "5c1778a99257c712d1ce7314a3e4fac988dd5332",
349
+ "gitHead": "5c1778a99257c712d1ce7314a3e4fac988dd5332",
350
+ "lisaReleaseTag": "v4.74.3"
351
351
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "4.74.2",
3
+ "version": "4.74.3",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "4.74.2",
3
+ "version": "4.74.3",
4
4
  "description": "Universal governance: agents, skills, commands, hooks, and rules for all projects.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "4.74.2",
3
+ "version": "4.74.3",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "4.74.2",
3
+ "version": "4.74.3",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "4.74.2",
3
+ "version": "4.74.3",
4
4
  "description": "AWS CDK-specific Lisa plugin.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "4.74.2",
3
+ "version": "4.74.3",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "4.74.2",
3
+ "version": "4.74.3",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "4.74.2",
3
+ "version": "4.74.3",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "4.74.2",
3
+ "version": "4.74.3",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "4.74.2",
3
+ "version": "4.74.3",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "4.74.2",
3
+ "version": "4.74.3",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "4.74.2",
3
+ "version": "4.74.3",
4
4
  "description": "Expo and React Native-specific skills, agents, rules, and MCP servers.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "4.74.2",
3
+ "version": "4.74.3",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "4.74.2",
3
+ "version": "4.74.3",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "4.74.2",
3
+ "version": "4.74.3",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "4.74.2",
3
+ "version": "4.74.3",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "4.74.2",
3
+ "version": "4.74.3",
4
4
  "description": "Harper/Fabric-specific Lisa rules for TypeScript component apps.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "4.74.2",
3
+ "version": "4.74.3",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "4.74.2",
3
+ "version": "4.74.3",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"