@crewhaus/tool-pkgmgr 0.7.0 → 0.8.1

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.
package/dist/fixtures.js DELETED
@@ -1,334 +0,0 @@
1
- // ---------------------------------------------------------------------------
2
- // Homebrew — macOS 15.6, Homebrew 4.3.8
3
- // ---------------------------------------------------------------------------
4
- export const BREW_VERSION = `Homebrew 4.3.8
5
- Homebrew/homebrew-core (git revision 2e6b2c3f4a1; last commit 2026-09-10)
6
- `;
7
- /** `brew info --json=v2 curl` — installed, and the tap has a newer version. */
8
- export const BREW_INFO_CURL = `{"formulae":[{"name":"curl","full_name":"curl","tap":"homebrew/core","oldnames":[],"aliases":[],"versions":{"stable":"8.9.1","head":"HEAD","bottle":true},"installed":[{"version":"8.8.0","used_options":[],"built_as_bottle":true,"poured_from_bottle":true,"installed_as_dependency":false,"installed_on_request":true}],"dependencies":["brotli","libnghttp2","libssh2","openldap","rtmpdump","zstd"],"pinned":false,"outdated":true,"deprecated":false,"disabled":false}],"casks":[]}`;
9
- /** `brew info --json=v2 tree` — known to the tap, not installed. */
10
- export const BREW_INFO_TREE = `{"formulae":[{"name":"tree","full_name":"tree","tap":"homebrew/core","versions":{"stable":"2.2.1","head":null,"bottle":true},"installed":[],"dependencies":[],"pinned":false,"outdated":false,"deprecated":false,"disabled":false}],"casks":[]}`;
11
- /**
12
- * `brew info --json=v2 python@3.11` — two kegs of one formula.
13
- *
14
- * The reason `installedVersions` is an array: reporting the first as "the"
15
- * installed version is wrong for exactly the formulae people ask about.
16
- */
17
- export const BREW_INFO_PYTHON = `{"formulae":[{"name":"python@3.11","full_name":"python@3.11","tap":"homebrew/core","versions":{"stable":"3.11.9","head":null,"bottle":true},"installed":[{"version":"3.11.9","installed_on_request":true},{"version":"3.11.8","installed_on_request":false}],"dependencies":["mpdecimal","openssl@3","sqlite","xz"],"pinned":true,"outdated":false}],"casks":[]}`;
18
- /** `brew info --json=v2 firefox` — a cask, which spells everything differently. */
19
- export const BREW_INFO_FIREFOX = `{"formulae":[],"casks":[{"token":"firefox","full_token":"homebrew/cask/firefox","tap":"homebrew/cask","name":["Mozilla Firefox"],"version":"142.0.1","installed":"141.0","outdated":true}]}`;
20
- /** `brew info --json=v2 nope-nope` — exit 1, and this exact sentence. */
21
- export const BREW_NO_SUCH_FORMULA = `Error: No available formula with the name "nope-nope".
22
- ==> Searching for similarly named formulae and casks...
23
- `;
24
- export const BREW_DEPS_CURL = `brotli
25
- libnghttp2
26
- libssh2
27
- openldap
28
- rtmpdump
29
- zstd
30
- `;
31
- export const BREW_DEPS_TREE = "";
32
- /** `brew list --formula --versions` — four of the six curl deps are present. */
33
- export const BREW_LIST_VERSIONS = `brotli 1.1.0
34
- ca-certificates 2026-08-12
35
- libnghttp2 1.62.1
36
- openldap 2.6.7
37
- python@3.11 3.11.9 3.11.8
38
- zstd 1.5.6
39
- `;
40
- export const BREW_INSTALL_TREE = `==> Fetching tree
41
- ==> Downloading https://ghcr.io/v2/homebrew/core/tree/blobs/sha256:9f3c1ad
42
- ==> Pouring tree--2.2.1.arm64_sonoma.bottle.tar.gz
43
- /opt/homebrew/Cellar/tree/2.2.1: 8 files, 162.5KB
44
- `;
45
- /** `brew info --json=v2 tree`, re-run after the install above succeeded. */
46
- export const BREW_INFO_TREE_AFTER = `{"formulae":[{"name":"tree","full_name":"tree","tap":"homebrew/core","versions":{"stable":"2.2.1","head":null,"bottle":true},"installed":[{"version":"2.2.1","installed_on_request":true}],"dependencies":[],"pinned":false,"outdated":false}],"casks":[]}`;
47
- // ---------------------------------------------------------------------------
48
- // apt / dpkg — Debian 12 (bookworm), dpkg 1.21.22, apt 2.6.1
49
- // ---------------------------------------------------------------------------
50
- export const DPKG_VERSION = `Debian dpkg-query package management program version 1.21.22 (amd64).
51
- This is free software; see the GNU General Public License version 2 or
52
- later for copying conditions. There is NO warranty.
53
- `;
54
- /** Note the trailing space: `${db:Status-Abbrev}` is three characters wide. */
55
- export const DPKG_QUERY_CURL = "curl\t7.88.1-10+deb12u5\tii \n";
56
- /**
57
- * A package dpkg still has a RECORD of but does not have installed: removed,
58
- * configuration files left behind. Reading `rc` as installed is the classic
59
- * dpkg mistake — the binary is gone and only `/etc` remains.
60
- */
61
- export const DPKG_QUERY_NANO_REMOVED = "nano\t7.2-1\trc \n";
62
- /** dpkg has no record at all of a package that was never installed. */
63
- export const DPKG_NO_SUCH_PACKAGE = "dpkg-query: no packages found matching htop\n";
64
- export const APT_POLICY_CURL = `curl:
65
- Installed: 7.88.1-10+deb12u5
66
- Candidate: 7.88.1-10+deb12u7
67
- Version table:
68
- *** 7.88.1-10+deb12u5 100
69
- 100 /var/lib/dpkg/status
70
- 7.88.1-10+deb12u7 500
71
- 500 http://deb.debian.org/debian-security bookworm-security/main amd64 Packages
72
- `;
73
- export const APT_POLICY_HTOP = `htop:
74
- Installed: (none)
75
- Candidate: 3.2.2-2
76
- Version table:
77
- 3.2.2-2 500
78
- 500 http://deb.debian.org/debian bookworm/main amd64 Packages
79
- `;
80
- /** A package apt has in its lists with no installable candidate at all. */
81
- export const APT_POLICY_NO_CANDIDATE = `phantom:
82
- Installed: (none)
83
- Candidate: (none)
84
- Version table:
85
- `;
86
- /** apt-cache prints NOTHING for a name it does not know, and exits 0. */
87
- export const APT_POLICY_UNKNOWN_STDERR = "N: Unable to locate package nosuchpkg\n";
88
- /**
89
- * The same `apt-cache policy curl` on a de_DE host.
90
- *
91
- * This is the fixture that gives the localisation trap a name. Every parser
92
- * in this package reads English labels, which is sound ONLY because
93
- * `../run.ts` pins `LC_ALL=C` on every child. Without that pin the parse does
94
- * not fail loudly — it finds nothing, and "nothing" reads as "not installed".
95
- */
96
- export const APT_POLICY_CURL_GERMAN = `curl:
97
- Installiert: 7.88.1-10+deb12u5
98
- Installationskandidat: 7.88.1-10+deb12u7
99
- Versionstabelle:
100
- *** 7.88.1-10+deb12u5 100
101
- 100 /var/lib/dpkg/status
102
- `;
103
- export const APT_SIMULATE_HTOP = `NOTE: This is only a simulation!
104
- apt-get needs root privileges for real execution.
105
- Keep also in mind that locking is deactivated,
106
- so don't depend on the relevance to the real current situation!
107
- Reading package lists...
108
- Building dependency tree...
109
- Reading state information...
110
- The following additional packages will be installed:
111
- libnl-3-200 libnl-genl-3-200
112
- The following NEW packages will be installed:
113
- htop libnl-3-200 libnl-genl-3-200
114
- 0 upgraded, 3 newly installed, 0 to remove and 0 not upgraded.
115
- Inst libnl-3-200 (3.7.0-0.2+b1 Debian:12.5/stable [amd64])
116
- Inst libnl-genl-3-200 (3.7.0-0.2+b1 Debian:12.5/stable [amd64])
117
- Inst htop (3.2.2-2 Debian:12.5/stable [amd64])
118
- Conf libnl-3-200 (3.7.0-0.2+b1 Debian:12.5/stable [amd64])
119
- Conf libnl-genl-3-200 (3.7.0-0.2+b1 Debian:12.5/stable [amd64])
120
- Conf htop (3.2.2-2 Debian:12.5/stable [amd64])
121
- `;
122
- /**
123
- * An UPGRADE that also removes something — the case an operator most needs to
124
- * see before approving an install. Note the `[old-version]` bracket between
125
- * the name and the parenthesis, which only an upgrade has.
126
- */
127
- export const APT_SIMULATE_CURL_UPGRADE = `Reading package lists...
128
- Building dependency tree...
129
- The following packages will be REMOVED:
130
- curl-legacy
131
- The following packages will be upgraded:
132
- curl
133
- 1 upgraded, 0 newly installed, 1 to remove and 0 not upgraded.
134
- Remv curl-legacy [7.74.0-1]
135
- Inst curl [7.88.1-10+deb12u5] (7.88.1-10+deb12u7 Debian-Security:12/stable-security [amd64])
136
- Conf curl (7.88.1-10+deb12u7 Debian-Security:12/stable-security [amd64])
137
- `;
138
- export const APT_INSTALL_HTOP = `Reading package lists...
139
- Building dependency tree...
140
- The following NEW packages will be installed:
141
- htop libnl-3-200 libnl-genl-3-200
142
- Setting up htop (3.2.2-2) ...
143
- Processing triggers for man-db (2.11.2-2) ...
144
- `;
145
- export const DPKG_QUERY_HTOP_AFTER = "htop\t3.2.2-2\tii \n";
146
- export const APT_NEEDS_ROOT = `E: Could not open lock file /var/lib/dpkg/lock-frontend - open (13: Permission denied)
147
- E: Unable to acquire the dpkg frontend lock (/var/lib/dpkg/lock-frontend), are you root?
148
- `;
149
- // ---------------------------------------------------------------------------
150
- // dnf / rpm — Rocky Linux 9.4, dnf 4.14.0, rpm 4.16.1.3
151
- // ---------------------------------------------------------------------------
152
- export const DNF_VERSION = `4.14.0
153
- Installed: dnf-0:4.14.0-9.el9.noarch at 2026-02-11 08:14
154
- Built : Rocky Enterprise Software Foundation at 2026-01-30 11:02
155
- `;
156
- export const RPM_QUERY_CURL = "curl\t7.76.1-29.el9_4\tx86_64\n";
157
- /** The same name installed for two architectures — real, and common. */
158
- export const RPM_QUERY_GLIBC = "glibc\t2.34-100.el9_4.2\tx86_64\nglibc\t2.34-100.el9_4.2\ti686\n";
159
- /** rpm writes this to STDOUT, not stderr, and exits 1. */
160
- export const RPM_NOT_INSTALLED = "package tree is not installed\n";
161
- export const DNF_LIST_TREE = `Available Packages
162
- tree.x86_64 1.8.0-10.el9 baseos
163
- `;
164
- export const DNF_LIST_NO_MATCH = "Error: No matching Packages to list\n";
165
- /**
166
- * The case `--cacheonly` makes common on a fresh container, and the case
167
- * house rule 6 is about: an empty metadata cache is NOT an absent package.
168
- */
169
- export const DNF_NO_CACHE = `Error: Cache-only enabled but no cache for 'baseos'
170
- `;
171
- export const DNF_SIMULATE_TREE = `Last metadata expiration check: 0:05:12 ago on Wed 17 Sep 2026 09:00:00 AM UTC.
172
- Dependencies resolved.
173
- ================================================================================
174
- Package Arch Version Repository Size
175
- ================================================================================
176
- Installing:
177
- tree x86_64 1.8.0-10.el9 baseos 55 k
178
- Installing dependencies:
179
- libfoo x86_64 1.2-3.el9 appstream 10 k
180
-
181
- Transaction Summary
182
- ================================================================================
183
- Install 2 Packages
184
-
185
- Total download size: 65 k
186
- Installed size: 143 k
187
- Operation aborted.
188
- `;
189
- export const DNF_NEEDS_ROOT = `Error: This command has to be run with superuser privileges (under the root user on most systems).
190
- `;
191
- export const DNF_INSTALL_TREE = `Dependencies resolved.
192
- Installing:
193
- tree x86_64 1.8.0-10.el9 baseos 55 k
194
-
195
- Complete!
196
- `;
197
- export const RPM_QUERY_TREE_AFTER = "tree\t1.8.0-10.el9\tx86_64\n";
198
- // ---------------------------------------------------------------------------
199
- // pacman — Arch, pacman 6.1.0
200
- // ---------------------------------------------------------------------------
201
- export const PACMAN_VERSION = ` .--. Pacman v6.1.0 - libalpm v14.0.0
202
- / _.-' .-. .-. .-. Copyright (C) 2006-2024 Pacman Development Team
203
- `;
204
- export const PACMAN_QUERY_CURL = "curl 8.9.1-1\n";
205
- export const PACMAN_NOT_FOUND = "error: package 'htop' was not found\n";
206
- export const PACMAN_SYNC_INFO_HTOP = `Repository : extra
207
- Name : htop
208
- Version : 3.3.0-1
209
- Description : Interactive process viewer
210
- Architecture : x86_64
211
- Licenses : GPL
212
- Depends On : glibc ncurses lm_sensors
213
- Download Size : 158.44 KiB
214
-
215
- Repository : community-testing
216
- Name : htop
217
- Version : 3.4.0-0.1
218
- `;
219
- export const PACMAN_SYNC_NOT_FOUND = "error: package 'nosuch' was not found\n";
220
- /** `pacman -S --print --print-format '%r/%n %v'` — targets AND dependencies. */
221
- export const PACMAN_SIMULATE_HTOP = `core/ncurses 6.5-3
222
- extra/lm_sensors 1:3.6.0.r41-3
223
- extra/htop 3.3.0-1
224
- `;
225
- export const PACMAN_NEEDS_ROOT = "error: you cannot perform this operation unless you are root.\n";
226
- export const PACMAN_INSTALL_HTOP = `resolving dependencies...
227
- looking for conflicting packages...
228
- (3) installing ncurses lm_sensors htop
229
- :: Running post-transaction hooks...
230
- `;
231
- export const PACMAN_QUERY_HTOP_AFTER = "htop 3.3.0-1\n";
232
- // ---------------------------------------------------------------------------
233
- // winget — Windows 11, winget 1.8.1911
234
- // ---------------------------------------------------------------------------
235
- export const WINGET_VERSION = "v1.8.1911\n";
236
- /** Five columns: Name, Id, Version, Available, Source. */
237
- export const WINGET_LIST_GIT = `Name Id Version Available Source
238
- -------------------------------------------
239
- Git Git.Git 2.45.1 2.46.0 winget
240
- `;
241
- /**
242
- * Four columns, which is the ambiguous case: this is `…Version Source`, but a
243
- * row with an available upgrade and no source is `…Version Available` and
244
- * looks identical. winget's headers are localised, so there is no way to tell
245
- * — which is why the parser reports a null `available` with a reason rather
246
- * than picking one.
247
- */
248
- export const WINGET_LIST_FOUR_COLUMNS = `Name Id Version Source
249
- --------------------------------
250
- 7-Zip 7zip.7zip 24.08 winget
251
- `;
252
- /**
253
- * A row winget had to CUT, marked with U+2026. The survey's proposed
254
- * header-offset parser would read `14.40.3` here as a complete version and
255
- * the Id as a complete Id; both are prefixes.
256
- */
257
- export const WINGET_LIST_TRUNCATED = `Name Id Version Source
258
- -------------------------------------------------------------------
259
- Microsoft Visual C++ 20… Microsoft.VCRedist.2015… 14.40.3 winget
260
- `;
261
- /**
262
- * A CJK display name. Each glyph is DOUBLE-WIDTH in the console and one
263
- * UTF-16 code unit in the string, so every character offset after it is
264
- * wrong — and splitting on two-or-more spaces is unaffected.
265
- */
266
- export const WINGET_LIST_CJK = `Name Id Version Source
267
- ----------------------------------------
268
- テキスト Vendor.Text 1.2.3 winget
269
- `;
270
- export const WINGET_NOT_FOUND = "No installed package found matching input criteria.\n";
271
- // ---------------------------------------------------------------------------
272
- // chocolatey — Windows 11, choco 2.2.2 and 0.10.15
273
- // ---------------------------------------------------------------------------
274
- export const CHOCO_VERSION_V2 = "2.2.2\n";
275
- export const CHOCO_VERSION_V1 = "0.10.15\n";
276
- export const CHOCO_LIST_GIT = "git|2.45.1\ngit.install|2.45.1\n";
277
- export const CHOCO_LIST_EMPTY = "";
278
- /** The key a command is recorded under. NUL cannot appear in an argv element. */
279
- export function argvKey(argv) {
280
- return argv.join("\u0000");
281
- }
282
- /**
283
- * Serve recorded output, and refuse anything nobody recorded.
284
- *
285
- * The refusal is the important half. A runner that answered an unrecorded
286
- * command with an empty success would be indistinguishable from a manager
287
- * that had nothing to say, and every "not installed" in the suite would stop
288
- * meaning anything. Instead the promise rejects with the argv, so a missing
289
- * fixture fails the test that needed it and names the command.
290
- *
291
- * `fallback` exists for the tests that are ABOUT an unrecognised host: pass
292
- * `{ missing: true }` to make every unrecorded command behave like a program
293
- * that is not installed.
294
- */
295
- export function recordedRunner(cases, fallback) {
296
- const calls = [];
297
- const requests = [];
298
- // How many times each argv has been asked for. A case recorded as an ARRAY
299
- // answers differently on successive calls, which is what an install needs:
300
- // the same `brew info` command legitimately answers "not installed" before
301
- // the install and "installed" after it, and a runner that could not express
302
- // that would make the post-install verification untestable.
303
- const seen = new Map();
304
- const runner = async (request) => {
305
- calls.push([...request.argv]);
306
- requests.push(request);
307
- const key = argvKey(request.argv);
308
- const index = seen.get(key) ?? 0;
309
- seen.set(key, index + 1);
310
- const entry = cases[key];
311
- const recorded = Array.isArray(entry)
312
- ? // Past the end the last recorded answer repeats, so a fixture does
313
- // not have to enumerate every retry.
314
- (entry[Math.min(index, entry.length - 1)] ?? fallback)
315
- : (entry ?? fallback);
316
- if (recorded === undefined) {
317
- throw new Error(`no recorded output for: ${request.argv.map((a) => JSON.stringify(a)).join(" ")}`);
318
- }
319
- return {
320
- code: recorded.code ?? 0,
321
- stdout: recorded.stdout ?? "",
322
- stderr: recorded.stderr ?? "",
323
- timedOut: recorded.timedOut ?? false,
324
- missing: recorded.missing ?? false,
325
- ...(recorded.stdoutTruncated === true ? { stdoutTruncated: true } : {}),
326
- ...(recorded.stderrTruncated === true ? { stderrTruncated: true } : {}),
327
- };
328
- };
329
- return { runner, calls, requests };
330
- }
331
- /** Shorthand: record a case under an argv rather than under a key. */
332
- export function record(argv, outcome) {
333
- return { [argvKey(argv)]: outcome };
334
- }