@codyswann/lisa 4.35.4 → 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 (89) hide show
  1. package/all/copy-overwrite/scripts/check-third-party-action-pins.mjs +554 -0
  2. package/all/copy-overwrite/scripts/lib/gate-failure-diagnosis.mjs +296 -3
  3. package/dist/core/downstream-references.d.ts.map +1 -1
  4. package/dist/core/downstream-references.js +4 -0
  5. package/dist/core/downstream-references.js.map +1 -1
  6. package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
  7. package/dist/core/lisa-owned-hash-ledger.js +16 -0
  8. package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
  9. package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
  10. package/dist/core/third-party-action-pins.d.ts +84 -0
  11. package/dist/core/third-party-action-pins.d.ts.map +1 -0
  12. package/dist/core/third-party-action-pins.js +153 -0
  13. package/dist/core/third-party-action-pins.js.map +1 -0
  14. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  15. package/dist/core/upstream-evidence-manifest.js +15 -7
  16. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  17. package/dist/migrations/ensure-third-party-action-pins.d.ts +123 -0
  18. package/dist/migrations/ensure-third-party-action-pins.d.ts.map +1 -0
  19. package/dist/migrations/ensure-third-party-action-pins.js +238 -0
  20. package/dist/migrations/ensure-third-party-action-pins.js.map +1 -0
  21. package/dist/migrations/index.d.ts +1 -0
  22. package/dist/migrations/index.d.ts.map +1 -1
  23. package/dist/migrations/index.js +3 -0
  24. package/dist/migrations/index.js.map +1 -1
  25. package/package.json +4 -4
  26. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  27. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  28. package/plugins/lisa/.codex-plugin/skills/lisa-jsdoc-best-practices/SKILL.md +60 -1
  29. package/plugins/lisa/rules/reference/measurement-integrity.md +10 -0
  30. package/plugins/lisa/skills/lisa-jsdoc-best-practices/SKILL.md +60 -1
  31. package/plugins/lisa-agy/plugin.json +1 -1
  32. package/plugins/lisa-agy/skills/lisa-jsdoc-best-practices/SKILL.md +60 -1
  33. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  34. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  35. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  36. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  37. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  38. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  39. package/plugins/lisa-copilot/rules/reference/measurement-integrity.md +10 -0
  40. package/plugins/lisa-copilot/skills/lisa-jsdoc-best-practices/SKILL.md +60 -1
  41. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  42. package/plugins/lisa-cursor/rules/measurement-integrity-reference.mdc +10 -0
  43. package/plugins/lisa-cursor/skills/lisa-jsdoc-best-practices/SKILL.md +60 -1
  44. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  45. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  46. package/plugins/lisa-expo-agy/plugin.json +1 -1
  47. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  48. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  49. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  50. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  51. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  52. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  53. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  54. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  55. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  56. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  57. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  58. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  59. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  60. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  61. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  62. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  63. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  64. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  65. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  66. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  67. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  68. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  69. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  70. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  71. package/plugins/lisa-rails-agy/plugin.json +1 -1
  72. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  73. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  74. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  75. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  76. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  77. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  78. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  79. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  80. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  81. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  82. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  83. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  84. package/plugins/src/base/rules/reference/measurement-integrity.md +10 -0
  85. package/plugins/src/base/skills/lisa-jsdoc-best-practices/SKILL.md +60 -1
  86. package/scripts/check-third-party-action-pins.mjs +111 -14
  87. package/scripts/two-channel-couplings.json +1 -1
  88. package/typescript/copy-overwrite/.prettierignore +1 -0
  89. package/typescript/package-lisa/package.lisa.json +1 -0
