@promptctl/cc-candybar 1.41.3 → 1.42.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 +4 -0
- package/dist/index.mjs +80 -79
- package/package.json +5 -5
- package/src/cli-flags.ts +8 -0
- package/src/daemon/client-stats.ts +1 -0
- package/src/daemon/stats.ts +8 -2
- package/src/help-text.ts +3 -1
- package/src/index.ts +15 -5
- package/src/install/currency.ts +197 -0
- package/src/install/index.ts +18 -7
- package/src/version.ts +17 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@promptctl/cc-candybar",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.42.1",
|
|
4
4
|
"description": "Statusline renderer for Claude Code — a JSON5-configurable DSL with daemon-cached data sources, byte-clean palette-aware composition, and OSC8 click verbs.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.mjs",
|
|
@@ -91,9 +91,9 @@
|
|
|
91
91
|
"mobx": "^6.15.0"
|
|
92
92
|
},
|
|
93
93
|
"optionalDependencies": {
|
|
94
|
-
"@promptctl/cc-candybar-darwin-arm64": "1.
|
|
95
|
-
"@promptctl/cc-candybar-darwin-x64": "1.
|
|
96
|
-
"@promptctl/cc-candybar-linux-x64": "1.
|
|
97
|
-
"@promptctl/cc-candybar-linux-arm64": "1.
|
|
94
|
+
"@promptctl/cc-candybar-darwin-arm64": "1.42.1",
|
|
95
|
+
"@promptctl/cc-candybar-darwin-x64": "1.42.1",
|
|
96
|
+
"@promptctl/cc-candybar-linux-x64": "1.42.1",
|
|
97
|
+
"@promptctl/cc-candybar-linux-arm64": "1.42.1"
|
|
98
98
|
}
|
|
99
99
|
}
|
package/src/cli-flags.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// [LAW:one-source-of-truth] The bare flags Node answers itself. The dispatch in
|
|
2
|
+
// index.ts reads it, `--help` renders its own lines from it, and the Rust client
|
|
3
|
+
// routes exactly these to Node (its NODE_FLAGS; check-protocol diffs the two),
|
|
4
|
+
// so a spelling added here without its mirror fails the build, not the user.
|
|
5
|
+
export const NODE_FLAGS = {
|
|
6
|
+
help: ["-h", "--help"],
|
|
7
|
+
version: ["-V", "--version"],
|
|
8
|
+
} as const;
|
|
@@ -64,6 +64,7 @@ export function formatStats(s: StatsSnapshot): string {
|
|
|
64
64
|
lines.push(`process`);
|
|
65
65
|
lines.push(` pid ${s.pid}`);
|
|
66
66
|
lines.push(` version ${s.version}`);
|
|
67
|
+
lines.push(` protocol ${s.protocolVersion}`);
|
|
67
68
|
lines.push(` startedAt ${s.startedAt}`);
|
|
68
69
|
lines.push(` uptime ${fmtUptime(s.uptimeSec)}`);
|
|
69
70
|
lines.push(` rss ${fmtBytes(s.rssBytes)}`);
|
package/src/daemon/stats.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import type { LaunchCategory } from "../proc/launch";
|
|
6
6
|
import type { LaunchStatsHandle } from "../proc/stats-handle";
|
|
7
7
|
import { PROTOCOL_VERSION } from "./protocol";
|
|
8
|
+
import { PACKAGE_VERSION } from "../version";
|
|
8
9
|
|
|
9
10
|
// Rolling window for "last minute" counts. Keep timestamps for each launch in
|
|
10
11
|
// a ring buffer; eviction happens lazily on read.
|
|
@@ -28,7 +29,11 @@ const HISTOGRAM_CAP = 16;
|
|
|
28
29
|
|
|
29
30
|
export interface StatsSnapshot {
|
|
30
31
|
pid: number;
|
|
31
|
-
|
|
32
|
+
// [LAW:one-source-of-truth] The daemon's own baked package stamp — set
|
|
33
|
+
// against `cc-candybar --version` to diagnose client-vs-daemon skew in one
|
|
34
|
+
// step. The wire contract number is a different fact under its own name.
|
|
35
|
+
version: string;
|
|
36
|
+
protocolVersion: number;
|
|
32
37
|
startedAt: string;
|
|
33
38
|
uptimeSec: number;
|
|
34
39
|
rssBytes: number;
|
|
@@ -199,7 +204,8 @@ export class RuntimeStats {
|
|
|
199
204
|
const mem = process.memoryUsage();
|
|
200
205
|
return {
|
|
201
206
|
pid: process.pid,
|
|
202
|
-
version:
|
|
207
|
+
version: PACKAGE_VERSION,
|
|
208
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
203
209
|
startedAt: this.startedAt.toISOString(),
|
|
204
210
|
uptimeSec: Math.floor((Date.now() - this.startedAt.getTime()) / 1000),
|
|
205
211
|
rssBytes: mem.rss,
|
package/src/help-text.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { DISCLOSURE_GLYPH_CLOSED } from "./config/disclosure";
|
|
2
2
|
import { HELP_GLYPH_CLOSED } from "./config/help";
|
|
3
|
+
import { NODE_FLAGS } from "./cli-flags";
|
|
3
4
|
|
|
4
5
|
// [LAW:effects-at-boundaries] Pure data, no I/O — index.ts owns the console.log
|
|
5
6
|
// effect. Kept as its own module so the text is importable (and testable) without
|
|
@@ -36,7 +37,8 @@ cc-candybar - Beautiful powerline statusline for Claude Code
|
|
|
36
37
|
Usage: cc-candybar [options]
|
|
37
38
|
|
|
38
39
|
Standalone Commands:
|
|
39
|
-
|
|
40
|
+
${NODE_FLAGS.help.join(", ").padEnd(25)}Show this help
|
|
41
|
+
${NODE_FLAGS.version.join(", ").padEnd(25)}Print the version of this runtime (cc-candybar <version>)
|
|
40
42
|
|
|
41
43
|
Debugging:
|
|
42
44
|
CC_CANDYBAR_DEBUG=1 Enable debug logging for troubleshooting
|
package/src/index.ts
CHANGED
|
@@ -16,6 +16,8 @@ import { runCheck } from "./check";
|
|
|
16
16
|
import { obtainDaemonKick } from "./daemon/acquire";
|
|
17
17
|
import { planOutcome } from "./render/outcome-plan";
|
|
18
18
|
import { HELP_TEXT } from "./help-text";
|
|
19
|
+
import { NODE_FLAGS } from "./cli-flags";
|
|
20
|
+
import { PACKAGE_VERSION } from "./version";
|
|
19
21
|
|
|
20
22
|
// Read terminal width from the live shell context (no subprocess). Returns
|
|
21
23
|
// undefined when nothing reliable is available; the daemon falls back to its
|
|
@@ -52,6 +54,9 @@ function detectTermCols(): number | undefined {
|
|
|
52
54
|
// widen recall of a fact that is otherwise reported as a plain `false`.
|
|
53
55
|
const SSH_ENV_VARS = ["SSH_CONNECTION", "SSH_CLIENT", "SSH_TTY"] as const;
|
|
54
56
|
|
|
57
|
+
const hasFlag = (flags: readonly string[]): boolean =>
|
|
58
|
+
flags.some((f) => process.argv.includes(f));
|
|
59
|
+
|
|
55
60
|
// [LAW:dataflow-not-control-flow] A fold over the vocabulary, not a chain of
|
|
56
61
|
// ifs — adding a name is a data edit.
|
|
57
62
|
//
|
|
@@ -69,20 +74,25 @@ function showHelpText(): void {
|
|
|
69
74
|
|
|
70
75
|
async function main(): Promise<void> {
|
|
71
76
|
try {
|
|
72
|
-
|
|
73
|
-
process.argv.includes("--help") || process.argv.includes("-h");
|
|
74
|
-
|
|
75
|
-
if (showHelp) {
|
|
77
|
+
if (hasFlag(NODE_FLAGS.help)) {
|
|
76
78
|
showHelpText();
|
|
77
79
|
process.exit(0);
|
|
78
80
|
}
|
|
81
|
+
// [LAW:one-type-per-behavior] Answers "what is THIS binary" from the baked
|
|
82
|
+
// stamp alone — never a daemon probe, which would fail exactly when the
|
|
83
|
+
// flag is most needed (no working daemon). Daemon skew is the stats
|
|
84
|
+
// snapshot's `version` field.
|
|
85
|
+
if (hasFlag(NODE_FLAGS.version)) {
|
|
86
|
+
console.log(`cc-candybar ${PACKAGE_VERSION}`);
|
|
87
|
+
process.exit(0);
|
|
88
|
+
}
|
|
79
89
|
|
|
80
90
|
// [LAW:dataflow-not-control-flow] Subcommand dispatch is data: argv[2]
|
|
81
91
|
// selects the handler. Each handler short-circuits via process.exit().
|
|
82
92
|
// Default fallthrough = the existing stdin-driven render flow.
|
|
83
93
|
const subcommand = process.argv[2];
|
|
84
94
|
if (subcommand === "install") {
|
|
85
|
-
runInstall(process.argv.slice(3));
|
|
95
|
+
await runInstall(process.argv.slice(3));
|
|
86
96
|
process.exit(0);
|
|
87
97
|
}
|
|
88
98
|
if (subcommand === "install-url-handler") {
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
// Is the runtime `install` just staged the newest published release? pnpm
|
|
2
|
+
// resolves `@latest` through its dlx cache and its release-age gate
|
|
3
|
+
// (`minimumReleaseAge`), either of which can hand back an older release with
|
|
4
|
+
// no error — so `pnpm dlx @promptctl/cc-candybar@latest install` can stage a
|
|
5
|
+
// version several releases behind and report success. This module answers the
|
|
6
|
+
// currency question as data: a strict version parser at the border, the
|
|
7
|
+
// registry lookup as an `Outcome`, one total fold into a `Currency`, and one
|
|
8
|
+
// formatter that describes the report for `runInstall` to perform.
|
|
9
|
+
|
|
10
|
+
import { ABSENT, failed, type Outcome } from "../utils/outcome";
|
|
11
|
+
|
|
12
|
+
// [LAW:types-are-the-program] A release version is exactly MAJOR.MINOR.PATCH.
|
|
13
|
+
// semantic-release on `main` mints nothing else, and the ordering the currency
|
|
14
|
+
// verdict needs is total only over that shape — so the parser refuses anything
|
|
15
|
+
// else rather than admitting a prerelease it could not order.
|
|
16
|
+
export type Version = readonly [major: number, minor: number, patch: number];
|
|
17
|
+
|
|
18
|
+
const RELEASE_VERSION = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/;
|
|
19
|
+
|
|
20
|
+
// A parse either produces a value or fails with a reason; "absent" is not a
|
|
21
|
+
// shape text can have.
|
|
22
|
+
type Parsed<T> = Exclude<Outcome<T>, { kind: "absent" }>;
|
|
23
|
+
|
|
24
|
+
// [LAW:parse-dont-validate] The one crossing from text to `Version`. Both the
|
|
25
|
+
// baked stamp and the registry's dist-tag pass through here; downstream code
|
|
26
|
+
// takes `Version` and never re-checks the shape. The failure is typed, not
|
|
27
|
+
// thrown: on either side it flows into the `unchecked` verdict, so the
|
|
28
|
+
// advisory check can never take the install down with it.
|
|
29
|
+
export function parseReleaseVersion(text: string): Parsed<Version> {
|
|
30
|
+
const m = RELEASE_VERSION.exec(text);
|
|
31
|
+
return m
|
|
32
|
+
? { kind: "ok", value: [Number(m[1]), Number(m[2]), Number(m[3])] }
|
|
33
|
+
: {
|
|
34
|
+
kind: "failed",
|
|
35
|
+
reason: `"${text}" is not a release version (expected MAJOR.MINOR.PATCH)`,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function formatVersion(v: Version): string {
|
|
40
|
+
return v.join(".");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Lexicographic over the triple: the first differing component decides.
|
|
44
|
+
function compareVersions(
|
|
45
|
+
[aMajor, aMinor, aPatch]: Version,
|
|
46
|
+
[bMajor, bMinor, bPatch]: Version,
|
|
47
|
+
): number {
|
|
48
|
+
return aMajor - bMajor || aMinor - bMinor || aPatch - bPatch;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export const REGISTRY_URL = "https://registry.npmjs.org";
|
|
52
|
+
|
|
53
|
+
// The check rides at the end of an install; it may not hang one. A registry
|
|
54
|
+
// that answers slower than this is reported as unreachable, not waited on.
|
|
55
|
+
export const REGISTRY_TIMEOUT_MS = 5_000;
|
|
56
|
+
|
|
57
|
+
// [LAW:effects-at-boundaries] The one network effect in the install path. It
|
|
58
|
+
// takes `fetch` as a parameter so the pure core above and the tests never
|
|
59
|
+
// touch the wire; the caller hands in the global. Every way the lookup can
|
|
60
|
+
// fail to answer — refused, timed out, non-2xx, unparseable body, dist-tag not
|
|
61
|
+
// a release — collapses to `failed` with its reason preserved, and a registry
|
|
62
|
+
// that lists no `latest` tag at all is `absent`. [LAW:no-silent-failure] None
|
|
63
|
+
// of those is ever reported as "current".
|
|
64
|
+
export async function fetchLatestVersion(
|
|
65
|
+
packageName: string,
|
|
66
|
+
fetchImpl: typeof fetch,
|
|
67
|
+
): Promise<Outcome<Version>> {
|
|
68
|
+
const url = `${REGISTRY_URL}/-/package/${encodeURIComponent(packageName)}/dist-tags`;
|
|
69
|
+
try {
|
|
70
|
+
const res = await fetchImpl(url, {
|
|
71
|
+
signal: AbortSignal.timeout(REGISTRY_TIMEOUT_MS),
|
|
72
|
+
});
|
|
73
|
+
if (!res.ok) {
|
|
74
|
+
return failed(`registry responded ${res.status} for ${url}`);
|
|
75
|
+
}
|
|
76
|
+
const tags = (await res.json()) as { latest?: unknown };
|
|
77
|
+
if (typeof tags.latest !== "string") {
|
|
78
|
+
return ABSENT;
|
|
79
|
+
}
|
|
80
|
+
return parseReleaseVersion(tags.latest);
|
|
81
|
+
} catch (err) {
|
|
82
|
+
return failed(err instanceof Error ? err.message : String(err));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// [LAW:types-are-the-program] The verdict. `unchecked` is its own arm rather
|
|
87
|
+
// than a `current` with a flag: an install that could not compare has no
|
|
88
|
+
// currency, and no consumer may read it as having one. It carries the stamp
|
|
89
|
+
// as text because the stamp itself may be what failed to parse.
|
|
90
|
+
export type Currency =
|
|
91
|
+
| { readonly kind: "current"; readonly installed: Version }
|
|
92
|
+
| {
|
|
93
|
+
readonly kind: "stale";
|
|
94
|
+
readonly installed: Version;
|
|
95
|
+
readonly latest: Version;
|
|
96
|
+
}
|
|
97
|
+
| {
|
|
98
|
+
readonly kind: "ahead";
|
|
99
|
+
readonly installed: Version;
|
|
100
|
+
readonly latest: Version;
|
|
101
|
+
}
|
|
102
|
+
| {
|
|
103
|
+
readonly kind: "unchecked";
|
|
104
|
+
readonly installed: string;
|
|
105
|
+
readonly reason: string;
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
// [LAW:dataflow-not-control-flow] One total fold: the stamp, the lookup
|
|
109
|
+
// outcome, and the version ordering all flow in as values, and every
|
|
110
|
+
// combination lands in exactly one arm.
|
|
111
|
+
export function assessCurrency(
|
|
112
|
+
stamp: string,
|
|
113
|
+
latest: Outcome<Version>,
|
|
114
|
+
): Currency {
|
|
115
|
+
const installed = parseReleaseVersion(stamp);
|
|
116
|
+
if (installed.kind === "failed") {
|
|
117
|
+
return { kind: "unchecked", installed: stamp, reason: installed.reason };
|
|
118
|
+
}
|
|
119
|
+
switch (latest.kind) {
|
|
120
|
+
case "failed":
|
|
121
|
+
return { kind: "unchecked", installed: stamp, reason: latest.reason };
|
|
122
|
+
case "absent":
|
|
123
|
+
return {
|
|
124
|
+
kind: "unchecked",
|
|
125
|
+
installed: stamp,
|
|
126
|
+
reason: "the registry lists no `latest` dist-tag",
|
|
127
|
+
};
|
|
128
|
+
case "ok": {
|
|
129
|
+
const order = compareVersions(installed.value, latest.value);
|
|
130
|
+
if (order < 0) {
|
|
131
|
+
return {
|
|
132
|
+
kind: "stale",
|
|
133
|
+
installed: installed.value,
|
|
134
|
+
latest: latest.value,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
if (order > 0) {
|
|
138
|
+
return {
|
|
139
|
+
kind: "ahead",
|
|
140
|
+
installed: installed.value,
|
|
141
|
+
latest: latest.value,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
return { kind: "current", installed: installed.value };
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// A description of the report, not the report itself: `runInstall` owns the
|
|
150
|
+
// write. Warnings go to stderr, confirmations to stdout — the CLI's stream
|
|
151
|
+
// contract, so a scripted install can separate the two.
|
|
152
|
+
export interface CurrencyReport {
|
|
153
|
+
readonly stream: "stdout" | "stderr";
|
|
154
|
+
readonly text: string;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// [LAW:no-silent-failure] The stale arm names the cause and the exact command
|
|
158
|
+
// that gets the current release now; the unchecked arm says the check was
|
|
159
|
+
// skipped and why, and never implies the install is current.
|
|
160
|
+
export function currencyReport(
|
|
161
|
+
packageName: string,
|
|
162
|
+
currency: Currency,
|
|
163
|
+
): CurrencyReport {
|
|
164
|
+
switch (currency.kind) {
|
|
165
|
+
case "current":
|
|
166
|
+
return {
|
|
167
|
+
stream: "stdout",
|
|
168
|
+
text: `✓ cc-candybar ${formatVersion(currency.installed)} is the latest release.\n`,
|
|
169
|
+
};
|
|
170
|
+
case "ahead":
|
|
171
|
+
return {
|
|
172
|
+
stream: "stdout",
|
|
173
|
+
text:
|
|
174
|
+
`cc-candybar ${formatVersion(currency.installed)} is newer than the registry's latest release ` +
|
|
175
|
+
`(${formatVersion(currency.latest)}): an unpublished build.\n`,
|
|
176
|
+
};
|
|
177
|
+
case "stale": {
|
|
178
|
+
const latest = formatVersion(currency.latest);
|
|
179
|
+
return {
|
|
180
|
+
stream: "stderr",
|
|
181
|
+
text:
|
|
182
|
+
`⚠ cc-candybar ${formatVersion(currency.installed)} was staged, but the latest release is ${latest}.\n` +
|
|
183
|
+
` pnpm's release-age gate (minimumReleaseAge) and its dlx cache can both\n` +
|
|
184
|
+
` resolve \`@latest\` to an older release without saying so.\n` +
|
|
185
|
+
` To install ${latest} now, name it explicitly:\n` +
|
|
186
|
+
` pnpm dlx ${packageName}@${latest} install\n`,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
case "unchecked":
|
|
190
|
+
return {
|
|
191
|
+
stream: "stderr",
|
|
192
|
+
text:
|
|
193
|
+
`⚠ Could not check for a cc-candybar release newer than ${currency.installed} ` +
|
|
194
|
+
`(${currency.reason}); the registry check was skipped.\n`,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
}
|
package/src/install/index.ts
CHANGED
|
@@ -8,12 +8,8 @@ import type { PermanentOutcome } from "../daemon/client-transport";
|
|
|
8
8
|
import { obtainDaemonKick } from "../daemon/acquire";
|
|
9
9
|
import { URL_SCHEME, VERB_COPY } from "../click/wire";
|
|
10
10
|
import { DISCLOSURE_GLYPH_CLOSED } from "../config/disclosure";
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
// from package.json — the single version stamp install output reports.
|
|
14
|
-
declare const __PACKAGE_VERSION__: string;
|
|
15
|
-
const PACKAGE_VERSION =
|
|
16
|
-
typeof __PACKAGE_VERSION__ !== "undefined" ? __PACKAGE_VERSION__ : "dev";
|
|
11
|
+
import { PACKAGE_VERSION } from "../version";
|
|
12
|
+
import { assessCurrency, currencyReport, fetchLatestVersion } from "./currency";
|
|
17
13
|
|
|
18
14
|
const PACKAGE_NAME = "@promptctl/cc-candybar";
|
|
19
15
|
const BUNDLE_ID = "com.cccandybar.url-handler";
|
|
@@ -456,7 +452,7 @@ function installSuccessMessage(): string {
|
|
|
456
452
|
);
|
|
457
453
|
}
|
|
458
454
|
|
|
459
|
-
export function runInstall(rendererArgs: string[]): void {
|
|
455
|
+
export async function runInstall(rendererArgs: string[]): Promise<void> {
|
|
460
456
|
const force = rendererArgs.includes("--force");
|
|
461
457
|
const filteredArgs = rendererArgs.filter((a) => a !== "--force");
|
|
462
458
|
|
|
@@ -476,6 +472,21 @@ export function runInstall(rendererArgs: string[]): void {
|
|
|
476
472
|
updateClaudeSettings(staged.binPath, argsToInstall, force);
|
|
477
473
|
|
|
478
474
|
process.stdout.write(installSuccessMessage());
|
|
475
|
+
|
|
476
|
+
// Last: a stale-version warning is the final thing on screen, and the
|
|
477
|
+
// lookup starts only after the synchronous work above — spawnSync blocks
|
|
478
|
+
// the event loop, so a fetch started earlier could not progress and would
|
|
479
|
+
// burn its timeout budget idle. [LAW:no-ambient-temporal-coupling] The
|
|
480
|
+
// staged runtime works either way; the verdict informs, it never fails the
|
|
481
|
+
// install. [LAW:no-silent-failure]
|
|
482
|
+
const report = currencyReport(
|
|
483
|
+
PACKAGE_NAME,
|
|
484
|
+
assessCurrency(
|
|
485
|
+
PACKAGE_VERSION,
|
|
486
|
+
await fetchLatestVersion(PACKAGE_NAME, fetch),
|
|
487
|
+
),
|
|
488
|
+
);
|
|
489
|
+
process[report.stream].write(report.text);
|
|
479
490
|
}
|
|
480
491
|
|
|
481
492
|
function updateClaudeSettings(
|
package/src/version.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// [LAW:one-source-of-truth] THE version stamp of this runtime. package.json is
|
|
2
|
+
// the sole authority: tsdown's `define` bakes it into the bundle, and
|
|
3
|
+
// scripts/version-stamp.cjs preloads it for untranspiled source. Every consumer
|
|
4
|
+
// — `--version`, the install banner, the daemon's stats snapshot — reads this
|
|
5
|
+
// one export.
|
|
6
|
+
declare const __PACKAGE_VERSION__: string;
|
|
7
|
+
|
|
8
|
+
// [LAW:no-silent-failure] A runtime that cannot say what it is must say THAT.
|
|
9
|
+
// The old `"dev"` fallback was an answer-shaped void in a flag whose whole job
|
|
10
|
+
// is answering this question; an unsubstituted build now fails at module load.
|
|
11
|
+
if (typeof __PACKAGE_VERSION__ === "undefined") {
|
|
12
|
+
throw new Error(
|
|
13
|
+
"__PACKAGE_VERSION__ was not substituted: build via tsdown (define), or preload scripts/version-stamp.cjs when running source",
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const PACKAGE_VERSION: string = __PACKAGE_VERSION__;
|