@codyswann/lisa 4.87.9 → 4.87.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 (83) hide show
  1. package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
  2. package/dist/core/nightly-e2e-guard-behavior-certificate.js.map +1 -1
  3. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  4. package/dist/core/upstream-evidence-manifest.js +2 -1
  5. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  6. package/package.json +4 -4
  7. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  8. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  9. package/plugins/lisa/.codex-plugin/skills/lisa-github-evidence/SKILL.md +57 -6
  10. package/plugins/lisa/skills/lisa-github-evidence/SKILL.md +57 -6
  11. package/plugins/lisa-agy/plugin.json +1 -1
  12. package/plugins/lisa-agy/skills/lisa-github-evidence/SKILL.md +57 -6
  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-cdk-devin/.claude-plugin/plugin.json +1 -1
  19. package/plugins/lisa-cdk-devin/.devin-plugin/plugin.json +1 -1
  20. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  21. package/plugins/lisa-copilot/skills/lisa-github-evidence/SKILL.md +57 -6
  22. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  23. package/plugins/lisa-cursor/skills/lisa-github-evidence/SKILL.md +57 -6
  24. package/plugins/lisa-devin/.claude-plugin/plugin.json +1 -1
  25. package/plugins/lisa-devin/.devin-plugin/plugin.json +1 -1
  26. package/plugins/lisa-devin/skills/lisa-github-evidence/SKILL.md +57 -6
  27. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  28. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  29. package/plugins/lisa-expo-agy/plugin.json +1 -1
  30. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  31. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  32. package/plugins/lisa-expo-devin/.claude-plugin/plugin.json +1 -1
  33. package/plugins/lisa-expo-devin/.devin-plugin/plugin.json +1 -1
  34. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  35. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  36. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  37. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  38. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  39. package/plugins/lisa-harper-fabric-devin/.claude-plugin/plugin.json +1 -1
  40. package/plugins/lisa-harper-fabric-devin/.devin-plugin/plugin.json +1 -1
  41. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  42. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  43. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  44. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  45. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  46. package/plugins/lisa-nestjs-devin/.claude-plugin/plugin.json +1 -1
  47. package/plugins/lisa-nestjs-devin/.devin-plugin/plugin.json +1 -1
  48. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  49. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  50. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  51. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  52. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  53. package/plugins/lisa-openclaw-devin/.claude-plugin/plugin.json +1 -1
  54. package/plugins/lisa-openclaw-devin/.devin-plugin/plugin.json +1 -1
  55. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  56. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  57. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  58. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  59. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  60. package/plugins/lisa-phaser-devin/.claude-plugin/plugin.json +1 -1
  61. package/plugins/lisa-phaser-devin/.devin-plugin/plugin.json +1 -1
  62. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  63. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  64. package/plugins/lisa-rails-agy/plugin.json +1 -1
  65. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  66. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  67. package/plugins/lisa-rails-devin/.claude-plugin/plugin.json +1 -1
  68. package/plugins/lisa-rails-devin/.devin-plugin/plugin.json +1 -1
  69. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  70. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  71. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  72. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  73. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  74. package/plugins/lisa-typescript-devin/.claude-plugin/plugin.json +1 -1
  75. package/plugins/lisa-typescript-devin/.devin-plugin/plugin.json +1 -1
  76. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  77. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  78. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  79. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  80. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  81. package/plugins/lisa-wiki-devin/.claude-plugin/plugin.json +1 -1
  82. package/plugins/lisa-wiki-devin/.devin-plugin/plugin.json +1 -1
  83. package/plugins/src/base/skills/lisa-github-evidence/SKILL.md +57 -6
package/package.json CHANGED
@@ -189,7 +189,7 @@
189
189
  "qs": "^6.16.0"
190
190
  },
191
191
  "name": "@codyswann/lisa",
192
- "version": "4.87.9",
192
+ "version": "4.87.10",
193
193
  "description": "Governance-as-code for AI coding agents: turns a repository into agent-operated software factories with guardrails, guidance and automated enforcement for Claude Code, Codex, Cursor, OpenCode, Antigravity, Copilot and Devin",
194
194
  "main": "dist/index.js",
195
195
  "exports": {
@@ -347,7 +347,7 @@
347
347
  "test": "tests"
348
348
  },
349
349
  "types": "./dist/index.d.ts",
