@codyswann/lisa 4.35.5 → 4.36.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 (78) hide show
  1. package/all/copy-overwrite/scripts/check-third-party-action-pins.mjs +554 -0
  2. package/dist/core/downstream-references.d.ts.map +1 -1
  3. package/dist/core/downstream-references.js +4 -0
  4. package/dist/core/downstream-references.js.map +1 -1
  5. package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
  6. package/dist/core/lisa-owned-hash-ledger.js +10 -0
  7. package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
  8. package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
  9. package/dist/core/third-party-action-pins.d.ts +84 -0
  10. package/dist/core/third-party-action-pins.d.ts.map +1 -0
  11. package/dist/core/third-party-action-pins.js +153 -0
  12. package/dist/core/third-party-action-pins.js.map +1 -0
  13. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  14. package/dist/core/upstream-evidence-manifest.js +11 -4
  15. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  16. package/dist/migrations/ensure-third-party-action-pins.d.ts +123 -0
  17. package/dist/migrations/ensure-third-party-action-pins.d.ts.map +1 -0
  18. package/dist/migrations/ensure-third-party-action-pins.js +238 -0
  19. package/dist/migrations/ensure-third-party-action-pins.js.map +1 -0
  20. package/dist/migrations/index.d.ts +1 -0
  21. package/dist/migrations/index.d.ts.map +1 -1
  22. package/dist/migrations/index.js +3 -0
  23. package/dist/migrations/index.js.map +1 -1
  24. package/package.json +4 -4
  25. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  26. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  27. package/plugins/lisa-agy/plugin.json +1 -1
  28. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  29. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  30. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  31. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  32. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  33. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  34. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  35. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  36. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  37. package/plugins/lisa-expo-agy/plugin.json +1 -1
  38. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  39. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  40. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  41. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  42. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  43. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  44. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  45. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  46. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  47. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  48. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  49. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  50. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  51. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  52. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  53. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  54. package/plugins/lisa-openclaw-cursor/.claude-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-rails/.claude-plugin/plugin.json +1 -1
  61. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  62. package/plugins/lisa-rails-agy/plugin.json +1 -1
  63. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  64. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  65. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  66. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  67. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  68. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  69. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  70. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  71. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  72. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  73. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  74. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  75. package/scripts/check-third-party-action-pins.mjs +111 -14
  76. package/scripts/two-channel-couplings.json +1 -1
  77. package/typescript/copy-overwrite/.prettierignore +1 -0
  78. package/typescript/package-lisa/package.lisa.json +1 -0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "4.35.5",
3
+ "version": "4.36.0",
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-nestjs",
3
- "version": "4.35.5",
3
+ "version": "4.36.0",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "4.35.5",
3
+ "version": "4.36.0",
4
4
  "description": "NestJS-specific skills and migration write-protection hooks.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "4.35.5",
3
+ "version": "4.36.0",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "4.35.5",
3
+ "version": "4.36.0",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "4.35.5",
3
+ "version": "4.36.0",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "4.35.5",
3
+ "version": "4.36.0",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "4.35.5",
3
+ "version": "4.36.0",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, across Claude and Codex.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "4.35.5",
3
+ "version": "4.36.0",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "4.35.5",
3
+ "version": "4.36.0",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "4.35.5",
3
+ "version": "4.36.0",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "4.35.5",
3
+ "version": "4.36.0",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "4.35.5",
3
+ "version": "4.36.0",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "4.35.5",
3
+ "version": "4.36.0",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "4.35.5",
3
+ "version": "4.36.0",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "4.35.5",
3
+ "version": "4.36.0",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "4.35.5",
3
+ "version": "4.36.0",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "4.35.5",
3
+ "version": "4.36.0",
4
4
  "description": "Ruby on Rails-specific skills and hooks for RuboCop and ast-grep scanning on edit.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "4.35.5",
3
+ "version": "4.36.0",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "4.35.5",
3
+ "version": "4.36.0",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "4.35.5",
3
+ "version": "4.36.0",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "4.35.5",
3
+ "version": "4.36.0",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "4.35.5",
3
+ "version": "4.36.0",
4
4
  "description": "TypeScript-specific hooks for formatting, linting, and ast-grep scanning on edit.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "4.35.5",
