@sunilaleti/hx 1.1.0 → 1.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/CHANGELOG.md +16 -1
- package/README.md +3 -3
- package/dist/hx.js +28 -13
- package/dist/hx.js.map +2 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -28,6 +28,20 @@ the project follows [semantic versioning](https://semver.org/).
|
|
|
28
28
|
|
|
29
29
|
---
|
|
30
30
|
|
|
31
|
+
## [1.1.1] - 2026-10-31
|
|
32
|
+
|
|
33
|
+
### Fixed
|
|
34
|
+
|
|
35
|
+
- HTTPS failed on macOS for every host - OpenRouter, ChatGPT, Tavily, npm - with "unable to get
|
|
36
|
+
local issuer certificate". HX verified against the OS trust store alone, and on macOS Node reads
|
|
37
|
+
only the certificates trusted by hand there, not the system roots. HX now trusts Node's own
|
|
38
|
+
roots and the OS store together, so a corporate CA in the keychain still works.
|
|
39
|
+
- A certificate HX will not accept is reported with what to do about it - add the CA to the
|
|
40
|
+
system trust store or set `HX_CA_BUNDLE` - instead of Node's advice to restart it with
|
|
41
|
+
`--use-system-ca`, and is not retried: another attempt meets the same certificate.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
31
45
|
## [1.1.0] - 2026-10-31
|
|
32
46
|
|
|
33
47
|
### Added
|
|
@@ -1123,7 +1137,8 @@ First release, published to PyPI as [`hx-cli`](https://pypi.org/project/hx-cli/)
|
|
|
1123
1137
|
- `/configure` and `hx auth` for the OpenRouter key, `hx upgrade` for
|
|
1124
1138
|
self-update, and `install.sh` bootstrapping uv with a pinned Python.
|
|
1125
1139
|
|
|
1126
|
-
[Unreleased]: https://github.com/aletisunil/hx/compare/v1.1.
|
|
1140
|
+
[Unreleased]: https://github.com/aletisunil/hx/compare/v1.1.1...HEAD
|
|
1141
|
+
[1.1.1]: https://github.com/aletisunil/hx/compare/v1.1.0...v1.1.1
|
|
1127
1142
|
[1.1.0]: https://github.com/aletisunil/hx/compare/v1.0.0...v1.1.0
|
|
1128
1143
|
[1.0.0]: https://github.com/aletisunil/hx/compare/v0.3.0-beta.1...v1.0.0
|
|
1129
1144
|
[0.3.0-beta.1]: https://github.com/aletisunil/hx/compare/v0.2.20...v0.3.0-beta.1
|
package/README.md
CHANGED
|
@@ -293,9 +293,9 @@ number.
|
|
|
293
293
|
Credits are *not* in the status bar's cost, which prices tokens: `/cost`
|
|
294
294
|
under-reports a session that searched.
|
|
295
295
|
|
|
296
|
-
**Behind a TLS-inspecting proxy.** HX verifies certificates against
|
|
297
|
-
operating system's trust store, so a corporate CA the
|
|
298
|
-
needs no setup. When the CA lives only in a file, name it:
|
|
296
|
+
**Behind a TLS-inspecting proxy.** HX verifies certificates against Node's own
|
|
297
|
+
roots and the operating system's trust store together, so a corporate CA the
|
|
298
|
+
machine already trusts needs no setup. When the CA lives only in a file, name it:
|
|
299
299
|
|
|
300
300
|
```sh
|
|
301
301
|
export HX_CA_BUNDLE=/path/to/corp-ca.pem # SSL_CERT_FILE and REQUESTS_CA_BUNDLE also work
|
package/dist/hx.js
CHANGED
|
@@ -534,10 +534,8 @@ function tlsAgentOptions() {
|
|
|
534
534
|
const bundle = caBundle();
|
|
535
535
|
let ca;
|
|
536
536
|
if (bundle !== null) ca = certificates(readText(bundle));
|
|
537
|
-
else
|
|
538
|
-
ca = tls.getCACertificates("system");
|
|
539
|
-
if (ca.length === 0) ca = tls.getCACertificates("default");
|
|
540
|
-
}
|
|
537
|
+
else
|
|
538
|
+
ca = [.../* @__PURE__ */ new Set([...tls.getCACertificates("default"), ...tls.getCACertificates("system")])];
|
|
541
539
|
tlsOptions = { ca, ALPNProtocols: ["http/1.1"] };
|
|
542
540
|
}
|
|
543
541
|
return tlsOptions;
|
|
@@ -582,12 +580,10 @@ function withTlsHint(message2) {
|
|
|
582
580
|
return `${rstrip(rstrip(message2), ".")}. ${hint2}`;
|
|
583
581
|
}
|
|
584
582
|
function describe(error) {
|
|
583
|
+
const certificate = certificateFailure(error);
|
|
584
|
+
if (certificate !== null) return certificate;
|
|
585
585
|
for (const err of chain(error)) {
|
|
586
586
|
const code2 = err.code ?? "";
|
|
587
|
-
if (VERIFY_CODES.has(code2)) {
|
|
588
|
-
const reason = flatten(err.message || "certificate verify failed");
|
|
589
|
-
return `TLS certificate verification failed (${reason}). ${tlsHint(reason)}`;
|
|
590
|
-
}
|
|
591
587
|
if (code2.startsWith("ERR_SSL") || code2.startsWith("ERR_TLS")) {
|
|
592
588
|
return `TLS handshake failed: ${flatten(err.message)}.`;
|
|
593
589
|
}
|
|
@@ -599,6 +595,19 @@ function describe(error) {
|
|
|
599
595
|
const failure2 = error;
|
|
600
596
|
return withTlsHint(`${failure2?.name ?? "Error"}: ${flatten(String(failure2?.message ?? error))}`);
|
|
601
597
|
}
|
|
598
|
+
function certificateFailure(error) {
|
|
599
|
+
for (const err of chain(error)) {
|
|
600
|
+
if (!VERIFY_CODES.has(err.code ?? "")) continue;
|
|
601
|
+
const reason = flatten(
|
|
602
|
+
(err.message || "certificate verify failed").replace(
|
|
603
|
+
/;\s*if the root CA[\s\S]*$/,
|
|
604
|
+
""
|
|
605
|
+
)
|
|
606
|
+
);
|
|
607
|
+
return `TLS certificate verification failed (${reason}). ${tlsHint(reason)}`;
|
|
608
|
+
}
|
|
609
|
+
return null;
|
|
610
|
+
}
|
|
602
611
|
function chain(error) {
|
|
603
612
|
const seen = [];
|
|
604
613
|
let current = error;
|
|
@@ -1725,11 +1734,17 @@ function streamEnd(stopReason, fields = {}) {
|
|
|
1725
1734
|
planWindows: fields.planWindows ?? []
|
|
1726
1735
|
};
|
|
1727
1736
|
}
|
|
1737
|
+
function unreached(error) {
|
|
1738
|
+
const certificate = certificateFailure(error);
|
|
1739
|
+
if (certificate !== null) return new ProviderError(certificate);
|
|
1740
|
+
return new ProviderError(error.message, { retryable: true });
|
|
1741
|
+
}
|
|
1728
1742
|
var delta, ProviderError;
|
|
1729
1743
|
var init_base = __esm({
|
|
1730
1744
|
"src/providers/base.ts"() {
|
|
1731
1745
|
"use strict";
|
|
1732
1746
|
init_usage();
|
|
1747
|
+
init_net();
|
|
1733
1748
|
delta = (fields) => ({
|
|
1734
1749
|
kind: "delta",
|
|
1735
1750
|
...fields
|
|
@@ -3288,7 +3303,7 @@ var init_openrouter = __esm({
|
|
|
3288
3303
|
});
|
|
3289
3304
|
} catch (error) {
|
|
3290
3305
|
if (signal.aborted) throw error;
|
|
3291
|
-
throw
|
|
3306
|
+
throw unreached(error);
|
|
3292
3307
|
}
|
|
3293
3308
|
try {
|
|
3294
3309
|
if (response.status >= 400) {
|
|
@@ -7190,7 +7205,7 @@ async function unaryCall(baseUrl, path, body, operation, timeout = 600, signal)
|
|
|
7190
7205
|
[status3, payload] = await post(`${baseUrl}${path}`, body, UNARY_HEADERS, timeout, signal);
|
|
7191
7206
|
} catch (error) {
|
|
7192
7207
|
if (signal?.aborted) throw error;
|
|
7193
|
-
throw
|
|
7208
|
+
throw unreached(error);
|
|
7194
7209
|
}
|
|
7195
7210
|
if (status3 >= 400) throw httpError(operation, status3, payload);
|
|
7196
7211
|
return payload;
|
|
@@ -7486,7 +7501,7 @@ var init_devin2 = __esm({
|
|
|
7486
7501
|
});
|
|
7487
7502
|
} catch (error) {
|
|
7488
7503
|
if (signal.aborted) throw error;
|
|
7489
|
-
throw
|
|
7504
|
+
throw unreached(error);
|
|
7490
7505
|
}
|
|
7491
7506
|
try {
|
|
7492
7507
|
if (response.status >= 400) {
|
|
@@ -67733,7 +67748,7 @@ init_net();
|
|
|
67733
67748
|
init_py();
|
|
67734
67749
|
|
|
67735
67750
|
// src/version.ts
|
|
67736
|
-
var VERSION = "1.1.
|
|
67751
|
+
var VERSION = "1.1.1";
|
|
67737
67752
|
var PACKAGE = "@sunilaleti/hx";
|
|
67738
67753
|
|
|
67739
67754
|
// src/providers/codex.ts
|
|
@@ -67805,7 +67820,7 @@ var CodexProvider = class {
|
|
|
67805
67820
|
});
|
|
67806
67821
|
} catch (error) {
|
|
67807
67822
|
if (signal.aborted) throw error;
|
|
67808
|
-
throw
|
|
67823
|
+
throw unreached(error);
|
|
67809
67824
|
}
|
|
67810
67825
|
const windows = planWindows(response.headers);
|
|
67811
67826
|
try {
|