@socketsecurity/lib 6.0.4 → 6.0.6

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 (211) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/ai/discover.js +3 -2
  3. package/dist/ai/spawn.js +8 -5
  4. package/dist/ai/worktree.js +11 -6
  5. package/dist/ansi/strip.js +2 -2
  6. package/dist/archives/_internal.js +4 -4
  7. package/dist/archives/zip.js +1 -1
  8. package/dist/arrays/_internal.js +2 -2
  9. package/dist/arrays/chunk.js +1 -1
  10. package/dist/arrays/join.js +2 -2
  11. package/dist/arrays/unique.js +1 -1
  12. package/dist/bin/acorn-bindgen.cjs +769 -0
  13. package/dist/bin/acorn.wasm +0 -0
  14. package/dist/bin/check-primordials.js +3 -2
  15. package/dist/bin/check.js +3 -2
  16. package/dist/bin/exec.js +1 -1
  17. package/dist/bin/prim.cjs +39064 -0
  18. package/dist/bin/resolve.js +1 -1
  19. package/dist/colors/socket-palette.js +2 -2
  20. package/dist/compression/_internal.js +3 -2
  21. package/dist/compression/brotli.js +5 -12
  22. package/dist/compression/gzip.js +5 -13
  23. package/dist/constants/agents.js +4 -4
  24. package/dist/constants/packages.js +6 -6
  25. package/dist/constants/socket.js +1 -1
  26. package/dist/crypto/hash.js +2 -2
  27. package/dist/debug/_internal.js +2 -2
  28. package/dist/debug/caller-info.js +1 -1
  29. package/dist/debug/namespace.js +5 -5
  30. package/dist/debug/output.js +3 -3
  31. package/dist/dlx/binary-download.js +3 -2
  32. package/dist/eco/npm/npm/flags.js +5 -5
  33. package/dist/eco/npm/pnpm/flags.js +3 -3
  34. package/dist/env/boolean.js +1 -1
  35. package/dist/env/ci.js +1 -1
  36. package/dist/env/debug.js +1 -1
  37. package/dist/env/github.js +8 -8
  38. package/dist/env/home.js +1 -1
  39. package/dist/env/locale.js +3 -3
  40. package/dist/env/node-auth-token.js +1 -1
  41. package/dist/env/node-env.js +1 -1
  42. package/dist/env/npm.js +5 -5
  43. package/dist/env/number.js +1 -1
  44. package/dist/env/package-manager.js +3 -3
  45. package/dist/env/path.js +1 -1
  46. package/dist/env/pre-commit.js +1 -1
  47. package/dist/env/rewire.js +2 -2
  48. package/dist/env/shell.js +1 -1
  49. package/dist/env/socket-cli.js +13 -13
  50. package/dist/env/socket.js +33 -32
  51. package/dist/env/string.js +1 -1
  52. package/dist/env/temp-dir.js +3 -3
  53. package/dist/env/term.js +1 -1
  54. package/dist/env/test.js +3 -3
  55. package/dist/env/windows.js +4 -4
  56. package/dist/env/xdg.js +3 -3
  57. package/dist/events/exit/_internal.js +5 -5
  58. package/dist/events/exit/handler.js +1 -1
  59. package/dist/events/exit/intercept.js +2 -2
  60. package/dist/events/exit/lifecycle.js +3 -3
  61. package/dist/events/exit/signals.js +1 -1
  62. package/dist/external/@sinclair/typebox/value.js +5 -1
  63. package/dist/external/@sinclair/typebox.js +5 -1
  64. package/dist/external/@socketregistry/packageurl-js.js +27 -0
  65. package/dist/external-tools/bazel/resolve.js +2 -1
  66. package/dist/external-tools/cdxgen/resolve.js +2 -1
  67. package/dist/external-tools/from-pip-venv.d.ts +73 -0
  68. package/dist/external-tools/from-pip-venv.js +98 -0
  69. package/dist/external-tools/janus/asset-names.js +1 -1
  70. package/dist/external-tools/janus/from-download.js +3 -5
  71. package/dist/external-tools/janus/resolve.js +2 -1
  72. package/dist/external-tools/jre/from-download.js +2 -1
  73. package/dist/external-tools/jre/resolve.js +2 -1
  74. package/dist/external-tools/manifest.js +7 -5
  75. package/dist/external-tools/opengrep/resolve.js +2 -1
  76. package/dist/external-tools/sbt/resolve.js +2 -1
  77. package/dist/external-tools/skillspector/from-dlx.d.ts +24 -0
  78. package/dist/external-tools/skillspector/from-dlx.js +41 -0
  79. package/dist/external-tools/skillspector/from-path.d.ts +8 -0
  80. package/dist/external-tools/skillspector/from-path.js +32 -0
  81. package/dist/external-tools/skillspector/from-vfs.d.ts +8 -0
  82. package/dist/external-tools/skillspector/from-vfs.js +27 -0
  83. package/dist/external-tools/skillspector/resolve.d.ts +34 -0
  84. package/dist/external-tools/skillspector/resolve.js +53 -0
  85. package/dist/external-tools/skillspector/types.d.ts +24 -0
  86. package/dist/external-tools/skillspector/types.js +2 -0
  87. package/dist/external-tools/synp/resolve.js +2 -1
  88. package/dist/external-tools/trivy/resolve.js +2 -1
  89. package/dist/external-tools/trufflehog/resolve.js +2 -1
  90. package/dist/external-tools/uv/resolve.js +2 -1
  91. package/dist/fs/access.js +4 -4
  92. package/dist/fs/encoding.js +2 -2
  93. package/dist/fs/find-up.js +2 -2
  94. package/dist/fs/inspect.js +6 -6
  95. package/dist/fs/read-dir.js +3 -3
  96. package/dist/fs/read-file.js +6 -6
  97. package/dist/fs/read-json.js +2 -2
  98. package/dist/fs/safe.js +2 -2
  99. package/dist/fs/unique.js +1 -1
  100. package/dist/fs/validate.js +1 -1
  101. package/dist/fs/write-json.js +1 -1
  102. package/dist/git/_internal.js +2 -1
  103. package/dist/globs/_internal.js +4 -4
  104. package/dist/globs/match.js +4 -3
  105. package/dist/globs/matcher.js +3 -3
  106. package/dist/globs/stream.js +1 -1
  107. package/dist/http-request/browser.js +17 -11
  108. package/dist/http-request/download.js +1 -1
  109. package/dist/http-request/headers.d.ts +32 -3
  110. package/dist/http-request/headers.js +42 -13
  111. package/dist/http-request/request-attempt.js +1 -0
  112. package/dist/http-request/request-types.d.ts +5 -0
  113. package/dist/http-request/request.js +32 -15
  114. package/dist/http-request/response-reader.d.ts +12 -1
  115. package/dist/http-request/response-reader.js +22 -2
  116. package/dist/http-request/user-agent.js +1 -1
  117. package/dist/json/edit.js +1 -1
  118. package/dist/json/parse.js +4 -4
  119. package/dist/logger/colors.js +2 -2
  120. package/dist/logger/console.js +1 -1
  121. package/dist/logger/node.js +0 -1
  122. package/dist/logger/symbols.js +1 -1
  123. package/dist/node/async-hooks.js +2 -2
  124. package/dist/node/child-process.js +2 -2
  125. package/dist/node/crypto.js +2 -2
  126. package/dist/node/events.js +2 -2
  127. package/dist/node/fs-promises.js +2 -2
  128. package/dist/node/fs.js +2 -2
  129. package/dist/node/http.js +2 -2
  130. package/dist/node/https.js +2 -2
  131. package/dist/node/module.js +3 -3
  132. package/dist/node/os.js +2 -2
  133. package/dist/node/path.js +2 -2
  134. package/dist/node/timers-promises.js +2 -2
  135. package/dist/node/url.js +2 -2
  136. package/dist/node/util.js +2 -2
  137. package/dist/objects/getters.js +2 -2
  138. package/dist/objects/inspect.js +3 -3
  139. package/dist/objects/mutate.js +1 -1
  140. package/dist/objects/predicates.js +4 -4
  141. package/dist/objects/sort.js +4 -4
  142. package/dist/packages/edit-class.js +1 -1
  143. package/dist/packages/edit.js +2 -2
  144. package/dist/packages/exports.js +6 -6
  145. package/dist/packages/licenses.js +8 -8
  146. package/dist/packages/manifest.js +3 -3
  147. package/dist/packages/normalize.js +4 -4
  148. package/dist/packages/operations.js +11 -11
  149. package/dist/packages/provenance.d.ts +6 -0
  150. package/dist/packages/provenance.js +12 -3
  151. package/dist/packages/specs.js +5 -5
  152. package/dist/packages/validation.js +3 -3
  153. package/dist/paths/_internal.js +3 -3
  154. package/dist/paths/conversion.js +4 -4
  155. package/dist/paths/normalize.js +3 -1
  156. package/dist/paths/packages.js +3 -3
  157. package/dist/paths/predicates.js +7 -7
  158. package/dist/paths/resolve.js +3 -3
  159. package/dist/process/spawn/_internal.js +3 -3
  160. package/dist/process/spawn/errors.js +2 -2
  161. package/dist/process/spawn/stdio.js +1 -1
  162. package/dist/promises/_internal.js +1 -1
  163. package/dist/promises/iterate.js +5 -5
  164. package/dist/promises/options.js +3 -3
  165. package/dist/promises/retry.js +1 -1
  166. package/dist/secrets/_internal.js +3 -2
  167. package/dist/secrets/keychain.js +5 -4
  168. package/dist/secrets/linux.js +6 -4
  169. package/dist/secrets/macos.js +5 -3
  170. package/dist/secrets/rc.js +9 -6
  171. package/dist/secrets/windows.js +7 -4
  172. package/dist/shell/parse.d.ts +108 -1
  173. package/dist/shell/parse.js +168 -2
  174. package/dist/smol/detect.js +1 -1
  175. package/dist/smol/http.js +1 -1
  176. package/dist/smol/https.js +1 -1
  177. package/dist/smol/manifest.js +1 -1
  178. package/dist/smol/path.js +1 -1
  179. package/dist/smol/primordial.js +1 -1
  180. package/dist/smol/purl.js +1 -1
  181. package/dist/smol/versions.js +1 -1
  182. package/dist/smol/vfs.js +1 -1
  183. package/dist/sorts/_internal.js +4 -4
  184. package/dist/sorts/natural.js +3 -3
  185. package/dist/sorts/semver.js +1 -1
  186. package/dist/sorts/strings.js +1 -1
  187. package/dist/spinner/default.js +1 -1
  188. package/dist/spinner/spinner.js +1 -1
  189. package/dist/ssri/convert.js +2 -2
  190. package/dist/ssri/parse.js +1 -1
  191. package/dist/ssri/validate.js +2 -2
  192. package/dist/stdio/prompts.js +1 -1
  193. package/dist/streams/parallel.js +2 -2
  194. package/dist/streams/transform.js +1 -1
  195. package/dist/strings/format.js +4 -4
  196. package/dist/strings/predicates.js +2 -2
  197. package/dist/strings/search.js +1 -1
  198. package/dist/strings/transform.js +3 -3
  199. package/dist/strings/width.js +3 -3
  200. package/dist/temporal/instant.js +4 -2
  201. package/dist/temporal/slots.js +3 -2
  202. package/dist/themes/context.js +2 -2
  203. package/dist/url/parse.js +2 -2
  204. package/dist/url/predicates.js +1 -1
  205. package/dist/url/search-params.js +6 -6
  206. package/dist/words/article.js +1 -1
  207. package/dist/words/capitalize.js +1 -1
  208. package/dist/words/pluralize.d.ts +24 -2
  209. package/dist/words/pluralize.js +37 -2
  210. package/dist/words/types.d.ts +25 -2
  211. package/package.json +45 -5
