@codyswann/lisa 4.84.6 → 4.84.7

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 (90) hide show
  1. package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
  2. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  3. package/dist/core/upstream-evidence-manifest.js +7 -3
  4. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  5. package/package.json +4 -4
  6. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  7. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  8. package/plugins/lisa/hooks/block-host-name-leak.mjs +25 -13
  9. package/plugins/lisa/hooks/host-name-command-context.mjs +16 -4
  10. package/plugins/lisa-agy/hooks/block-host-name-leak.mjs +25 -13
  11. package/plugins/lisa-agy/hooks/host-name-command-context.mjs +16 -4
  12. package/plugins/lisa-agy/plugin.json +1 -1
  13. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  14. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  15. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  16. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  17. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  18. package/plugins/lisa-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/hooks/block-host-name-leak.mjs +25 -13
  22. package/plugins/lisa-copilot/hooks/host-name-command-context.mjs +16 -4
  23. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  24. package/plugins/lisa-cursor/hooks/block-host-name-leak.mjs +25 -13
  25. package/plugins/lisa-cursor/hooks/host-name-command-context.mjs +16 -4
  26. package/plugins/lisa-devin/.claude-plugin/plugin.json +1 -1
  27. package/plugins/lisa-devin/.devin-plugin/plugin.json +1 -1
  28. package/plugins/lisa-devin/hooks/block-host-name-leak.mjs +25 -13
  29. package/plugins/lisa-devin/hooks/host-name-command-context.mjs +16 -4
  30. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  31. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  32. package/plugins/lisa-expo-agy/plugin.json +1 -1
  33. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  34. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  35. package/plugins/lisa-expo-devin/.claude-plugin/plugin.json +1 -1
  36. package/plugins/lisa-expo-devin/.devin-plugin/plugin.json +1 -1
  37. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  38. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  39. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  40. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  41. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  42. package/plugins/lisa-harper-fabric-devin/.claude-plugin/plugin.json +1 -1
  43. package/plugins/lisa-harper-fabric-devin/.devin-plugin/plugin.json +1 -1
  44. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  45. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  46. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  47. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  48. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  49. package/plugins/lisa-nestjs-devin/.claude-plugin/plugin.json +1 -1
  50. package/plugins/lisa-nestjs-devin/.devin-plugin/plugin.json +1 -1
  51. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  52. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  53. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  54. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  55. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  56. package/plugins/lisa-openclaw-devin/.claude-plugin/plugin.json +1 -1
  57. package/plugins/lisa-openclaw-devin/.devin-plugin/plugin.json +1 -1
  58. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  59. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  60. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  61. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  62. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  63. package/plugins/lisa-phaser-devin/.claude-plugin/plugin.json +1 -1
  64. package/plugins/lisa-phaser-devin/.devin-plugin/plugin.json +1 -1
  65. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  66. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  67. package/plugins/lisa-rails-agy/plugin.json +1 -1
  68. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  69. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  70. package/plugins/lisa-rails-devin/.claude-plugin/plugin.json +1 -1
  71. package/plugins/lisa-rails-devin/.devin-plugin/plugin.json +1 -1
  72. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  73. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  74. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  75. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  76. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  77. package/plugins/lisa-typescript-devin/.claude-plugin/plugin.json +1 -1
  78. package/plugins/lisa-typescript-devin/.devin-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/lisa-wiki-devin/.claude-plugin/plugin.json +1 -1
  85. package/plugins/lisa-wiki-devin/.devin-plugin/plugin.json +1 -1
  86. package/plugins/src/base/hooks/block-host-name-leak.mjs +25 -13
  87. package/plugins/src/base/hooks/host-name-command-context.mjs +16 -4
  88. package/scripts/lib/host-name-expanded-command-cases.mjs +286 -0
  89. package/scripts/lib/host-name-field-occurrence-cases.mjs +60 -0
  90. package/scripts/verify-host-name-target-scope.mjs +27 -1
@@ -103,6 +103,7 @@ function words(command) {
103
103
  */
104
104
  function argumentsOf(input) {
105
105
  const flags = new Map(),
106
+ fieldOccurrences = [],
106
107
  positional = [],
107
108
  tokens = [];
108
109
  // Any expansion can add/replace routing arguments after shell word splitting.
@@ -139,23 +140,34 @@ function argumentsOf(input) {
139
140
  flag === "-R" ? "--repo" : flag === "-X" ? "--method" : flag,
140
141
  value
141
142
  );
143
+ // API fields are additive even though routing options use last values.
144
+ if (FIELD_FLAGS.has(flag)) fieldOccurrences.push([flag, value]);
142
145
  tokens.push(value.value);
143
146
  } else if (!word.value.startsWith("-")) positional.push(word);
144
147
  else if (!word.literal) certain = false;
145
148
  }
