@guilz-dev/belay 0.9.1 → 0.9.2

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.
@@ -11120,6 +11120,7 @@ function worstEffectDecision(decisions) {
11120
11120
 
11121
11121
  // src/core/effect-ir/shell-lower.ts
11122
11122
  init_git_resource_identity();
11123
+ init_path_utils();
11123
11124
  init_shell_tokenizer();
11124
11125
  import { lstatSync as lstatSync2, realpathSync as realpathSync4 } from "node:fs";
11125
11126
  import path39 from "node:path";
@@ -12850,6 +12851,159 @@ function gitRequirement(tag, action, resource, segment, signals) {
12850
12851
  // src/core/verdict/launcher-resolve.ts
12851
12852
  import { existsSync as existsSync11, readFileSync as readFileSync5 } from "node:fs";
12852
12853
  import path37 from "node:path";
12854
+
12855
+ // src/core/verdict/makefile-expand.ts
12856
+ var MAX_EXPAND_DEPTH = 16;
12857
+ function parseMakefileVariables(content) {
12858
+ const variables = /* @__PURE__ */ new Map();
12859
+ for (const line of content.split("\n")) {
12860
+ const trimmed = line.trim();
12861
+ if (!trimmed || trimmed.startsWith("#")) {
12862
+ continue;
12863
+ }
12864
+ const match = /^([A-Za-z_][A-Za-z0-9_]*)\s*[:?]?=\s*(.+)$/.exec(trimmed);
12865
+ if (!match) {
12866
+ continue;
12867
+ }
12868
+ variables.set(match[1] ?? "", (match[2] ?? "").trim());
12869
+ }
12870
+ return variables;
12871
+ }
12872
+ function parsePhonyTargets(content) {
12873
+ const phony = /* @__PURE__ */ new Set();
12874
+ for (const line of content.split("\n")) {
12875
+ const trimmed = line.trim();
12876
+ const match = /^\.PHONY:\s*(.+)$/.exec(trimmed);
12877
+ if (!match) {
12878
+ continue;
12879
+ }
12880
+ for (const token of (match[1] ?? "").split(/\s+/)) {
12881
+ if (token) {
12882
+ phony.add(token);
12883
+ }
12884
+ }
12885
+ }
12886
+ return phony;
12887
+ }
12888
+ function normalizeMakeRecipeLine(line) {
12889
+ let normalized = line.trim();
12890
+ while (normalized.startsWith("@") || normalized.startsWith("-") || normalized.startsWith("+")) {
12891
+ normalized = normalized.slice(1).trimStart();
12892
+ }
12893
+ return normalized;
12894
+ }
12895
+ function expandMakeExpression(expression, cliVars, makefileVars) {
12896
+ if (/\$\(\s*shell\b/i.test(expression) || expression.includes("$$")) {
12897
+ return null;
12898
+ }
12899
+ try {
12900
+ const expanded = expandMakeValue(expression, cliVars, makefileVars, 0);
12901
+ if (expanded === null || /\$\(/.test(expanded) || /\$\{/.test(expanded)) {
12902
+ return null;
12903
+ }
12904
+ return expanded;
12905
+ } catch {
12906
+ return null;
12907
+ }
12908
+ }
12909
+ function expandMakeValue(expression, cliVars, makefileVars, depth) {
12910
+ if (depth > MAX_EXPAND_DEPTH) {
12911
+ return null;
12912
+ }
12913
+ let value = expression.trim();
12914
+ let changed = true;
12915
+ let iterations = 0;
12916
+ while (changed && iterations < MAX_EXPAND_DEPTH) {
12917
+ changed = false;
12918
+ iterations += 1;
12919
+ const orMatch = value.match(/\$\(\s*or\s+([^()]*(?:\([^)]*\)[^()]*)*)\)/);
12920
+ if (orMatch) {
12921
+ const [fullMatch, inner] = orMatch;
12922
+ const parts = splitMakeFunctionArgs(inner ?? "");
12923
+ let selected = null;
12924
+ for (const part of parts) {
12925
+ const expanded = expandMakeValue(part.trim(), cliVars, makefileVars, depth + 1);
12926
+ if (expanded !== null && expanded.trim() !== "") {
12927
+ selected = expanded;
12928
+ break;
12929
+ }
12930
+ }
12931
+ if (selected === null) {
12932
+ const fallback = parts.at(-1)?.trim();
12933
+ selected = fallback === void 0 ? "" : expandMakeValue(fallback, cliVars, makefileVars, depth + 1);
12934
+ }
12935
+ if (selected === null) {
12936
+ return null;
12937
+ }
12938
+ value = value.replace(fullMatch, selected);
12939
+ changed = true;
12940
+ continue;
12941
+ }
12942
+ const varMatch = value.match(/\$\(([A-Za-z_][A-Za-z0-9_]*)\)/);
12943
+ if (varMatch) {
12944
+ const [fullMatch, name] = varMatch;
12945
+ const resolved = resolveMakeVariable(name ?? "", cliVars, makefileVars, depth + 1);
12946
+ if (resolved === null) {
12947
+ return null;
12948
+ }
12949
+ value = value.replace(fullMatch, resolved);
12950
+ changed = true;
12951
+ continue;
12952
+ }
12953
+ const bracedMatch = value.match(/\$\{([A-Za-z_][A-Za-z0-9_]*)\}/);
12954
+ if (bracedMatch) {
12955
+ const [fullMatch, name] = bracedMatch;
12956
+ const resolved = name === "PWD" ? "." : resolveMakeVariable(name ?? "", cliVars, makefileVars, depth + 1);
12957
+ if (resolved === null) {
12958
+ return null;
12959
+ }
12960
+ value = value.replace(fullMatch, resolved);
12961
+ changed = true;
12962
+ continue;
12963
+ }
12964
+ break;
12965
+ }
12966
+ return value;
12967
+ }
12968
+ function resolveMakeVariable(name, cliVars, makefileVars, depth) {
12969
+ if (Object.hasOwn(cliVars, name)) {
12970
+ return cliVars[name] ?? "";
12971
+ }
12972
+ const definition = makefileVars.get(name);
12973
+ if (definition === void 0) {
12974
+ return null;
12975
+ }
12976
+ return expandMakeValue(definition, cliVars, makefileVars, depth);
12977
+ }
12978
+ function splitMakeFunctionArgs(input) {
12979
+ const parts = [];
12980
+ let current = "";
12981
+ let depth = 0;
12982
+ for (const char of input) {
12983
+ if (char === "(") {
12984
+ depth += 1;
12985
+ current += char;
12986
+ continue;
12987
+ }
12988
+ if (char === ")") {
12989
+ depth -= 1;
12990
+ current += char;
12991
+ continue;
12992
+ }
12993
+ if (char === "," && depth === 0) {
12994
+ parts.push(current.trim());
12995
+ current = "";
12996
+ continue;
12997
+ }
12998
+ current += char;
12999
+ }
13000
+ if (current.trim()) {
13001
+ parts.push(current.trim());
13002
+ }
13003
+ return parts;
13004
+ }
13005
+
13006
+ // src/core/verdict/launcher-resolve.ts
12853
13007
  var MAX_RESOLVE_DEPTH = 8;
12854
13008
  var PNPM_BUILTIN_COMMANDS = /* @__PURE__ */ new Set([
12855
13009
  "add",
@@ -12990,10 +13144,9 @@ function resolveNpmRecipe(cwd, repoRoot, scriptName, extraArgs) {
12990
13144
  reason: "npm_script_resolved"
12991
13145
  };
12992
13146
  }
12993
- function parseMakefileRecipes(makefilePath) {
13147
+ function parseMakefileRecipeContent(content) {
12994
13148
  const targets = /* @__PURE__ */ new Map();
12995
13149
  try {
12996
- const content = readFileSync5(makefilePath, "utf8");
12997
13150
  const lines = content.split("\n");
12998
13151
  let currentTarget = null;
12999
13152
  let recipeLines = [];
@@ -13052,7 +13205,7 @@ function parseMakefileRecipes(makefilePath) {
13052
13205
  }
13053
13206
  return targets;
13054
13207
  }
13055
- function resolveMakeRecipe(cwd, repoRoot, target) {
13208
+ function resolveMakeRecipe(cwd, repoRoot, target, cliVars = {}) {
13056
13209
  const candidates = ["Makefile", "makefile", "GNUmakefile"];
13057
13210
  let makefilePath = null;
13058
13211
  let searchDir = path37.resolve(cwd);
@@ -13073,7 +13226,10 @@ function resolveMakeRecipe(cwd, repoRoot, target) {
13073
13226
  if (!makefilePath) {
13074
13227
  return { recipes: [], opaque: true, reason: "unknown_local_effect" };
13075
13228
  }
13076
- const targets = parseMakefileRecipes(makefilePath);
13229
+ const makefileContent = readFileSync5(makefilePath, "utf8");
13230
+ const makefileVars = parseMakefileVariables(makefileContent);
13231
+ const phonyTargets = parsePhonyTargets(makefileContent);
13232
+ const targets = parseMakefileRecipeContent(makefileContent);
13077
13233
  if (!targets.has(target)) {
13078
13234
  return { recipes: [], opaque: true, reason: "make_target_undefined" };
13079
13235
  }
@@ -13099,7 +13255,10 @@ function resolveMakeRecipe(cwd, repoRoot, target) {
13099
13255
  return false;
13100
13256
  }
13101
13257
  }
13102
- recipeLines.push(...entry.recipes);
13258
+ const skipPhonyPrerequisiteRecipes = name !== target && (phonyTargets.has(name) || name.startsWith("_")) && (targets.get(target)?.recipes.length ?? 0) > 0;
13259
+ if (!skipPhonyPrerequisiteRecipes) {
13260
+ recipeLines.push(...entry.recipes);
13261
+ }
13103
13262
  visiting.delete(name);
13104
13263
  visited.add(name);
13105
13264
  return true;
@@ -13107,15 +13266,24 @@ function resolveMakeRecipe(cwd, repoRoot, target) {
13107
13266
  if (!collect(target)) {
13108
13267
  return { recipes: recipeLines, opaque: true, reason: "make_dependency_cycle" };
13109
13268
  }
13269
+ const expandedRecipes = [];
13110
13270
  for (const line of recipeLines) {
13111
- if (/\$\(/.test(line) || /\$\{/.test(line)) {
13271
+ const normalized = normalizeMakeRecipeLine(line);
13272
+ const expanded = expandMakeExpression(normalized, cliVars, makefileVars);
13273
+ if (expanded === null) {
13112
13274
  return { recipes: recipeLines, opaque: true, reason: "make_recipe_dynamic" };
13113
13275
  }
13276
+ expandedRecipes.push(expanded);
13277
+ }
13278
+ for (const line of expandedRecipes) {
13279
+ if (/\$\(/.test(line) || /\$\{/.test(line)) {
13280
+ return { recipes: expandedRecipes, opaque: true, reason: "make_recipe_dynamic" };
13281
+ }
13114
13282
  }
13115
13283
  if (opaquePrerequisites) {
13116
- return { recipes: recipeLines, opaque: true, reason: "make_prerequisite_dynamic" };
13284
+ return { recipes: expandedRecipes, opaque: true, reason: "make_prerequisite_dynamic" };
13117
13285
  }
13118
- return { recipes: recipeLines, opaque: false, reason: "make_recipe_resolved" };
13286
+ return { recipes: expandedRecipes, opaque: false, reason: "make_recipe_resolved" };
13119
13287
  }
13120
13288
  function resolveLauncherRecipe(params) {
13121
13289
  if (params.depth >= MAX_RESOLVE_DEPTH) {
@@ -13139,8 +13307,28 @@ function resolveLauncherRecipe(params) {
13139
13307
  }
13140
13308
  return resolution;
13141
13309
  }
13142
- if (tokens[0] === "make" && tokens[1] && !tokens[1].startsWith("-")) {
13143
- return resolveMakeRecipe(params.cwd, params.repoRoot, tokens[1]);
13310
+ if (tokens[0] === "make") {
13311
+ if (tokens.includes("-n") || tokens.includes("--dry-run")) {
13312
+ return null;
13313
+ }
13314
+ let target = null;
13315
+ const cliVars = {};
13316
+ for (const token of tokens.slice(1)) {
13317
+ if (token.startsWith("-")) {
13318
+ continue;
13319
+ }
13320
+ const assignment = /^([A-Za-z_][A-Za-z0-9_]*)=(.*)$/.exec(token);
13321
+ if (assignment) {
13322
+ cliVars[assignment[1] ?? ""] = assignment[2] ?? "";
13323
+ continue;
13324
+ }
13325
+ if (!target) {
13326
+ target = token;
13327
+ }
13328
+ }
13329
+ if (target) {
13330
+ return resolveMakeRecipe(params.cwd, params.repoRoot, target, cliVars);
13331
+ }
13144
13332
  }
13145
13333
  if (tokens[0] === "pnpm" && tokens[1] === "exec" && tokens[2]) {
13146
13334
  return {
@@ -13657,7 +13845,6 @@ function extractRecursiveScript(tokens) {
13657
13845
  return null;
13658
13846
  }
13659
13847
  const head = normalizeHead(filtered[0] ?? "");
13660
- const second = filtered[1] ?? "";
13661
13848
  if (head === "eval") {
13662
13849
  const body = filtered.slice(1).join(" ").trim();
13663
13850
  return body || null;
@@ -13665,12 +13852,33 @@ function extractRecursiveScript(tokens) {
13665
13852
  if (SHELL_INTERPRETERS.has(head) || CODE_INTERPRETERS.has(head)) {
13666
13853
  const flagIndex = filtered.findIndex((token) => SCRIPT_FLAGS.has(token));
13667
13854
  if (flagIndex !== -1) {
13668
- const body = filtered.slice(flagIndex + 1).join(" ").replace(/^['"]|['"]$/g, "").trim();
13855
+ const body = filtered[flagIndex + 1] ?? "";
13669
13856
  return body || null;
13670
13857
  }
13671
13858
  }
13672
- if (head === "bash" && (second === "-lc" || second === "-c")) {
13673
- const body = filtered.slice(2).join(" ").replace(/^['"]|['"]$/g, "").trim();
13859
+ return null;
13860
+ }
13861
+ function extractDockerComposeRunScript(tokens) {
13862
+ const head = normalizeHead(tokens[0] ?? "");
13863
+ const usesCompose = head === "docker-compose" || head === "docker" && (tokens[1] ?? "") === "compose";
13864
+ if (!usesCompose) {
13865
+ return null;
13866
+ }
13867
+ if (!tokens.includes("run")) {
13868
+ return null;
13869
+ }
13870
+ const runIndex = tokens.indexOf("run");
13871
+ const tail = tokens.slice(runIndex + 1);
13872
+ for (let index = 0; index < tail.length; index += 1) {
13873
+ const shellHead = normalizeHead(tail[index] ?? "");
13874
+ if (!SHELL_INTERPRETERS.has(shellHead)) {
13875
+ continue;
13876
+ }
13877
+ const flag = tail[index + 1] ?? "";
13878
+ if (flag !== "-lc" && flag !== "-c") {
13879
+ continue;
13880
+ }
13881
+ const body = tail[index + 2] ?? "";
13674
13882
  return body || null;
13675
13883
  }
13676
13884
  return null;
@@ -14034,9 +14242,10 @@ function lowerSegment(command, context) {
14034
14242
  const environment = extractEnvironment(rawTokens, context.env);
14035
14243
  const env = environment.env;
14036
14244
  const parsed = parseSegment(command);
14037
- const tokens = stripRedirects(environment.commandTokens ?? parsed.tokens).map(
14038
- (token) => expandKnownVariables(token, env)
14039
- );
14245
+ const parsedTokens = environment.commandTokens ?? parsed.tokens;
14246
+ const tokens = stripRedirects(
14247
+ parsedTokens.length === 0 && rawTokens.length > 0 && rawTokens.every((token) => ENV_PREFIX_PATTERN2.test(token)) ? rawTokens : parsedTokens
14248
+ ).map((token) => expandKnownVariables(token, env));
14040
14249
  const head = path39.basename(tokens[0] ?? parsed.head);
14041
14250
  let opacity = segmentOpacity(command);
14042
14251
  const signals = /* @__PURE__ */ new Set();
@@ -14138,6 +14347,31 @@ function lowerSegment(command, context) {
14138
14347
  }
14139
14348
  return shellSegment(commandRedacted, head, requirements, "recursive", signals);
14140
14349
  }
14350
+ const dockerComposeScript = extractDockerComposeRunScript(tokens);
14351
+ if (dockerComposeScript && opacity !== "opaque" && opacity !== "unparseable") {
14352
+ requirements.push(
14353
+ processRequirement(head, "spawn", commandRedacted, ["process.docker_compose_run"])
14354
+ );
14355
+ const nested = lowerTopLevelSegments(dockerComposeScript, {
14356
+ ...context,
14357
+ command: dockerComposeScript,
14358
+ env,
14359
+ depth: context.depth + 1
14360
+ });
14361
+ for (const nestedSegment of nested) {
14362
+ requirements.push(
14363
+ ...nestedSegment.requirements.map(
14364
+ (entry) => withInnerProvenance(entry, dockerComposeScript, head, commandRedacted)
14365
+ )
14366
+ );
14367
+ for (const signal of nestedSegment.signals) {
14368
+ signals.add(signal);
14369
+ }
14370
+ opacity = joinNestedOpacity(opacity, nestedSegment);
14371
+ }
14372
+ signals.add("process.docker_compose_run");
14373
+ return shellSegment(commandRedacted, head, requirements, "recursive", signals);
14374
+ }
14141
14375
  const launcher = resolveLauncherRecipe({
14142
14376
  tokens,
14143
14377
  cwd: context.cwd,
@@ -14359,6 +14593,111 @@ function railsReadOnlySubcommand(args) {
14359
14593
  }
14360
14594
  return RAILS_READ_ONLY_SUBCOMMANDS.has(subcommand);
14361
14595
  }
14596
+ function isRubyTestScript(scriptPath) {
14597
+ const base = path39.basename(scriptPath);
14598
+ return base.endsWith("_test.rb") || base.endsWith("_spec.rb");
14599
+ }
14600
+ function parseRubyTestInvocation(args) {
14601
+ const includePaths = [];
14602
+ for (let index = 0; index < args.length; index += 1) {
14603
+ const arg = args[index] ?? "";
14604
+ if (arg === "-e" || arg === "-r") {
14605
+ return null;
14606
+ }
14607
+ if (arg === "-I") {
14608
+ const includePath = args[index + 1];
14609
+ if (!includePath) {
14610
+ return null;
14611
+ }
14612
+ includePaths.push(includePath);
14613
+ index += 1;
14614
+ continue;
14615
+ }
14616
+ if (arg.startsWith("-I") && arg.length > 2) {
14617
+ includePaths.push(arg.slice(2));
14618
+ continue;
14619
+ }
14620
+ if (arg.startsWith("-")) {
14621
+ if (arg === "-n") {
14622
+ if (!args[index + 1]) {
14623
+ return null;
14624
+ }
14625
+ index += 1;
14626
+ continue;
14627
+ }
14628
+ if (arg.startsWith("-n")) {
14629
+ continue;
14630
+ }
14631
+ return null;
14632
+ }
14633
+ if (isRubyTestScript(arg)) {
14634
+ return { includePaths, scriptPath: arg };
14635
+ }
14636
+ return null;
14637
+ }
14638
+ return null;
14639
+ }
14640
+ function isRubocopMutating(args) {
14641
+ return args.some(
14642
+ (arg) => arg === "-A" || arg === "-a" || arg === "--auto-correct" || arg === "--autocorrect" || arg.startsWith("--auto-correct-all") || arg.startsWith("--autocorrect-all")
14643
+ );
14644
+ }
14645
+ function decodeBundleExecInner(innerHead, innerArgs, segment) {
14646
+ const innerBase = executableBaseName(innerHead);
14647
+ if (innerBase === "rubocop") {
14648
+ const mutating = isRubocopMutating(innerArgs);
14649
+ return [
14650
+ processRequirement(
14651
+ innerHead,
14652
+ mutating ? "spawn" : "inspect",
14653
+ segment,
14654
+ mutating ? ["process.linter.mutating"] : ["process.inspect.linter"]
14655
+ )
14656
+ ];
14657
+ }
14658
+ if (innerBase === "rspec") {
14659
+ const targetArgs = innerArgs.filter((arg) => !arg.startsWith("-"));
14660
+ if (targetArgs.length === 0) {
14661
+ return null;
14662
+ }
14663
+ return [processRequirement(innerHead, "spawn", segment, ["process.test_runner.rspec"])];
14664
+ }
14665
+ return null;
14666
+ }
14667
+ function decodeRuby(args, cwd, repoRoot, segment) {
14668
+ const parsed = parseRubyTestInvocation(args);
14669
+ if (!parsed) {
14670
+ return unsupportedProcess("ruby", segment, "process.ruby_grammar_incomplete");
14671
+ }
14672
+ const scriptPath = resolvePathOperand(parsed.scriptPath, cwd);
14673
+ if (!pathWithinRoot(canonicalPath(repoRoot), canonicalPath(scriptPath))) {
14674
+ return unsupportedProcess("ruby", segment, "process.ruby_outside_repo");
14675
+ }
14676
+ for (const includePath of parsed.includePaths) {
14677
+ const resolvedInclude = resolvePathOperand(includePath, cwd);
14678
+ if (!pathWithinRoot(canonicalPath(repoRoot), canonicalPath(resolvedInclude))) {
14679
+ return unsupportedProcess("ruby", segment, "process.ruby_outside_repo");
14680
+ }
14681
+ }
14682
+ const lowered = [
14683
+ processRequirement("ruby", "spawn", segment, ["process.test_runner.minitest"]),
14684
+ requirement2("fs.read", "fs.read", { kind: "path", path: scriptPath }, segment, [
14685
+ "ruby.minitest_script_read"
14686
+ ])
14687
+ ];
14688
+ for (const includePath of parsed.includePaths) {
14689
+ lowered.push(
14690
+ requirement2(
14691
+ "fs.read",
14692
+ "fs.read",
14693
+ { kind: "path", path: resolvePathOperand(includePath, cwd) },
14694
+ segment,
14695
+ ["ruby.minitest_load_path_read"]
14696
+ )
14697
+ );
14698
+ }
14699
+ return lowered;
14700
+ }
14362
14701
  function decodeRuntimeMetadataProcess(head, args, segment) {
14363
14702
  if (head === "bundle") {
14364
14703
  if (args.length === 1 && isMetadataOnlyArgv(args)) {
@@ -14380,6 +14719,10 @@ function decodeRuntimeMetadataProcess(head, args, segment) {
14380
14719
  ])
14381
14720
  ];
14382
14721
  }
14722
+ const bundleExecInner = decodeBundleExecInner(innerHead, innerArgs, segment);
14723
+ if (bundleExecInner) {
14724
+ return bundleExecInner;
14725
+ }
14383
14726
  }
14384
14727
  return null;
14385
14728
  }
@@ -14395,9 +14738,74 @@ function decodeRuntimeMetadataProcess(head, args, segment) {
14395
14738
  }
14396
14739
  return null;
14397
14740
  }
14741
+ function decodeSetBuiltin(args) {
14742
+ let index = 0;
14743
+ while (index < args.length) {
14744
+ const arg = args[index] ?? "";
14745
+ if (arg === "--") {
14746
+ index += 1;
14747
+ continue;
14748
+ }
14749
+ if (arg === "-o" || arg === "+o") {
14750
+ if (!args[index + 1]) {
14751
+ return false;
14752
+ }
14753
+ index += 2;
14754
+ continue;
14755
+ }
14756
+ if (/^[-+][A-Za-z0-9]+$/.test(arg)) {
14757
+ index += 1;
14758
+ continue;
14759
+ }
14760
+ return false;
14761
+ }
14762
+ return true;
14763
+ }
14764
+ function decodeShellControlBuiltin(head, args) {
14765
+ if (head === "set") {
14766
+ return decodeSetBuiltin(args) ? [] : null;
14767
+ }
14768
+ if (head === "wait") {
14769
+ if (args.length === 0 || args.every((arg) => /^\d+$/.test(arg))) {
14770
+ return [];
14771
+ }
14772
+ return null;
14773
+ }
14774
+ if (head === "exit") {
14775
+ if (args.length === 0 || args.length === 1 && /^-?\d+$/.test(args[0] ?? "")) {
14776
+ return [];
14777
+ }
14778
+ return null;
14779
+ }
14780
+ return null;
14781
+ }
14782
+ function decodeDockerComposeRun(head, args, segment) {
14783
+ let composeArgs = null;
14784
+ let command = head;
14785
+ if (head === "docker-compose") {
14786
+ composeArgs = args;
14787
+ } else if (head === "docker" && args[0] === "compose") {
14788
+ composeArgs = args.slice(1);
14789
+ command = "docker";
14790
+ }
14791
+ if (!composeArgs) {
14792
+ return null;
14793
+ }
14794
+ if (composeArgs.includes("run")) {
14795
+ return [processRequirement(command, "spawn", segment, ["process.docker_compose_run"])];
14796
+ }
14797
+ return unsupportedProcess(command, segment, "process.docker_compose_grammar_incomplete");
14798
+ }
14398
14799
  function decodeProcessOrFilesystem(params) {
14399
14800
  const { tokens, head, env, cwd, repoRoot, segment } = params;
14400
14801
  const args = tokens.slice(1);
14802
+ if (tokens.length > 0 && tokens.every((token) => ENV_PREFIX_PATTERN2.test(token))) {
14803
+ return [];
14804
+ }
14805
+ const shellControl = decodeShellControlBuiltin(head, args);
14806
+ if (shellControl) {
14807
+ return shellControl;
14808
+ }
14401
14809
  if (isCommandInspection(tokens)) {
14402
14810
  return [processRequirement(head, "inspect", segment, ["process.inspect.command_lookup"])];
14403
14811
  }
@@ -14480,6 +14888,19 @@ function decodeProcessOrFilesystem(params) {
14480
14888
  if (runtimeMetadata) {
14481
14889
  return runtimeMetadata;
14482
14890
  }
14891
+ if (head === "ruby") {
14892
+ return decodeRuby(args, cwd, repoRoot, segment);
14893
+ }
14894
+ if (head === "rubocop" || head === "rspec") {
14895
+ const decoded = decodeBundleExecInner(head, args, segment);
14896
+ if (decoded) {
14897
+ return decoded;
14898
+ }
14899
+ }
14900
+ const dockerCompose = decodeDockerComposeRun(head, args, segment);
14901
+ if (dockerCompose) {
14902
+ return dockerCompose;
14903
+ }
14483
14904
  if ((head === "npm" || head === "pnpm") && args.length === 1 && isMetadataOnlyArgv(args)) {
14484
14905
  return [processRequirement(head, "inspect", segment, ["process.inspect.package_manager"])];
14485
14906
  }
@@ -16718,7 +17139,7 @@ function hashDecisionConfig(config) {
16718
17139
  init_fingerprint2();
16719
17140
 
16720
17141
  // src/version.ts
16721
- var PACKAGE_VERSION = "0.9.1";
17142
+ var PACKAGE_VERSION = "0.9.2";
16722
17143
 
16723
17144
  // src/runtime-provenance.ts
16724
17145
  function resolveRuntimeArtifactHash(artifactHash) {