@@ -8,10 +8,100 @@
8
8
  * against `env`; unresolved ones collapse to an empty string.
9
9
  */
10
10
  import type { ParseEntry } from '../external/shell-quote';
11
+ /**
12
+ * Visit each simple command in `cmd` in order. A "simple command" is the
13
+ * POSIX-grammar term for a run of bare-string tokens between shell
14
+ * control-operator boundaries (`&&`, `;`, `||`, `|`) — e.g. in `sudo apt && rm
15
+ * -rf /`, the two simple commands are `['sudo', 'apt']` and `['rm', '-rf',
16
+ * '/']`. Glob and comment tokens are ignored.
17
+ *
18
+ * The visitor receives each simple command's tokens as a `readonly string[]`;
19
+ * returning `true` short-circuits the walk so callers like `hasBinCall` /
20
+ * `findBinCall` can bail on the first match without finishing the parse.
21
+ *
22
+ * Public so consumers can write their own per-command matchers without
23
+ * re-parsing the command line. Used internally by `findBinCall` /
24
+ * `findBinCalls` / `hasBinCall`.
25
+ *
26
+ * Shell-quote is permissive (partial parses don't throw); the walk tolerates
27
+ * any shape it returns.
28
+ *
29
+ * @example
30
+ * eachSimpleCommand('sudo apt && rm -rf /', tokens => {
31
+ * console.log(tokens)
32
+ * // → ['sudo', 'apt']
33
+ * // → ['rm', '-rf', '/']
34
+ * })
35
+ *
36
+ * // Short-circuit on first match:
37
+ * eachSimpleCommand('a ; b ; c', tokens => {
38
+ * if (tokens[0] === 'b') {
39
+ * return true // stop the walk
40
+ * }
41
+ * })
42
+ */
43
+ export declare function eachSimpleCommand(cmd: string, visit: (tokens: readonly string[]) => boolean | void): void;
44
+ /**
45
+ * Walk a parsed shell command and return the args of the FIRST binary call
46
+ * whose leading tokens match `prefix` (e.g. `['sudo']`, `['gh', 'auth',
47
+ * 'refresh']`). Returns `undefined` when no call matches.
48
+ *
49
+ * Short-circuits on the first match — does NOT materialize every match. Use
50
+ * this when "did any call match, and what were its args?" is enough. For audit
51
+ * / counting use cases where every match matters, use `findBinCalls`.
52
+ *
53
+ * @example
54
+ * findBinCall('sudo apt update && sudo -k', ['sudo'])
55
+ * // → ['apt', 'update']
56
+ *
57
+ * findBinCall('echo "sudo foo"', ['sudo'])
58
+ * // → undefined
59
+ */
60
+ export declare function findBinCall(cmd: string, prefix: readonly string[]): readonly string[] | undefined;
61
+ /**
62
+ * Walk a parsed shell command and return the args of every binary call whose
63
+ * leading tokens match `prefix` (e.g. `['sudo']`, `['gh', 'auth', 'refresh']`).
64
+ * Returns an empty array when no call matches.
65
+ *
66
+ * Segments split at op tokens (`&&`, `;`, `||`, `|`) so each chained command is
67
+ * scanned independently. Each match's args are returned as a `string[]` slice
68
+ * positioned after the matched prefix — useful for caller-side `.some(...)`
69
+ * over flag/value pairs.
70
+ *
71
+ * The AST walk means embedded args (`echo "sudo foo"`), variable substitutions
72
+ * (`$gh`), and command substitution (`$(...)`) don't trip the matcher — only
73
+ * actual calls do.
74
+ *
75
+ * @example
76
+ * findBinCalls('sudo apt update && sudo -k', ['sudo'])
77
+ * // → [['apt', 'update'], ['-k']]
78
+ *
79
+ * findBinCalls('gh auth refresh -s workflow', ['gh', 'auth', 'refresh'])
80
+ * // → [['-s', 'workflow']]
81
+ *
82
+ * findBinCalls('echo "sudo foo"', ['sudo'])
83
+ * // → []
84
+ */
85
+ export declare function findBinCalls(cmd: string, prefix: readonly string[]): readonly string[][];
86
+ /**
87
+ * Convenience: does `cmd` contain at least one binary call matching the
88
+ * leading-tokens `prefix`? The most common audit-pattern shape.
89
+ *
90
+ * Short-circuits on the first match — walks the parsed entries once and returns
91
+ * `true` as soon as a simple command matches. No intermediate match list or
92
+ * args slices are allocated.
93
+ *
94
+ * @example
95
+ * hasBinCall('echo hi && sudo rm', ['sudo']) // → true
96
+ * hasBinCall('echo "sudo foo"', ['sudo']) // → false
97
+ * hasBinCall('gh auth refresh -s workflow', ['gh', 'auth', 'refresh']) // → true
98
+ */
99
+ export declare function hasBinCall(cmd: string, prefix: readonly string[]): boolean;
11
100
  export type { ParseEntry, ShellComment, ShellGlob, ShellOp, } from '../external/shell-quote';