@@ -0,0 +1,123 @@
1
+ import type { Migration, MigrationContext, MigrationResult } from "./migration.interface.js";
2
+ /** Resolve the commit a ref points at, or null when it cannot be determined. */
3
+ export type ShaResolver = (owner: string, repo: string, ref: string) => Promise<string | null>;
4
+ /**
5
+ * Ask GitHub what a ref resolves to right now.
6
+ *
7
+ * Deliberately resolves live rather than reading a table shipped inside Lisa.
8
+ * A shipped table pins every consumer to whatever those refs meant on the night
9
+ * it was generated, which converts a mutable-ref problem into a stale-ref
10
+ * problem and calls it fixed. Resolving live also satisfies the harder half of
11
+ * the requirement: the SHA written is the one THAT repository's ref resolves to
12
+ * at migration time, so pinning never silently upgrades anything.
13
+ *
14
+ * Returns null rather than throwing on every failure path. The caller turns a
15
+ * null into a reported skip; an exception here would turn a missing network
16
+ * into a failed `lisa` run, which is not what an unreachable API means.
17
+ *
18
+ * Unauthenticated on purpose. Every action being resolved is public — a private
19
+ * one could not be `uses:`-ed by a consumer's runner either — and the endpoint's
20
+ * anonymous allowance is far above the handful of distinct refs one repository
21
+ * has. Reading a token here would mean reaching into the environment from
22
+ * `src/`, and buying a higher rate limit is not worth that: being rate-limited
23
+ * lands on the same reported-skip path as being offline, which is a correct
24
+ * outcome rather than a failure. A caller that wants authenticated lookups
25
+ * injects its own resolver.
26
+ * @param owner - Action owner
27
+ * @param repo - Action repository
28
+ * @param ref - The mutable ref to resolve
29
+ * @returns The 40-character commit SHA, or null when it cannot be resolved
30
+ */
31
+ export declare const resolveViaGitHub: ShaResolver;
32
+ /**
33
+ * Pin the third-party actions in an already-seeded consumer's workflows.
34
+ *
35
+ * #3585 pinned Lisa's own workflows and its `create-only` templates. Those
36
+ * templates are seeded once and never overwritten, so that fix reaches new
37
+ * adoptions and no repository that already exists. This migration is the
38
+ * surface that reaches the installed base — the same role, and the same
39
+ * reasoning, as `ensure-nightly-e2e-workflow-pins` (#3476, #3485, #3588).
40
+ *
41
+ * It rewrites matched `uses:` lines only, never the file, so a host that has
42
+ * edited its seeded workflow keeps every other edit.
43
+ */
44
+ export declare class EnsureThirdPartyActionPinsMigration implements Migration {
45
+ private readonly resolve;
46
+ readonly name = "ensure-third-party-action-pins";
47
+ readonly description = "Pin third-party GitHub Actions in this project's workflows to the commit SHA their ref resolves to today";
48
+ /**
49
+ * Create the migration.
50
+ * @param resolve - SHA resolver, injectable so tests never touch the network
51
+ */
52
+ constructor(resolve?: ShaResolver);
53
+ /**
54
+ * Whether any workflow in this project carries a mutable third-party ref.
55
+ *
56
+ * Never touches the network: an offline machine must still get a truthful
57
+ * answer about whether there is anything to do.
58
+ * @param ctx - Migration context
59
+ * @returns True when at least one reference needs pinning
60
+ */
61
+ applies(ctx: MigrationContext): Promise<boolean>;
62
+ /**
63
+ * Resolve every mutable ref and rewrite the ones that resolved.
64
+ * @param ctx - Migration context
65
+ * @returns Applied, skipped, or no-op result
66
+ */
67
+ apply(ctx: MigrationContext): Promise<MigrationResult>;
68
+ /**
69
+ * Read every workflow file and collect its mutable third-party refs.
70
+ * @param projectDir - Destination project directory
71
+ * @returns One entry per workflow file that has at least one finding
72
+ */
73
+ private scan;
74
+ /**
75
+ * Resolve each distinct reference, dropping the ones that do not resolve.
76
+ * @param found - Every finding across the scanned files
77
+ * @returns The references that resolved to a commit SHA
78
+ */
79
+ private resolveAll;
80
+ /**
81
+ * Decline during a package manager's install, and say what was declined.
82
+ *
83
+ * A workflow file is not a generated artifact — it is a reviewed,
84
+ * checked-in declaration of what runs against this repository, and nobody
85
+ * types `bun install` meaning to change that. The same rule, and the same
86
+ * incident behind it, as `ensure-seeded-gates` (#3574).
87
+ *
88
+ * It reports rather than going quiet, because a migration that silently
89
+ * skipped here would be this codebase's signature defect: work that stops
90
+ * happening with nothing anywhere saying so.
91
+ * @param ctx - Migration context
92
+ * @param found - Every finding across the scanned files
93
+ * @returns A skipped result carrying the operator-readable explanation
94
+ */
95
+ private refuse;
96
+ /**
97
+ * Report that nothing could be resolved, without claiming to have applied.
98
+ *
99
+ * No network and no credentials are ordinary conditions on a developer
100
+ * machine, so neither is a failure. What matters is that the result says
101
+ * `skipped`: a migration that reported `applied` here would be recorded as
102
+ * done and never run again, leaving the references mutable forever.
103
+ * @param ctx - Migration context
104
+ * @param found - Every finding across the scanned files
105
+ * @returns A skipped result carrying the operator-readable explanation
106
+ */
107
+ private declineUnresolved;
108
+ /**
109
+ * One operator-readable line per distinct reference.
110
+ * @param found - Every finding across the scanned files
111
+ * @returns Indented description lines
112
+ */
113
+ private describe;
114
+ /**
115
+ * Summarize what was pinned, naming anything that was left alone.
116
+ * @param pins - References that resolved
117
+ * @param found - Every finding across the scanned files
118
+ * @param changedFiles - Files that were rewritten
119
+ * @returns Operator-readable summary
120
+ */
121
+ private summarize;
122
+ }
123
+ //# sourceMappingURL=ensure-third-party-action-pins.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ensure-third-party-action-pins.d.ts","sourceRoot":"","sources":["../../src/migrations/ensure-third-party-action-pins.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,SAAS,EACT,gBAAgB,EAChB,eAAe,EAChB,MAAM,0BAA0B,CAAC;AAKlC,gFAAgF;AAChF,MAAM,MAAM,WAAW,GAAG,CACxB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,KACR,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;AAU5B;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,gBAAgB,EAAE,WAmB9B,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,qBAAa,mCAAoC,YAAW,SAAS;IASvD,OAAO,CAAC,QAAQ,CAAC,OAAO;IARpC,QAAQ,CAAC,IAAI,oCAAoC;IACjD,QAAQ,CAAC,WAAW,8GACyF;IAE7G;;;OAGG;gBAC0B,OAAO,GAAE,WAA8B;IAEpE;;;;;;;OAOG;IACG,OAAO,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC;IAItD;;;;OAIG;IACG,KAAK,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC;IAqC5D;;;;OAIG;YACW,IAAI;IAqBlB;;;;OAIG;YACW,UAAU;IAcxB;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,MAAM;IAmBd;;;;;;;;;;OAUG;IACH,OAAO,CAAC,iBAAiB;IAoBzB;;;;OAIG;IACH,OAAO,CAAC,QAAQ;IAIhB;;;;;;OAMG;IACH,OAAO,CAAC,SAAS;CAalB"}
@@ -0,0 +1,238 @@
1
+ import { readFile, readdir, writeFile } from "node:fs/promises";
2
+ import * as path from "node:path";
3
+ import * as fse from "fs-extra";
4
+ import { applyPins, distinctRefs, findUnpinnedRefs, } from "../core/third-party-action-pins.js";
5
+ const WORKFLOW_DIR = path.join(".github", "workflows");
6
+ const WORKFLOW_FILE = /\.ya?ml$/;
7
+ /**
8
+ * Ask GitHub what a ref resolves to right now.
9
+ *
10
+ * Deliberately resolves live rather than reading a table shipped inside Lisa.
11
+ * A shipped table pins every consumer to whatever those refs meant on the night
12
+ * it was generated, which converts a mutable-ref problem into a stale-ref
13
+ * problem and calls it fixed. Resolving live also satisfies the harder half of
14
+ * the requirement: the SHA written is the one THAT repository's ref resolves to
15
+ * at migration time, so pinning never silently upgrades anything.
16
+ *
17
+ * Returns null rather than throwing on every failure path. The caller turns a
18
+ * null into a reported skip; an exception here would turn a missing network
19
+ * into a failed `lisa` run, which is not what an unreachable API means.
20
+ *
21
+ * Unauthenticated on purpose. Every action being resolved is public — a private
22
+ * one could not be `uses:`-ed by a consumer's runner either — and the endpoint's
23
+ * anonymous allowance is far above the handful of distinct refs one repository
24
+ * has. Reading a token here would mean reaching into the environment from
25
+ * `src/`, and buying a higher rate limit is not worth that: being rate-limited
26
+ * lands on the same reported-skip path as being offline, which is a correct
27
+ * outcome rather than a failure. A caller that wants authenticated lookups
28
+ * injects its own resolver.
29
+ * @param owner - Action owner
30
+ * @param repo - Action repository
31
+ * @param ref - The mutable ref to resolve
32
+ * @returns The 40-character commit SHA, or null when it cannot be resolved
33
+ */
34
+ export const resolveViaGitHub = async (owner, repo, ref) => {
35
+ try {
36
+ const response = await fetch(`https://api.github.com/repos/${owner}/${repo}/commits/${encodeURIComponent(ref)}`, {
37
+ headers: {
38
+ Accept: "application/vnd.github.sha",
39
+ "User-Agent": "lisa-third-party-action-pins",
40
+ },
41
+ });
42
+ if (!response.ok) {
43
+ return null;
44
+ }
45
+ const sha = (await response.text()).trim();
46
+ return /^[0-9a-f]{40}$/.test(sha) ? sha : null;
47
+ }
48
+ catch {
49
+ return null;
50
+ }
51
+ };
52
+ /**
53
+ * Pin the third-party actions in an already-seeded consumer's workflows.
54
+ *
55
+ * #3585 pinned Lisa's own workflows and its `create-only` templates. Those
56
+ * templates are seeded once and never overwritten, so that fix reaches new
57
+ * adoptions and no repository that already exists. This migration is the
58
+ * surface that reaches the installed base — the same role, and the same
59
+ * reasoning, as `ensure-nightly-e2e-workflow-pins` (#3476, #3485, #3588).
60
+ *
61
+ * It rewrites matched `uses:` lines only, never the file, so a host that has
62
+ * edited its seeded workflow keeps every other edit.
63
+ */
64
+ export class EnsureThirdPartyActionPinsMigration {
65
+ resolve;
66
+ name = "ensure-third-party-action-pins";
67
+ description = "Pin third-party GitHub Actions in this project's workflows to the commit SHA their ref resolves to today";
68
+ /**
69
+ * Create the migration.
70
+ * @param resolve - SHA resolver, injectable so tests never touch the network
71
+ */
72
+ constructor(resolve = resolveViaGitHub) {
73
+ this.resolve = resolve;
74
+ }
75
+ /**
76
+ * Whether any workflow in this project carries a mutable third-party ref.
77
+ *
78
+ * Never touches the network: an offline machine must still get a truthful
79
+ * answer about whether there is anything to do.
80
+ * @param ctx - Migration context
81
+ * @returns True when at least one reference needs pinning
82
+ */
83
+ async applies(ctx) {
84
+ return (await this.scan(ctx.projectDir)).length > 0;
85
+ }
86
+ /**
87
+ * Resolve every mutable ref and rewrite the ones that resolved.
88
+ * @param ctx - Migration context
89
+ * @returns Applied, skipped, or no-op result
90
+ */
91
+ async apply(ctx) {
92
+ const scanned = await this.scan(ctx.projectDir);
93
+ if (scanned.length === 0) {
94
+ return { name: this.name, action: "noop" };
95
+ }
96
+ const found = scanned.flatMap(file => file.refs);
97
+ if (ctx.postinstallSafe === true) {
98
+ return this.refuse(ctx, found);
99
+ }
100
+ const pins = await this.resolveAll(found);
101
+ if (pins.length === 0) {
102
+ return this.declineUnresolved(ctx, found);
103
+ }
104
+ const updates = scanned
105
+ .map(file => ({ file, source: applyPins(file.source, pins) }))
106
+ .filter(update => update.source !== update.file.source);
107
+ if (updates.length === 0) {
108
+ return { name: this.name, action: "noop" };
109
+ }
110
+ const changedFiles = updates.map(update => update.file.relative);
111
+ const message = this.summarize(pins, found, changedFiles);
112
+ if (ctx.dryRun) {
113
+ ctx.logger.dry(`Would pin ${pins.length} reference(s) in ${changedFiles.join(", ")}`);
114
+ return { name: this.name, action: "applied", changedFiles, message };
115
+ }
116
+ for (const update of updates) {
117
+ await writeFile(update.file.absolute, update.source);
118
+ }
119
+ ctx.logger.success(message);
120
+ return { name: this.name, action: "applied", changedFiles, message };
121
+ }
122
+ /**
123
+ * Read every workflow file and collect its mutable third-party refs.
124
+ * @param projectDir - Destination project directory
125
+ * @returns One entry per workflow file that has at least one finding
126
+ */
127
+ async scan(projectDir) {
128
+ const dir = path.join(projectDir, WORKFLOW_DIR);
129
+ if (!(await fse.pathExists(dir))) {
130
+ return [];
131
+ }
132
+ const names = (await readdir(dir)).filter(name => WORKFLOW_FILE.test(name));
133
+ const files = await Promise.all(names.map(async (name) => {
134
+ const absolute = path.join(dir, name);
135
+ const source = await readFile(absolute, "utf8");
136
+ return {
137
+ relative: path.join(WORKFLOW_DIR, name),
138
+ absolute,
139
+ source,
140
+ refs: findUnpinnedRefs(source),
141
+ };
142
+ }));
143
+ return files.filter(file => file.refs.length > 0);
144
+ }
145
+ /**
146
+ * Resolve each distinct reference, dropping the ones that do not resolve.
147
+ * @param found - Every finding across the scanned files
148
+ * @returns The references that resolved to a commit SHA
149
+ */
150
+ async resolveAll(found) {
151
+ const resolutions = await Promise.all(distinctRefs(found).map(async (ref) => ({
152
+ ref,
153
+ sha: await this.resolve(ref.owner, ref.repo, ref.ref),
154
+ })));
155
+ return resolutions.flatMap(({ ref, sha }) => sha === null ? [] : [{ action: ref.action, ref: ref.ref, sha }]);
156
+ }
157
+ /**
158
+ * Decline during a package manager's install, and say what was declined.
159
+ *
160
+ * A workflow file is not a generated artifact — it is a reviewed,
161
+ * checked-in declaration of what runs against this repository, and nobody
162
+ * types `bun install` meaning to change that. The same rule, and the same
163
+ * incident behind it, as `ensure-seeded-gates` (#3574).
164
+ *
165
+ * It reports rather than going quiet, because a migration that silently
166
+ * skipped here would be this codebase's signature defect: work that stops
167
+ * happening with nothing anywhere saying so.
168
+ * @param ctx - Migration context
169
+ * @param found - Every finding across the scanned files
170
+ * @returns A skipped result carrying the operator-readable explanation
171
+ */
172
+ refuse(ctx, found) {
173
+ const message = [
174
+ "Left this project's workflows unchanged: an install must not rewrite what runs against this repository.",
175
+ "",
176
+ ` ${found.length} third-party action reference(s) resolve at job start to whatever their owner has pushed:`,
177
+ "",
178
+ ...this.describe(found),
179
+ "",
180
+ " To pin them deliberately, so the change lands in a commit somebody reviews:",
181
+ "",
182
+ " npx @codyswann/lisa@latest .",
183
+ ].join("\n");
184
+ ctx.logger.warn(message);
185
+ return { name: this.name, action: "skipped", changedFiles: [], message };
186
+ }
187
+ /**
188
+ * Report that nothing could be resolved, without claiming to have applied.
189
+ *
190
+ * No network and no credentials are ordinary conditions on a developer
191
+ * machine, so neither is a failure. What matters is that the result says
192
+ * `skipped`: a migration that reported `applied` here would be recorded as
193
+ * done and never run again, leaving the references mutable forever.
194
+ * @param ctx - Migration context
195
+ * @param found - Every finding across the scanned files
196
+ * @returns A skipped result carrying the operator-readable explanation
197
+ */
198
+ declineUnresolved(ctx, found) {
199
+ const message = [
200
+ "Could not reach GitHub to look up what these action references point at, so nothing was changed.",
201
+ "",
202
+ ` ${found.length} third-party action reference(s) are still resolved at job start by their owner:`,
203
+ "",
204
+ ...this.describe(found),
205
+ "",
206
+ " Nothing is broken and nothing has changed. Re-run once this machine can",
207
+ " reach github.com; if the lookups were rate-limited, a few minutes is enough:",
208
+ "",
209
+ " npx @codyswann/lisa@latest .",
210
+ ].join("\n");
211
+ ctx.logger.warn(message);
212
+ return { name: this.name, action: "skipped", changedFiles: [], message };
213
+ }
214
+ /**
215
+ * One operator-readable line per distinct reference.
216
+ * @param found - Every finding across the scanned files
217
+ * @returns Indented description lines
218
+ */
219
+ describe(found) {
220
+ return distinctRefs(found).map(ref => ` • ${ref.action}@${ref.ref}`);
221
+ }
222
+ /**
223
+ * Summarize what was pinned, naming anything that was left alone.
224
+ * @param pins - References that resolved
225
+ * @param found - Every finding across the scanned files
226
+ * @param changedFiles - Files that were rewritten
227
+ * @returns Operator-readable summary
228
+ */
229
+ summarize(pins, found, changedFiles) {
230
+ const distinct = distinctRefs(found).length;
231
+ const unresolved = distinct - pins.length;
232
+ const tail = unresolved > 0
233
+ ? ` ${unresolved} reference(s) could not be looked up and were left as they are.`
234
+ : "";
235
+ return `Pinned ${pins.length} third-party action reference(s) to commit SHAs in ${changedFiles.join(", ")}.${tail}`;
236
+ }
237
+ }
238
+ //# sourceMappingURL=ensure-third-party-action-pins.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ensure-third-party-action-pins.js","sourceRoot":"","sources":["../../src/migrations/ensure-third-party-action-pins.ts"],"names":[],"mappings":"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"}
@@ -13,6 +13,7 @@ export { EnsurePushDefaultSafeMigration } from "./ensure-push-default-safe.js";
13
13
  export { EnsureQualityCallerScopesMigration } from "./ensure-quality-caller-scopes.js";