146
- const noun = positional[0]?.value,
147
- verb = positional[1]?.value;
149
+ const nounWord = positional[0],
150
+ verbWord = positional[1];
151
+ const noun = nounWord?.literal ? nounWord.value : undefined,
152
+ verb = verbWord?.value;
153
+ // Command-name expansions can supply several argv words. A following
154
+ // read-looking literal does not prove that the expanded command is a read.
155
+ const uncertainName =
156
+ nounWord?.literal === false ||
157
+ (["issue", "pr"].includes(noun) && verbWord?.literal === false);
148
158
  const method = flags.get("--method");
149
159
  const writes =
150
- noun === "api"
160
+ uncertainName ||
161
+ (noun === "api"
151
162
  ? method
152
163
  ? !method.literal || METHODS.has(method.value.toUpperCase())
153
164
  : [...FIELD_FLAGS].some(flag => flags.has(flag)) ||
154
165
  Boolean(flags.get("--input")?.value)
155
166
  : ["issue", "pr"].includes(noun) &&
156
- ["create", "comment", "edit"].includes(verb);
167
+ ["create", "comment", "edit"].includes(verb));
157
168
  return {
158
169
  flags,
170
+ fieldOccurrences,
159
171
  positional,
160
172
  tokens: ["gh", ...tokens],
161
173
  noun,
@@ -0,0 +1,286 @@
1
+ /** Direct expanded command-name regressions; all identities are synthetic. */
2
+ import assert from "node:assert/strict";
3
+ import { boundedExecFileSync } from "./bounded-spawn.mjs";
4
+
5
+ /** @param {object} context Isolated actual-wrapper fixtures. @returns {Array[]} Named cases. */
6
+ export function hostNameExpandedCommandCases(context) {
7
+ const { lisaCwd, unknownCwd, hostCwd, lisa, host, fixtureName, body } =
8
+ context;
9
+ const cases = [];
10
+ for (const [target, cwd, repo] of [
11
+ ["protected", lisaCwd, ` --repo ${lisa}`],
12
+ ["unknown", unknownCwd, ""],
13
+ ]) {
14
+ for (const [name, noun] of [
15
+ ["unquoted", "$N"],
16
+ ["double quoted", '"$N"'],
17
+ ["braced", '"${N}"'],
18
+ ["concatenated", 'is"$SUFFIX"'],
19
+ ]) {
20
+ cases.push([
21
+ `expanded noun ${name} ${target} write`,
22
+ cwd,
23
+ `gh ${noun} create${repo} --body '${fixtureName}'`,
24
+ 2,
25
+ ]);
26
+ }
27
+ for (const [name, verb] of [
28
+ ["unquoted", "$V"],
29
+ ["double quoted", '"$V"'],
30
+ ["braced", '"${V}"'],
31
+ ["concatenated", 'cre"$TAIL"'],
32
+ ]) {
33
+ cases.push([
34
+ `expanded verb ${name} ${target} write`,
35
+ cwd,
36
+ `gh issue ${verb}${repo} --body '${fixtureName}'`,
37
+ 2,
38
+ ]);
39
+ }
40
+ for (const [name, prefix] of [
41
+ ["multiple-word noun", "gh $N"],
42
+ ["multiple-word verb", "gh issue $V"],
43
+ ["noun before read-looking word", "gh $N view"],
44
+ ["verb before read-looking word", "gh issue $V view"],
45
+ ]) {
46
+ cases.push([
47
+ `expanded ${name} ${target} write`,
48
+ cwd,
49
+ `${prefix}${repo} --body '${fixtureName}'`,
50
+ 2,
51
+ ]);
52
+ }
53
+ for (const [name, args] of [
54
+ ["API field text", `-F body=${fixtureName}`],
55
+ ["API field file", `-F body=@${body}`],
56
+ ["API attached field file", `-Fbody=@${body}`],
57
+ ["API raw field", `-f body=${fixtureName}`],
58
+ ["API input file", `--input ${body}`],
59
+ ]) {
60
+ cases.push([
61
+ `expanded noun possible ${name} ${target} write`,
62
+ cwd,
63
+ `gh "$N" repos/${lisa}/issues ${args}`,
64
+ 2,
65
+ ]);
66
+ }
67
+ cases.push(
68
+ [
69
+ `expanded noun issue body-file ${target} write`,
70
+ cwd,
71
+ `gh "$N" create${repo} -F ${body}`,
72
+ 2,
73
+ ],
74
+ [
75
+ `expanded both command positions ${target} write`,
76
+ cwd,
77
+ `gh${repo} "$N" "$V" --body '${fixtureName}'`,
78
+ 2,
79
+ ]
80
+ );
81
+ }
82
+ cases.push(
83
+ [
84
+ "expanded PR verb protected body-file write",
85
+ lisaCwd,
86
+ `gh pr "$V" --repo ${lisa} --body-file ${body}`,
87
+ 2,
88
+ ],
89
+ [
90
+ "expanded PR verb unknown body-file write",
91
+ unknownCwd,
92
+ `gh pr "$V" --body-file ${body}`,
93
+ 2,
94
+ ],
95
+ [
96
+ "expanded noun literal host flag cannot certify target",
97
+ hostCwd,
98
+ `gh "$N" create --repo ${host} --body '${fixtureName}'`,
99
+ 2,
100
+ ],
101
+ [
102
+ "expanded-name API GET prose with dynamic filter control",
103
+ lisaCwd,
104
+ `gh api repos/${lisa}/issues -X GET -F body=${fixtureName} -q "$FILTER"`,
105
+ 0,
106
+ ],
107
+ [
108
+ "expanded-name API GET input with dynamic filter control",
109
+ lisaCwd,
110
+ `gh api repos/${lisa}/issues -X GET --input ${body} -q "$FILTER"`,
111
+ 0,
112
+ ],
113
+ [
114
+ "expanded-name literal host control",
115
+ hostCwd,
116
+ `gh issue create --repo ${host} --body '${fixtureName}'`,
117
+ 0,
118
+ ],
119
+ [
120
+ "expanded-name literal protected control",
121
+ lisaCwd,
122
+ `gh issue create --repo ${lisa} --body '${fixtureName}'`,
123
+ 2,
124
+ ],
125
+ [
126
+ "expanded-name literal unknown control",
127
+ unknownCwd,
128
+ `gh issue create --body '${fixtureName}'`,
129
+ 2,
130
+ ],
131
+ [
132
+ "expanded-name dynamic read filter control",
133
+ lisaCwd,
134
+ `gh issue list --repo ${lisa} --json title --jq "$FILTER"`,
135
+ 0,
136
+ ],
137
+ [
138
+ "expanded-name dynamic read selector control",
139
+ lisaCwd,
140
+ `gh issue view "$NUMBER" --repo ${lisa} --json title --jq '${fixtureName}'`,
141
+ 0,
142
+ ],
143
+ [
144
+ "expanded-name API GET dynamic filter control",
145
+ lisaCwd,
146
+ `gh api repos/${lisa}/issues -X GET -q "$FILTER"`,
147
+ 0,
148
+ ],
149
+ [
150
+ "expanded-name single-quoted noun control",
151
+ lisaCwd,
152
+ `gh '$N' create --repo ${lisa} --body '${fixtureName}'`,
153
+ 0,
154
+ ],
155
+ [
156
+ "expanded-name single-quoted verb control",
157
+ lisaCwd,
158
+ `gh issue '$V' --repo ${lisa} --body '${fixtureName}'`,
159
+ 0,
160
+ ],
161
+ [
162
+ "expanded-name escaped noun control",
163
+ lisaCwd,
164
+ `gh \\$N create --repo ${lisa} --body '${fixtureName}'`,
165
+ 0,
166
+ ],
167
+ [
168
+ "expanded-name quoted non-command control",
169
+ lisaCwd,
170
+ `printf '%s' 'gh $N create --repo ${lisa} --body ${fixtureName}'`,
171
+ 0,
172
+ ],
173
+ [
174
+ "expanded-name clean prose control",
175
+ lisaCwd,
176
+ `gh "$N" create --repo ${lisa} --body 'A clean report.'`,
177
+ 0,
178
+ ],
179
+ [
180
+ "expanded-name options before noun preserve prose boundaries",
181
+ lisaCwd,
182
+ `gh --repo ${lisa} --title 'view list' "$N" create --body '${fixtureName}'`,
183
+ 2,
184
+ ],
185
+ [
186
+ "expanded-name literal host API control",
187
+ hostCwd,
188
+ `gh api repos/${host}/issues -F body=${fixtureName}`,
189
+ 0,
190
+ ]
191
+ );
192
+ return cases;
193
+ }
194
+
195
+ /**
196
+ * Establish expansion premises with a Bash function that only prints argv.
197
+ * @param {object} context Synthetic fixtures.
198
+ * @param {object} env Isolated child environment.
199
+ * @returns {void}
200
+ */
201
+ export function verifyExpandedCommandArgv(context, env) {
202
+ const { lisaCwd, lisa, fixtureName, body } = context;
203
+ const suffix = ` --repo ${lisa} --body '${fixtureName}'`;
204
+ for (const [name, command, values, expected] of [
205
+ [
206
+ "unquoted noun",
207
+ `gh $N create${suffix}`,
208
+ { N: "issue" },
209
+ ["issue", "create", "--repo", lisa, "--body", fixtureName],
210
+ ],
211
+ [
212
+ "quoted braced noun",
213
+ `gh "${"${N}"}" create${suffix}`,
214
+ { N: "issue" },
215
+ ["issue", "create", "--repo", lisa, "--body", fixtureName],
216
+ ],
217
+ [
218
+ "concatenated noun",
219
+ `gh is"$SUFFIX" create${suffix}`,
220
+ { SUFFIX: "sue" },
221
+ ["issue", "create", "--repo", lisa, "--body", fixtureName],
222
+ ],
223
+ [
224
+ "concatenated verb",
225
+ `gh issue cre"$TAIL"${suffix}`,
226
+ { TAIL: "ate" },
227
+ ["issue", "create", "--repo", lisa, "--body", fixtureName],
228
+ ],
229
+ [
230
+ "multiword noun before read-looking word",
231
+ `gh $N view${suffix}`,
232
+ { N: "issue create --title" },
233
+ [
234
+ "issue",
235
+ "create",
236
+ "--title",
237
+ "view",
238
+ "--repo",
239
+ lisa,
240
+ "--body",
241
+ fixtureName,
242
+ ],
243
+ ],
244
+ [
245
+ "multiword verb before read-looking word",
246
+ `gh issue $V view${suffix}`,
247
+ { V: "create --title" },
248
+ [
249
+ "issue",
250
+ "create",
251
+ "--title",
252
+ "view",
253
+ "--repo",
254
+ lisa,
255
+ "--body",
256
+ fixtureName,
257
+ ],
258
+ ],
259
+ [
260
+ "possible API field file",
261
+ `gh "$N" repos/${lisa}/issues -F body=@${body}`,
262
+ { N: "api" },
263
+ ["api", `repos/${lisa}/issues`, "-F", `body=@${body}`],
264
+ ],
265
+ ]) {
266
+ const argv = boundedExecFileSync(
267
+ "/bin/bash",
268
+ ["-c", `gh() { printf '%s\\0' "$@"; }; ${command}`],
269
+ { cwd: lisaCwd, env: { ...env, ...values }, encoding: "utf8" }
270
+ )
271
+ .split("\0")
272
+ .slice(0, -1);
273
+ assert.deepEqual(argv, expected, name);
274
+ console.log(
275
+ JSON.stringify({
276
+ localExpandedArgvControl: {
277
+ name,
278
+ command,
279
+ argv,
280
+ inspectedTrackerWriteExecuted: false,
281
+ ghImplementation: "Bash argv-only printer",
282
+ },
283
+ })
284
+ );
285
+ }
286
+ }
@@ -0,0 +1,60 @@
1
+ /** Repeated typed API fields must not hide an earlier unresolved prose file. */
2
+ export function hostNameFieldOccurrenceCases({ lisaCwd, lisa, relative }) {
3
+ const prefix = 'cd "$D" && gh',
4
+ endpoint = `repos/${lisa}/issues`,
5
+ clean = `${lisaCwd}/body.md`,
6
+ refusal = "BLOCKED: the working directory";
7
+ const unknown = (name, command) => [name, lisaCwd, command, 2, {}, refusal];
8
+ return [
9
+ unknown(
10
+ "expanded repeated field retains earlier relative prose file",
11
+ `${prefix} "$N" ${endpoint} --field body=@body.md --field title=clean`
12
+ ),
13
+ unknown(
14
+ "literal API repeated field retains earlier relative prose file",
15
+ `${prefix} api ${endpoint} --field body=@body.md --field title=clean`
16
+ ),
17
+ unknown(
18
+ "literal API repeated F before absolute clean field retains relative file",
19
+ `${prefix} api ${endpoint} -F body=@body.md -F title=@${clean}`
20
+ ),
21
+ unknown(
22
+ "expanded repeated F union retains unresolved file control",
23
+ `${prefix} "$N" ${endpoint} -F body=@body.md -F title=@${clean}`
24
+ ),
25
+ unknown(
26
+ "expanded repeated field body-last control",
27
+ `${prefix} "$N" ${endpoint} --field title=clean --field body=@body.md`
28
+ ),
29
+ [
30
+ "literal API repeated fields known cwd reads original prose file",
31
+ lisaCwd,
32
+ `cd '${relative}' && gh api ${endpoint} --field body=@body.md --field title=clean`,
33
+ 2,
34
+ ],
35
+ [
36
+ "literal API repeated fields GET remains read-only",
37
+ lisaCwd,
38
+ `${prefix} api ${endpoint} -X GET --field body=@body.md --field title=clean -q "$FILTER"`,
39
+ 0,
40
+ ],
41
+ [
42
+ "nonadditive body-file last value remains authoritative",
43
+ lisaCwd,
44
+ `${prefix} issue create --repo ${lisa} --body-file missing.md --body-file ${clean}`,
45
+ 0,
46
+ ],
47
+ unknown(
48
+ "expanded mixed field aliases retain earlier relative file control",
49
+ `${prefix} "$N" ${endpoint} --field body=@body.md -F title=@${clean}`
50
+ ),
51
+ unknown(
52
+ "expanded repeated equal field retains earlier relative file",
53
+ `${prefix} "$N" ${endpoint} --field=body=@body.md --field=title=clean`
54
+ ),
55
+ unknown(
56
+ "literal API repeated attached F retains earlier relative file",
57
+ `${prefix} api ${endpoint} -Fbody=@body.md -Ftitle=@${clean}`
58
+ ),
59
+ ];
60
+ }
@@ -17,6 +17,11 @@ import path from "node:path";
17
17
  import { boundedExecFileSync, boundedSpawnSync } from "./lib/bounded-spawn.mjs";
18
18
  import { hostNameTargetCases } from "./lib/host-name-target-cases.mjs";
19
19
  import { hostNameReviewCases } from "./lib/host-name-review-cases.mjs";
20
+ import {
21
+ hostNameExpandedCommandCases,
22
+ verifyExpandedCommandArgv,
23
+ } from "./lib/host-name-expanded-command-cases.mjs";
24
+ import { hostNameFieldOccurrenceCases } from "./lib/host-name-field-occurrence-cases.mjs";
20
25
 
21
26
  const root = process.cwd();
22
27
  const DETECTOR_RELATIVE = "dist/core/downstream-references.js";
@@ -118,6 +123,15 @@ try {
118
123
  const identity = {
119
124
  proverCheckoutHead: git(root, ["rev-parse", "HEAD"]),
120
125
  proverSha256: digest(new URL(import.meta.url)),
126
+ caseModules: [
127
+ "host-name-target-cases.mjs",
128
+ "host-name-review-cases.mjs",
129
+ "host-name-expanded-command-cases.mjs",
130
+ "host-name-field-occurrence-cases.mjs",
131
+ ].map(file => ({
132
+ file,
133
+ sha256: digest(new URL(`./lib/${file}`, import.meta.url)),
134
+ })),
121
135
  payloadRoot,
122
136
  payloadPackageVersion: JSON.parse(
123
137
  readFileSync(path.join(payloadRoot, "package.json"), "utf8")
@@ -299,7 +313,10 @@ try {
299
313
  const cases = [
300
314
  ...hostNameTargetCases(context),
301
315
  ...hostNameReviewCases(context),
316
+ ...hostNameExpandedCommandCases(context),
317
+ ...hostNameFieldOccurrenceCases(context),
302
318
  ];
319
+ verifyExpandedCommandArgv(context, fixtureEnv);
303
320
  for (const [
304
321
  name,
305
322
  cwd,
@@ -330,7 +347,16 @@ try {
330
347
  );
331
348
  const passed =
332
349
  run.status === expected && (expected !== 2 || output.includes(refusal));
333
- records.push({ name, expected, actual: run.status, passed, output });
350
+ records.push({
351
+ name,
352
+ cwd,
353
+ command,
354
+ overrides,
355
+ expected,
356
+ actual: run.status,
357
+ passed,
358
+ output,
359
+ });
334
360
  console.log(JSON.stringify(records.at(-1)));
335
361
  }
336
362
  const failed = records.filter(record => !record.passed);