12
101
  /**
13
102
  * Tokenize `cmd` into `ParseEntry` items, preserving operators and comments.
14
- * Throws on unterminated quotes.
103
+ * `shell-quote` is permissive — an unterminated quote does not throw; the
104
+ * parser drops the opening quote and returns the rest as plain tokens.
15
105
  *
16
106
  * @example
17
107
  * parseShell('git commit -m "hello world"')
@@ -24,3 +114,20 @@ export type { ParseEntry, ShellComment, ShellGlob, ShellOp, } from '../external/
24
114
  * // → ['echo', '/root']
25
115
  */
26
116
  export declare function parseShell(cmd: string, env?: Record<string, string> | ((key: string) => string | undefined) | undefined): ParseEntry[];
117
+ /**
118
+ * Does the simple command represented by `tokens` start with `prefix`? The
119
+ * natural companion to `eachSimpleCommand` — the visitor callback uses this to
120
+ * test whether a simple command is a call to a specific binary or command-line
121
+ * prefix.
122
+ *
123
+ * @example
124
+ * simpleCommandStartsWith(['sudo', 'apt', 'update'], ['sudo'])
125
+ * // → true
126
+ *
127
+ * simpleCommandStartsWith(
128
+ * ['gh', 'auth', 'status'],
129
+ * ['gh', 'auth', 'refresh'],
130
+ * )
131
+ * // → false
132
+ */
133
+ export declare function simpleCommandStartsWith(tokens: readonly string[], prefix: readonly string[]): boolean;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  /* Socket Lib - Built with rolldown */
3
3
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
+ const require_primordials_array = require('../primordials/array.js');
4
5
  let src_external_shell_quote = require("../external/shell-quote");