14
14
  export { EnsureSeededGatesMigration } from "./ensure-seeded-gates.js";
15
15
  export { EnsureSonarExcludesLisaHarnessMigration } from "./ensure-sonar-excludes-lisa-harness.js";
16
+ export { EnsureThirdPartyActionPinsMigration } from "./ensure-third-party-action-pins.js";
16
17
  export { EnsureTsconfigLocalFilesFallbackMigration } from "./ensure-tsconfig-local-files-fallback.js";
17
18
  export { EnsureWikiSourceDeclaredMigration } from "./ensure-wiki-source-declared.js";
18
19
  export { EnsureTsconfigLocalIncludesMigration } from "./ensure-tsconfig-local-includes.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EACV,SAAS,EACT,gBAAgB,EAChB,eAAe,EAChB,MAAM,0BAA0B,CAAC;AAElC,YAAY,EACV,SAAS,EACT,eAAe,EACf,gBAAgB,EAChB,eAAe,GAChB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,yCAAyC,EAAE,MAAM,2CAA2C,CAAC;AACtG,OAAO,EAAE,6CAA6C,EAAE,MAAM,gDAAgD,CAAC;AAC/G,OAAO,EAAE,qCAAqC,EAAE,MAAM,qCAAqC,CAAC;AAC5F,OAAO,EAAE,mCAAmC,EAAE,MAAM,oCAAoC,CAAC;AACzF,OAAO,EAAE,uCAAuC,EAAE,MAAM,wCAAwC,CAAC;AACjG,OAAO,EAAE,qCAAqC,EAAE,MAAM,uCAAuC,CAAC;AAC9F,OAAO,EAAE,8BAA8B,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAE,gCAAgC,EAAE,MAAM,iCAAiC,CAAC;AACnF,OAAO,EAAE,wCAAwC,EAAE,MAAM,yCAAyC,CAAC;AACnG,OAAO,EAAE,8BAA8B,EAAE,MAAM,+BAA+B,CAAC;AAC/E,OAAO,EAAE,kCAAkC,EAAE,MAAM,mCAAmC,CAAC;AACvF,OAAO,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,uCAAuC,EAAE,MAAM,yCAAyC,CAAC;AAClG,OAAO,EAAE,yCAAyC,EAAE,MAAM,2CAA2C,CAAC;AACtG,OAAO,EAAE,iCAAiC,EAAE,MAAM,kCAAkC,CAAC;AACrF,OAAO,EAAE,oCAAoC,EAAE,MAAM,qCAAqC,CAAC;AAC3F,OAAO,EAAE,oCAAoC,EAAE,MAAM,sCAAsC,CAAC;AAC5F,OAAO,EAAE,oCAAoC,EAAE,MAAM,qCAAqC,CAAC;AAC3F,OAAO,EAAE,gCAAgC,EAAE,MAAM,gCAAgC,CAAC;AAElF;;GAEG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAuB;IAElD;;;OAGG;gBACS,UAAU,CAAC,EAAE,SAAS,SAAS,EAAE;IAwB7C;;;OAGG;IACH,MAAM,IAAI,SAAS,SAAS,EAAE;IAI9B;;;;OAIG;IACG,mBAAmB,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ/D;;;;OAIG;IACG,MAAM,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,SAAS,eAAe,EAAE,CAAC;CAazE;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,IAAI,iBAAiB,CAE3D"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EACV,SAAS,EACT,gBAAgB,EAChB,eAAe,EAChB,MAAM,0BAA0B,CAAC;AAElC,YAAY,EACV,SAAS,EACT,eAAe,EACf,gBAAgB,EAChB,eAAe,GAChB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,yCAAyC,EAAE,MAAM,2CAA2C,CAAC;AACtG,OAAO,EAAE,6CAA6C,EAAE,MAAM,gDAAgD,CAAC;AAC/G,OAAO,EAAE,qCAAqC,EAAE,MAAM,qCAAqC,CAAC;AAC5F,OAAO,EAAE,mCAAmC,EAAE,MAAM,oCAAoC,CAAC;AACzF,OAAO,EAAE,uCAAuC,EAAE,MAAM,wCAAwC,CAAC;AACjG,OAAO,EAAE,qCAAqC,EAAE,MAAM,uCAAuC,CAAC;AAC9F,OAAO,EAAE,8BAA8B,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAE,gCAAgC,EAAE,MAAM,iCAAiC,CAAC;AACnF,OAAO,EAAE,wCAAwC,EAAE,MAAM,yCAAyC,CAAC;AACnG,OAAO,EAAE,8BAA8B,EAAE,MAAM,+BAA+B,CAAC;AAC/E,OAAO,EAAE,kCAAkC,EAAE,MAAM,mCAAmC,CAAC;AACvF,OAAO,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,uCAAuC,EAAE,MAAM,yCAAyC,CAAC;AAClG,OAAO,EAAE,mCAAmC,EAAE,MAAM,qCAAqC,CAAC;AAC1F,OAAO,EAAE,yCAAyC,EAAE,MAAM,2CAA2C,CAAC;AACtG,OAAO,EAAE,iCAAiC,EAAE,MAAM,kCAAkC,CAAC;AACrF,OAAO,EAAE,oCAAoC,EAAE,MAAM,qCAAqC,CAAC;AAC3F,OAAO,EAAE,oCAAoC,EAAE,MAAM,sCAAsC,CAAC;AAC5F,OAAO,EAAE,oCAAoC,EAAE,MAAM,qCAAqC,CAAC;AAC3F,OAAO,EAAE,gCAAgC,EAAE,MAAM,gCAAgC,CAAC;AAElF;;GAEG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAuB;IAElD;;;OAGG;gBACS,UAAU,CAAC,EAAE,SAAS,SAAS,EAAE;IAyB7C;;;OAGG;IACH,MAAM,IAAI,SAAS,SAAS,EAAE;IAI9B;;;;OAIG;IACG,mBAAmB,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ/D;;;;OAIG;IACG,MAAM,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,SAAS,eAAe,EAAE,CAAC;CAazE;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,IAAI,iBAAiB,CAE3D"}
