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 +21 -21
- package/README.md +142 -20
- package/dist/diagnostics/postinstall.validator.js +54 -0
- package/dist/index.js +757 -723
- package/package.json +24 -9
- package/scripts/launcher.cjs +52 -29
- package/scripts/postinstall.cjs +210 -36
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
|
|
21
|
-
- **🛡️ Safety:** `gdx clear` wipes
|
|
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
|
|
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
|
|
134
|
-
gdx sta
|
|
135
|
-
gdx statu
|
|
136
|
-
gdx lg
|
|
137
|
-
gdx
|
|
138
|
-
gdx ps -fl
|
|
139
|
-
gdx
|
|
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
|
|
159
|
+
### 3. The Safety Net
|
|
159
160
|
|
|
160
|
-
We've all accidentally
|
|
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
|
|
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
|
|
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.
|
|
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
|
+

|
|
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
|
|
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
|
-
###
|
|
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
|
|
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
|
-
| `
|
|
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
|
-
- [
|
|
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};
|