350
- "lisaReleaseCommit": "43da3f6a370f104973b8543b08eba3157498ab32",
351
- "gitHead": "43da3f6a370f104973b8543b08eba3157498ab32",
352
- "lisaReleaseTag": "v4.87.9"
350
+ "lisaReleaseCommit": "4f51a75361cb9455299f3e857e9156792c8c6b59",
351
+ "gitHead": "4f51a75361cb9455299f3e857e9156792c8c6b59",
352
+ "lisaReleaseTag": "v4.87.10"
353
353
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "4.87.9",
3
+ "version": "4.87.10",
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.87.9",
3
+ "version": "4.87.10",
4
4
  "description": "Universal governance: agents, skills, commands, hooks, and rules for all projects.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -54,14 +54,65 @@ If either is missing, **refuse to post**: stop and report the missing Not-establ
54
54
  3. **Upload each evidence file**
55
55
 
56
56
  ```bash
57
- for f in "$EVIDENCE_DIR"/[0-9][0-9]-*.txt "$EVIDENCE_DIR"/[0-9][0-9]-*.json; do
58
- [ -f "$f" ] || continue
59
- name="pr-${PR_NUMBER}-$(basename "$f")"
60
- gh release upload pr-assets --repo <impl-org>/<impl-repo> --clobber "$f#$name"
61
- done
57
+ (
58
+ set -e
59
+ export LC_ALL=C
60
+ upload_dir=$(mktemp -d "${TMPDIR:-/tmp}/lisa-github-evidence.XXXXXXXX")
61
+ trap 'rm -rf "$upload_dir"' EXIT
62
+ expected_names="$upload_dir/expected-names.txt"
63
+ basenames="$upload_dir/basenames.txt"
64
+ : > "$expected_names"
65
+ : > "$basenames"
66
+
67
+ for f in "$EVIDENCE_DIR"/[0-9][0-9]-*.txt "$EVIDENCE_DIR"/[0-9][0-9]-*.json; do
68
+ [ -f "$f" ] || continue
69
+ base=$(basename "$f")
70
+ if [[ ! "$base" =~ ^[0-9]{2}-[a-z0-9]+(-[a-z0-9]+)*\.(txt|json)$ ]]; then
71
+ printf 'Invalid evidence filename; use a name like 01-health-check.json or 02-output.txt: %s\n' "$base" >&2
72
+ exit 1
73
+ fi
74
+ printf '%s\n' "$base" >> "$basenames"
75
+ done
76
+
77
+ while IFS= read -r base; do
78
+ name="pr-${PR_NUMBER}-${base}"
79
+ cp "$EVIDENCE_DIR/$base" "$upload_dir/$name"
80
+ gh release upload pr-assets --repo <impl-org>/<impl-repo> --clobber "$upload_dir/$name"
81
+ printf '%s\n' "$name" >> "$expected_names"
82
+ done < "$basenames"
83
+
84
+ gh release view pr-assets --repo <impl-org>/<impl-repo> \
85
+ --json assets --jq '.assets[].name' > "$upload_dir/asset-names.txt"
86
+ while IFS= read -r name; do
87
+ if ! grep -Fxq -- "$name" "$upload_dir/asset-names.txt"; then
88
+ printf 'Expected evidence asset is missing: %s\n' "$name" >&2
89
+ exit 1
90
+ fi
91
+ printf 'Uploaded evidence asset: %s\n' "$name"
92
+ done < "$expected_names"
93
+ )
94
+ upload_status=$?
95
+ if [ "$upload_status" -ne 0 ]; then
96
+ printf 'Evidence upload failed; stop before posting.\n' >&2
97
+ exit "$upload_status"
98
+ fi
62
99
  ```
63
100
 