@@ -11,6 +11,7 @@ import { EnsurePushDefaultSafeMigration } from "./ensure-push-default-safe.js";
11
11
  import { EnsureQualityCallerScopesMigration } from "./ensure-quality-caller-scopes.js";
12
12
  import { EnsureSeededGatesMigration } from "./ensure-seeded-gates.js";
13
13
  import { EnsureSonarExcludesLisaHarnessMigration } from "./ensure-sonar-excludes-lisa-harness.js";
14
+ import { EnsureThirdPartyActionPinsMigration } from "./ensure-third-party-action-pins.js";
14
15
  import { EnsureTsconfigLocalFilesFallbackMigration } from "./ensure-tsconfig-local-files-fallback.js";
15
16
  import { EnsureWikiSourceDeclaredMigration } from "./ensure-wiki-source-declared.js";
16
17
  import { EnsureTsconfigLocalIncludesMigration } from "./ensure-tsconfig-local-includes.js";
@@ -30,6 +31,7 @@ export { EnsurePushDefaultSafeMigration } from "./ensure-push-default-safe.js";
30
31
  export { EnsureQualityCallerScopesMigration } from "./ensure-quality-caller-scopes.js";
31
32
  export { EnsureSeededGatesMigration } from "./ensure-seeded-gates.js";