5
6
 
6
7
  //#region src/shell/parse.ts
@@ -14,8 +15,146 @@ let src_external_shell_quote = require("../external/shell-quote");
14
15
  * against `env`; unresolved ones collapse to an empty string.
15
16
  */
16
17
  /**
18
+ * Visit each simple command in `cmd` in order. A "simple command" is the
19
+ * POSIX-grammar term for a run of bare-string tokens between shell
20
+ * control-operator boundaries (`&&`, `;`, `||`, `|`) — e.g. in `sudo apt && rm
21
+ * -rf /`, the two simple commands are `['sudo', 'apt']` and `['rm', '-rf',
22
+ * '/']`. Glob and comment tokens are ignored.
23
+ *
24
+ * The visitor receives each simple command's tokens as a `readonly string[]`;
25
+ * returning `true` short-circuits the walk so callers like `hasBinCall` /
26
+ * `findBinCall` can bail on the first match without finishing the parse.
27
+ *
28
+ * Public so consumers can write their own per-command matchers without
29
+ * re-parsing the command line. Used internally by `findBinCall` /
30
+ * `findBinCalls` / `hasBinCall`.
31
+ *
32
+ * Shell-quote is permissive (partial parses don't throw); the walk tolerates
33
+ * any shape it returns.
34
+ *
35
+ * @example
36
+ * eachSimpleCommand('sudo apt && rm -rf /', tokens => {
37
+ * console.log(tokens)
38
+ * // → ['sudo', 'apt']
39
+ * // → ['rm', '-rf', '/']
40
+ * })
41
+ *
42
+ * // Short-circuit on first match:
43
+ * eachSimpleCommand('a ; b ; c', tokens => {
44
+ * if (tokens[0] === 'b') {
45
+ * return true // stop the walk
46
+ * }
47
+ * })
48
+ */
49
+ function eachSimpleCommand(cmd, visit) {
50
+ const entries = (0, src_external_shell_quote.parse)(cmd);
51
+ let current = [];
52
+ const flush = () => {
53
+ if (current.length > 0) {
54
+ const stop = visit(current);
55
+ current = [];
56
+ return stop === true;
57
+ }
58
+ current = [];
59
+ return false;
60
+ };
61
+ for (let i = 0, { length } = entries; i < length; i += 1) {
62
+ const entry = entries[i];
63
+ if (entry && typeof entry === "object" && "op" in entry) {
64
+ if (flush()) return;
65
+ continue;
66
+ }
67
+ if (typeof entry === "string") require_primordials_array.ArrayPrototypePush(current, entry);
68
+ }
69
+ flush();
70
+ }
71
+ /**
72
+ * Walk a parsed shell command and return the args of the FIRST binary call
73
+ * whose leading tokens match `prefix` (e.g. `['sudo']`, `['gh', 'auth',
74
+ * 'refresh']`). Returns `undefined` when no call matches.
75
+ *
76
+ * Short-circuits on the first match — does NOT materialize every match. Use
77
+ * this when "did any call match, and what were its args?" is enough. For audit
78
+ * / counting use cases where every match matters, use `findBinCalls`.
79
+ *
80
+ * @example
81
+ * findBinCall('sudo apt update && sudo -k', ['sudo'])
82
+ * // → ['apt', 'update']
83
+ *
84
+ * findBinCall('echo "sudo foo"', ['sudo'])
85
+ * // → undefined
86
+ */
87
+ function findBinCall(cmd, prefix) {
88
+ if (prefix.length === 0) return;
89
+ let found;
90
+ eachSimpleCommand(cmd, (tokens) => {
91
+ if (!simpleCommandStartsWith(tokens, prefix)) return false;
92
+ found = require_primordials_array.ArrayPrototypeSlice(tokens, prefix.length);
93
+ return true;
94
+ });
95
+ return found;
96
+ }
97
+ /**
98
+ * Walk a parsed shell command and return the args of every binary call whose
99
+ * leading tokens match `prefix` (e.g. `['sudo']`, `['gh', 'auth', 'refresh']`).
100
+ * Returns an empty array when no call matches.
101
+ *
102
+ * Segments split at op tokens (`&&`, `;`, `||`, `|`) so each chained command is
103
+ * scanned independently. Each match's args are returned as a `string[]` slice
104
+ * positioned after the matched prefix — useful for caller-side `.some(...)`
105
+ * over flag/value pairs.
106
+ *
107
+ * The AST walk means embedded args (`echo "sudo foo"`), variable substitutions
108
+ * (`$gh`), and command substitution (`$(...)`) don't trip the matcher — only
109
+ * actual calls do.
110
+ *
111
+ * @example
112
+ * findBinCalls('sudo apt update && sudo -k', ['sudo'])
113
+ * // → [['apt', 'update'], ['-k']]
114
+ *
115
+ * findBinCalls('gh auth refresh -s workflow', ['gh', 'auth', 'refresh'])
116
+ * // → [['-s', 'workflow']]
117
+ *
118
+ * findBinCalls('echo "sudo foo"', ['sudo'])
119
+ * // → []
120
+ */
121
+ function findBinCalls(cmd, prefix) {
122
+ if (prefix.length === 0) return [];
123
+ const matches = [];
124
+ eachSimpleCommand(cmd, (tokens) => {
125
+ if (simpleCommandStartsWith(tokens, prefix)) require_primordials_array.ArrayPrototypePush(matches, require_primordials_array.ArrayPrototypeSlice(tokens, prefix.length));
126
+ });
127
+ return matches;
128
+ }
129
+ /**
130
+ * Convenience: does `cmd` contain at least one binary call matching the
131
+ * leading-tokens `prefix`? The most common audit-pattern shape.
132
+ *
133
+ * Short-circuits on the first match — walks the parsed entries once and returns
134
+ * `true` as soon as a simple command matches. No intermediate match list or
135
+ * args slices are allocated.
136
+ *
137
+ * @example
138
+ * hasBinCall('echo hi && sudo rm', ['sudo']) // → true
139
+ * hasBinCall('echo "sudo foo"', ['sudo']) // → false
140
+ * hasBinCall('gh auth refresh -s workflow', ['gh', 'auth', 'refresh']) // → true
141
+ */
142
+ function hasBinCall(cmd, prefix) {
143
+ if (prefix.length === 0) return false;
144
+ let found = false;
145
+ eachSimpleCommand(cmd, (tokens) => {
146
+ if (simpleCommandStartsWith(tokens, prefix)) {
147
+ found = true;
148
+ return true;
149
+ }
150
+ return false;
151
+ });
152
+ return found;
153
+ }
154
+ /**
17
155
  * Tokenize `cmd` into `ParseEntry` items, preserving operators and comments.
18
- * Throws on unterminated quotes.
156
+ * `shell-quote` is permissive — an unterminated quote does not throw; the
157
+ * parser drops the opening quote and returns the rest as plain tokens.
19
158
  *
20
159
  * @example
21
160
  * parseShell('git commit -m "hello world"')
@@ -30,6 +169,33 @@ let src_external_shell_quote = require("../external/shell-quote");
30
169
  function parseShell(cmd, env) {
31
170
  return (0, src_external_shell_quote.parse)(cmd, env);
32
171
  }
172
+ /**
173
+ * Does the simple command represented by `tokens` start with `prefix`? The
174
+ * natural companion to `eachSimpleCommand` — the visitor callback uses this to
175
+ * test whether a simple command is a call to a specific binary or command-line
176
+ * prefix.
177
+ *
178
+ * @example
179
+ * simpleCommandStartsWith(['sudo', 'apt', 'update'], ['sudo'])
180
+ * // → true
181
+ *
182
+ * simpleCommandStartsWith(
183
+ * ['gh', 'auth', 'status'],
184
+ * ['gh', 'auth', 'refresh'],
185
+ * )
186
+ * // → false
187
+ */
188
+ function simpleCommandStartsWith(tokens, prefix) {
189
+ const { length: pl } = prefix;
190
+ if (tokens.length < pl) return false;
191
+ for (let i = 0; i < pl; i += 1) if (tokens[i] !== prefix[i]) return false;
192
+ return true;
193
+ }
33
194
 
