gdx 0.4.5 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2025 Type-Delta
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Type-Delta
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -17,8 +17,8 @@ It wraps standard git commands with intelligent shorthands and adds powerful new
17
17
 
18
18
  **Why gdx?**
19
19
 
20
- - **👍 Convenience:** Type less, do more. `git status`? how about `gdx s`?, `git reset HEAD~3`? why not `gdx res ~3`?
21
- - **🛡️ Safety:** `gdx clear` wipes your directory but saves a backup patch. No more "oops" moments.
20
+ - **👍 Convenience:** Type less, do more. `git status`? how about `gdx s`, `git reset HEAD~3`? why not `gdx res ~3`
21
+ - **🛡️ Safety:** `gdx clear` backs up before it wipes, and `gdx history undo` is Ctrl+Z for your repo. No more "oops" moments.
22
22
  - **✨ Enhanced Output:** Git's output is... functional. `gdx` makes it beautiful and easier for _humans_ to digest.
23
23
  - **🧠 Logic:** Handles the things Git makes hard, like dropping a range of stashes, working with worktrees, or submodules.
24
24
  - **📊 Local-First Stats:** Beautiful TrueColor graphs and stats generated from your local history.
@@ -92,7 +92,7 @@ To enable features like `gdx parallel switch` (auto-cd into worktrees) and **tab
92
92
 
93
93
  Shell integration provides:
94
94
 
95
- - **Auto-cd support**: Allows `gdx parallel switch` to change directories
95
+ - **Auto-cd support**: Allows switching between parallel **worktrees** and **submodules** without needing to `cd` into them manually.
96
96
  - **Tab completion**: Intelligent completion for gdx commands, shorthands, and git subcommands