32
33
  export { EnsureSonarExcludesLisaHarnessMigration } from "./ensure-sonar-excludes-lisa-harness.js";
34
+ export { EnsureThirdPartyActionPinsMigration } from "./ensure-third-party-action-pins.js";
33
35
  export { EnsureTsconfigLocalFilesFallbackMigration } from "./ensure-tsconfig-local-files-fallback.js";
34
36
  export { EnsureWikiSourceDeclaredMigration } from "./ensure-wiki-source-declared.js";
35
37
  export { EnsureTsconfigLocalIncludesMigration } from "./ensure-tsconfig-local-includes.js";
@@ -62,6 +64,7 @@ export class MigrationRegistry {
62
64
  new EnsureQualityCallerScopesMigration(),
63
65
  new EnsureSeededGatesMigration(),
64
66
  new EnsureSonarExcludesLisaHarnessMigration(),
67
+ new EnsureThirdPartyActionPinsMigration(),
65
68
  new EnsureWikiSourceDeclaredMigration(),
66
69
  new PruneRetiredClaudeDenyRulesMigration(),
67
70
  new ReconcileClaudeStackPluginsMigration(),
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -166,7 +166,7 @@
166
166
  "zod-validation-error": "^4.0.0"
167
167
  },
168
168
  "name": "@codyswann/lisa",
