ccdeck 3.29.11 → 3.31.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/README.md +4 -3
- package/bin/agent-dag.js +67 -118
- package/bin/cli/help.js +67 -0
- package/bin/cli/login-item.js +182 -0
- package/bin/cli/one-shot.js +254 -0
- package/bin/cli/package.js +39 -0
- package/bin/cli/pulse.js +98 -0
- package/bin/cli/restart.js +179 -0
- package/bin/cli/screen.js +166 -0
- package/bin/cli/second-start.js +120 -0
- package/bin/cli/startup.js +459 -0
- package/bin/cli/uninstall.js +169 -0
- package/bin/deck.js +112 -1559
- package/dist/web/assets/BrowserWatchModal-n63GjLhv.js +1 -0
- package/dist/web/assets/UsageHistoryModal-DEwBX4Fk.js +1 -0
- package/dist/web/assets/index-CZJf1Cpp.js +299 -0
- package/dist/web/assets/index-D4q1ElXU.css +1 -0
- package/dist/web/index.html +2 -2
- package/hook/hook.js +15 -14
- package/package.json +1 -1
- package/release-notes.json +40 -0
- package/src/server/account-projects.mjs +25 -11
- package/src/server/account-routes.mjs +254 -0
- package/src/server/activity.mjs +3 -3
- package/src/server/append-budget.mjs +185 -0
- package/src/server/append-failures.mjs +147 -0
- package/src/server/args.mjs +37 -5
- package/src/server/atomic-write.mjs +300 -0
- package/src/server/block-notify.mjs +0 -5
- package/src/server/boot-lock.mjs +1 -1
- package/src/server/brand.mjs +7 -6
- package/src/server/browser-react.mjs +10 -2
- package/src/server/browser-watch-decks.mjs +146 -0
- package/src/server/browser-watch-feed.mjs +69 -0
- package/src/server/browser-watch-log.mjs +173 -0
- package/src/server/browser-watch-mtime.mjs +18 -0
- package/src/server/browser-watch-relay.mjs +112 -0
- package/src/server/browser-watch-routes.mjs +172 -0
- package/src/server/browser-watch-seen.mjs +127 -0
- package/src/server/browser-watch-store.mjs +14 -143
- package/src/server/browser-watch.mjs +278 -626
- package/src/server/canonical-path.mjs +150 -0
- package/src/server/ccusage-failure.mjs +64 -0
- package/src/server/ccusage-install.mjs +459 -0
- package/src/server/ccusage-runner.mjs +271 -0
- package/src/server/ccusage.mjs +21 -756
- package/src/server/claude-accounts.mjs +220 -464
- package/src/server/claude-collector.mjs +189 -0
- package/src/server/claude-dir.mjs +7 -3
- package/src/server/claude-identity.mjs +5 -4
- package/src/server/claude-reset-credits.mjs +130 -0
- package/src/server/claude-verdicts.mjs +174 -0
- package/src/server/clear-route.mjs +191 -0
- package/src/server/codex-auth.mjs +4 -4
- package/src/server/codex-dir.mjs +52 -8
- package/src/server/codex-enrichment.mjs +310 -0
- package/src/server/codex-quota.mjs +5 -3
- package/src/server/codex-translate.mjs +407 -0
- package/src/server/codex-usage.mjs +8 -5
- package/src/server/codex-watch.mjs +496 -0
- package/src/server/cswap-auto-loop.mjs +342 -0
- package/src/server/cswap-auto-readers.mjs +303 -0
- package/src/server/cswap-auto.mjs +51 -609
- package/src/server/cswap-install.mjs +69 -265
- package/src/server/cswap-layout.mjs +242 -0
- package/src/server/deck-home.mjs +2 -2
- package/src/server/deck-prefs.mjs +58 -184
- package/src/server/deck-scope.mjs +52 -0
- package/src/server/desktop-update-routes.mjs +75 -0
- package/src/server/detach.mjs +78 -0
- package/src/server/discovery.mjs +298 -0
- package/src/server/event-log.mjs +328 -0
- package/src/server/event-pipeline.mjs +235 -0
- package/src/server/event-ring.mjs +214 -0
- package/src/server/event-routes.mjs +352 -0
- package/src/server/event-sink.mjs +26 -0
- package/src/server/exec-children.mjs +128 -0
- package/src/server/exec-not-found.mjs +213 -0
- package/src/server/exec-output.mjs +23 -0
- package/src/server/exec-spec.mjs +341 -0
- package/src/server/exec.mjs +74 -661
- package/src/server/health-route.mjs +42 -0
- package/src/server/hook-challenge.mjs +37 -0
- package/src/server/http-io.mjs +104 -0
- package/src/server/index.mjs +174 -7620
- package/src/server/install-layout.mjs +506 -0
- package/src/server/installer.mjs +79 -608
- package/src/server/jsonl-chunks.mjs +139 -0
- package/src/server/lan-accounts.mjs +27 -0
- package/src/server/lan-beacon.mjs +457 -0
- package/src/server/lan-call.mjs +239 -0
- package/src/server/lan-copies.mjs +270 -0
- package/src/server/lan-deck.mjs +583 -0
- package/src/server/lan-dials.mjs +161 -0
- package/src/server/lan-engine.mjs +475 -1024
- package/src/server/lan-hearing.mjs +49 -0
- package/src/server/lan-inbound.mjs +100 -0
- package/src/server/lan-invite-offer.mjs +77 -0
- package/src/server/lan-invite.mjs +207 -0
- package/src/server/lan-lines.mjs +73 -0
- package/src/server/lan-manifest.mjs +74 -0
- package/src/server/lan-reach.mjs +82 -69
- package/src/server/lan-requests.mjs +249 -0
- package/src/server/lan-round-record.mjs +45 -0
- package/src/server/lan-round-timer.mjs +62 -0
- package/src/server/lan-routes.mjs +143 -0
- package/src/server/lan-serve.mjs +112 -0
- package/src/server/lan-socket.mjs +243 -925
- package/src/server/lan-sync.mjs +58 -1026
- package/src/server/lan-tailnet-poll.mjs +57 -0
- package/src/server/lan-turns.mjs +80 -0
- package/src/server/lan-wire.mjs +620 -0
- package/src/server/lifecycle.mjs +421 -0
- package/src/server/listen.mjs +110 -0
- package/src/server/live-decks.mjs +138 -0
- package/src/server/load-average.mjs +32 -0
- package/src/server/log-election.mjs +235 -0
- package/src/server/log-replay.mjs +374 -0
- package/src/server/log-writer.mjs +72 -557
- package/src/server/login-service.mjs +3 -2
- package/src/server/macmon.mjs +1 -1
- package/src/server/memory-files.mjs +163 -0
- package/src/server/memory-metrics.mjs +178 -0
- package/src/server/metrics-history.mjs +94 -0
- package/src/server/metrics-run.mjs +100 -0
- package/src/server/music-routes.mjs +134 -0
- package/src/server/network-metrics.mjs +5 -3
- package/src/server/network-sampler.mjs +256 -0
- package/src/server/npm-latest.mjs +385 -0
- package/src/server/npm-upgrade.mjs +352 -0
- package/src/server/npx.mjs +41 -7
- package/src/server/output-watch.mjs +5 -4
- package/src/server/pinned-build.mjs +110 -0
- package/src/server/prefs-give-back.mjs +206 -0
- package/src/server/prefs-path.mjs +14 -0
- package/src/server/prefs-refusal.mjs +86 -0
- package/src/server/prefs-routes.mjs +99 -0
- package/src/server/prefs-set-aside.mjs +86 -0
- package/src/server/prefs-state.mjs +70 -0
- package/src/server/process-command.mjs +104 -0
- package/src/server/process-list.mjs +547 -0
- package/src/server/provider-status.mjs +307 -0
- package/src/server/pulse-line.mjs +132 -0
- package/src/server/purge-key.mjs +7 -7
- package/src/server/quota-cli.mjs +174 -0
- package/src/server/quota-oauth.mjs +190 -0
- package/src/server/quota-shape.mjs +229 -0
- package/src/server/quota-store-resets.mjs +206 -0
- package/src/server/quota.mjs +123 -509
- package/src/server/relay-guard.mjs +3 -3
- package/src/server/request-gates.mjs +441 -0
- package/src/server/restart-note.mjs +180 -0
- package/src/server/retire-sound-hook.mjs +3 -3
- package/src/server/ring-bounds.mjs +215 -0
- package/src/server/running-deck.mjs +1 -1
- package/src/server/running-version.mjs +24 -0
- package/src/server/self-update.mjs +39 -1371
- package/src/server/session-enrichment.mjs +622 -0
- package/src/server/session-read-gate.mjs +49 -0
- package/src/server/session-tracking.mjs +242 -0
- package/src/server/sse-clients.mjs +222 -0
- package/src/server/stale-discovery.mjs +30 -0
- package/src/server/static-serve.mjs +81 -0
- package/src/server/supervisor.mjs +73 -12
- package/src/server/system-metrics.mjs +169 -1935
- package/src/server/term.mjs +11 -249
- package/src/server/thermal-metrics.mjs +520 -0
- package/src/server/thermal-sampler.mjs +204 -0
- package/src/server/token-redact.mjs +123 -0
- package/src/server/transcript-gate.mjs +107 -0
- package/src/server/transcript-scan.mjs +563 -0
- package/src/server/usage-routes.mjs +108 -0
- package/src/server/uv-bootstrap.mjs +1 -1
- package/src/server/wordmark.mjs +127 -0
- package/dist/web/assets/BrowserWatchModal-CyAFTvAY.js +0 -1
- package/dist/web/assets/UsageHistoryModal-KJfli0oa.js +0 -1
- package/dist/web/assets/index-Ck2RAla3.css +0 -1
- package/dist/web/assets/index-jmrcEsCj.js +0 -298
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
// The one spelling of a directory the deck compares against: the
|
|
2
|
+
// `--workspace` flag, and the cwd a Codex rollout says it ran in.
|
|
3
|
+
//
|
|
4
|
+
// These lived in src/server/index.mjs, between the health payload's workspace
|
|
5
|
+
// and the Clear route. Neither touches the server: canonicalWorkspace runs once
|
|
6
|
+
// in bin/deck.js before a server exists, and canonicalCwd is a realpath the
|
|
7
|
+
// rollout watcher asks for once per file. So they moved to a leaf, unchanged,
|
|
8
|
+
// and index.mjs imports the one it calls and re-exports both under the names
|
|
9
|
+
// bin/deck.js and the tests have always imported.
|
|
10
|
+
import { realpath as realpathCb, realpathSync } from "node:fs";
|
|
11
|
+
import { resolve } from "node:path";
|
|
12
|
+
import { promisify } from "node:util";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The one spelling of `--workspace` everything downstream compares against.
|
|
16
|
+
* Empty — including a value that is nothing but spaces — stays empty, which is
|
|
17
|
+
* how every reader of it says "machine-wide".
|
|
18
|
+
*
|
|
19
|
+
* Called once, in bin/deck.js, where the flag arrives: that process's cwd is the
|
|
20
|
+
* shell the user typed the command in, and it is the only process on either
|
|
21
|
+
* capture path whose cwd is the one a relative `--workspace ./sub` was written
|
|
22
|
+
* against. The raw string used to go straight into the discovery file, and
|
|
23
|
+
* hook.js resolved it inside its own process — which the host CLI runs with the
|
|
24
|
+
* AGENT's cwd — so `--workspace ./sub` scoped Claude sessions to a `sub`
|
|
25
|
+
* directory under whatever the agent happened to be working in, a different
|
|
26
|
+
* directory per agent and none of them the one asked for. The Codex path
|
|
27
|
+
* resolved the same string in the server process and was right. Resolving here
|
|
28
|
+
* makes both of them right, and for the same reason bin/deck.js already resolves
|
|
29
|
+
* the events log before publishing it: what goes in the discovery file is read
|
|
30
|
+
* by other processes that cannot reconstruct the context it was written in.
|
|
31
|
+
*
|
|
32
|
+
* Symlinks are resolved too, so that `--workspace /tmp/proj` on a Mac is not
|
|
33
|
+
* scoped to /tmp/proj while every session inside it reports /private/tmp/proj,
|
|
34
|
+
* leaving the deck empty. A path that does not exist yet keeps its resolved form
|
|
35
|
+
* rather than failing: scoping a deck to a directory you are about to create is
|
|
36
|
+
* not an error.
|
|
37
|
+
*
|
|
38
|
+
* That resolution is only half the rule. Canonicalising the flag means nothing
|
|
39
|
+
* unless the cwd it is compared against is canonicalised the same way, and that
|
|
40
|
+
* is a separate job on each capture path: hook.js does it with normPath, and the
|
|
41
|
+
* rollout watcher does it with canonicalCwd below. This comment used to claim
|
|
42
|
+
* the second half came for free — that "a process's cwd comes from getcwd() and
|
|
43
|
+
* has none left in it" — which is true on POSIX and false on Windows. See
|
|
44
|
+
* canonicalCwd.
|
|
45
|
+
*
|
|
46
|
+
* WHICH REALPATH, AND WHY IT IS `.native` AT ALL THREE SITES. Node ships two
|
|
47
|
+
* implementations with different Windows behaviour, and picking one per site is
|
|
48
|
+
* how the flag and the two cwd paths end up meaning different things again:
|
|
49
|
+
*
|
|
50
|
+
* fs.realpathSync / fs.realpath a JavaScript lstat-and-readlink walk. It
|
|
51
|
+
* resolves symlinks and junctions and NOTHING
|
|
52
|
+
* else — a DOS 8.3 short component survives it
|
|
53
|
+
* untouched.
|
|
54
|
+
* …Sync.native / …native / the uv_fs_realpath, which on Windows is
|
|
55
|
+
* fs/promises realpath GetFinalPathNameByHandleW: symlinks and
|
|
56
|
+
* junctions, the UNC form of a mapped drive,
|
|
57
|
+
* the LONG form of an 8.3 short name, and the
|
|
58
|
+
* on-disk case of every component.
|
|
59
|
+
*
|
|
60
|
+
* The long form is the canonical one, and not by preference: it is the only
|
|
61
|
+
* spelling that is a fixed point. Short names are an alias for the same
|
|
62
|
+
* directory exactly as a junction is, they cannot be derived back from the long
|
|
63
|
+
* form (8.3 generation can be disabled per volume), and they are not a corner
|
|
64
|
+
* case a test invented — `%TEMP%` under a shortened profile directory answers
|
|
65
|
+
* with one, which is what every GitHub Windows runner has. It is also already
|
|
66
|
+
* this codebase's answer: persistAuth in src/server/codex-auth.mjs resolves
|
|
67
|
+
* through the fs/promises realpath, i.e. this one.
|
|
68
|
+
*
|
|
69
|
+
* So all three sites name `.native` explicitly rather than one of them reaching
|
|
70
|
+
* for whichever realpath came to hand. Being explicit is the point — the reason
|
|
71
|
+
* this had to be said twice is that fs/promises' realpath IS the native one
|
|
72
|
+
* while its sync namesake is not, an equivalence nothing documents and no reader
|
|
73
|
+
* should have to know.
|
|
74
|
+
*/
|
|
75
|
+
export function canonicalWorkspace(raw) {
|
|
76
|
+
if (typeof raw !== "string" || raw.trim() === "") return "";
|
|
77
|
+
const abs = resolve(raw);
|
|
78
|
+
try { return realpathSync.native(abs); } catch { return abs; }
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// The async half of the rule canonicalWorkspace states above, named the same way
|
|
82
|
+
// it is: fs.realpath.native is the documented callback form of uv_fs_realpath,
|
|
83
|
+
// and promisifying it says which realpath this is at the point of use. The
|
|
84
|
+
// fs/promises realpath is the same call and would have read as if it were the
|
|
85
|
+
// JavaScript one.
|
|
86
|
+
const realpathNative = promisify(realpathCb.native);
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* The one spelling of the directory a Codex session says it is running in —
|
|
90
|
+
* hook.js's normPath, for the capture path that never goes through the hook.
|
|
91
|
+
*
|
|
92
|
+
* `--workspace` is canonicalised above before anything compares against it, and
|
|
93
|
+
* the Claude side canonicalises the session's cwd to match: hook.js runs every
|
|
94
|
+
* incoming cwd through normPath (resolve + realpath) before asking
|
|
95
|
+
* capturesSession. The Codex side compared the rollout header's `cwd` raw, and
|
|
96
|
+
* the comment above said that was safe because a cwd comes from getcwd(), which
|
|
97
|
+
* has already resolved every link.
|
|
98
|
+
*
|
|
99
|
+
* That is true of getcwd(3) and not true of Windows. There the current directory
|
|
100
|
+
* is stored as the string it was set with, and GetCurrentDirectoryW — what
|
|
101
|
+
* Rust's std::env::current_dir() behind Codex calls — hands that string back
|
|
102
|
+
* without resolving a junction, a `subst` drive or a mapped network drive.
|
|
103
|
+
* realpath does resolve them, and on a mapped drive goes further and returns the
|
|
104
|
+
* UNC form, because libuv asks GetFinalPathNameByHandleW. So a deck started as
|
|
105
|
+
* `--workspace Z:\proj` scoped itself to `\\server\share\proj`, the Claude
|
|
106
|
+
* session in that tree reported `Z:\proj` and was realpath'd into the workspace
|
|
107
|
+
* and drawn, and the Codex session beside it reported `Z:\proj` in its rollout
|
|
108
|
+
* header, was compared raw, and silently never appeared — no error printed
|
|
109
|
+
* anywhere, the banner still claiming the rollout watcher was running. The same
|
|
110
|
+
* asymmetry runs in reverse for a user who passes the resolved path and works
|
|
111
|
+
* through the junction. The log election went wrong with it: writesCodexLog
|
|
112
|
+
* models the OTHER decks' capture with this same predicate against their
|
|
113
|
+
* published (canonical) workspaces, so it was picking the wrong group.
|
|
114
|
+
*
|
|
115
|
+
* Called at the one read of the header (readCodexHeader, in codex-watch.mjs)
|
|
116
|
+
* rather than inside codexCwdInWorkspace: the result is cached in codexFileState for
|
|
117
|
+
* the life of the file, so it costs one realpath per rollout instead of one per
|
|
118
|
+
* tick, and it leaves the predicate the pure string function that lets it be
|
|
119
|
+
* pinned against hook.js's copy in a test.
|
|
120
|
+
*
|
|
121
|
+
* `.native`, for the reason canonicalWorkspace sets out at length: three sites
|
|
122
|
+
* canonicalise a path against each other and all three must fold the same way,
|
|
123
|
+
* 8.3 short names included. Case IS canonicalised as a side effect — that is
|
|
124
|
+
* what GetFinalPathNameByHandleW and realpath(3) on a case-insensitive volume
|
|
125
|
+
* return — but nothing here DEPENDS on it: the two predicates still fold case
|
|
126
|
+
* per-platform themselves, which is the only place that decision can stay
|
|
127
|
+
* correct on Linux, where /srv/Proj and /srv/proj are two real directories and
|
|
128
|
+
* realpath quite rightly keeps them apart.
|
|
129
|
+
*
|
|
130
|
+
* Async, unlike canonicalWorkspace, because of where each one runs.
|
|
131
|
+
* canonicalWorkspace runs once in bin/deck.js before the server exists, so
|
|
132
|
+
* blocking there costs nothing. This runs inside the watcher's 1.5s tick, in the
|
|
133
|
+
* live event loop, against a path a rollout recorded some time ago — which on
|
|
134
|
+
* the very platform this exists for is quite likely to name a mapped drive that
|
|
135
|
+
* is no longer connected, and a synchronous realpath on one of those blocks the
|
|
136
|
+
* whole dashboard until SMB times out.
|
|
137
|
+
*
|
|
138
|
+
* A cwd that no longer resolves keeps its resolved form, exactly as the flag
|
|
139
|
+
* does: a deleted directory or a disconnected drive is not a reason to drop a
|
|
140
|
+
* session the deck can still draw, and the resolved string is the best answer
|
|
141
|
+
* available — for a rollout recorded in the tree the deck is scoped to and never
|
|
142
|
+
* moved, it is also the right one. Anything that is not a non-empty string is
|
|
143
|
+
* null, which is what readCodexHeader returned before and what both copies of
|
|
144
|
+
* the predicate read as "this session never said where it runs".
|
|
145
|
+
*/
|
|
146
|
+
export async function canonicalCwd(raw) {
|
|
147
|
+
if (typeof raw !== "string" || raw.trim() === "") return null;
|
|
148
|
+
const abs = resolve(raw);
|
|
149
|
+
try { return await realpathNative(abs); } catch { return abs; }
|
|
150
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// How a failed ccusage read is told, to the two audiences it has.
|
|
2
|
+
//
|
|
3
|
+
// The usage-history modal gets a `reason`, the `stage` that failed and, when it
|
|
4
|
+
// is a file of the user's, the `bin` — so it can say which path went wrong in
|
|
5
|
+
// its own words and keep the raw text one hover away. The terminal gets one
|
|
6
|
+
// line. Every module that runs or installs ccusage says what went wrong
|
|
7
|
+
// through these four, so the words stay the same whichever of them it was.
|
|
8
|
+
import { oneLine, termColumns } from "./term.mjs";
|
|
9
|
+
import { PRODUCT } from "./brand.mjs";
|
|
10
|
+
|
|
11
|
+
// A run can end four ways that mean four different things to whoever opened the
|
|
12
|
+
// modal — installs are forbidden, the deadline expired, the output was not usage
|
|
13
|
+
// data, the CLI exited on its own — and all four used to arrive as one `error`
|
|
14
|
+
// string, leaving the modal nothing to say but whatever `err.message` happened
|
|
15
|
+
// to be. The code rides on the error and comes back out as `reason`; `error`
|
|
16
|
+
// keeps the raw text, which the modal shows only on hover.
|
|
17
|
+
export function tagged(reason, message) {
|
|
18
|
+
return Object.assign(new Error(message), { reason });
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Everything the ccusage modules say out loud goes through here, and it says one
|
|
22
|
+
// line.
|
|
23
|
+
//
|
|
24
|
+
// Both failures it reports, a failed install and a failed run, carry a
|
|
25
|
+
// subprocess's entire stderr as their `message`, and on a machine whose npm
|
|
26
|
+
// shim is broken that is a fifteen-line Node stack trace. Handed to
|
|
27
|
+
// console.error whole, it landed across the deck's own status rows and its
|
|
28
|
+
// `\r`-repainted pulse line — and because primeCcusage runs at boot, it was
|
|
29
|
+
// the first thing such a machine ever showed (#432). The evidence
|
|
30
|
+
// is not lost by shortening this: a failed RUN carries its full text back to
|
|
31
|
+
// the browser in `error`, which the usage-history modal keeps on the status
|
|
32
|
+
// line's title, one hover away — the same division of labour admin-failure.ts
|
|
33
|
+
// states for claude-swap's output. What this line is for is the operator
|
|
34
|
+
// watching the terminal, who needs to know which of the two things failed and
|
|
35
|
+
// why, not to read a stack.
|
|
36
|
+
//
|
|
37
|
+
// The width is read per call: a terminal can be resized while the deck runs,
|
|
38
|
+
// and this can fire hours in.
|
|
39
|
+
export function note(what, err) {
|
|
40
|
+
const head = `${PRODUCT} ccusage: ${what}: `;
|
|
41
|
+
console.error(head + oneLine(err?.message ?? err, termColumns(process.stderr) - head.length));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Which of ccusage's three paths a failure came from, in the deck's own words.
|
|
45
|
+
* `stage` travels to the browser; the modal leads with it rather than making
|
|
46
|
+
* the reader guess from a stack trace which path they are looking at. */
|
|
47
|
+
const STAGE = { node: "managed", path: "path", npx: "npx" };
|
|
48
|
+
|
|
49
|
+
/** Mark a failure with the path that produced it, and with the managed
|
|
50
|
+
* install's own account when that is why this path was taken at all. Set once:
|
|
51
|
+
* runCcusage's retry re-stamps with the runner that actually failed, and an
|
|
52
|
+
* error that already knows where it came from is not overwritten. */
|
|
53
|
+
export function stamp(err, runner) {
|
|
54
|
+
if (err && typeof err === "object") {
|
|
55
|
+
if (!err.stage) err.stage = STAGE[runner?.kind] ?? "npx";
|
|
56
|
+
// Which file, when the answer is a file the deck did not put there. The
|
|
57
|
+
// stage alone says "your own copy failed" and leaves the reader to work out
|
|
58
|
+
// WHICH copy, and on a machine with an override, a PATH entry and a managed
|
|
59
|
+
// install that is exactly the question they cannot answer from here.
|
|
60
|
+
if (runner?.kind === "path" && err.bin === undefined) err.bin = runner.file;
|
|
61
|
+
if (runner?.installError && err.install === undefined) err.install = runner.installError;
|
|
62
|
+
}
|
|
63
|
+
return err;
|
|
64
|
+
}
|