97
97
  - **Completion fallback**: Falls back to native git completion when gdx has no suggestions (git fallback requires you to install git's completion scripts separately)
98
98
 
@@ -130,13 +130,14 @@ Invoke-Expression (& { (gdx --init pwsh | Out-String) })
130
130
  `gdx` isn't just a list of static aliases. It understands partial commands and expands them smartly.
131
131
 
132
132
  ```bash
133
- gdx s # -> git status
134
- gdx sta # -> git stash
135
- gdx statu # -> git status
136
- gdx lg # -> git log --oneline --graph --all --decorate
137
- gdx pl -au # -> git pull --allow-unrelated-histories
138
- gdx ps -fl # -> git push --force-with-lease
139
- gdx reset ~2 # -> git reset HEAD~2
133
+ gdx s # -> git status
134
+ gdx sta # -> git stash
135
+ gdx statu # -> git status
136
+ gdx lg # -> git log --oneline --graph --all --decorate
137
+ gdx pu -au # -> git pull --allow-unrelated-histories
138
+ gdx ps -fl # -> git push --force-with-lease
139
+ gdx cmi -m "Fix bug" # -> git commit -m "Fix bug"
140
+ gdx reset ~2 # -> git reset HEAD~2
140
141
  ```
141
142
 
142
143
  > [!NOTE]
@@ -155,12 +156,23 @@ Catch issues before they reach the remote. `gdx lint` checks for:
155
156
 
156
157
  You can configure `gdx` to run this automatically before every push.
157
158
 
158
- ### 3. The Safety Net: `clear` vs `reset`
159
+ ### 3. The Safety Net
159
160
 
160
- We've all accidentally reset files we meant to keep. `gdx clear` is the solution.
161
+ We've all accidentally nuked changes we meant to keep. `gdx` gives you ways back:
161
162
 
162
- - **`gdx clear`**: Creates a timestamped patch backup in a temp folder, then effectively runs `reset --hard` & `clean -fd`.
163
+ - **`gdx clear`**: Creates a timestamped patch backup, then effectively runs `reset --hard` & `clean -fd`.
163
164
  - **`gdx clear pardon`**: "Wait, I didn't mean to do that." Applies the backup patch and restores your changes.
165
+ - **`gdx snap`**: Creates a repository/worktree+index backup you can switch back to later.
166
+ - **`gdx history` (Experimental)**: Ctrl+Z for Git. `gdx` keeps a repository-local journal of the commands it runs (and picks up direct `git` ref changes from reflogs, or live via `gdx history hook`) so you can step through them:
167
+
168
+ ```bash
169
+ gdx history # List recorded transactions (newest first)
170
+ gdx history undo # Undo the most recent transaction
171
+ gdx history redo # ...changed your mind? bring it back
172
+ gdx history show 0 # Inspect a transaction in detail
173
+ ```
174
+
175
+ Undo and redo refuse to touch anything that has diverged since the recording — no silent overwrites. Entries respect a retention limit (`history.maxEntries`), and recording can be turned off with `history.enabled`.
164
176
 
165
177
  ### 4. Parallel Worktrees (Experimental)
166
178
 
@@ -185,7 +197,7 @@ using detected package managers (see `parallel.init` config for options), and **
185
197
  ignored env files** if configured (see `parallel.envPaths` config for options),
186
198
  getting the fork ready for work in no time.
187
199
 
188
- ### 5. Git Output for Human (Experimental)
200
+ ### 5. Git Output for Humans
189
201
 
190
202
  Admit it, Git's default output isn't exactly designed for readability.
191
203
  `gdx` enhances the output of some commands with better formatting to make it less "git" to read.
@@ -217,7 +229,114 @@ gdx sta drop 2..6 # Drops stashes 2 through 6.
217
229
  gdx stash d pardon # Restores the last dropped stash.
218
230
  ```
219
231
 
220
- ### 7. Commits Message Generation
232
+ ### 7. GitHub CLI Wrapper (Experimental)
233
+
234
+ Similar to how `gdx` wraps git, `gdx gh` wraps the GitHub CLI (`gh`) to provides better UX and some QoL features like:
235
+
236
+ #### Example: `gdx gh repo create`
237
+
238
+ Instead of asking you millions of obvious questions, gdx looks around to figure out what you want and only asks what matter.
239
+
240
+ <details>
241
+ <summary><strong>See how it works</strong></summary>
242
+
243
+ ```mermaid
244
+ flowchart TD
245
+ classDef ask fill:#f59e0b,stroke:#b45309,color:#1f2937,font-weight:bold
246
+ classDef auto fill:#34d399,stroke:#059669,color:#064e3b,font-weight:bold
247
+ classDef skip fill:#94a3b8,stroke:#475569,color:#1e293b
248
+ classDef decision fill:#e0e7ff,stroke:#6366f1,color:#312e81
249
+ classDef mode fill:#6366f1,stroke:#4338ca,color:#ffffff,font-weight:bold
250
+ classDef final fill:#0ea5e9,stroke:#0369a1,color:#ffffff,font-weight:bold
251
+
252
+ START(["gdx gh repo create"]) --> MODE{"Which mode?"}
253
+ class MODE decision
254
+
255
+ MODE -- "--template / -p given" --> T["🧩 From template"]:::mode
256
+ MODE -- "--source given,<br/>or inside a git repo" --> P["📤 Push local"]:::mode
257
+ MODE -- "otherwise" --> S["✨ From scratch"]:::mode
258
+
259
+ %% ───────────── From scratch ─────────────
260
+ subgraph SG_S [" From scratch "]
261
+ S --> S_NAME{"Name in args?"}:::decision
262
+ S_NAME -- yes --> S_NAME_A["Skip — use positional arg"]:::skip
263
+ S_NAME -- no --> S_NAME_Q["Ask: repository name"]:::ask
264
+
265
+ S_NAME_A & S_NAME_Q --> S_DESC{"--description given?"}:::decision
266
+ S_DESC -- yes --> S_DESC_A["Skip"]:::skip
267
+ S_DESC -- no --> S_DESC_Q["Ask: description<br/><i>(optional)</i>"]:::ask
268
+
269
+ S_DESC_A & S_DESC_Q --> S_LIC{"--license given?"}:::decision
270
+ S_LIC -- yes --> S_LIC_A["Skip"]:::skip
271
+ S_LIC -- no --> S_LIC_Q["Ask: license<br/><i>(optional dropdown)</i>"]:::ask
272
+
273
+ S_LIC_A & S_LIC_Q --> S_VIS{"--public/--private/<br/>--internal given?"}:::decision
274
+ S_VIS -- yes --> S_VIS_A["Skip"]:::skip
275
+ S_VIS -- no --> S_VIS_Q["Ask: visibility<br/><i>(default: private)</i>"]:::ask
276
+
277
+ S_VIS_A & S_VIS_Q --> S_CLONE["Auto: --clone<br/><i>(unless --clone/--no-clone given)</i>"]:::auto
278
+ end
279
+
280
+ %% ───────────── From template ─────────────
281
+ subgraph SG_T [" From template "]
282
+ T --> T_NAME{"Name in args?"}:::decision
283
+ T_NAME -- yes --> T_NAME_A["Skip — use positional arg"]:::skip
284
+ T_NAME -- no --> T_NAME_Q["Ask: repository name"]:::ask
285
+
286
+ T_NAME_A & T_NAME_Q --> T_DESC{"--description given?"}:::decision
287
+ T_DESC -- yes --> T_DESC_A["Skip"]:::skip
288
+ T_DESC -- no --> T_DESC_Q["Ask: description<br/><i>(optional)</i>"]:::ask
289
+
290
+ T_DESC_A & T_DESC_Q --> T_LIC["License question skipped<br/><i>(template provides files)</i>"]:::skip
291
+
292
+ T_LIC --> T_VIS{"--public/--private/<br/>--internal given?"}:::decision
293
+ T_VIS -- yes --> T_VIS_A["Skip"]:::skip
294
+ T_VIS -- no --> T_VIS_Q["Ask: visibility<br/><i>(default: private)</i>"]:::ask
295
+
296
+ T_VIS_A & T_VIS_Q --> T_CLONE["Auto: --clone if outside a repo<br/><i>(unless --clone/--no-clone given)</i>"]:::auto
297
+ end
298
+
299
+ %% ───────────── Push local ─────────────
300
+ subgraph SG_P [" Push local "]
301
+ P --> P_META["Read package.json /<br/>pyproject.toml metadata"]:::auto
302
+
303
+ P_META --> P_NAME{"Name in args<br/>or in metadata?"}:::decision
304
+ P_NAME -- "in args" --> P_NAME_A["Skip"]:::skip
305
+ P_NAME -- "in metadata" --> P_NAME_M["Auto-fill from manifest"]:::auto
306
+ P_NAME -- neither --> P_NAME_Q["Ask: repository name"]:::ask
307
+
308
+ P_NAME_A & P_NAME_M & P_NAME_Q --> P_DESC{"--description given<br/>or in metadata?"}:::decision
309
+ P_DESC -- "in args" --> P_DESC_A["Skip"]:::skip
310
+ P_DESC -- "in metadata" --> P_DESC_M["Auto-fill from manifest"]:::auto
311
+ P_DESC -- neither --> P_DESC_Q["Ask: description<br/><i>(optional)</i>"]:::ask
312
+
313
+ P_DESC_A & P_DESC_M & P_DESC_Q --> P_VIS{"--public/--private/<br/>--internal given?"}:::decision
314
+ P_VIS -- yes --> P_VIS_A["Skip"]:::skip
315
+ P_VIS -- no --> P_VIS_Q["Ask: visibility<br/><i>(default: private)</i>"]:::ask
316
+
317
+ P_VIS_A & P_VIS_Q --> P_FILL["Auto: --source ‹repo root›<br/>--remote origin · --push"]:::auto
318
+ end
319
+
320
+ S_CLONE & T_CLONE & P_FILL --> CONFIRM["📋 Show summary &<br/>confirm"]:::final
321
+ CONFIRM --> RUN(["▶ gh repo create ‹args›"]):::final
322
+
323
+ %% Legend
324
+ subgraph LEGEND ["Legend"]
325
+ L1["Asked interactively"]:::ask
326
+ L2["Auto-filled"]:::auto
327
+ L3["Skipped — already provided"]:::skip
328
+ end
329
+ ```
330
+
331
+ </details>
332
+
333
+ With this you will only be asked a maximum of 4 questions, only the ones you care about.
334
+
335
+ Oh! did I mention that the "Form" now looks like this?
336
+
337
+ ![gh repo create tui](https://github.com/Type-Delta/gdx/raw/main/resources/images/gdx-gh-repo-create-form.png)
338
+
339
+ ### 8. Commits Message Generation
221
340
 
222
341
  Struggling to come up with a commit message? Let `gdx` do it for you.
223
342
 
@@ -230,11 +349,11 @@ gdx cmi auto --no-commit --copy
230
349
  # You can also configure which LLM to use with `gdx-config`
231
350
  ```
232
351
 
233
- Unlike most AI commit message generators, by default `gdx` creates messages generation guidelines and instructions based on your repo's history and conventions.
352
+ Unlike most AI commit message generators, by default `gdx` creates messages generation guidelines based on your repo's history and conventions.
234
353
  This ensures the generated messages fit your project's style and tone.
235
354
  Said guidelines are updated every month to reflect your evolving commit style.
236
355
 
237
- ### 8. Fun & Analytics
356
+ ### 9. Fun & Analytics
238
357
 
239
358
  Tools to help you feel productive without leaving the terminal.
240
359
 
@@ -253,7 +372,7 @@ Tools to help you feel productive without leaving the terminal.
253
372
  | Command | Expansion / Function |
254
373
  | :---------------- | :------------------------------------------------------------------------------------------- |
255
374
  | `s`, `stat` | `git status` (use `-r` recursively run "status" on all submodules) |
256
- | `lg`, `lo` | `git log --oneline --graph --all --decorate` |
375
+ | `lg` | `git log --oneline --graph --all --decorate` |
257
376
  | `sw`, `swit` | `git switch` |
258
377
  | `br`, `bra` | `git branch` |
259
378
  | `ps` | `git push` with option expansion `-fl`=`--force-with-lease` |
@@ -265,6 +384,7 @@ Tools to help you feel productive without leaving the terminal.
265
384
  | `dif` | `git diff` (supports `dif ~3`, `dif origin ~2` expansion) |
266
385
  | `sho` | `git show` (supports `sho ~3`, `sho origin ~2` expansion) |
267
386
  | `sta`, `st` | `git stash` |
387
+ | `rst` | `git restore` |
268
388
  | `lint` | Run pre-push checks (spelling, secrets, etc.) |
269
389
  | `gdx-config` | Manage gdx configuration |
270
390
  | `reword`, `rew` | Rewrite commit messages |
@@ -274,8 +394,10 @@ Tools to help you feel productive without leaving the terminal.
274
394
  | `graph` | Render a GitHub-style contribution heatmap in the terminal |
275
395
  | `nocap` | Roast your latest commit message with AI |
276
396
  | `clear` | Wipe changes in the working directory with a backup patch |
397
+ | `history`, `his` | Inspect, undo, and redo recorded repository transactions |
277
398
  | `cache` | Manage gdx cache |
278
399
  | `macro` | Create custom gdx command macros to run multiple commands with a single macro |
400
+ | `gh` | GitHub CLI wrapper, provides better UX and QoL features |
279
401
 
280
402
  _Run `gdx ghelp` to see the full list of expansions/commands._
281
403
 
@@ -284,7 +406,7 @@ _Run `gdx ghelp` to see the full list of expansions/commands._
284
406
  | Command | Expansion / Function |
285
407
  | :-------------------------------- | :--------------------------------------------------------------------------------------------------- |
286
408
  | `tag mv`, `tag move` | Move a tag to a new commit (supports ref expansion) |
287
- | `lg export` | Export git log to a markdown file with enhanced formatting |
409
+ | `log export` | Export git log to a markdown file with enhanced formatting |
288
410
  | `commit auto` | Generate commit messages with AI based on staged changes (supports `--no-commit` and `--copy` flags) |
289
411
  | `stash drop` | Drop stashes with advanced options (e.g., `drop 2..6`) |
290
412
  | `stash drop pardon` | Restore the last dropped stash |
@@ -332,7 +454,7 @@ Since this is currently a solo "scratch your own itch" project, the roadmap is f
332
454
  - [x] **Submodule dir switching**: extension of `git submodule`, `gdx submodule switch` to jump into a submodule's directory from the parent repo (requires shell integration)
333
455
  - [x] **Snapshot**: `gdx snap` to create snapshot of current state of your working directory (including uncommitted changes, untracked files) that can be easily switched back to later (similar to a lightweight, temporary branch that doesn't clutter your branch list)
334
456
  - [ ] **Enhanced output for more commands**: Extend the "Git Output for Humans"
335
- - [ ] **Undo and Redo**: `gdx undo` and `gdx redo` to step backward and forward through git actions (reset, commit, stash, etc.) with safety nets.
457
+ - [x] **Undo and Redo**: `gdx history undo` and `gdx history redo` to step backward and forward through git actions (commit, add, branch, switch, etc.) with safety nets.
336
458
  - [x] **Edit commit messages**: `gdx reword` to quickly reword the last commit message or a specific commit without needing to do an interactive rebase.
337
459
 
338
460
  ## License
@@ -0,0 +1,54 @@
1
+ import{execFile as U}from"node:child_process";import J from"node:fs";import O from"node:path";import{promisify as Y}from"node:util";var Z=Y(U),$=20000,C=["shiki"];async function T(w){let j=[L(w),M(w),V(w)];if(w.isNative)return j.push({name:"External dependencies",status:"pass",detail:"Bundled into the native executable; Node package probes are not required."}),j;let z;try{z=K(w.packageRoot)}catch(G){return j.push({name:"External dependencies",status:"fail",detail:G instanceof Error?G.message:String(G)}),j}let B=await Promise.all(z.map((G)=>W(w.packageRoot,G)));return j.push(...B),j}function K(w){let j=O.join(w,"package.json"),z=JSON.parse(J.readFileSync(j,"utf8"));return[...new Set([...Object.keys(z.dependencies??{}),...C])]}function L(w){let j=["package.json","scripts/launcher.cjs","scripts/postinstall.cjs"],z=w.isNative?j:[...j,"dist/index.js","dist/workers/generic.worker.min.js"],B=z.filter((H)=>!J.existsSync(O.join(w.packageRoot,H))),G=["dist/diagnostics/postinstall.validator.js","bin/diagnostics/postinstall.validator.js"];if(!G.some((H)=>J.existsSync(O.join(w.packageRoot,H))))B.push(G.join(" or "));return B.length===0?{name:"Required artifacts",status:"pass",detail:`${z.length+1} packaged artifacts are present.`}:{name:"Required artifacts",status:"fail",detail:`Missing: ${B.join(", ")}`}}function M(w){if(!w.installInfo)return{name:"Install metadata",status:"fail",detail:"Postinstall did not produce bin/native/install.json."};try{let j=JSON.parse(J.readFileSync(O.join(w.packageRoot,"package.json"),"utf8")),z=[];if(w.installInfo.version!==j.version)z.push(`version ${String(w.installInfo.version)} (expected ${j.version})`);if(w.installInfo.platform!==process.platform)z.push(`platform ${String(w.installInfo.platform)} (expected ${process.platform})`);if(w.installInfo.arch!==process.arch)z.push(`architecture ${String(w.installInfo.arch)} (expected ${process.arch})`);return z.length===0?{name:"Install metadata",status:"pass",detail:"Version, platform, and architecture match this installation."}:{name:"Install metadata",status:"fail",detail:`Mismatched ${z.join("; ")}.`}}catch(j){return{name:"Install metadata",status:"fail",detail:j instanceof Error?j.message:String(j)}}}function V(w){let j=w.installInfo;if(!j)return{name:"Command shim",status:"fail",detail:"bin/native/install.json is missing or unreadable."};if(w.isNative){if(j.mode==="node"||j.mode==="runtime")return{name:"Command shim",status:"fail",detail:"Install metadata selects a JavaScript runtime fallback, but a stale native binary was launched."};let H=typeof j.binaryPath==="string"?j.binaryPath:process.execPath,Q=j.useNativeShim===!0;return{name:"Command shim",status:Q?"pass":"warn",detail:Q?`The npm shim targets the native binary (${H}).`:"The native binary is running, but postinstall did not confirm a native shim."}}let z=j.useGlobalShim===!0||j.useLocalShim===!0,B=process.env.GDX_RUNTIME_SHIM==="1"||process.env.GDX_NODE_SHIM==="1",G=typeof j.runtime==="string"?j.runtime:"node";if(!z)return{name:"Command shim",status:"warn",detail:"Postinstall did not record a rewritten runtime shim (common with non-npm installers)."};return{name:"Command shim",status:B?"pass":"fail",detail:B?`The postinstall ${G} shim is installed and active for this invocation.`:`A rewritten ${G} shim was recorded, but this invocation bypassed it.`}}async function W(w,j){try{let{stdout:z}=await Z(process.execPath,["--input-type=module","--eval",X(),w,j],{cwd:w,timeout:$,windowsHide:!0,env:{...process.env,GDX_DOCTOR_PROBE:"1"}}),B=JSON.parse(z.trim()),G=j==="keytar"&&!B.ok;return{name:`Dependency: ${j}`,status:B.ok?"pass":G?"warn":"fail",detail:B.detail}}catch(z){let B=z instanceof Error?z.message:String(z);return{name:`Dependency: ${j}`,status:j==="keytar"?"warn":"fail",detail:`Probe failed: ${B}`}}}function X(){return String.raw`
2
+ const packageRoot = process.argv[1];
3
+ const dependency = process.argv[2];
4
+
5
+ try {
6
+ process.chdir(packageRoot);
7
+ const imported = await import(dependency);
8
+ const module = imported.default && Object.keys(imported).length === 1 ? imported.default : imported;
9
+
10
+ if (dependency === 'keytar') {
11
+ const keytar = imported.default ?? imported;
12
+ const service = 'gdx-doctor-probe';
13
+ const account = 'probe-' + process.pid + '-' + Date.now();
14
+ const secret = 'gdx-keychain-round-trip';
15
+ try {
16
+ await keytar.setPassword(service, account, secret);
17
+ const value = await keytar.getPassword(service, account);
18
+ if (value !== secret) throw new Error('Keychain returned an unexpected value.');
19
+ } finally {
20
+ await keytar.deletePassword(service, account).catch(() => false);
21
+ }
22
+ } else if (dependency === 'yaml') {
23
+ if (imported.parse('healthy: true').healthy !== true) throw new Error('YAML parse failed.');
24
+ } else if (dependency === 'fflate') {
25
+ const input = imported.strToU8('gdx');
26
+ if (imported.strFromU8(imported.gunzipSync(imported.gzipSync(input))) !== 'gdx') throw new Error('Compression round-trip failed.');
27
+ } else if (dependency === 'diff') {
28
+ if (!imported.diffChars('gdx', 'GDX').some((part) => part.added)) throw new Error('Diff smoke test failed.');
29
+ } else if (dependency === '@leeoniya/ufuzzy') {
30
+ const U = imported.default;
31
+ const fuzzy = new U();
32
+ if (!Array.isArray(fuzzy.filter(['gdx'], 'gdx'))) throw new Error('Fuzzy-search smoke test failed.');
33
+ } else if (dependency === 'openai') {
34
+ const OpenAI = imported.default ?? imported.OpenAI;
35
+ if (!new OpenAI({ apiKey: 'doctor-probe-key' }).chat) throw new Error('OpenAI client construction failed.');
36
+ } else if (dependency === 'cspell-lib') {
37
+ if (typeof imported.getDefaultSettings !== 'function') throw new Error('cspell settings API is unavailable.');
38
+ imported.getDefaultSettings();
39
+ } else if (dependency === '@shikijs/cli') {
40
+ if (typeof imported.codeToANSI !== 'function') throw new Error('Shiki ANSI API is unavailable.');
41
+ await imported.codeToANSI('const gdx = true', 'typescript', 'github-dark');
42
+ } else if (dependency === 'shiki') {
43
+ if (typeof imported.codeToHtml !== 'function') throw new Error('Shiki HTML API is unavailable.');
44
+ const html = await imported.codeToHtml('const gdx = true', { lang: 'typescript', theme: 'github-dark' });
45
+ if (!html.includes('<pre')) throw new Error('Syntax highlighting smoke test failed.');
46
+ } else if (!module) {
47
+ throw new Error('Imported module was empty.');
48
+ }
49
+
50
+ process.stdout.write(JSON.stringify({ ok: true, detail: 'Resolved, imported, and passed its smoke test.' }));
51
+ } catch (error) {
52
+ process.stdout.write(JSON.stringify({ ok: false, detail: error instanceof Error ? error.message : String(error) }));
53
+ }
54
+ `}export{T as runPostInstallDiagnostics};