169
- "version": "4.35.4",
169
+ "version": "4.36.0",
170
170
  "description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
171
171
  "main": "dist/index.js",
172
172
  "exports": {
@@ -314,7 +314,7 @@
314
314
  "test": "tests"
315
315
  },
316
316
  "types": "./dist/index.d.ts",
317
- "lisaReleaseCommit": "cdfd50ffb82cb4a61189aa88ac5079f7191d5af3",
318
- "gitHead": "cdfd50ffb82cb4a61189aa88ac5079f7191d5af3",
319
- "lisaReleaseTag": "v4.35.4"
317
+ "lisaReleaseCommit": "e680357faafbc7d19a410bc517bd6fb48e3c5929",
318
+ "gitHead": "e680357faafbc7d19a410bc517bd6fb48e3c5929",
319
+ "lisaReleaseTag": "v4.36.0"
320
320
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "4.35.4",
3
+ "version": "4.36.0",
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.35.4",
3
+ "version": "4.36.0",
4
4
  "description": "Universal governance: agents, skills, commands, hooks, and rules for all projects.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -348,7 +348,66 @@ In `@example` blocks, use fenced code blocks and escape `@` as `\@`:
348
348
  */
349
349
  ```
350
350
 
351
- ### Quick Reference for Escaping
351
+ ### Path Examples Must Not Contain the Block Terminator
352
+
353
+ A path written as an example inside a doc comment **ends the comment** if it
354
+ contains `*/` — a glob such as `sandbox-*/`, or any real directory whose
355
+ name ends in an asterisk. Everything below that point is then parsed as source:
356
+ path segments become identifiers, and the separator between them becomes
357
+ division.
358
+
359
+ **Write the wildcard as a placeholder, not a glob:**
360
+
361
+ ```typescript
362
+ // WRONG — the comment ends inside the path, mid-line
363
+ /**
364
+ * Debris lands at `.stryker-tmp/bite-guard-intact/sandbox-*/rails/scripts/foo.sh`
365
+ * and this line is no longer a comment.
366
+ */
367
+
368
+ // RIGHT — a placeholder cannot terminate the block
369
+ /**
370
+ * Debris lands at `.stryker-tmp/bite-guard-intact/sandbox-<id>/rails/scripts/foo.sh`
371
+ * and this line is still a comment.
372
+ */
373
+ ```
374
+
375
+ `<id>`, `<name>`, `<n>` — the same placeholder convention used everywhere else
376
+ in Lisa's docs. Escaping (`*\/`) also works but produces an example nobody can
377
+ copy and paste, which defeats the point of writing one.
378
+
379
+ ### What it looks like when you get it wrong
380
+
381
+ The build goes red immediately — `bun run typecheck`, `bun run lint` and the
382
+ test run all fail — but **none of them mentions a comment**, and every line
383
+ they report sits *below* the real cause. Measured, with the true cause on
384
+ line 89:
385
+
386
+ ```text
387
+ src/configs/repo-scan.ts(90,9): error TS1005: ';' expected.
388
+ src/configs/repo-scan.ts(90,20): error TS1443: Module declaration names may only use ' or " quoted strings.
389
+ src/configs/repo-scan.ts(94,1): error TS1160: Unterminated template literal.
390
+ ```
391
+
392
+ Errors naming identifiers you never wrote — `Cannot find name 'mutation'`,
393
+ `Cannot find name 'src'` — are the giveaway: those are backtick contents from
394
+ inside the comment, now being read as code. **Look upward for a doc comment
395
+ before looking for a missing import.**
396
+
397
+ Lisa's gate runner says this for you. When a gate fails, it scans the files the
398
+ failure named and reports the closed comment by name:
399
+
400
+ ```text
401
+ a doc comment in src/configs/repo-scan.ts ends early, on line 89 — every error
402
+ reported below that line is downstream of it, not a fault of its own
403
+ ↳ src/configs/repo-scan.ts:89 — the block opened on line 87 ends at the
404
+ terminator INSIDE this line, not on line 92
405
+ ```
406
+
407
+ It is a text scan rather than a lint rule on purpose: the file does not parse,
408
+ so ESLint reports `Parsing error` and runs zero rules on it.
409
+
410
+ ## Quick Reference for Escaping
352
411
 
