@theappagency/valinor 0.9.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 ADDED
@@ -0,0 +1,27 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Camber–The App Agency
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
+ NOTE: This license covers the LAUNCHER ONLY (the contents of this package).
16
+ The Valinor CLI bundle this launcher downloads and executes is PROPRIETARY
17
+ software of Camber–The App Agency, licensed separately under the terms shipped
18
+ inside the bundle (see the LICENSE file within the downloaded artifact). This
19
+ MIT grant conveys no rights to the downloaded bundle.
20
+
21
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,38 @@
1
+ # @theappagency/valinor
2
+
3
+ The public launcher for the **Valinor CLI** — Camber's CI-native quality-governance tool.
4
+
5
+ ```sh
6
+ npx @theappagency/valinor@latest --version
7
+ npx @theappagency/valinor@0.10.0 claims-verify claims.yml
8
+ ```
9
+
10
+ The launcher is **trivial by design** and contains no Valinor functionality itself. On each run it:
11
+
12
+ 1. resolves the requested version against the Valinor downloads endpoint
13
+ (`https://downloads.valinorci.com/manifest.json`) — the launcher's own version pins the bundle
14
+ version (the pipeline publishes them in lockstep), so `@theappagency/valinor@X.Y.Z` runs Valinor `X.Y.Z`;
15
+ 2. fetches the version's bundle (`/v/<version>/valinor.tgz`) and **verifies its SHA-256 against the
16
+ published `SHA256SUMS`, failing closed** — a mismatched artifact is deleted, never executed;
17
+ 3. caches the verified bundle at `~/.valinor/cache/<version>/` — an already-cached, exactly-pinned
18
+ version runs **fully offline** with no network I/O;
19
+ 4. executes the cached CLI, passing through all arguments and the exit code.
20
+
21
+ No npm registry auth, no `.npmrc`, no tokens, no secrets — `npx` it anywhere, including CI.
22
+ **The launcher sends no telemetry.** Its only network activity is fetching the artifact above.
23
+
24
+ ## Environment variables
25
+
26
+ | Variable | Effect |
27
+ | --- | --- |
28
+ | `VALINOR_VERSION` | Run a specific version or dist-tag (e.g. `0.10.0`, `latest`), overriding the launcher's own pinned version. |
29
+ | `VALINOR_DOWNLOADS_URL` | Override the downloads endpoint base URL (staging/fixtures). |
30
+ | `VALINOR_CACHE_DIR` | Override the cache location (default `~/.valinor/cache`). |
31
+ | `VALINOR_FETCH_TIMEOUT_MS` | Per-request fetch timeout in milliseconds (default `30000`) — a silent/blackholed endpoint aborts here rather than hanging. |
32
+ | `VALINOR_LAUNCHER_DEBUG` | Print full error causes (default output is the actionable message only). |
33
+
34
+ ## Licensing
35
+
36
+ This launcher is MIT-licensed. **The Valinor CLI bundle it downloads is proprietary software of
37
+ Camber–The App Agency**, licensed under the terms shipped inside the downloaded artifact (the
38
+ `LICENSE` file in the bundle). Installing this launcher conveys no rights to the bundle.
package/bin/valinor.js ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ // The launcher bin: delegate to lib/launcher.js and render its loud, actionable errors without a
3
+ // stack trace (the cause chain is preserved on the error for VALINOR_LAUNCHER_DEBUG=1 diagnosis).
4
+ import { run } from "../lib/launcher.js";
5
+
6
+ try {
7
+ process.exitCode = await run(process.argv.slice(2));
8
+ } catch (e) {
9
+ console.error(`valinor launcher: ${e instanceof Error ? e.message : String(e)}`);
10
+ if (process.env.VALINOR_LAUNCHER_DEBUG) console.error(e);
11
+ process.exitCode = 1;
12
+ }
@@ -0,0 +1,257 @@
1
+ // The Valinor launcher — the trivial-BY-DESIGN public half of the zero-secret distribution model
2
+ // (task #130 Phase 1). It contains NO secret sauce: it resolves a version against the downloads
3
+ // endpoint's manifest, fetches the proprietary bundle, VERIFIES ITS SHA-256 FAIL-CLOSED, caches it
4
+ // at ~/.valinor/cache/<version>/, and spawns the cached CLI with argv + exit code passed through —
5
+ // preserving `npx valinor@X.Y.Z <cmd>` semantics with zero npm auth, zero .npmrc, zero secrets.
6
+ //
7
+ // Design constraints (deliberate):
8
+ // • ZERO runtime dependencies — nothing to audit, nothing to resolve from any registry.
9
+ // • NO TELEMETRY — the launcher reports nothing anywhere; only the artifact fetch itself.
10
+ // • Fail closed on integrity: a checksum mismatch DELETES the download and refuses to run.
11
+ // • Offline-friendly: an exactly-pinned, already-cached version runs with NO network at all;
12
+ // only a dist-tag (`latest`) needs the manifest.
13
+ // • Loud, actionable degradation: an unreachable endpoint names the URL it tried AND the local
14
+ // cache state (what versions could still run offline) — never a bare stack trace.
15
+ import { execFileSync, spawnSync } from "node:child_process";
16
+ import { createHash, randomBytes } from "node:crypto";
17
+ import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
18
+ import { homedir } from "node:os";
19
+ import { join } from "node:path";
20
+ import { fileURLToPath } from "node:url";
21
+
22
+ /** The production downloads endpoint (override with VALINOR_DOWNLOADS_URL — staging/fixtures/tests). */
23
+ export const DEFAULT_DOWNLOADS_URL = "https://downloads.valinorci.com";
24
+
25
+ const SEMVER_RE = /^\d+\.\d+\.\d+(-[0-9A-Za-z.-]+)?$/;
26
+
27
+ /** The endpoint base URL, env-overridable, without a trailing slash. */
28
+ export function downloadsUrl(env = process.env) {
29
+ return (env.VALINOR_DOWNLOADS_URL || DEFAULT_DOWNLOADS_URL).replace(/\/+$/, "");
30
+ }
31
+
32
+ /** The local cache root, env-overridable (tests point it at a temp dir). */
33
+ export function cacheRoot(env = process.env) {
34
+ return env.VALINOR_CACHE_DIR || join(homedir(), ".valinor", "cache");
35
+ }
36
+
37
+ /**
38
+ * The version this launcher requests: VALINOR_VERSION (exact version or dist-tag) wins, else the
39
+ * launcher's OWN package version — the release pipeline publishes the launcher in LOCKSTEP with each
40
+ * bundle, so `npx @theappagency/valinor@0.9.1` runs bundle 0.9.1 (the `valinor@X.Y.Z` semantics preserved).
41
+ * A dev/unpublished launcher (version 0.0.0) defaults to the `latest` dist-tag.
42
+ */
43
+ export function requestedVersion(env = process.env) {
44
+ if (env.VALINOR_VERSION) return env.VALINOR_VERSION;
45
+ const own = JSON.parse(readFileSync(fileURLToPath(new URL("../package.json", import.meta.url)), "utf8")).version;
46
+ return own === "0.0.0" ? "latest" : own;
47
+ }
48
+
49
+ /** The versions present in the local cache (complete installs only), newest-ish last. Never throws. */
50
+ export function cachedVersions(root) {
51
+ try {
52
+ return readdirSync(root)
53
+ .filter((name) => SEMVER_RE.test(name) && existsSync(join(root, name, ".complete")))
54
+ .sort();
55
+ } catch (e) {
56
+ // ENOENT only = "no cache dir yet" — a genuinely empty cache. Anything else (EACCES, EIO, …)
57
+ // is a REAL problem the user should see; swallowing it silently would misreport the offline
58
+ // hint as "nothing cached". It is still non-fatal here (this function only feeds diagnostics —
59
+ // rethrowing would mask the primary error being rendered), so: warn loudly, return empty.
60
+ if (e?.code !== "ENOENT") {
61
+ console.error(`valinor launcher: warning — could not read the cache at ${root} (${e?.code ?? e}); treating it as empty`);
62
+ }
63
+ return [];
64
+ }
65
+ }
66
+
67
+ /**
68
+ * Resolve a requested version (exact semver or dist-tag) against the endpoint manifest. Pure.
69
+ * Throws a descriptive error when the version is absent — which is exactly how a RETRACTED bundle
70
+ * presents (retraction is server-side deletion; the launcher must refuse, loudly, not fall back).
71
+ */
72
+ export function resolveVersion(manifest, requested) {
73
+ const versions = Array.isArray(manifest?.versions) ? manifest.versions : null;
74
+ const distTags = manifest?.distTags;
75
+ if (!versions || typeof distTags !== "object" || distTags === null) {
76
+ throw new Error("the downloads manifest is malformed (expected { versions: [...], distTags: {...} })");
77
+ }
78
+ if (SEMVER_RE.test(requested)) {
79
+ if (versions.includes(requested)) return requested;
80
+ throw new Error(
81
+ `version ${requested} is not available from the downloads endpoint (it may have been retracted). Available: ${versions.join(", ") || "(none)"}`,
82
+ );
83
+ }
84
+ const tagged = distTags[requested];
85
+ if (typeof tagged === "string" && SEMVER_RE.test(tagged)) return tagged;
86
+ throw new Error(
87
+ `unknown version or dist-tag ${JSON.stringify(requested)}. Tags: ${Object.keys(distTags).join(", ") || "(none)"}; versions: ${versions.join(", ") || "(none)"}`,
88
+ );
89
+ }
90
+
91
+ /**
92
+ * Parse a sha256sum-format SHA256SUMS body and return the hex digest recorded for `filename`.
93
+ * Throws when the file carries no entry for it (fail closed — never "skip verification").
94
+ */
95
+ export function parseSha256Sums(text, filename) {
96
+ for (const line of String(text).split("\n")) {
97
+ const m = line.trim().match(/^([0-9a-f]{64})\s+\*?(.+)$/i);
98
+ if (m && m[2].trim() === filename) return m[1].toLowerCase();
99
+ }
100
+ throw new Error(`SHA256SUMS carries no entry for ${filename} — refusing to run an unverifiable artifact`);
101
+ }
102
+
103
+ /**
104
+ * The per-request timeout (ms): a firewalled/blackholed endpoint that ACCEPTS a connection but never
105
+ * replies must fail LOUDLY in seconds, not hang forever. Reads the supplied env (NOT a hard-coded
106
+ * `process.env` — `run()` threads its own env through so a caller/test override actually engages).
107
+ * Default 30s; tests dial it down to prove the abort fires.
108
+ */
109
+ export function fetchTimeoutMs(env = process.env) {
110
+ const parsed = Number(env.VALINOR_FETCH_TIMEOUT_MS);
111
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : 30_000;
112
+ }
113
+
114
+ /**
115
+ * GET a URL, throwing a loud error naming the URL on any non-200, TIMEOUT, or network failure.
116
+ * `timeoutMs` is REQUIRED (resolved once by the caller from its env) — passing it explicitly is what
117
+ * fixes the bug where `fetchTimeoutMs()` read the ambient `process.env` and a `run(args, env)`
118
+ * override was silently dropped. A timed-out abort surfaces as `TimeoutError`, named in the message.
119
+ */
120
+ async function fetchOrThrow(url, fetchImpl, timeoutMs) {
121
+ let res;
122
+ try {
123
+ res = await (fetchImpl ?? fetch)(url, { redirect: "follow", signal: AbortSignal.timeout(timeoutMs) });
124
+ } catch (e) {
125
+ // AbortSignal.timeout rejects with a DOMException named "TimeoutError" — surface that distinctly
126
+ // so the failure reads as "timed out after Nms", not an opaque cause code.
127
+ const cause =
128
+ e?.name === "TimeoutError"
129
+ ? `timed out after ${timeoutMs}ms`
130
+ : (e?.cause?.code ?? e?.code ?? (e instanceof Error ? e.message : String(e)));
131
+ throw new Error(`could not reach ${url} (${cause})`, { cause: e });
132
+ }
133
+ if (!res.ok) throw new Error(`${url} returned HTTP ${res.status}`);
134
+ return res;
135
+ }
136
+
137
+ /** Fetch + validate the endpoint manifest. `timeoutMs` is threaded from the caller's env. */
138
+ export async function fetchManifest(base, fetchImpl, timeoutMs = fetchTimeoutMs()) {
139
+ const res = await fetchOrThrow(`${base}/manifest.json`, fetchImpl, timeoutMs);
140
+ return res.json();
141
+ }
142
+
143
+ /**
144
+ * Ensure `version` is present + verified in the cache; returns the cache dir for that version.
145
+ * Cache HIT (a completed prior install) is served with NO network I/O. On a miss: download the
146
+ * tarball AND its SHA256SUMS, recompute the digest, and FAIL CLOSED on mismatch (the partial
147
+ * download is deleted; nothing executable is left behind). The verified tarball is extracted into
148
+ * a temp dir and atomically renamed into place, so a crashed install can never half-populate a
149
+ * version dir that a later run would trust.
150
+ */
151
+ export async function ensureVersion(base, version, root, fetchImpl, timeoutMs = fetchTimeoutMs()) {
152
+ const versionDir = join(root, version);
153
+ if (existsSync(join(versionDir, ".complete"))) return versionDir; // cache hit — zero network.
154
+
155
+ const tarballUrl = `${base}/v/${version}/valinor.tgz`;
156
+ const [tarballRes, sumsRes] = await Promise.all([
157
+ fetchOrThrow(tarballUrl, fetchImpl, timeoutMs),
158
+ fetchOrThrow(`${base}/v/${version}/SHA256SUMS`, fetchImpl, timeoutMs),
159
+ ]);
160
+ const tarball = Buffer.from(await tarballRes.arrayBuffer());
161
+ const expected = parseSha256Sums(await sumsRes.text(), "valinor.tgz");
162
+ const actual = createHash("sha256").update(tarball).digest("hex");
163
+ if (actual !== expected) {
164
+ throw new Error(
165
+ `SHA-256 MISMATCH for ${tarballUrl}: expected ${expected}, got ${actual}. ` +
166
+ "Refusing to run — the artifact may have been tampered with or corrupted in transit. Nothing was cached.",
167
+ );
168
+ }
169
+
170
+ const stagingDir = join(root, `.tmp-${version}-${randomBytes(6).toString("hex")}`);
171
+ mkdirSync(stagingDir, { recursive: true });
172
+ try {
173
+ const tgzPath = join(stagingDir, "valinor.tgz");
174
+ writeFileSync(tgzPath, tarball);
175
+ // `tar` ships with every supported platform (incl. Windows 10+'s bsdtar); using it (rather than
176
+ // npm) keeps the install registry-free and auth-free by construction.
177
+ execFileSync("tar", ["-xzf", tgzPath, "-C", stagingDir]);
178
+ rmSync(tgzPath);
179
+ writeFileSync(join(stagingDir, ".complete"), `${expected}\n`);
180
+ try {
181
+ renameSync(stagingDir, versionDir);
182
+ } catch (e) {
183
+ if (existsSync(join(versionDir, ".complete"))) return versionDir; // lost a concurrent race — theirs is verified too.
184
+ throw e;
185
+ }
186
+ } catch (e) {
187
+ rmSync(stagingDir, { recursive: true, force: true });
188
+ throw e;
189
+ }
190
+ return versionDir;
191
+ }
192
+
193
+ /** The cached CLI's entry path, read from the artifact package.json's `bin` (never hard-coded). */
194
+ export function cachedBinPath(versionDir) {
195
+ const pkg = JSON.parse(readFileSync(join(versionDir, "package", "package.json"), "utf8"));
196
+ const bin = typeof pkg.bin === "string" ? pkg.bin : pkg.bin?.valinor;
197
+ if (!bin) throw new Error(`the cached artifact at ${versionDir} declares no runnable bin — the cache may be corrupt; delete it and retry`);
198
+ return join(versionDir, "package", bin);
199
+ }
200
+
201
+ /** Spawn the cached CLI with argv passed through; returns its exit code (stdio inherited). */
202
+ export function spawnCli(binPath, args) {
203
+ const result = spawnSync(process.execPath, [binPath, ...args], { stdio: "inherit" });
204
+ if (result.error) throw result.error;
205
+ if (result.signal) {
206
+ process.kill(process.pid, result.signal); // propagate the signal-death faithfully (Ctrl-C etc.).
207
+ return 1; // unreachable in practice; a safe fallback if the signal is ignored.
208
+ }
209
+ return result.status ?? 1;
210
+ }
211
+
212
+ /**
213
+ * The end-to-end run: resolve → ensure cached+verified → spawn → return the CLI's exit code.
214
+ * Network is touched ONLY when needed (a dist-tag resolution, or a cache miss). Throws the loud,
215
+ * actionable errors above; the bin wrapper renders them.
216
+ */
217
+ export async function run(args, env = process.env) {
218
+ const base = downloadsUrl(env);
219
+ const root = cacheRoot(env);
220
+ const requested = requestedVersion(env);
221
+ // Resolve the timeout ONCE from THIS call's env (the bug fix — `fetchOrThrow` used to read the
222
+ // ambient process.env, so a `run(args, env)` override never engaged) and thread it into every fetch.
223
+ const timeoutMs = fetchTimeoutMs(env);
224
+
225
+ let version;
226
+ if (SEMVER_RE.test(requested)) {
227
+ version = requested; // exact pin — resolvable (and runnable, if cached) without the manifest.
228
+ } else {
229
+ let manifest;
230
+ try {
231
+ manifest = await fetchManifest(base, undefined, timeoutMs);
232
+ } catch (e) {
233
+ throw new Error(`${e instanceof Error ? e.message : String(e)}\n${offlineHint(base, root)}`, { cause: e });
234
+ }
235
+ version = resolveVersion(manifest, requested);
236
+ }
237
+
238
+ let versionDir;
239
+ try {
240
+ versionDir = await ensureVersion(base, version, root, undefined, timeoutMs);
241
+ } catch (e) {
242
+ const msg = e instanceof Error ? e.message : String(e);
243
+ // Integrity failures are terminal as-is; reachability failures get the offline hint.
244
+ throw new Error(msg.includes("SHA-256 MISMATCH") ? msg : `${msg}\n${offlineHint(base, root)}`, { cause: e });
245
+ }
246
+ return spawnCli(cachedBinPath(versionDir), args);
247
+ }
248
+
249
+ /** The actionable degradation message: name the endpoint + the offline cache state. */
250
+ function offlineHint(base, root) {
251
+ const cached = cachedVersions(root);
252
+ const cacheLine =
253
+ cached.length > 0
254
+ ? `Cached versions available OFFLINE at ${root}: ${cached.join(", ")} — pin one to run without the network (e.g. VALINOR_VERSION=${cached[cached.length - 1]} or npx @theappagency/valinor@${cached[cached.length - 1]}).`
255
+ : `No versions are cached locally at ${root}, so nothing can run offline.`;
256
+ return `The Valinor downloads endpoint (${base}) is unreachable or missing the requested artifact.\n${cacheLine}\nIf this persists, check https://downloads.valinorci.com and your network/proxy configuration.`;
257
+ }
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "@theappagency/valinor",
3
+ "version": "0.9.0",
4
+ "description": "Public launcher for the Valinor CLI — fetches, SHA-256-verifies, caches, and runs the proprietary Valinor bundle from downloads.valinorci.com. Zero setup, zero secrets, zero npm auth.",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/cmbrcreative/valinor.git",
8
+ "directory": "launcher"
9
+ },
10
+ "type": "module",
11
+ "bin": {
12
+ "valinor": "bin/valinor.js"
13
+ },
14
+ "files": [
15
+ "bin",
16
+ "lib"
17
+ ],
18
+ "engines": {
19
+ "node": ">=24"
20
+ },
21
+ "license": "MIT",
22
+ "publishConfig": {
23
+ "registry": "https://registry.npmjs.org",
24
+ "access": "public"
25
+ },
26
+ "scripts": {
27
+ "test": "cd .. && npx vitest run launcher/test"
28
+ }
29
+ }