pi-checkup 0.1.0 → 0.1.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/README.md +26 -25
- package/package.json +1 -1
- package/src/checks/binaries.js +26 -10
- package/src/checks/config.js +5 -2
package/README.md
CHANGED
|
@@ -77,9 +77,10 @@ Packages
|
|
|
77
77
|
Binaries
|
|
78
78
|
✓ dangling links 19 links all resolve
|
|
79
79
|
· shadowed names no package command resolved on PATH
|
|
80
|
-
|
|
81
|
-
pi
|
|
82
|
-
pi-
|
|
80
|
+
· unreachable bins 6 package command(s) live in
|
|
81
|
+
/root/.pi/agent/npm/node_modules/.bin, which is not on
|
|
82
|
+
PATH: pi-web-access-mcp, pi-subagents, pi-mcp-adapter,
|
|
83
|
+
pi-lens, pi-lens-mcp, pi-lens-analyze
|
|
83
84
|
Network
|
|
84
85
|
✓ providers 2 endpoint(s) reachable
|
|
85
86
|
✓ dns 1 provider host(s) resolve normally
|
|
@@ -94,20 +95,20 @@ Config
|
|
|
94
95
|
Runtime
|
|
95
96
|
✓ node v22.23.3
|
|
96
97
|
✓ pi launcher /root/.pi/agent/bin/pi
|
|
97
|
-
✓ disk 6% used on /, 950.
|
|
98
|
+
✓ disk 6% used on /, 950.4 GB free
|
|
98
99
|
✓ proxy http://127.0.0.1:10808 accepting connections
|
|
99
100
|
|
|
100
|
-
19 checks: 14 ok,
|
|
101
|
+
19 checks: 14 ok, 0 warnings, 0 failed, 5 skipped
|
|
101
102
|
Run `npx pi-checkup --verbose` to show what to do about each finding.
|
|
102
103
|
|
|
103
|
-
|
|
104
|
+
✓ 14 ok, 5 skipped · run /checkup inside Pi for registry checks
|
|
104
105
|
```
|
|
105
106
|
|
|
106
107
|
Both captures below and above come from a real machine, taken with pi-checkup 0.1.0; free space, Node versions and which packages are installed are properties of that machine, not of the tool, and the row counts grow when checks are added.
|
|
107
108
|
|
|
108
109
|
## Real output
|
|
109
110
|
|
|
110
|
-
This is an actual run on a working install, copied out of the TUI at 80 columns — not a mock-up. The two `Network` rows describe the moment it ran; everything else is a property of the install. 20 of 24 checks pass
|
|
111
|
+
This is an actual run on a working install, copied out of the TUI at 80 columns — not a mock-up. The two `Network` rows describe the moment it ran; everything else is a property of the install. 20 of 24 checks pass and the other four are skipped because there is genuinely nothing to look at: no live registry to audit, no project-level settings, no `$VAR` credentials, and no package command on `PATH` to compare. Nothing warns, which is the point — the package commands live in a `.bin` directory Pi never adds to `PATH`, that is Pi's own layout rather than a fault, and the row says so instead of putting a permanent amber mark on a healthy install.
|
|
111
112
|
|
|
112
113
|
```text
|
|
113
114
|
Registry
|
|
@@ -126,9 +127,10 @@ Packages
|
|
|
126
127
|
Binaries
|
|
127
128
|
✓ dangling links 19 links all resolve
|
|
128
129
|
· shadowed names no package command resolved on PATH
|
|
129
|
-
|
|
130
|
-
pi
|
|
131
|
-
pi-
|
|
130
|
+
· unreachable bins 6 package command(s) live in
|
|
131
|
+
/root/.pi/agent/npm/node_modules/.bin, which is not on
|
|
132
|
+
PATH: pi-web-access-mcp, pi-subagents, pi-mcp-adapter,
|
|
133
|
+
pi-lens, pi-lens-mcp, pi-lens-analyze
|
|
132
134
|
Network
|
|
133
135
|
✓ providers 2 endpoint(s) reachable
|
|
134
136
|
✓ dns 1 provider host(s) resolve normally
|
|
@@ -143,10 +145,10 @@ Config
|
|
|
143
145
|
Runtime
|
|
144
146
|
✓ node v22.23.3
|
|
145
147
|
✓ pi launcher /root/.pi/agent/bin/pi
|
|
146
|
-
✓ disk 6% used on /, 950.
|
|
148
|
+
✓ disk 6% used on /, 950.4 GB free
|
|
147
149
|
✓ proxy http://127.0.0.1:10808 accepting connections
|
|
148
150
|
|
|
149
|
-
24 checks: 20 ok,
|
|
151
|
+
24 checks: 20 ok, 0 warnings, 0 failed, 4 skipped
|
|
150
152
|
Run `/checkup verbose` to show what to do about each finding.
|
|
151
153
|
```
|
|
152
154
|
|
|
@@ -179,7 +181,7 @@ The `attribution` row is the part no other tool gives you: which package owns wh
|
|
|
179
181
|
| | Install leftovers | `.<name>-<random>` staging links in `.bin`: an install is running right now, or was interrupted. Its own finding, not a broken package |
|
|
180
182
|
| | Missing shims | The package declares a `bin` but npm never linked it into `.bin` — usually an install run with `--ignore-scripts` |
|
|
181
183
|
| | Shadowed names | A package's command name resolves to an unrelated program earlier on `PATH`. Skipped when no declared command resolved at all: there is nothing to compare, and a green tick there would sit next to a row saying the commands are missing |
|
|
182
|
-
| | Unreachable bins | A package ships a CLI
|
|
184
|
+
| | Unreachable bins | A package ships a CLI that is not reachable by name. A `skip` when `.bin` itself is not on `PATH` — that is Pi's own layout and Pi calls these by full path — and a warning only when the directory *is* on `PATH` and the command still did not resolve, which points at PATH order or an unreadable link |
|
|
183
185
|
| **Network** | Endpoint reachability | Probes `<baseUrl>/models` for every provider. `401`/`403` counts as alive — this never validates your key and never spends tokens. An endpoint that answers with something other than life — a refused connection, a rejected certificate, an HTTP error — is a failure, and fails the run; only a probe that was cut off locally by its own timeout stays a warning, because the deadline is this process's, not the endpoint's |
|
|
184
186
|
| | Cleartext auth | A provider on `http://` to another machine with a credential configured — an `apiKey`, a password embedded in the `baseUrl`, a credential-named header value, or a query string, which cannot be inspected for secrets. The `apiKey` and `baseUrl` credentials are withheld from the probe; a query string is never sent, so that endpoint is reported unprobed. Loopback hosts are exempt |
|
|
185
187
|
| | baseUrl shape | A `baseUrl` that is not a string or an object. A string that is not a URL — including the `localhost:11434/v1` paste with no scheme — is reported as an unhealthy provider, and also named in this row, because the endpoint is what would have to be probed |
|
|
@@ -214,18 +216,17 @@ A repair that rewrites `settings.json` re-serialises it with two-space indentati
|
|
|
214
216
|
|
|
215
217
|
## Ignoring a finding you have decided to live with
|
|
216
218
|
|
|
217
|
-
Some
|
|
219
|
+
Some findings are correct and permanent: a gateway you deliberately reach over plain `http` on your own network, a package installed with `--ignore-scripts` whose links you do not want. A health check you have learned to ignore is worse than no health check, so rows can be suppressed by name.
|
|
218
220
|
|
|
219
221
|
```bash
|
|
220
|
-
PI_CHECKUP_IGNORE=
|
|
222
|
+
PI_CHECKUP_IGNORE=Network:cleartext npx pi-checkup
|
|
221
223
|
```
|
|
222
224
|
|
|
223
|
-
Each entry matches a row's `id`, its `Group:id` form, or its title. A suppressed row is downgraded to `skip`, keeps its original detail, and says what it replaced
|
|
225
|
+
Each entry matches a row's `id`, its `Group:id` form, or its title. A suppressed row is downgraded to `skip`, keeps its original detail, and says what it replaced — here from a scratch install with one provider deliberately configured over plain `http`:
|
|
224
226
|
|
|
225
227
|
```text
|
|
226
|
-
·
|
|
227
|
-
|
|
228
|
-
pi-mcp-adapter, pi-lens, pi-lens-mcp, pi-lens-analyze
|
|
228
|
+
· cleartext auth ignored via PI_CHECKUP_IGNORE (would be warn): gw use
|
|
229
|
+
http:// with credentials configured
|
|
229
230
|
```
|
|
230
231
|
|
|
231
232
|
Suppression is never silent, and it drops the row's repair offer so a hidden finding cannot be fixed behind your back. It applies to failures too: a suppressed `fail` no longer affects the exit code, which is the point of the variable — use it for a state you have decided to accept, not to turn a red build green. Export it from your shell profile if you want it to apply inside Pi too.
|
|
@@ -239,9 +240,9 @@ Suppression is never silent, and it drops the row's repair offer so a hidden fin
|
|
|
239
240
|
"summary": {
|
|
240
241
|
"total": 24,
|
|
241
242
|
"ok": 20,
|
|
242
|
-
"warn":
|
|
243
|
+
"warn": 0,
|
|
243
244
|
"fail": 0,
|
|
244
|
-
"skip":
|
|
245
|
+
"skip": 4
|
|
245
246
|
},
|
|
246
247
|
"version": "0.1.0",
|
|
247
248
|
"node": "22.23.3",
|
|
@@ -251,9 +252,9 @@ Suppression is never silent, and it drops the row's repair offer so a hidden fin
|
|
|
251
252
|
"group": "Binaries",
|
|
252
253
|
"id": "unreachable",
|
|
253
254
|
"title": "unreachable bins",
|
|
254
|
-
"status": "
|
|
255
|
-
"detail": "6 package command(s) not on PATH: pi-web-access-mcp, pi-subagents, pi-mcp-adapter, pi-lens, pi-lens-mcp, pi-lens-analyze",
|
|
256
|
-
"hint": "Pi
|
|
255
|
+
"status": "skip",
|
|
256
|
+
"detail": "6 package command(s) live in /root/.pi/agent/npm/node_modules/.bin, which is not on PATH: pi-web-access-mcp, pi-subagents, pi-mcp-adapter, pi-lens, pi-lens-mcp, pi-lens-analyze",
|
|
257
|
+
"hint": "Pi calls these by full path, so an extension that uses them still works. Add /root/.pi/agent/npm/node_modules/.bin to PATH only if you want to run them by name."
|
|
257
258
|
},
|
|
258
259
|
{
|
|
259
260
|
"group": "Config",
|
|
@@ -268,7 +269,7 @@ Suppression is never silent, and it drops the row's repair offer so a hidden fin
|
|
|
268
269
|
|
|
269
270
|
The `checks` array always has one entry per row of the text report, in the same order. The excerpt above omits the other 22 entries; real output is printed by `JSON.stringify(payload, null, 2)`.
|
|
270
271
|
|
|
271
|
-
Exit-worthy statuses are `fail`; `warn` means something needs attention without by itself failing the run —
|
|
272
|
+
Exit-worthy statuses are `fail`; `warn` means something needs attention without by itself failing the run — an `apiKey` that no HTTP request can carry, or a credential on a plain-`http` endpoint. Repair metadata is stripped from the JSON payload.
|
|
272
273
|
|
|
273
274
|
## Design principles
|
|
274
275
|
|
package/package.json
CHANGED
package/src/checks/binaries.js
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
exists,
|
|
13
13
|
isMissing,
|
|
14
14
|
isWindows,
|
|
15
|
+
normalizePath,
|
|
15
16
|
readJson,
|
|
16
17
|
resolvePackageDir,
|
|
17
18
|
sameCommand,
|
|
@@ -334,20 +335,35 @@ export async function run({ settings, settingsLoaded = true, agentDir: root, bin
|
|
|
334
335
|
);
|
|
335
336
|
|
|
336
337
|
if (unreachable.length) {
|
|
338
|
+
// Is the .bin directory itself on PATH? Pi's default install does not add
|
|
339
|
+
// it, and Pi resolves package binaries by full path — so "unreachable"
|
|
340
|
+
// there is the layout, not a fault. Reporting it as a warning put a
|
|
341
|
+
// permanent amber row on every healthy install and taught the reader to
|
|
342
|
+
// skip the group that is supposed to mean something. It stays a warning
|
|
343
|
+
// only where the directory *is* on PATH and the command still did not
|
|
344
|
+
// resolve, which points at PATH order or an unreadable shim.
|
|
345
|
+
const wanted = normalizePath(binDir);
|
|
346
|
+
const binDirOnPath =
|
|
347
|
+
Boolean(wanted) &&
|
|
348
|
+
String(env.PATH ?? env.Path ?? env.path ?? "")
|
|
349
|
+
.split(path.delimiter)
|
|
350
|
+
.filter(Boolean)
|
|
351
|
+
.some((dir) => normalizePath(dir) === wanted);
|
|
352
|
+
const listed = names(unreachable, 6);
|
|
337
353
|
results.push({
|
|
338
354
|
group,
|
|
339
355
|
id: "unreachable",
|
|
340
356
|
title: "unreachable bins",
|
|
341
|
-
status: "warn",
|
|
342
|
-
detail:
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
//
|
|
346
|
-
//
|
|
347
|
-
//
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
357
|
+
status: binDirOnPath ? "warn" : "skip",
|
|
358
|
+
detail: binDirOnPath
|
|
359
|
+
? `${unreachable.length} package command(s) did not resolve even though ${binDir} is on PATH: ${listed}`
|
|
360
|
+
: `${unreachable.length} package command(s) live in ${binDir}, which is not on PATH: ${listed}`,
|
|
361
|
+
// The file exists — it is just not reachable — so the fix is the
|
|
362
|
+
// directory, not a reinstall. Without this the row reads as "something is
|
|
363
|
+
// broken" with no way to tell what to do about it.
|
|
364
|
+
hint: binDirOnPath
|
|
365
|
+
? "The directory is on PATH, so a different program answers first or the link cannot be read. Check the order of PATH entries and the link's permissions."
|
|
366
|
+
: `Pi calls these by full path, so an extension that uses them still works. Add ${binDir} to PATH only if you want to run them by name.`,
|
|
351
367
|
});
|
|
352
368
|
}
|
|
353
369
|
|
package/src/checks/config.js
CHANGED
|
@@ -155,9 +155,12 @@ export async function run({
|
|
|
155
155
|
: `${backedUp} file(s) backed up`,
|
|
156
156
|
{
|
|
157
157
|
// The named path is the point: "copy it somewhere safe" with no `it` left
|
|
158
|
-
// the reader to work out which file the paragraph was about.
|
|
158
|
+
// the reader to work out which file the paragraph was about. The count of
|
|
159
|
+
// backups is not claimed: "both backups are older" was hardcoded and
|
|
160
|
+
// wrong as soon as one file was stale and the other was not — and a
|
|
161
|
+
// file may have any number of backups.
|
|
159
162
|
hint: stale.length
|
|
160
|
-
? `The
|
|
163
|
+
? `The newest backup of ${stale.join(" and ")} predates the current file${stale.length > 1 ? "s" : ""}, so restoring it would discard the edits made since. Copy ${stale
|
|
161
164
|
.map((label) => files.find((f) => f.label === label)?.file ?? label)
|
|
162
165
|
.join(" and ")} somewhere you can restore from before the next edit.`
|
|
163
166
|
: undefined,
|