agent-shim 8.21.0 → 8.22.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 +1 -0
- package/dist/cli.cjs +764 -376
- package/dist/index.cjs +43 -16
- package/dist/index.mjs +43 -16
- package/dist/types/index.d.ts +8 -8
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -10577,6 +10577,17 @@ function bearerOf(headers) {
|
|
|
10577
10577
|
}
|
|
10578
10578
|
return presented.slice(0, "bearer ".length).toLowerCase() === "bearer " ? presented.slice("bearer ".length) : void 0;
|
|
10579
10579
|
}
|
|
10580
|
+
function presentationRefusal(headers) {
|
|
10581
|
+
const presented = singleHeader2(headers, "authorization");
|
|
10582
|
+
if (presented === void 0) {
|
|
10583
|
+
return "absent";
|
|
10584
|
+
}
|
|
10585
|
+
if (presented.slice(0, "bearer ".length).toLowerCase() !== "bearer ") {
|
|
10586
|
+
return "not-a-bearer";
|
|
10587
|
+
}
|
|
10588
|
+
const bearer = presented.slice("bearer ".length);
|
|
10589
|
+
return bearer.slice(0, "bearer ".length).toLowerCase() === "bearer " ? "doubled-scheme-word" : "unrecognised";
|
|
10590
|
+
}
|
|
10580
10591
|
async function readBody2(request4, capBytes) {
|
|
10581
10592
|
return await new Promise((resolve, reject) => {
|
|
10582
10593
|
const chunks = [];
|
|
@@ -10665,6 +10676,9 @@ function createRcSelfHostSurface(deps) {
|
|
|
10665
10676
|
}
|
|
10666
10677
|
return false;
|
|
10667
10678
|
};
|
|
10679
|
+
const credentialRefusal = (headers) => presentsCredential(headers) ? void 0 : presentationRefusal(headers);
|
|
10680
|
+
const workerRefusal = (headers, session) => presentsWorkerJwt(headers, session) ? void 0 : presentationRefusal(headers);
|
|
10681
|
+
const workerOrCredentialRefusal = (headers, session) => presentsWorkerJwt(headers, session) || presentsCredential(headers) ? void 0 : presentationRefusal(headers);
|
|
10668
10682
|
const frameOf = (event) => {
|
|
10669
10683
|
const envelope = {
|
|
10670
10684
|
event_id: event.eventId,
|
|
@@ -10753,8 +10767,14 @@ data: ${JSON.stringify(envelope)}
|
|
|
10753
10767
|
const epochStale = async (response) => {
|
|
10754
10768
|
await answerJson2(response, HTTP_CONFLICT, { type: "error", error: { type: "api_error", message: "worker_epoch does not match the session's live epoch" } }, { [CONFLICT_REASON_HEADER2]: CONFLICT_REASON_EPOCH_STALE });
|
|
10755
10769
|
};
|
|
10756
|
-
const
|
|
10757
|
-
|
|
10770
|
+
const refusalMessages = {
|
|
10771
|
+
absent: "the self-hosted Remote Control surface authenticates by the Authorization header, and this call carried none",
|
|
10772
|
+
"not-a-bearer": "the self-hosted Remote Control surface reads a Bearer authorization, and this call's Authorization header did not carry the Bearer scheme word",
|
|
10773
|
+
"doubled-scheme-word": "the self-hosted Remote Control surface reads one Bearer scheme word, and this call's Authorization header carried it twice: a persisted session record holds the whole header value with the scheme word included, so prefixing Bearer onto it presents a different credential",
|
|
10774
|
+
unrecognised: "the self-hosted Remote Control surface did not recognise the presented credential"
|
|
10775
|
+
};
|
|
10776
|
+
const unauthorized = async (response, refusal) => {
|
|
10777
|
+
await answerJson2(response, HTTP_STATUS.unauthorized, { type: "error", error: { type: "authentication_error", message: refusalMessages[refusal] } });
|
|
10758
10778
|
};
|
|
10759
10779
|
const serveSessionPath = async (session, tail, request4, response) => {
|
|
10760
10780
|
const method = request4.method.toUpperCase();
|
|
@@ -10772,8 +10792,9 @@ data: ${JSON.stringify(envelope)}
|
|
|
10772
10792
|
return;
|
|
10773
10793
|
}
|
|
10774
10794
|
if (tail === "bridge" && method === "POST") {
|
|
10775
|
-
|
|
10776
|
-
|
|
10795
|
+
const refusal = credentialRefusal(request4.headers);
|
|
10796
|
+
if (refusal !== void 0) {
|
|
10797
|
+
await unauthorized(response, refusal);
|
|
10777
10798
|
return;
|
|
10778
10799
|
}
|
|
10779
10800
|
const workerJwt = mintWorkerJwt(deps.randomToken, deps.now());
|
|
@@ -10783,8 +10804,9 @@ data: ${JSON.stringify(envelope)}
|
|
|
10783
10804
|
return;
|
|
10784
10805
|
}
|
|
10785
10806
|
if (tail === "archive" && method === "POST") {
|
|
10786
|
-
|
|
10787
|
-
|
|
10807
|
+
const refusal = credentialRefusal(request4.headers);
|
|
10808
|
+
if (refusal !== void 0) {
|
|
10809
|
+
await unauthorized(response, refusal);
|
|
10788
10810
|
return;
|
|
10789
10811
|
}
|
|
10790
10812
|
for (const sink of [...session.workerStreams, ...session.clientStreams]) {
|
|
@@ -10798,8 +10820,9 @@ data: ${JSON.stringify(envelope)}
|
|
|
10798
10820
|
if (tail === "worker" || tail.startsWith("worker/")) {
|
|
10799
10821
|
const workerTail = tail === "worker" ? "" : tail.slice("worker/".length);
|
|
10800
10822
|
const webProxy = workerTail === "web-fetch" || workerTail === "web-search";
|
|
10801
|
-
|
|
10802
|
-
|
|
10823
|
+
const refusal = webProxy ? workerOrCredentialRefusal(request4.headers, session) : workerRefusal(request4.headers, session);
|
|
10824
|
+
if (refusal !== void 0) {
|
|
10825
|
+
await unauthorized(response, refusal);
|
|
10803
10826
|
return;
|
|
10804
10827
|
}
|
|
10805
10828
|
if (workerTail === "" && method === "GET") {
|
|
@@ -10955,8 +10978,9 @@ data: ${JSON.stringify(envelope)}
|
|
|
10955
10978
|
await answerJson2(response, HTTP_STATUS.notFound, { type: "error", error: { type: "api_error", message: `the self-hosted Remote Control surface serves no worker path "${workerTail}"` } });
|
|
10956
10979
|
return;
|
|
10957
10980
|
}
|
|
10958
|
-
|
|
10959
|
-
|
|
10981
|
+
const clientRefusal = credentialRefusal(request4.headers);
|
|
10982
|
+
if (clientRefusal !== void 0) {
|
|
10983
|
+
await unauthorized(response, clientRefusal);
|
|
10960
10984
|
return;
|
|
10961
10985
|
}
|
|
10962
10986
|
if (tail === "events" && method === "POST") {
|
|
@@ -11021,8 +11045,9 @@ data: ${JSON.stringify(envelope)}
|
|
|
11021
11045
|
await answerJson2(response, HTTP_STATUS.methodNotAllowed, { type: "error", error: { type: "api_error", message: "the compatibility session list is a GET" } });
|
|
11022
11046
|
return;
|
|
11023
11047
|
}
|
|
11024
|
-
|
|
11025
|
-
|
|
11048
|
+
const listRefusal = credentialRefusal(request4.headers);
|
|
11049
|
+
if (listRefusal !== void 0) {
|
|
11050
|
+
await unauthorized(response, listRefusal);
|
|
11026
11051
|
return;
|
|
11027
11052
|
}
|
|
11028
11053
|
await answerJson2(response, HTTP_STATUS.ok, { data: [] });
|
|
@@ -11034,8 +11059,9 @@ data: ${JSON.stringify(envelope)}
|
|
|
11034
11059
|
}
|
|
11035
11060
|
if (pathname === RC_SESSIONS_PATH_PREFIX2) {
|
|
11036
11061
|
if (method === "POST") {
|
|
11037
|
-
|
|
11038
|
-
|
|
11062
|
+
const createRefusal = credentialRefusal(request4.headers);
|
|
11063
|
+
if (createRefusal !== void 0) {
|
|
11064
|
+
await unauthorized(response, createRefusal);
|
|
11039
11065
|
return;
|
|
11040
11066
|
}
|
|
11041
11067
|
const body = parseJsonObject2(await readBody2(request4.body, CONTROL_BODY_CAP_BYTES));
|
|
@@ -11060,8 +11086,9 @@ data: ${JSON.stringify(envelope)}
|
|
|
11060
11086
|
return;
|
|
11061
11087
|
}
|
|
11062
11088
|
if (method === "GET") {
|
|
11063
|
-
|
|
11064
|
-
|
|
11089
|
+
const readRefusal = credentialRefusal(request4.headers);
|
|
11090
|
+
if (readRefusal !== void 0) {
|
|
11091
|
+
await unauthorized(response, readRefusal);
|
|
11065
11092
|
return;
|
|
11066
11093
|
}
|
|
11067
11094
|
await answerJson2(response, HTTP_STATUS.ok, { data: [...sessions.values()].map((session) => ({ id: session.id, title: session.title, created_at: new Date(session.createdAt).toISOString(), updated_at: new Date(session.lastTrafficAt).toISOString(), session_status: "active" })) });
|
package/dist/index.mjs
CHANGED
|
@@ -10305,6 +10305,17 @@ function bearerOf(headers) {
|
|
|
10305
10305
|
}
|
|
10306
10306
|
return presented.slice(0, "bearer ".length).toLowerCase() === "bearer " ? presented.slice("bearer ".length) : void 0;
|
|
10307
10307
|
}
|
|
10308
|
+
function presentationRefusal(headers) {
|
|
10309
|
+
const presented = singleHeader2(headers, "authorization");
|
|
10310
|
+
if (presented === void 0) {
|
|
10311
|
+
return "absent";
|
|
10312
|
+
}
|
|
10313
|
+
if (presented.slice(0, "bearer ".length).toLowerCase() !== "bearer ") {
|
|
10314
|
+
return "not-a-bearer";
|
|
10315
|
+
}
|
|
10316
|
+
const bearer = presented.slice("bearer ".length);
|
|
10317
|
+
return bearer.slice(0, "bearer ".length).toLowerCase() === "bearer " ? "doubled-scheme-word" : "unrecognised";
|
|
10318
|
+
}
|
|
10308
10319
|
async function readBody2(request4, capBytes) {
|
|
10309
10320
|
return await new Promise((resolve, reject) => {
|
|
10310
10321
|
const chunks = [];
|
|
@@ -10393,6 +10404,9 @@ function createRcSelfHostSurface(deps) {
|
|
|
10393
10404
|
}
|
|
10394
10405
|
return false;
|
|
10395
10406
|
};
|
|
10407
|
+
const credentialRefusal = (headers) => presentsCredential(headers) ? void 0 : presentationRefusal(headers);
|
|
10408
|
+
const workerRefusal = (headers, session) => presentsWorkerJwt(headers, session) ? void 0 : presentationRefusal(headers);
|
|
10409
|
+
const workerOrCredentialRefusal = (headers, session) => presentsWorkerJwt(headers, session) || presentsCredential(headers) ? void 0 : presentationRefusal(headers);
|
|
10396
10410
|
const frameOf = (event) => {
|
|
10397
10411
|
const envelope = {
|
|
10398
10412
|
event_id: event.eventId,
|
|
@@ -10481,8 +10495,14 @@ data: ${JSON.stringify(envelope)}
|
|
|
10481
10495
|
const epochStale = async (response) => {
|
|
10482
10496
|
await answerJson2(response, HTTP_CONFLICT, { type: "error", error: { type: "api_error", message: "worker_epoch does not match the session's live epoch" } }, { [CONFLICT_REASON_HEADER2]: CONFLICT_REASON_EPOCH_STALE });
|
|
10483
10497
|
};
|
|
10484
|
-
const
|
|
10485
|
-
|
|
10498
|
+
const refusalMessages = {
|
|
10499
|
+
absent: "the self-hosted Remote Control surface authenticates by the Authorization header, and this call carried none",
|
|
10500
|
+
"not-a-bearer": "the self-hosted Remote Control surface reads a Bearer authorization, and this call's Authorization header did not carry the Bearer scheme word",
|
|
10501
|
+
"doubled-scheme-word": "the self-hosted Remote Control surface reads one Bearer scheme word, and this call's Authorization header carried it twice: a persisted session record holds the whole header value with the scheme word included, so prefixing Bearer onto it presents a different credential",
|
|
10502
|
+
unrecognised: "the self-hosted Remote Control surface did not recognise the presented credential"
|
|
10503
|
+
};
|
|
10504
|
+
const unauthorized = async (response, refusal) => {
|
|
10505
|
+
await answerJson2(response, HTTP_STATUS.unauthorized, { type: "error", error: { type: "authentication_error", message: refusalMessages[refusal] } });
|
|
10486
10506
|
};
|
|
10487
10507
|
const serveSessionPath = async (session, tail, request4, response) => {
|
|
10488
10508
|
const method = request4.method.toUpperCase();
|
|
@@ -10500,8 +10520,9 @@ data: ${JSON.stringify(envelope)}
|
|
|
10500
10520
|
return;
|
|
10501
10521
|
}
|
|
10502
10522
|
if (tail === "bridge" && method === "POST") {
|
|
10503
|
-
|
|
10504
|
-
|
|
10523
|
+
const refusal = credentialRefusal(request4.headers);
|
|
10524
|
+
if (refusal !== void 0) {
|
|
10525
|
+
await unauthorized(response, refusal);
|
|
10505
10526
|
return;
|
|
10506
10527
|
}
|
|
10507
10528
|
const workerJwt = mintWorkerJwt(deps.randomToken, deps.now());
|
|
@@ -10511,8 +10532,9 @@ data: ${JSON.stringify(envelope)}
|
|
|
10511
10532
|
return;
|
|
10512
10533
|
}
|
|
10513
10534
|
if (tail === "archive" && method === "POST") {
|
|
10514
|
-
|
|
10515
|
-
|
|
10535
|
+
const refusal = credentialRefusal(request4.headers);
|
|
10536
|
+
if (refusal !== void 0) {
|
|
10537
|
+
await unauthorized(response, refusal);
|
|
10516
10538
|
return;
|
|
10517
10539
|
}
|
|
10518
10540
|
for (const sink of [...session.workerStreams, ...session.clientStreams]) {
|
|
@@ -10526,8 +10548,9 @@ data: ${JSON.stringify(envelope)}
|
|
|
10526
10548
|
if (tail === "worker" || tail.startsWith("worker/")) {
|
|
10527
10549
|
const workerTail = tail === "worker" ? "" : tail.slice("worker/".length);
|
|
10528
10550
|
const webProxy = workerTail === "web-fetch" || workerTail === "web-search";
|
|
10529
|
-
|
|
10530
|
-
|
|
10551
|
+
const refusal = webProxy ? workerOrCredentialRefusal(request4.headers, session) : workerRefusal(request4.headers, session);
|
|
10552
|
+
if (refusal !== void 0) {
|
|
10553
|
+
await unauthorized(response, refusal);
|
|
10531
10554
|
return;
|
|
10532
10555
|
}
|
|
10533
10556
|
if (workerTail === "" && method === "GET") {
|
|
@@ -10683,8 +10706,9 @@ data: ${JSON.stringify(envelope)}
|
|
|
10683
10706
|
await answerJson2(response, HTTP_STATUS.notFound, { type: "error", error: { type: "api_error", message: `the self-hosted Remote Control surface serves no worker path "${workerTail}"` } });
|
|
10684
10707
|
return;
|
|
10685
10708
|
}
|
|
10686
|
-
|
|
10687
|
-
|
|
10709
|
+
const clientRefusal = credentialRefusal(request4.headers);
|
|
10710
|
+
if (clientRefusal !== void 0) {
|
|
10711
|
+
await unauthorized(response, clientRefusal);
|
|
10688
10712
|
return;
|
|
10689
10713
|
}
|
|
10690
10714
|
if (tail === "events" && method === "POST") {
|
|
@@ -10749,8 +10773,9 @@ data: ${JSON.stringify(envelope)}
|
|
|
10749
10773
|
await answerJson2(response, HTTP_STATUS.methodNotAllowed, { type: "error", error: { type: "api_error", message: "the compatibility session list is a GET" } });
|
|
10750
10774
|
return;
|
|
10751
10775
|
}
|
|
10752
|
-
|
|
10753
|
-
|
|
10776
|
+
const listRefusal = credentialRefusal(request4.headers);
|
|
10777
|
+
if (listRefusal !== void 0) {
|
|
10778
|
+
await unauthorized(response, listRefusal);
|
|
10754
10779
|
return;
|
|
10755
10780
|
}
|
|
10756
10781
|
await answerJson2(response, HTTP_STATUS.ok, { data: [] });
|
|
@@ -10762,8 +10787,9 @@ data: ${JSON.stringify(envelope)}
|
|
|
10762
10787
|
}
|
|
10763
10788
|
if (pathname === RC_SESSIONS_PATH_PREFIX2) {
|
|
10764
10789
|
if (method === "POST") {
|
|
10765
|
-
|
|
10766
|
-
|
|
10790
|
+
const createRefusal = credentialRefusal(request4.headers);
|
|
10791
|
+
if (createRefusal !== void 0) {
|
|
10792
|
+
await unauthorized(response, createRefusal);
|
|
10767
10793
|
return;
|
|
10768
10794
|
}
|
|
10769
10795
|
const body = parseJsonObject2(await readBody2(request4.body, CONTROL_BODY_CAP_BYTES));
|
|
@@ -10788,8 +10814,9 @@ data: ${JSON.stringify(envelope)}
|
|
|
10788
10814
|
return;
|
|
10789
10815
|
}
|
|
10790
10816
|
if (method === "GET") {
|
|
10791
|
-
|
|
10792
|
-
|
|
10817
|
+
const readRefusal = credentialRefusal(request4.headers);
|
|
10818
|
+
if (readRefusal !== void 0) {
|
|
10819
|
+
await unauthorized(response, readRefusal);
|
|
10793
10820
|
return;
|
|
10794
10821
|
}
|
|
10795
10822
|
await answerJson2(response, HTTP_STATUS.ok, { data: [...sessions.values()].map((session) => ({ id: session.id, title: session.title, created_at: new Date(session.createdAt).toISOString(), updated_at: new Date(session.lastTrafficAt).toISOString(), session_status: "active" })) });
|
package/dist/types/index.d.ts
CHANGED
|
@@ -3998,13 +3998,13 @@ declare function createControlApiRouter(deps: ControlApiDeps): {
|
|
|
3998
3998
|
"config-profile": "config-profile";
|
|
3999
3999
|
identity: "identity";
|
|
4000
4000
|
provider: "provider";
|
|
4001
|
-
pool: "pool";
|
|
4002
|
-
keychain: "keychain";
|
|
4003
4001
|
"ambient-credential": "ambient-credential";
|
|
4004
4002
|
"binary-discovery": "binary-discovery";
|
|
4005
4003
|
"claude-shim": "claude-shim";
|
|
4006
4004
|
"path-resolution": "path-resolution";
|
|
4007
4005
|
"legacy-name": "legacy-name";
|
|
4006
|
+
pool: "pool";
|
|
4007
|
+
keychain: "keychain";
|
|
4008
4008
|
"directory-rules": "directory-rules";
|
|
4009
4009
|
"categories-local": "categories-local";
|
|
4010
4010
|
"active-identity": "active-identity";
|
|
@@ -4475,13 +4475,13 @@ declare function createDoorApiRouter(deps: DoorApiDeps): {
|
|
|
4475
4475
|
"config-profile": "config-profile";
|
|
4476
4476
|
identity: "identity";
|
|
4477
4477
|
provider: "provider";
|
|
4478
|
-
pool: "pool";
|
|
4479
|
-
keychain: "keychain";
|
|
4480
4478
|
"ambient-credential": "ambient-credential";
|
|
4481
4479
|
"binary-discovery": "binary-discovery";
|
|
4482
4480
|
"claude-shim": "claude-shim";
|
|
4483
4481
|
"path-resolution": "path-resolution";
|
|
4484
4482
|
"legacy-name": "legacy-name";
|
|
4483
|
+
pool: "pool";
|
|
4484
|
+
keychain: "keychain";
|
|
4485
4485
|
"directory-rules": "directory-rules";
|
|
4486
4486
|
"categories-local": "categories-local";
|
|
4487
4487
|
"active-identity": "active-identity";
|
|
@@ -4769,13 +4769,13 @@ declare const DoctorFindingSchema: z.ZodObject<{
|
|
|
4769
4769
|
"config-profile": "config-profile";
|
|
4770
4770
|
identity: "identity";
|
|
4771
4771
|
provider: "provider";
|
|
4772
|
-
pool: "pool";
|
|
4773
|
-
keychain: "keychain";
|
|
4774
4772
|
"ambient-credential": "ambient-credential";
|
|
4775
4773
|
"binary-discovery": "binary-discovery";
|
|
4776
4774
|
"claude-shim": "claude-shim";
|
|
4777
4775
|
"path-resolution": "path-resolution";
|
|
4778
4776
|
"legacy-name": "legacy-name";
|
|
4777
|
+
pool: "pool";
|
|
4778
|
+
keychain: "keychain";
|
|
4779
4779
|
"directory-rules": "directory-rules";
|
|
4780
4780
|
"categories-local": "categories-local";
|
|
4781
4781
|
"active-identity": "active-identity";
|
|
@@ -4798,13 +4798,13 @@ declare const DoctorRunOutputSchema: z.ZodObject<{
|
|
|
4798
4798
|
"config-profile": "config-profile";
|
|
4799
4799
|
identity: "identity";
|
|
4800
4800
|
provider: "provider";
|
|
4801
|
-
pool: "pool";
|
|
4802
|
-
keychain: "keychain";
|
|
4803
4801
|
"ambient-credential": "ambient-credential";
|
|
4804
4802
|
"binary-discovery": "binary-discovery";
|
|
4805
4803
|
"claude-shim": "claude-shim";
|
|
4806
4804
|
"path-resolution": "path-resolution";
|
|
4807
4805
|
"legacy-name": "legacy-name";
|
|
4806
|
+
pool: "pool";
|
|
4807
|
+
keychain: "keychain";
|
|
4808
4808
|
"directory-rules": "directory-rules";
|
|
4809
4809
|
"categories-local": "categories-local";
|
|
4810
4810
|
"active-identity": "active-identity";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-shim",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.22.0",
|
|
4
4
|
"description": "A profile manager and launcher for Claude Code that lets one person run multiple logins from one machine while controlling what gets shared between them.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Joseph Mearman <joseph@mearman.co.uk>",
|