64
- The `#$name` syntax sets the asset name. `--clobber` lets re-runs overwrite.
101
+ Validate the complete input batch before uploading anything: use numbered,
102
+ ASCII kebab-case names such as `01-health-check.json`. GitHub can
103
+ [normalize special characters in asset names](https://docs.github.com/en/rest/releases/assets#upload-a-release-asset),
104
+ so invalid names are refused rather than renamed into another asset.
105
+
106
+ An asset takes its name from the uploaded file's basename. A `#` suffix only
107
+ sets its display label; it cannot rename the asset. Stage the copy under the
108
+ intended name before uploading. The subshell stops on copy, upload or release
109
+ read failure, checks every expected name, and removes staging on exit.
110
+ Run steps 4 and 5 only if the upload block exits successfully. On failure,
111
+ stop and report it without updating the PR or posting an issue comment.
112
+ `--clobber` replaces an existing asset with that same PR-prefixed name.
113
+
114
+ Link to the actual name:
115
+ `https://github.com/<impl-org>/<impl-repo>/releases/download/pr-assets/pr-<number>-<file>`.
65
116
 
66
117
  4. **Update the PR description**
67
118
 
@@ -52,14 +52,65 @@ If either is missing, **refuse to post**: stop and report the missing Not-establ
52
52
  3. **Upload each evidence file**
53
53
 
54
54
  ```bash
55
- for f in "$EVIDENCE_DIR"/[0-9][0-9]-*.txt "$EVIDENCE_DIR"/[0-9][0-9]-*.json; do
56
- [ -f "$f" ] || continue
57
- name="pr-${PR_NUMBER}-$(basename "$f")"
58
- gh release upload pr-assets --repo <impl-org>/<impl-repo> --clobber "$f#$name"
59
- done
55
+ (
56
+ set -e
57
+ export LC_ALL=C
58
+ upload_dir=$(mktemp -d "${TMPDIR:-/tmp}/lisa-github-evidence.XXXXXXXX")
59
+ trap 'rm -rf "$upload_dir"' EXIT
60
+ expected_names="$upload_dir/expected-names.txt"
61
+ basenames="$upload_dir/basenames.txt"
62
+ : > "$expected_names"
63
+ : > "$basenames"
64
+
65
+ for f in "$EVIDENCE_DIR"/[0-9][0-9]-*.txt "$EVIDENCE_DIR"/[0-9][0-9]-*.json; do
66
+ [ -f "$f" ] || continue
67
+ base=$(basename "$f")
68
+ if [[ ! "$base" =~ ^[0-9]{2}-[a-z0-9]+(-[a-z0-9]+)*\.(txt|json)$ ]]; then
69
+ printf 'Invalid evidence filename; use a name like 01-health-check.json or 02-output.txt: %s\n' "$base" >&2
70
+ exit 1
71
+ fi
72
+ printf '%s\n' "$base" >> "$basenames"
73
+ done
74
+
75
+ while IFS= read -r base; do
76
+ name="pr-${PR_NUMBER}-${base}"
77
+ cp "$EVIDENCE_DIR/$base" "$upload_dir/$name"
78
+ gh release upload pr-assets --repo <impl-org>/<impl-repo> --clobber "$upload_dir/$name"
79
+ printf '%s\n' "$name" >> "$expected_names"
80
+ done < "$basenames"
81
+
82
+ gh release view pr-assets --repo <impl-org>/<impl-repo> \
83
+ --json assets --jq '.assets[].name' > "$upload_dir/asset-names.txt"
84
+ while IFS= read -r name; do
85
+ if ! grep -Fxq -- "$name" "$upload_dir/asset-names.txt"; then
86
+ printf 'Expected evidence asset is missing: %s\n' "$name" >&2
87
+ exit 1
88
+ fi
89
+ printf 'Uploaded evidence asset: %s\n' "$name"
90
+ done < "$expected_names"
91
+ )
92
+ upload_status=$?
93
+ if [ "$upload_status" -ne 0 ]; then
94
+ printf 'Evidence upload failed; stop before posting.\n' >&2
95
+ exit "$upload_status"
96
+ fi
60
97
  ```
61
98
 
62
- The `#$name` syntax sets the asset name. `--clobber` lets re-runs overwrite.
99
+ Validate the complete input batch before uploading anything: use numbered,
100
+ ASCII kebab-case names such as `01-health-check.json`. GitHub can
101
+ [normalize special characters in asset names](https://docs.github.com/en/rest/releases/assets#upload-a-release-asset),
102
+ so invalid names are refused rather than renamed into another asset.
103
+
104
+ An asset takes its name from the uploaded file's basename. A `#` suffix only
105
+ sets its display label; it cannot rename the asset. Stage the copy under the
106
+ intended name before uploading. The subshell stops on copy, upload or release
107
+ read failure, checks every expected name, and removes staging on exit.
108
+ Run steps 4 and 5 only if the upload block exits successfully. On failure,
109
+ stop and report it without updating the PR or posting an issue comment.
110
+ `--clobber` replaces an existing asset with that same PR-prefixed name.
111
+
112
+ Link to the actual name:
113
+ `https://github.com/<impl-org>/<impl-repo>/releases/download/pr-assets/pr-<number>-<file>`.
63
114
 
64
115
  4. **Update the PR description**
65
116
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "4.87.9",
3
+ "version": "4.87.10",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -52,14 +52,65 @@ If either is missing, **refuse to post**: stop and report the missing Not-establ
52
52
  3. **Upload each evidence file**
53
53
 
54
54
  ```bash
55
- for f in "$EVIDENCE_DIR"/[0-9][0-9]-*.txt "$EVIDENCE_DIR"/[0-9][0-9]-*.json; do
56
- [ -f "$f" ] || continue
57
- name="pr-${PR_NUMBER}-$(basename "$f")"
58
- gh release upload pr-assets --repo <impl-org>/<impl-repo> --clobber "$f#$name"
59
- done
55
+ (
56
+ set -e
57
+ export LC_ALL=C
58
+ upload_dir=$(mktemp -d "${TMPDIR:-/tmp}/lisa-github-evidence.XXXXXXXX")
59
+ trap 'rm -rf "$upload_dir"' EXIT
60
+ expected_names="$upload_dir/expected-names.txt"
61
+ basenames="$upload_dir/basenames.txt"
62
+ : > "$expected_names"
63
+ : > "$basenames"
64
+
65
+ for f in "$EVIDENCE_DIR"/[0-9][0-9]-*.txt "$EVIDENCE_DIR"/[0-9][0-9]-*.json; do
66
+ [ -f "$f" ] || continue
67
+ base=$(basename "$f")
68
+ if [[ ! "$base" =~ ^[0-9]{2}-[a-z0-9]+(-[a-z0-9]+)*\.(txt|json)$ ]]; then
69
+ printf 'Invalid evidence filename; use a name like 01-health-check.json or 02-output.txt: %s\n' "$base" >&2
70
+ exit 1
71
+ fi
72
+ printf '%s\n' "$base" >> "$basenames"
73
+ done
74
+
75
+ while IFS= read -r base; do
76
+ name="pr-${PR_NUMBER}-${base}"
77
+ cp "$EVIDENCE_DIR/$base" "$upload_dir/$name"
78
+ gh release upload pr-assets --repo <impl-org>/<impl-repo> --clobber "$upload_dir/$name"
79
+ printf '%s\n' "$name" >> "$expected_names"
80
+ done < "$basenames"
81
+
82
+ gh release view pr-assets --repo <impl-org>/<impl-repo> \
83
+ --json assets --jq '.assets[].name' > "$upload_dir/asset-names.txt"
84
+ while IFS= read -r name; do
85
+ if ! grep -Fxq -- "$name" "$upload_dir/asset-names.txt"; then
86
+ printf 'Expected evidence asset is missing: %s\n' "$name" >&2
87
+ exit 1
88
+ fi
89
+ printf 'Uploaded evidence asset: %s\n' "$name"
90
+ done < "$expected_names"
91
+ )
92
+ upload_status=$?
93
+ if [ "$upload_status" -ne 0 ]; then
94
+ printf 'Evidence upload failed; stop before posting.\n' >&2
95
+ exit "$upload_status"
96
+ fi
60
97
  ```
61
98
 
62
- The `#$name` syntax sets the asset name. `--clobber` lets re-runs overwrite.
99
+ Validate the complete input batch before uploading anything: use numbered,
100
+ ASCII kebab-case names such as `01-health-check.json`. GitHub can
101
+ [normalize special characters in asset names](https://docs.github.com/en/rest/releases/assets#upload-a-release-asset),
102
+ so invalid names are refused rather than renamed into another asset.
103
+
104
+ An asset takes its name from the uploaded file's basename. A `#` suffix only
105
+ sets its display label; it cannot rename the asset. Stage the copy under the
106
+ intended name before uploading. The subshell stops on copy, upload or release
107
+ read failure, checks every expected name, and removes staging on exit.
108
+ Run steps 4 and 5 only if the upload block exits successfully. On failure,
109
+ stop and report it without updating the PR or posting an issue comment.
110
+ `--clobber` replaces an existing asset with that same PR-prefixed name.
111
+
112
+ Link to the actual name:
113
+ `https://github.com/<impl-org>/<impl-repo>/releases/download/pr-assets/pr-<number>-<file>`.
63
114
 
64
115
  4. **Update the PR description**
65
116
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "4.87.9",
3
+ "version": "4.87.10",
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.87.9",
3
+ "version": "4.87.10",
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.87.9",
3
+ "version": "4.87.10",
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.87.9",
3
+ "version": "4.87.10",
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.87.9",
3
+ "version": "4.87.10",
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.87.9",
3
+ "version": "4.87.10",
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.87.9",
3
+ "version": "4.87.10",
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.87.9",
3
+ "version": "4.87.10",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -52,14 +52,65 @@ If either is missing, **refuse to post**: stop and report the missing Not-establ
52
52
  3. **Upload each evidence file**
53
53
 
54
54
  ```bash
55
- for f in "$EVIDENCE_DIR"/[0-9][0-9]-*.txt "$EVIDENCE_DIR"/[0-9][0-9]-*.json; do
56
- [ -f "$f" ] || continue
57
- name="pr-${PR_NUMBER}-$(basename "$f")"
58
- gh release upload pr-assets --repo <impl-org>/<impl-repo> --clobber "$f#$name"
59
- done
55
+ (
56
+ set -e
57
+ export LC_ALL=C
58
+ upload_dir=$(mktemp -d "${TMPDIR:-/tmp}/lisa-github-evidence.XXXXXXXX")
59
+ trap 'rm -rf "$upload_dir"' EXIT
60
+ expected_names="$upload_dir/expected-names.txt"
61
+ basenames="$upload_dir/basenames.txt"
62
+ : > "$expected_names"
63
+ : > "$basenames"
64
+
65
+ for f in "$EVIDENCE_DIR"/[0-9][0-9]-*.txt "$EVIDENCE_DIR"/[0-9][0-9]-*.json; do
66
+ [ -f "$f" ] || continue
67
+ base=$(basename "$f")
68
+ if [[ ! "$base" =~ ^[0-9]{2}-[a-z0-9]+(-[a-z0-9]+)*\.(txt|json)$ ]]; then
69
+ printf 'Invalid evidence filename; use a name like 01-health-check.json or 02-output.txt: %s\n' "$base" >&2
70
+ exit 1
71
+ fi
72
+ printf '%s\n' "$base" >> "$basenames"
73
+ done
74
+
75
+ while IFS= read -r base; do
76
+ name="pr-${PR_NUMBER}-${base}"
77
+ cp "$EVIDENCE_DIR/$base" "$upload_dir/$name"
78
+ gh release upload pr-assets --repo <impl-org>/<impl-repo> --clobber "$upload_dir/$name"
79
+ printf '%s\n' "$name" >> "$expected_names"
80
+ done < "$basenames"
81
+
82
+ gh release view pr-assets --repo <impl-org>/<impl-repo> \
83
+ --json assets --jq '.assets[].name' > "$upload_dir/asset-names.txt"
84
+ while IFS= read -r name; do
85
+ if ! grep -Fxq -- "$name" "$upload_dir/asset-names.txt"; then
86
+ printf 'Expected evidence asset is missing: %s\n' "$name" >&2
87
+ exit 1
88
+ fi
89
+ printf 'Uploaded evidence asset: %s\n' "$name"
90
+ done < "$expected_names"
91
+ )
92
+ upload_status=$?
93
+ if [ "$upload_status" -ne 0 ]; then
94
+ printf 'Evidence upload failed; stop before posting.\n' >&2
95
+ exit "$upload_status"
96
+ fi
60
97
  ```
61
98
 
62
- The `#$name` syntax sets the asset name. `--clobber` lets re-runs overwrite.
99
+ Validate the complete input batch before uploading anything: use numbered,
100
+ ASCII kebab-case names such as `01-health-check.json`. GitHub can
101
+ [normalize special characters in asset names](https://docs.github.com/en/rest/releases/assets#upload-a-release-asset),
102
+ so invalid names are refused rather than renamed into another asset.
103
+
104
+ An asset takes its name from the uploaded file's basename. A `#` suffix only
105
+ sets its display label; it cannot rename the asset. Stage the copy under the
106
+ intended name before uploading. The subshell stops on copy, upload or release
107
+ read failure, checks every expected name, and removes staging on exit.
108
+ Run steps 4 and 5 only if the upload block exits successfully. On failure,
109
+ stop and report it without updating the PR or posting an issue comment.
110
+ `--clobber` replaces an existing asset with that same PR-prefixed name.
111
+
112
+ Link to the actual name:
113
+ `https://github.com/<impl-org>/<impl-repo>/releases/download/pr-assets/pr-<number>-<file>`.
63
114
 
64
115
  4. **Update the PR description**
65
116
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "4.87.9",
3
+ "version": "4.87.10",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -52,14 +52,65 @@ If either is missing, **refuse to post**: stop and report the missing Not-establ
52
52
  3. **Upload each evidence file**
53
53
 
54
54
  ```bash
55
- for f in "$EVIDENCE_DIR"/[0-9][0-9]-*.txt "$EVIDENCE_DIR"/[0-9][0-9]-*.json; do
56
- [ -f "$f" ] || continue
57
- name="pr-${PR_NUMBER}-$(basename "$f")"
58
- gh release upload pr-assets --repo <impl-org>/<impl-repo> --clobber "$f#$name"
59
- done
55
+ (
56
+ set -e
57
+ export LC_ALL=C
58
+ upload_dir=$(mktemp -d "${TMPDIR:-/tmp}/lisa-github-evidence.XXXXXXXX")
59
+ trap 'rm -rf "$upload_dir"' EXIT
60
+ expected_names="$upload_dir/expected-names.txt"
61
+ basenames="$upload_dir/basenames.txt"
62
+ : > "$expected_names"
63
+ : > "$basenames"
64
+
65
+ for f in "$EVIDENCE_DIR"/[0-9][0-9]-*.txt "$EVIDENCE_DIR"/[0-9][0-9]-*.json; do
66
+ [ -f "$f" ] || continue
67
+ base=$(basename "$f")
68
+ if [[ ! "$base" =~ ^[0-9]{2}-[a-z0-9]+(-[a-z0-9]+)*\.(txt|json)$ ]]; then
69
+ printf 'Invalid evidence filename; use a name like 01-health-check.json or 02-output.txt: %s\n' "$base" >&2
70
+ exit 1
71
+ fi
72
+ printf '%s\n' "$base" >> "$basenames"
73
+ done
74
+
75
+ while IFS= read -r base; do
76
+ name="pr-${PR_NUMBER}-${base}"
77
+ cp "$EVIDENCE_DIR/$base" "$upload_dir/$name"
78
+ gh release upload pr-assets --repo <impl-org>/<impl-repo> --clobber "$upload_dir/$name"
79
+ printf '%s\n' "$name" >> "$expected_names"
80
+ done < "$basenames"
81
+
82
+ gh release view pr-assets --repo <impl-org>/<impl-repo> \
83
+ --json assets --jq '.assets[].name' > "$upload_dir/asset-names.txt"
84
+ while IFS= read -r name; do
85
+ if ! grep -Fxq -- "$name" "$upload_dir/asset-names.txt"; then
86
+ printf 'Expected evidence asset is missing: %s\n' "$name" >&2
87
+ exit 1
88
+ fi
89
+ printf 'Uploaded evidence asset: %s\n' "$name"
90
+ done < "$expected_names"
91
+ )
92
+ upload_status=$?
93
+ if [ "$upload_status" -ne 0 ]; then
94
+ printf 'Evidence upload failed; stop before posting.\n' >&2
95
+ exit "$upload_status"
96
+ fi
60
97
  ```
61
98
 
62
- The `#$name` syntax sets the asset name. `--clobber` lets re-runs overwrite.
99
+ Validate the complete input batch before uploading anything: use numbered,
100
+ ASCII kebab-case names such as `01-health-check.json`. GitHub can
101
+ [normalize special characters in asset names](https://docs.github.com/en/rest/releases/assets#upload-a-release-asset),
102
+ so invalid names are refused rather than renamed into another asset.
103
+
104
+ An asset takes its name from the uploaded file's basename. A `#` suffix only
105
+ sets its display label; it cannot rename the asset. Stage the copy under the
106
+ intended name before uploading. The subshell stops on copy, upload or release
107
+ read failure, checks every expected name, and removes staging on exit.
108
+ Run steps 4 and 5 only if the upload block exits successfully. On failure,
109
+ stop and report it without updating the PR or posting an issue comment.
110
+ `--clobber` replaces an existing asset with that same PR-prefixed name.
111
+
112
+ Link to the actual name:
113
+ `https://github.com/<impl-org>/<impl-repo>/releases/download/pr-assets/pr-<number>-<file>`.
63
114
 
64
115
  4. **Update the PR description**
65
116
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "4.87.9",
3
+ "version": "4.87.10",
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.87.9",
3
+ "version": "4.87.10",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -52,14 +52,65 @@ If either is missing, **refuse to post**: stop and report the missing Not-establ
52
52
  3. **Upload each evidence file**
53
53
 
54
54
  ```bash
55
- for f in "$EVIDENCE_DIR"/[0-9][0-9]-*.txt "$EVIDENCE_DIR"/[0-9][0-9]-*.json; do
56
- [ -f "$f" ] || continue
57
- name="pr-${PR_NUMBER}-$(basename "$f")"
58
- gh release upload pr-assets --repo <impl-org>/<impl-repo> --clobber "$f#$name"
59
- done
55
+ (
56
+ set -e
57
+ export LC_ALL=C
58
+ upload_dir=$(mktemp -d "${TMPDIR:-/tmp}/lisa-github-evidence.XXXXXXXX")
59
+ trap 'rm -rf "$upload_dir"' EXIT
60
+ expected_names="$upload_dir/expected-names.txt"
61
+ basenames="$upload_dir/basenames.txt"
62
+ : > "$expected_names"
63
+ : > "$basenames"
64
+
65
+ for f in "$EVIDENCE_DIR"/[0-9][0-9]-*.txt "$EVIDENCE_DIR"/[0-9][0-9]-*.json; do
66
+ [ -f "$f" ] || continue
67
+ base=$(basename "$f")
68
+ if [[ ! "$base" =~ ^[0-9]{2}-[a-z0-9]+(-[a-z0-9]+)*\.(txt|json)$ ]]; then
69
+ printf 'Invalid evidence filename; use a name like 01-health-check.json or 02-output.txt: %s\n' "$base" >&2
70
+ exit 1
71
+ fi
72
+ printf '%s\n' "$base" >> "$basenames"
73
+ done
74
+
75
+ while IFS= read -r base; do
76
+ name="pr-${PR_NUMBER}-${base}"
77
+ cp "$EVIDENCE_DIR/$base" "$upload_dir/$name"
78
+ gh release upload pr-assets --repo <impl-org>/<impl-repo> --clobber "$upload_dir/$name"
79
+ printf '%s\n' "$name" >> "$expected_names"
80
+ done < "$basenames"
81
+
82
+ gh release view pr-assets --repo <impl-org>/<impl-repo> \
83
+ --json assets --jq '.assets[].name' > "$upload_dir/asset-names.txt"
84
+ while IFS= read -r name; do
85
+ if ! grep -Fxq -- "$name" "$upload_dir/asset-names.txt"; then
86
+ printf 'Expected evidence asset is missing: %s\n' "$name" >&2
87
+ exit 1
88
+ fi
89
+ printf 'Uploaded evidence asset: %s\n' "$name"
90
+ done < "$expected_names"
91
+ )
92
+ upload_status=$?
93
+ if [ "$upload_status" -ne 0 ]; then
94
+ printf 'Evidence upload failed; stop before posting.\n' >&2
95
+ exit "$upload_status"
96
+ fi
60
97
  ```
61
98
 
62
- The `#$name` syntax sets the asset name. `--clobber` lets re-runs overwrite.
99
+ Validate the complete input batch before uploading anything: use numbered,
100
+ ASCII kebab-case names such as `01-health-check.json`. GitHub can
101
+ [normalize special characters in asset names](https://docs.github.com/en/rest/releases/assets#upload-a-release-asset),
102
+ so invalid names are refused rather than renamed into another asset.
103
+
104
+ An asset takes its name from the uploaded file's basename. A `#` suffix only
105
+ sets its display label; it cannot rename the asset. Stage the copy under the
106
+ intended name before uploading. The subshell stops on copy, upload or release
107
+ read failure, checks every expected name, and removes staging on exit.
108
+ Run steps 4 and 5 only if the upload block exits successfully. On failure,
109
+ stop and report it without updating the PR or posting an issue comment.
110
+ `--clobber` replaces an existing asset with that same PR-prefixed name.
111
+
112
+ Link to the actual name:
113
+ `https://github.com/<impl-org>/<impl-repo>/releases/download/pr-assets/pr-<number>-<file>`.
63
114
 
64
115
  4. **Update the PR description**
65
116
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "4.87.9",
3
+ "version": "4.87.10",
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.87.9",
3
+ "version": "4.87.10",
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.87.9",
3
+ "version": "4.87.10",
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.87.9",
3
+ "version": "4.87.10",
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.87.9",
3
+ "version": "4.87.10",
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.87.9",
3
+ "version": "4.87.10",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"