353
412
  | Context | Approach | Example |
354
413
  |---------|----------|---------|
@@ -33,6 +33,16 @@ An entire corpus sits outside the query's scope and nothing says so. `gh search
33
33
 
34
34
  **Catch it:** validate the detector against known-true items before believing any count.
35
35
 
36
+ #### A second domain, which is what makes this a category rather than a quirk
37
+
38
+ The same mode, on a filesystem rather than a tracker. A survey of agent worktrees enumerating `.claude/worktrees/` and `.worktrees/` returns a well-formed list — and omits every worktree created outside the repository tree, under the per-user temporary directory. Four such worktrees existed, three of them with uncommitted changes; none appeared.
39
+
40
+ Run it through the membership test and it qualifies on all three counts: the list is **well formed** (no error, no warning, no partial marker); the omission is **invisible from the list itself**, which looks exactly like a complete survey of a machine with fewer worktrees on it; and **a mechanical step would have caught it** — the same one A1 already prescribes, validating the enumeration against a worktree you know exists.
41
+
42
+ This example is here rather than folded into the paragraph above because **a second domain tests whether the category is real or just a description of one tool's behaviour.** A mode observed only through `gh search` could be a fact about GitHub's search semantics; the same shape in a `find` over directories says the failure belongs to *enumeration with an unstated boundary*, whichever substrate is enumerating. When extending this document, a new domain for an existing mode is worth as much as a new mode.
43
+
44
+ **The consequence in that instance was not academic.** Uncommitted work outside the repository tree is invisible to every query anyone would run before deciding what to clean up, and looks identical to abandoned scratch — so a survey feeding a deletion decision under-reports precisely the thing that must not be deleted. See the worktree-and-binding hazards for the separate question of a mitigation whose cost is invisibility; the measurement half is this mode.
45
+
36
46
  ### A2. Truncation — under, enumeration