34
195
  //#endregion
35
- exports.parseShell = parseShell;
196
+ exports.eachSimpleCommand = eachSimpleCommand;
197
+ exports.findBinCall = findBinCall;
198
+ exports.findBinCalls = findBinCalls;
199
+ exports.hasBinCall = hasBinCall;
200
+ exports.parseShell = parseShell;
201
+ exports.simpleCommandStartsWith = simpleCommandStartsWith;
@@ -39,7 +39,7 @@ let _smolUtilProbed = false;
39
39
  * Returns `node:smol-util` when running on the smol Node binary, otherwise
40
40
  * `undefined`. Result is cached across calls.
41
41
  */
42
- /* @__NO_SIDE_EFFECTS__ */
42
+ /*@__NO_SIDE_EFFECTS__*/
43
43
  function getSmolUtil() {
44
44
  if (!_smolUtilProbed) {
45
45
  _smolUtilProbed = true;
package/dist/smol/http.js CHANGED
@@ -24,7 +24,7 @@ let _smolHttpProbed = false;
24
24
  * Returns `node:smol-http` when running on the smol Node binary, otherwise
25
25
  * `undefined`. Result is cached across calls.
26
26
  */
27
- /* @__NO_SIDE_EFFECTS__ */
27
+ /*@__NO_SIDE_EFFECTS__*/
28
28
  function getSmolHttp() {
29
29
  if (!_smolHttpProbed) {
30
30
  _smolHttpProbed = true;
@@ -22,7 +22,7 @@ let _smolHttpsProbed = false;
22
22
  * Returns `node:smol-https` when running on the smol Node binary, otherwise
23
23
  * `undefined`. Result is cached across calls.
24
24
  */
25
- /* @__NO_SIDE_EFFECTS__ */
25
+ /*@__NO_SIDE_EFFECTS__*/
26
26
  function getSmolHttps() {
27
27
  if (!_smolHttpsProbed) {
28
28
  _smolHttpsProbed = true;
@@ -24,7 +24,7 @@ let _smolManifestProbed = false;
24
24
  * Returns `node:smol-manifest` when running on the smol Node binary, otherwise
25
25
  * `undefined`. Result is cached across calls.
26
26
  */
27
- /* @__NO_SIDE_EFFECTS__ */
27
+ /*@__NO_SIDE_EFFECTS__*/
28
28
  function getSmolManifest() {
29
29
  if (!_smolManifestProbed) {
30
30
  _smolManifestProbed = true;
package/dist/smol/path.js CHANGED
@@ -24,7 +24,7 @@ let _smolPathProbed = false;
24
24
  *
25
25
  * @returns The native binding, or `undefined` to signal "use the JS fallback".
26
26
  */
27
- /* @__NO_SIDE_EFFECTS__ */
27
+ /*@__NO_SIDE_EFFECTS__*/
28
28
  function getSmolPath() {
29
29
  if (!_smolPathProbed) {
30
30
  _smolPathProbed = true;
@@ -26,7 +26,7 @@ let _smolPrimordialProbed = false;
26
26
  * Returns `node:smol-primordial` when running on the smol Node binary,
27
27
  * otherwise `undefined`. Result is cached across calls.
28
28
  */
29
- /* @__NO_SIDE_EFFECTS__ */
29
+ /*@__NO_SIDE_EFFECTS__*/
30
30
  function getSmolPrimordial() {
31
31
  if (!_smolPrimordialProbed) {
32
32
  _smolPrimordialProbed = true;
package/dist/smol/purl.js CHANGED
@@ -25,7 +25,7 @@ let _smolPurlProbed = false;
25
25
  * Returns `node:smol-purl` when running on the smol Node binary, otherwise
26
26
  * `undefined`. Result is cached across calls.
27
27
  */
28
- /* @__NO_SIDE_EFFECTS__ */
28
+ /*@__NO_SIDE_EFFECTS__*/
29
29
  function getSmolPurl() {
30
30
  if (!_smolPurlProbed) {
31
31
  _smolPurlProbed = true;
@@ -22,7 +22,7 @@ let _smolVersionsProbed = false;
22
22
  * Returns `node:smol-versions` when running on the smol Node binary, otherwise
23
23
  * `undefined`. Result is cached across calls.
24
24
  */
25
- /* @__NO_SIDE_EFFECTS__ */
25
+ /*@__NO_SIDE_EFFECTS__*/
26
26
  function getSmolVersions() {
27
27
  if (!_smolVersionsProbed) {
28
28
  _smolVersionsProbed = true;
package/dist/smol/vfs.js CHANGED
@@ -37,7 +37,7 @@ let _smolVfsProbed = false;
37
37
  * binding-module loader is collapsed into this function so callers don't deal
38
38
  * with two indirection levels.
39
39
  */
40
- /* @__NO_SIDE_EFFECTS__ */
40
+ /*@__NO_SIDE_EFFECTS__*/
41
41
  function getSmolVfs() {
42
42
  if (!_smolVfsProbed) {
43
43
  _smolVfsProbed = true;
@@ -5,14 +5,14 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
5
5
  //#region src/sorts/_internal.ts
6
6
  let _fastSort;
7
7
  let _semver;
8
- /* @__NO_SIDE_EFFECTS__ */
8
+ /*@__NO_SIDE_EFFECTS__*/
9
9
  function getFastSort() {
10
- if (_fastSort === void 0) _fastSort = /* @__PURE__ */ require("../external/fast-sort.js");
10
+ if (_fastSort === void 0) _fastSort = /*@__PURE__*/ require("../external/fast-sort.js");
11
11
  return _fastSort;
12
12
  }
13
- /* @__NO_SIDE_EFFECTS__ */
13
+ /*@__NO_SIDE_EFFECTS__*/
14
14
  function getSemver() {
15
- if (_semver === void 0) _semver = /* @__PURE__ */ require("../external/semver.js");
15
+ if (_semver === void 0) _semver = /*@__PURE__*/ require("../external/semver.js");
16
16
  return _semver;
17
17
  }
18
18
 
@@ -24,7 +24,7 @@ let _naturalSorter;
24
24
  * localeCompare('a', 'a') // 0
25
25
  * ```
26
26
  */
27
- /* @__NO_SIDE_EFFECTS__ */
27
+ /*@__NO_SIDE_EFFECTS__*/
28
28
  function localeCompare(x, y) {
29
29
  if (_localeCompare === void 0) _localeCompare = new Intl.Collator().compare;
30
30
  return _localeCompare(x, y);
@@ -38,7 +38,7 @@ function localeCompare(x, y) {
38
38
  * naturalCompare('img10', 'img2') // positive (img10 after img2)
39
39
  * ```
40
40
  */
41
- /* @__NO_SIDE_EFFECTS__ */
41
+ /*@__NO_SIDE_EFFECTS__*/
42
42
  function naturalCompare(x, y) {
43
43
  if (_naturalCompare === void 0) _naturalCompare = new Intl.Collator(void 0, {
44
44
  numeric: true,
@@ -55,7 +55,7 @@ function naturalCompare(x, y) {
55
55
  * // ['file1', 'file2', 'file10']
56
56
  * ```
57
57
  */
58
- /* @__NO_SIDE_EFFECTS__ */
58
+ /*@__NO_SIDE_EFFECTS__*/
59
59
  function naturalSorter(arrayToSort) {
60
60
  if (_naturalSorter === void 0) _naturalSorter = (/* @__PURE__ */ require_sorts__internal.getFastSort()).createNewSortInstance({ comparer: naturalCompare });
61
61
  return _naturalSorter(arrayToSort);
@@ -18,7 +18,7 @@ const require_sorts__internal = require('./_internal.js');
18
18
  * compareSemver('1.0.0', '1.0.0') // 0
19
19
  * ```
20
20
  */
21
- /* @__NO_SIDE_EFFECTS__ */
21
+ /*@__NO_SIDE_EFFECTS__*/
22
22
  function compareSemver(a, b) {
23
23
  /* c8 ignore start */
24
24
  const semver = /* @__PURE__ */ require_sorts__internal.getSemver();
@@ -18,7 +18,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
18
18
  * compareStr('a', 'a') // 0
19
19
  * ```
20
20
  */
21
- /* @__NO_SIDE_EFFECTS__ */
21
+ /*@__NO_SIDE_EFFECTS__*/
22
22
  function compareStr(a, b) {
23
23
  return a < b ? -1 : a > b ? 1 : 0;
24
24
  }
@@ -42,7 +42,7 @@ let _spinner;
42
42
  *
43
43
  * @see https://github.com/sindresorhus/cli-spinners/blob/main/spinners.json
44
44
  */
45
- /* @__NO_SIDE_EFFECTS__ */
45
+ /*@__NO_SIDE_EFFECTS__*/
46
46
  function getCliSpinners(styleName) {
47
47
  if (_cliSpinners === void 0)
48
48
  /* c8 ignore stop */
@@ -55,7 +55,7 @@ let _defaultSpinner;
55
55
  *
56
56
  * @returns New spinner instance
57
57
  */
58
- /* @__NO_SIDE_EFFECTS__ */
58
+ /*@__NO_SIDE_EFFECTS__*/
59
59
  function Spinner(options) {
60
60
  if (_Spinner === void 0) {
61
61
  const YoctoSpinnerClass = (0, src_external__socketregistry_yocto_spinner.default)({}).constructor;
@@ -31,7 +31,7 @@ const require_primordials_error = require('../primordials/error.js');
31
31
  *
32
32
  * @throws Error if hex format is invalid
33
33
  */
34
- /* @__NO_SIDE_EFFECTS__ */
34
+ /*@__NO_SIDE_EFFECTS__*/
35
35
  function hexToSsri(hex, algorithm = "sha256") {
36
36
  if (!/^[a-f0-9]+$/i.test(hex)) throw new require_primordials_error.ErrorCtor(`Invalid hex format: ${hex}`);
37
37
  return `${algorithm}-${require_primordials_buffer.BufferPrototypeToString(require_primordials_buffer.BufferFrom(hex, "hex"), "base64")}`;
@@ -56,7 +56,7 @@ function hexToSsri(hex, algorithm = "sha256") {
56
56
  *
57
57
  * @throws Error if SSRI format is invalid
58
58
  */
59
- /* @__NO_SIDE_EFFECTS__ */
59
+ /*@__NO_SIDE_EFFECTS__*/
60
60
  function ssriToHex(ssri) {
61
61
  const match = /^([a-z0-9]+)-([A-Za-z0-9+/]+=*)$/i.exec(ssri);
62
62
  if (!match || !match[2] || match[2].length < 2) throw new require_primordials_error.ErrorCtor(`Invalid SSRI format: ${ssri}`);
@@ -27,7 +27,7 @@ const require_primordials_error = require('../primordials/error.js');
27
27
  *
28
28
  * @throws Error if SSRI format is invalid
29
29
  */
30
- /* @__NO_SIDE_EFFECTS__ */
30
+ /*@__NO_SIDE_EFFECTS__*/
31
31
  function parseSsri(ssri) {
32
32
  const match = /^([a-z0-9]+)-([A-Za-z0-9+/]+=*)$/i.exec(ssri);
33
33
  if (!match || !match[1] || !match[2] || match[2].length < 2) throw new require_primordials_error.ErrorCtor(`Invalid SSRI format: ${ssri}`);
@@ -26,7 +26,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
26
26
  *
27
27
  * @returns True if string is valid hex format
28
28
  */
29
- /* @__NO_SIDE_EFFECTS__ */
29
+ /*@__NO_SIDE_EFFECTS__*/
30
30
  function isValidHex(value) {
31
31
  return /^[a-f0-9]+$/i.test(value);
32
32
  }
@@ -46,7 +46,7 @@ function isValidHex(value) {
46
46
  *
47
47
  * @returns True if string matches SSRI format
48
48
  */
49
- /* @__NO_SIDE_EFFECTS__ */
49
+ /*@__NO_SIDE_EFFECTS__*/
50
50
  function isValidSsri(value) {
51
51
  return /^[a-z0-9]+-[A-Za-z0-9+/]{2,}=*$/i.test(value);
52
52
  }
@@ -152,7 +152,7 @@ function resolveTheme(theme) {
152
152
  *
153
153
  * @returns Wrapped prompt function with spinner, theme, and signal handling
154
154
  */
155
- /* @__NO_SIDE_EFFECTS__ */
155
+ /*@__NO_SIDE_EFFECTS__*/
156
156
  function wrapPrompt(inquirerPrompt) {
157
157
  return async (...args) => {
158
158
  const origContext = args.length > 1 ? args[1] : void 0;
@@ -26,7 +26,7 @@ let src_external_streaming_iterables = require("../external/streaming-iterables"
26
26
  * )
27
27
  * ```
28
28
  */
29
- /* @__NO_SIDE_EFFECTS__ */
29
+ /*@__NO_SIDE_EFFECTS__*/
30
30
  async function parallelEach(iterable, func, options) {
31
31
  for await (const _ of /* @__PURE__ */ parallelMap(iterable, func, options));
32
32
  }
@@ -47,7 +47,7 @@ async function parallelEach(iterable, func, options) {
47
47
  * }
48
48
  * ```
49
49
  */
50
- /* @__NO_SIDE_EFFECTS__ */
50
+ /*@__NO_SIDE_EFFECTS__*/
51
51
  function parallelMap(iterable, func, options) {
52
52
  const opts = /* @__PURE__ */ require_promises_options.normalizeIterationOptions(options);
53
53
  return (0, src_external_streaming_iterables.parallelMap)(opts.concurrency, async (item) => {
@@ -24,7 +24,7 @@ let src_external_streaming_iterables = require("../external/streaming-iterables"
24
24
  * }
25
25
  * ```
26
26
  */
27
- /* @__NO_SIDE_EFFECTS__ */
27
+ /*@__NO_SIDE_EFFECTS__*/
28
28
  function transform(iterable, func, options) {
29
29
  const opts = /* @__PURE__ */ require_promises_options.normalizeIterationOptions(options);
30
30
  return (0, src_external_streaming_iterables.transform)(opts.concurrency, async (item) => {
@@ -38,7 +38,7 @@ const fromCharCode = String.fromCharCode;
38
38
  *
39
39
  * @returns The string with prefix applied to each line
40
40
  */
41
- /* @__NO_SIDE_EFFECTS__ */
41
+ /*@__NO_SIDE_EFFECTS__*/
42
42
  function applyLinePrefix(str, options) {
43
43
  const { prefix = "" } = {
44
44
  __proto__: null,
@@ -80,7 +80,7 @@ function applyLinePrefix(str, options) {
80
80
  *
81
81
  * @returns The centered text with padding
82
82
  */
83
- /* @__NO_SIDE_EFFECTS__ */
83
+ /*@__NO_SIDE_EFFECTS__*/
84
84
  function centerText(text, width) {
85
85
  const textLength = (/* @__PURE__ */ require_ansi_strip.stripAnsi(text)).length;
86
86
  if (textLength >= width) return text;
@@ -114,7 +114,7 @@ function centerText(text, width) {
114
114
  *
115
115
  * @returns The indented string
116
116
  */
117
- /* @__NO_SIDE_EFFECTS__ */
117
+ /*@__NO_SIDE_EFFECTS__*/
118
118
  function indentString(str, options) {
119
119
  const { count = 1 } = {
120
120
  __proto__: null,
@@ -141,7 +141,7 @@ function indentString(str, options) {
141
141
  *
142
142
  * @returns The repeated string, or empty string if count <= 0
143
143
  */
144
- /* @__NO_SIDE_EFFECTS__ */
144
+ /*@__NO_SIDE_EFFECTS__*/
145
145
  function repeatString(str, count) {
146
146
  if (count <= 0) return "";
147
147
  return require_primordials_string.StringPrototypeRepeat(str, count);
@@ -26,7 +26,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
26
26
  *
27
27
  * @returns `true` if the value is a blank string, `false` otherwise
28
28
  */
29
- /* @__NO_SIDE_EFFECTS__ */
29
+ /*@__NO_SIDE_EFFECTS__*/
30
30
  function isBlankString(value) {
31
31
  return typeof value === "string" && (!value.length || /^\s+$/.test(value));
32
32
  }
@@ -51,7 +51,7 @@ function isBlankString(value) {
51
51
  *
52
52
  * @returns `true` if the value is a non-empty string, `false` otherwise
53
53
  */
54
- /* @__NO_SIDE_EFFECTS__ */
54
+ /*@__NO_SIDE_EFFECTS__*/
55
55
  function isNonEmptyString(value) {
56
56
  return typeof value === "string" && value.length > 0;
57
57
  }
@@ -37,7 +37,7 @@ const require_primordials_math = require('../primordials/math.js');
37
37
  *
38
38
  * @returns The index of the first match, or -1 if not found
39
39
  */
40
- /* @__NO_SIDE_EFFECTS__ */
40
+ /*@__NO_SIDE_EFFECTS__*/
41
41
  function search(str, regexp, options) {
42
42
  const { fromIndex = 0 } = {
43
43
  __proto__: null,