3
+ "version": "4.36.0",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "4.35.5",
3
+ "version": "4.36.0",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "4.35.5",
3
+ "version": "4.36.0",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "4.35.5",
3
+ "version": "4.36.0",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "4.35.5",
3
+ "version": "4.36.0",
4
4
  "description": "Distributable LLM Wiki kernel — ingest, query, lint, and maintain a git-native markdown knowledge base across Claude and Codex.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "4.35.5",
3
+ "version": "4.36.0",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "4.35.5",
3
+ "version": "4.36.0",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "4.35.5",
3
+ "version": "4.36.0",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -69,16 +69,41 @@
69
69
  * - the file list comes from `git ls-files`, so the gate sees exactly what a
70
70
  * release would carry.
71
71
  *
72
+ * ## `--warn`: how this arrives in a consumer without breaking it
73
+ *
74
+ * This file also ships to consumers through `all/copy-overwrite/scripts/`,
75
+ * which — unlike `create-only` — reaches every repository that already exists,
76
+ * on its next update. That reach is exactly why it must not arrive blocking.
77
+ *
78
+ * A consumer's seeded workflows carry mutable refs *today*: that is the defect
79
+ * #3588 exists to migrate away. A detector that hard-failed on arrival would
80
+ * redden the entire installed base at once, for a condition those repositories
81
+ * did not introduce and could not have fixed yet, since the migration that
82
+ * fixes it lands in the same update. That is not hypothetical — a guard added
83
+ * to a workflow consumed at `@main` failed closed on a pre-existing consumer
84
+ * misconfiguration and took four repositories' releases down for five hours;
85
+ * the repair was to keep it loud and stop it blocking (#3755, #3757).
86
+ *
87
+ * So `--warn` reports every finding and exits 0, and the shipped consumer
88
+ * script entry uses it. Tightening to blocking is a separate, deliberate
89
+ * decision for once the installed base has had a chance to migrate — one flag
90
+ * on one line — not something to "finish" while consumers are still mutable.
91
+ *
92
+ * `--warn` also softens the empty-scan usage error, because a consumer with no
93
+ * workflow files is an ordinary shape rather than a broken invocation. A
94
+ * misspelled flag stays a hard error in every mode: that one is the caller's.
95
+ *
72
96
  * CLI:
73
- * node scripts/check-third-party-action-pins.mjs [--root <dir>] [--json]
97
+ * node scripts/check-third-party-action-pins.mjs [--root <dir>] [--json] [--warn]
74
98
  *
75
99
  * Exit codes (mirroring the sibling gates in this directory):
76
- * 0 — every third-party reference is a 40-hex SHA carrying a version comment.
100
+ * 0 — every third-party reference is a 40-hex SHA carrying a version comment;
101
+ * or `--warn` was passed and the findings are being reported, not enforced.
77
102
  * 1 — >=1 reference is mutable, or pinned without a version comment.
78
103
  * 2 — operational/usage error: unknown flag, a flag missing its value,
79
104
  * `--root` absent or not a git repository, git unavailable, or zero
80
105
  * workflow files discovered. Finding nothing to check is a broken
81
- * invocation, not conformance.
106
+ * invocation, not conformance — except under `--warn`, see above.
82
107
  *
83
108
  * @module scripts/check-third-party-action-pins
84
109
  */
@@ -134,14 +159,60 @@ const NO_VERSION = "missing-version-comment";
134
159
  * a trailing `# v1.2.3` can be read. Local (`./path`) and container
135
160
  * (`docker://`) references have no owner and never match.
136
161
  */
137
- const USES_RE =
138
- /^\s*(?:-\s*)?uses:\s*(?<owner>[A-Za-z0-9][A-Za-z0-9-]*)\/(?<rest>[A-Za-z0-9_.][A-Za-z0-9_./-]*)@(?<ref>[^\s"'#]+)(?<trailer>.*)$/;
162
+ const USES_RE = /^[ \t]*(?:-[ \t]*)?uses:[ \t]*(?<value>[^\s"'#]+)/;
163
+
164
+ /** A well-formed action owner. Anchored, so matching is linear. */
165
+ const OWNER_RE = /^[A-Za-z0-9][A-Za-z0-9-]*$/;
166
+
167
+ /** A well-formed action path below the owner. Anchored, so linear. */
168
+ const ACTION_PATH_RE = /^[A-Za-z0-9_.][A-Za-z0-9_./-]*$/;
169
+
170
+ /**
171
+ * Split a `uses:` value into owner, action path, and ref.
172
+ *
173
+ * The shape is validated with anchored parts rather than described as one
174
+ * pattern. Spelling `owner/repo/path@ref` as adjacent character classes gives
175
+ * the engine several ways to divide the same text, which is super-linear on a
176
+ * long line; splitting first and validating each piece has one.
177
+ *
178
+ * @param {string} value - the raw value of a `uses:` line.
179
+ * @returns {{ owner: string, rest: string, ref: string } | null} parts, or null
180
+ * when this is not an `owner/repo@ref` reference (a local `./path` or a
181
+ * `docker://` image never is).
182
+ */
183
+ function parseUsesValue(value) {
184
+ const at = value.lastIndexOf("@");
185
+ if (at <= 0) return null;
186
+ const action = value.slice(0, at);
187
+ const ref = value.slice(at + 1);
188
+ const slash = action.indexOf("/");
189
+ if (ref === "" || slash <= 0 || action.includes("://")) return null;
190
+ const owner = action.slice(0, slash);
191
+ const rest = action.slice(slash + 1);
192
+ if (!OWNER_RE.test(owner) || !ACTION_PATH_RE.test(rest)) return null;
193
+ return { owner, rest, ref };
194
+ }
139
195
 
140
196
  /** A full commit SHA. Abbreviated SHAs are ambiguous and do not count. */
141
197
  const FULL_SHA_RE = /^[0-9a-f]{40}$/;
142
198
 
143
- /** A trailing `# <version>` comment with at least one non-space character. */
144
- const VERSION_COMMENT_RE = /#\s*(?<version>\S.*?)\s*$/;
199
+ /**
200
+ * Read the version out of a line's trailing `# ...` comment.
201
+ *
202
+ * Deliberately not a regex. Every spelling of "text after a hash to end of
203
+ * line" is either a backtracking shape or an unanchored `.*$` the engine
204
+ * retries from each position, and neither is worth it for a one-character
205
+ * search.
206
+ *
207
+ * @param {string} trailer - everything on the line after the `uses:` value.
208
+ * @returns {string | null} the comment text, or null when there is none.
209
+ */
210
+ function versionComment(trailer) {
211
+ const hash = trailer.indexOf("#");
212
+ if (hash < 0) return null;
213
+ const version = trailer.slice(hash + 1).trim();
214
+ return version === "" ? null : version;
215
+ }
145
216
 
146
217
  /** Max bytes of `git ls-files` output (7k+ tracked paths is ~0.3 MB today). */
147
218
  const MAX_GIT_OUTPUT_BYTES = 64 * 1024 * 1024;
@@ -182,15 +253,19 @@ export function findActionRefs(content) {
182
253
  for (let index = 0; index < lines.length; index++) {
183
254
  const match = USES_RE.exec(lines[index]);
184
255
  if (match === null) continue;
185
- const { owner, ref, rest, trailer } = match.groups;
186
- const comment = VERSION_COMMENT_RE.exec(trailer);
256
+ const parsed = parseUsesValue(match.groups.value);
257
+ if (parsed === null) continue;
258
+ const { owner, ref, rest } = parsed;
187
259
  refs.push({
188
260
  action: `${owner}/${rest}`,
189
261
  kind: classifyOwner(owner),
190
262
  line: index + 1,
191
263
  owner,
192
264
  ref,
193
- version: comment === null ? null : comment.groups.version,
265
+ // The rest of the line is sliced rather than captured: a trailing `.*`
266
+ // after the value's character class gives the engine two ways to divide
267
+ // the same text, which is the super-linear shape.
268
+ version: versionComment(lines[index].slice(match[0].length)),
194
269
  });
195
270
  }
196
271
  return refs;
@@ -350,10 +425,13 @@ function humanReport(report) {
350
425
  export function parseArgs(argv) {
351
426
  let root = null;
352
427
  let json = false;
428
+ let warn = false;
353
429
  for (let i = 0; i < argv.length; i++) {
354
430
  const arg = argv[i];
355
431
  if (arg === "--json") {
356
432
  json = true;
433
+ } else if (arg === "--warn") {
434
+ warn = true;
357
435
  } else if (arg === "--root") {
358
436
  const next = argv[i + 1];
359
437
  if (next === undefined || next.startsWith("--")) {
@@ -365,7 +443,7 @@ export function parseArgs(argv) {
365
443
  throw new UsageError(`unknown argument: ${arg}`);
366
444
  }
367
445
  }
368
- return { json, root: path.resolve(root ?? REPO_ROOT) };
446
+ return { json, warn, root: path.resolve(root ?? REPO_ROOT) };
369
447
  }
370
448
 
371
449
  /**
@@ -406,14 +484,22 @@ export function main(argv, io = {}) {
406
484
  const out = io.stdout ?? process.stdout;
407
485
  const err = io.stderr ?? process.stderr;
408
486
  let opts;
409
- let scan;
410
487
  try {
411
488
  opts = parseArgs(argv);
412
- scan = collectWorkflows(opts.root);
413
489
  } catch (error) {
490
+ // A misspelled flag is the caller's mistake and stays loud in every mode.
414
491
  err.write(`error: ${error.message}\n`);
415
492
  return 2;
416
493
  }
494
+ let scan;
495
+ try {
496
+ scan = collectWorkflows(opts.root);
497
+ } catch (error) {
498
+ // Under --warn this is a repository with nothing to scan, which for a
499
+ // consumer is an ordinary shape rather than a broken invocation.
500
+ err.write(`error: ${error.message}\n`);
501
+ return opts.warn ? 0 : 2;
502
+ }
417
503
 
418
504
  let checked = 0;
419
505
  let thirdParty = 0;
@@ -445,7 +531,18 @@ export function main(argv, io = {}) {
445
531
  out.write(
446
532
  `${opts.json ? JSON.stringify(report, null, 2) : humanReport(report)}\n`
447
533
  );
448
- return report.findings.length === 0 ? 0 : 1;
534
+ if (report.findings.length === 0) {
535
+ return 0;
536
+ }
537
+ if (opts.warn) {
538
+ out.write(
539
+ "\nReporting only: this check is not blocking here. Nothing above stops " +
540
+ "a build.\nRun `npx @codyswann/lisa@latest .` to pin these " +
541
+ "references, then re-run.\n"
542
+ );
543
+ return 0;
544
+ }
545
+ return 1;
449
546
  }
450
547
 
451
548
  if (invokedAsScript(import.meta.url)) {
@@ -7,7 +7,7 @@
7
7
  "workflows": 22,
8
8
  "steps": 716,
9
9
  "couplings": 34,
10
- "inventory": 71
10
+ "inventory": 72
11
11
  },
12
12
  "counts": {
13
13
  "package-backed": 10,
@@ -73,6 +73,7 @@ scripts/check-npm-publish-landed.mjs
73
73
  scripts/check-release-package-identity.mjs
74
74
  scripts/check-skipped-required-checks.mjs
75
75
  scripts/check-state-classification.mjs
76
+ scripts/check-third-party-action-pins.mjs
76
77
  scripts/check-third-party-review-evidence.mjs
77
78
  scripts/check-threshold-ratchet.mjs
78
79
  scripts/check-verification-coverage.mjs
@@ -26,6 +26,7 @@
26
26
  "test:node": "LISA_TEST_SCRATCH_PREFIXES='[\"node-\"]' lisa-test-run --profile typescript --adapter direct -- node scripts/lisa-test-node.mjs",
27
27
  "check:work-item": "node scripts/lisa-work-item.mjs validate-pr",
28
28
  "check:conflict-markers": "node scripts/check-conflict-markers.mjs",
29
+ "check:third-party-action-pins": "node scripts/check-third-party-action-pins.mjs --warn",
29
30
  "check:work-item:push": "node scripts/lisa-work-item.mjs validate-push",
30
31
  "check:verification": "node scripts/check-verification-coverage.mjs"
31
32
  },