37
47
 
38
48
  Real members past the first page are dropped with no truncation signal. `gh issue list` and `gh pr list` default to 30 and cap silently at whatever `--limit` is passed: one audit reported **37 items where the answer was 513**, a 14× undercount. A paging API returning **249 of 845 rows with `hasNextPage: false`** is the same mode on another substrate.
@@ -348,7 +348,66 @@ In `@example` blocks, use fenced code blocks and escape `@` as `\@`:
348
348
  */
349
349
  ```
350
350
 
351
- ### Quick Reference for Escaping
351
+ ### Path Examples Must Not Contain the Block Terminator
352
+
353
+ A path written as an example inside a doc comment **ends the comment** if it
354
+ contains `*/` — a glob such as `sandbox-*/`, or any real directory whose
355
+ name ends in an asterisk. Everything below that point is then parsed as source:
356
+ path segments become identifiers, and the separator between them becomes
357
+ division.
358
+
359
+ **Write the wildcard as a placeholder, not a glob:**
360
+
361
+ ```typescript
362
+ // WRONG — the comment ends inside the path, mid-line
363
+ /**
364
+ * Debris lands at `.stryker-tmp/bite-guard-intact/sandbox-*/rails/scripts/foo.sh`
365
+ * and this line is no longer a comment.
366
+ */
367
+
368
+ // RIGHT — a placeholder cannot terminate the block
369
+ /**
370
+ * Debris lands at `.stryker-tmp/bite-guard-intact/sandbox-<id>/rails/scripts/foo.sh`
371
+ * and this line is still a comment.
372
+ */
373
+ ```
374
+
375
+ `<id>`, `<name>`, `<n>` — the same placeholder convention used everywhere else
376
+ in Lisa's docs. Escaping (`*\/`) also works but produces an example nobody can
377
+ copy and paste, which defeats the point of writing one.
378
+
379
+ ### What it looks like when you get it wrong
380
+
381
+ The build goes red immediately — `bun run typecheck`, `bun run lint` and the
382
+ test run all fail — but **none of them mentions a comment**, and every line
383
+ they report sits *below* the real cause. Measured, with the true cause on
384
+ line 89:
385
+
386
+ ```text
387
+ src/configs/repo-scan.ts(90,9): error TS1005: ';' expected.
388
+ src/configs/repo-scan.ts(90,20): error TS1443: Module declaration names may only use ' or " quoted strings.
389
+ src/configs/repo-scan.ts(94,1): error TS1160: Unterminated template literal.
390
+ ```
391
+
392
+ Errors naming identifiers you never wrote — `Cannot find name 'mutation'`,
393
+ `Cannot find name 'src'` — are the giveaway: those are backtick contents from
394
+ inside the comment, now being read as code. **Look upward for a doc comment
395
+ before looking for a missing import.**
396
+
397
+ Lisa's gate runner says this for you. When a gate fails, it scans the files the
398
+ failure named and reports the closed comment by name:
399
+
400
+ ```text
401
+ a doc comment in src/configs/repo-scan.ts ends early, on line 89 — every error
402
+ reported below that line is downstream of it, not a fault of its own
403
+ ↳ src/configs/repo-scan.ts:89 — the block opened on line 87 ends at the
404
+ terminator INSIDE this line, not on line 92
405
+ ```
406
+
407
+ It is a text scan rather than a lint rule on purpose: the file does not parse,
408
+ so ESLint reports `Parsing error` and runs zero rules on it.
409
+
410
+ ## Quick Reference for Escaping
352
411
 
353
412
  | Context | Approach | Example |
354
413
  |---------|----------|---------|
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "4.35.4",
3
+ "version": "4.36.0",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"