agent-shim 8.8.0 → 8.10.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 +5 -1
- package/dist/cli.cjs +6191 -2168
- package/dist/index.cjs +2259 -1523
- package/dist/index.mjs +2254 -1531
- package/dist/types/index.d.ts +400 -22
- package/package.json +3 -1
package/dist/types/index.d.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
import * as zod from 'zod';
|
|
1
2
|
import { z } from 'zod';
|
|
2
3
|
import { IncomingHttpHeaders, IncomingMessage, ServerResponse } from 'node:http';
|
|
3
4
|
import * as net from 'node:net';
|
|
4
5
|
import { Duplex } from 'node:stream';
|
|
6
|
+
import * as zod_v4_core from 'zod/v4/core';
|
|
7
|
+
import * as _orpc_server from '@orpc/server';
|
|
8
|
+
import { RouterClient } from '@orpc/server';
|
|
5
9
|
|
|
6
10
|
/**
|
|
7
11
|
* Every category a `~/.claude` entry can be classified into. `secret` is deliberately part of this list — it is a real classification the resolver acts on — but it is NOT part of `CategoryMapSchema`'s shape, because no configuration layer may ever toggle it. See OVERRIDABLE_CATEGORIES.
|
|
@@ -72,6 +76,7 @@ declare const LaunchSchema: z.ZodObject<{
|
|
|
72
76
|
provider: z.ZodOptional<z.ZodString>;
|
|
73
77
|
headroom: z.ZodOptional<z.ZodBoolean>;
|
|
74
78
|
trackUsage: z.ZodOptional<z.ZodBoolean>;
|
|
79
|
+
claudeVersion: z.ZodOptional<z.ZodString>;
|
|
75
80
|
}, z.core.$strict>;
|
|
76
81
|
type LaunchFlags = z.infer<typeof LaunchSchema>;
|
|
77
82
|
/**
|
|
@@ -333,6 +338,7 @@ declare const ConfigProfileSchema: z.ZodObject<{
|
|
|
333
338
|
provider: z.ZodOptional<z.ZodString>;
|
|
334
339
|
headroom: z.ZodOptional<z.ZodBoolean>;
|
|
335
340
|
trackUsage: z.ZodOptional<z.ZodBoolean>;
|
|
341
|
+
claudeVersion: z.ZodOptional<z.ZodString>;
|
|
336
342
|
}, z.core.$strict>>;
|
|
337
343
|
}, z.core.$strict>;
|
|
338
344
|
type ConfigProfile = z.infer<typeof ConfigProfileSchema>;
|
|
@@ -376,6 +382,7 @@ declare const DirectoryRuleSchema: z.ZodObject<{
|
|
|
376
382
|
provider: z.ZodOptional<z.ZodString>;
|
|
377
383
|
headroom: z.ZodOptional<z.ZodBoolean>;
|
|
378
384
|
trackUsage: z.ZodOptional<z.ZodBoolean>;
|
|
385
|
+
claudeVersion: z.ZodOptional<z.ZodString>;
|
|
379
386
|
}, z.core.$strict>>;
|
|
380
387
|
path: z.ZodString;
|
|
381
388
|
configProfile: z.ZodOptional<z.ZodString>;
|
|
@@ -424,6 +431,7 @@ declare const DirectoryRulesSchema: z.ZodObject<{
|
|
|
424
431
|
provider: z.ZodOptional<z.ZodString>;
|
|
425
432
|
headroom: z.ZodOptional<z.ZodBoolean>;
|
|
426
433
|
trackUsage: z.ZodOptional<z.ZodBoolean>;
|
|
434
|
+
claudeVersion: z.ZodOptional<z.ZodString>;
|
|
427
435
|
}, z.core.$strict>>;
|
|
428
436
|
path: z.ZodString;
|
|
429
437
|
configProfile: z.ZodOptional<z.ZodString>;
|
|
@@ -473,6 +481,7 @@ declare const PortableConfigSchema: z.ZodObject<{
|
|
|
473
481
|
provider: z.ZodOptional<z.ZodString>;
|
|
474
482
|
headroom: z.ZodOptional<z.ZodBoolean>;
|
|
475
483
|
trackUsage: z.ZodOptional<z.ZodBoolean>;
|
|
484
|
+
claudeVersion: z.ZodOptional<z.ZodString>;
|
|
476
485
|
}, z.core.$strict>>;
|
|
477
486
|
configProfile: z.ZodOptional<z.ZodString>;
|
|
478
487
|
identity: z.ZodOptional<z.ZodString>;
|
|
@@ -541,6 +550,7 @@ declare const GlobalConfigSchema: z.ZodObject<{
|
|
|
541
550
|
provider: z.ZodOptional<z.ZodString>;
|
|
542
551
|
headroom: z.ZodOptional<z.ZodBoolean>;
|
|
543
552
|
trackUsage: z.ZodOptional<z.ZodBoolean>;
|
|
553
|
+
claudeVersion: z.ZodOptional<z.ZodString>;
|
|
544
554
|
}, z.core.$strict>>;
|
|
545
555
|
headroom: z.ZodOptional<z.ZodObject<{
|
|
546
556
|
source: z.ZodOptional<z.ZodString>;
|
|
@@ -1602,6 +1612,44 @@ declare function realConnectCertStore(paths: {
|
|
|
1602
1612
|
readonly frontdoorCaKeyFile: string;
|
|
1603
1613
|
}): ConnectCertStore;
|
|
1604
1614
|
|
|
1615
|
+
/**
|
|
1616
|
+
* The Zod schemas of the Remote Control surfaces: one definition each for the summaries, statuses and pending lists the tracker produces, the stream events the door's client attachment fans out, and every input and output the typed API accepts. The tracker's own TypeScript interfaces in `rcSessions.ts` stay the implementations' types; these schemas are what the oRPC contract validates through, and because the procedures wrap the very operations that produce those interfaces' values, a drift between a schema and its interface fails the API's own output validation (exercised by its tests) rather than shipping silently. This module deliberately imports nothing from oRPC: it is a plain Zod leaf, so the tracker and the stream half can share it without either depending on the API layer.
|
|
1617
|
+
*/
|
|
1618
|
+
/** The permission modes the SDK's own `set_permission_mode` control request accepts, as the input schema of the set-permission-mode operation and the subscribe-free vocabulary every surface narrows untrusted strings through. */
|
|
1619
|
+
declare const RcPermissionModeSchema: z.ZodEnum<{
|
|
1620
|
+
default: "default";
|
|
1621
|
+
acceptEdits: "acceptEdits";
|
|
1622
|
+
bypassPermissions: "bypassPermissions";
|
|
1623
|
+
plan: "plan";
|
|
1624
|
+
dontAsk: "dontAsk";
|
|
1625
|
+
auto: "auto";
|
|
1626
|
+
}>;
|
|
1627
|
+
/** One event off the client read stream, exactly as the door forwards it to subscribers: the envelope the API host sent, with the fields the door itself relies on typed and the rest (the payload above all) carried verbatim for the consumer to narrow. */
|
|
1628
|
+
declare const RcStreamEnvelopeSchema: z.ZodObject<{
|
|
1629
|
+
event_id: z.ZodOptional<z.ZodString>;
|
|
1630
|
+
event_type: z.ZodString;
|
|
1631
|
+
sequence_num: z.ZodInt;
|
|
1632
|
+
source: z.ZodString;
|
|
1633
|
+
payload: z.ZodOptional<z.ZodUnknown>;
|
|
1634
|
+
created_at: z.ZodOptional<z.ZodUnknown>;
|
|
1635
|
+
}, z.core.$loose>;
|
|
1636
|
+
/** One fan-out event: the session the stream it rode belongs to, beside the envelope itself. */
|
|
1637
|
+
declare const RcStreamEventSchema: z.ZodObject<{
|
|
1638
|
+
session: z.ZodString;
|
|
1639
|
+
envelope: z.ZodObject<{
|
|
1640
|
+
event_id: z.ZodOptional<z.ZodString>;
|
|
1641
|
+
event_type: z.ZodString;
|
|
1642
|
+
sequence_num: z.ZodInt;
|
|
1643
|
+
source: z.ZodString;
|
|
1644
|
+
payload: z.ZodOptional<z.ZodUnknown>;
|
|
1645
|
+
created_at: z.ZodOptional<z.ZodUnknown>;
|
|
1646
|
+
}, z.core.$loose>;
|
|
1647
|
+
}, z.core.$strict>;
|
|
1648
|
+
/** One event off the client read stream, as the TypeScript every in-process consumer of the fan-out handles it (the schema's own inferred type, so the two cannot drift). */
|
|
1649
|
+
type RcStreamEnvelope = z.output<typeof RcStreamEnvelopeSchema>;
|
|
1650
|
+
/** One fan-out event, as the TypeScript every in-process consumer handles it. */
|
|
1651
|
+
type RcStreamEvent = z.output<typeof RcStreamEventSchema>;
|
|
1652
|
+
|
|
1605
1653
|
/** What the identity step learned about one request from the launcher-injected headers. */
|
|
1606
1654
|
interface SessionIdentity {
|
|
1607
1655
|
/** The identity name the launch resolved, when it resolved one. */
|
|
@@ -1750,6 +1798,14 @@ interface RcSessionTracker {
|
|
|
1750
1798
|
readonly pendingOf: (sessionId?: string) => readonly RcPendingRequestSummary[];
|
|
1751
1799
|
/** The observed credential and protocol headers for one session, the client-half writes' accessor: present only while the session is tracked, and never surfaced anywhere a summary, log or capture goes. */
|
|
1752
1800
|
readonly credentialOf: (sessionId: string) => RcObservedCredential | undefined;
|
|
1801
|
+
/** Advances the session's sequence cursor to the highest number named, which every confirmed client-half write calls with the numbers the real service assigned its events. */
|
|
1802
|
+
readonly noteSequenceNums: (sessionId: string, sequenceNums: readonly number[]) => void;
|
|
1803
|
+
/** The session's sequence cursor: the highest number the door has seen, from the client read stream's envelopes or from its own confirmed writes; undefined while neither has been seen. */
|
|
1804
|
+
readonly sequenceNumOf: (sessionId: string) => number | undefined;
|
|
1805
|
+
/**
|
|
1806
|
+
* Files one client read stream envelope: advances the session's sequence cursor, and treats the payload exactly as an observed event-batch body's would be treated, which is how an approval reaches the pending list from the stream (the live finding behind the client attachment: the CLI routes `control_request`s only toward attached clients, so the stream, not the worker's own writes, is where a `can_use_tool` the door must answer becomes visible). A `control_request` whose envelope names the worker as its source births a pending entry; a `control_response` retires the request it answers, whoever answered it.
|
|
1807
|
+
*/
|
|
1808
|
+
readonly fileStreamEvent: (sessionId: string, event: RcStreamEnvelope) => void;
|
|
1753
1809
|
/** Retires one pending control request as answered: what a successful answer write calls, so the request stops being listed the moment it is answered. */
|
|
1754
1810
|
readonly completePending: (sessionId: string, requestId: string) => void;
|
|
1755
1811
|
/** Stops the idle sweep timer. The entries themselves are unreachable the moment the door drops them. */
|
|
@@ -1759,8 +1815,12 @@ interface RcSessionTracker {
|
|
|
1759
1815
|
declare function createRcSessionTracker(deps: RcSessionTrackerDeps): RcSessionTracker;
|
|
1760
1816
|
/**
|
|
1761
1817
|
* Wraps one route so the tracker sees every exchange the route serves: the request's facts are handed over first, and when they are Remote Control facts the request's body chunks and the response the route writes are teed to the tracker's observer while flowing on unchanged. Used on the door's route resolution, so the bare `/v1/` pass-through an OAuth session's Remote Control calls ride is where observation happens.
|
|
1818
|
+
*
|
|
1819
|
+
* `onExchangeSettled`, when given, is called once the exchange's response has ended and the observer has filed whatever it filed: it is where the door re-pokes the client stream attachment, so a session becomes attached the moment its create's own response completes rather than at whatever exchange happens to follow.
|
|
1762
1820
|
*/
|
|
1763
|
-
declare function observingRoutedRoute(route: FrontDoorRoute, tracker: RcSessionTracker
|
|
1821
|
+
declare function observingRoutedRoute(route: FrontDoorRoute, tracker: RcSessionTracker, hooks?: {
|
|
1822
|
+
readonly onExchangeSettled?: () => void;
|
|
1823
|
+
}): FrontDoorRoute;
|
|
1764
1824
|
/** Adapts the tracker's exchange observer to the passthrough forwarding's observer shape, so the connect test world (which forwards rather than routes) observes through the same tracker. */
|
|
1765
1825
|
declare function rcObserverAsPassthrough(observer: RcExchangeObserver): PassthroughObserver;
|
|
1766
1826
|
/**
|
|
@@ -1800,6 +1860,8 @@ type RcObservedCredential = RcWriteHeaders;
|
|
|
1800
1860
|
interface RcInjectDeps {
|
|
1801
1861
|
/** Reads the observed credential for a session: the tracker's accessor, in production. */
|
|
1802
1862
|
readonly credentialOf: (sessionId: string) => RcObservedCredential | undefined;
|
|
1863
|
+
/** Advances the session's sequence cursor: the tracker's accessor, in production, so a delivered write's numbers are what a stream resume continues after. */
|
|
1864
|
+
readonly noteSequenceNums: (sessionId: string, sequenceNums: readonly number[]) => void;
|
|
1803
1865
|
/** The dial to the real API host. */
|
|
1804
1866
|
readonly dial: RcEventDial;
|
|
1805
1867
|
/** Mints the payload event's uuid: a v4 UUID or better in production. */
|
|
@@ -1847,6 +1909,8 @@ interface RcAnswerDeps {
|
|
|
1847
1909
|
readonly pendingOf: (sessionId: string) => readonly RcPendingRequestSummary[];
|
|
1848
1910
|
/** Retires a pending request as answered: the tracker's accessor, in production, called only once the write is confirmed delivered. */
|
|
1849
1911
|
readonly completePending: (sessionId: string, requestId: string) => void;
|
|
1912
|
+
/** Advances the session's sequence cursor: the tracker's accessor, in production, so a delivered write's numbers are what a stream resume continues after. */
|
|
1913
|
+
readonly noteSequenceNums: (sessionId: string, sequenceNums: readonly number[]) => void;
|
|
1850
1914
|
/** The dial to the real API host. */
|
|
1851
1915
|
readonly dial: RcEventDial;
|
|
1852
1916
|
}
|
|
@@ -1858,6 +1922,8 @@ declare function answerRcControlRequest(deps: RcAnswerDeps, sessionId: string, r
|
|
|
1858
1922
|
interface RcControlRequestDeps {
|
|
1859
1923
|
/** Reads the observed credential for a session: the tracker's accessor, in production. */
|
|
1860
1924
|
readonly credentialOf: (sessionId: string) => RcObservedCredential | undefined;
|
|
1925
|
+
/** Advances the session's sequence cursor: the tracker's accessor, in production, so a delivered write's numbers are what a stream resume continues after. */
|
|
1926
|
+
readonly noteSequenceNums: (sessionId: string, sequenceNums: readonly number[]) => void;
|
|
1861
1927
|
/** The dial to the real API host. */
|
|
1862
1928
|
readonly dial: RcEventDial;
|
|
1863
1929
|
/** Mints the request's id: a v4 UUID or better in production, the id the worker's `control_response` echoes. */
|
|
@@ -1876,6 +1942,88 @@ declare function setRcSessionModel(deps: RcControlRequestDeps, sessionId: string
|
|
|
1876
1942
|
*/
|
|
1877
1943
|
declare function setRcSessionPermissionMode(deps: RcControlRequestDeps, sessionId: string, mode: RcPermissionMode): Promise<RcEventWriteResult>;
|
|
1878
1944
|
|
|
1945
|
+
/**
|
|
1946
|
+
* How long a failed attachment backs off before retrying. Not a fresh number: it is the session's own liveness bound (`RC_IDLE_EXPIRY_MS`, the 45 s stream timeout the tracker's idle expiry already derives from), so an attachment that cannot be re-established retries at exactly the cadence the protocol itself gives up on a quiet session at. Production passes that constant; tests pass small values so a backoff is reached in milliseconds.
|
|
1947
|
+
*/
|
|
1948
|
+
declare const RC_STREAM_BACKOFF_MS = 45000;
|
|
1949
|
+
/** One event the SSE parser completed: the fields the wire's own framing carried, before any protocol interpretation. */
|
|
1950
|
+
interface SseParsedEvent {
|
|
1951
|
+
/** The `event:` field's value, when the block carried one; the protocol's own events always do. */
|
|
1952
|
+
readonly event: string | undefined;
|
|
1953
|
+
/** The `id:` field's value in force at dispatch (the most recent one the connection saw, per the SSE framing rules); on this stream it carries the event's sequence number. */
|
|
1954
|
+
readonly id: string | undefined;
|
|
1955
|
+
/** The `data:` lines joined with newlines, exactly as the SSE framing defines. */
|
|
1956
|
+
readonly data: string;
|
|
1957
|
+
}
|
|
1958
|
+
/**
|
|
1959
|
+
* An incremental Server-Sent Events parser: feed it the stream's text chunks as they arrive and it returns the events each write completed. Chunks may split lines, fields and even a CRLF pair anywhere; the parser buffers until a line ending is certain, so a `\r` at a chunk's end waits for the byte that decides whether it is `\r\n`. Comments (`:`-prefixed lines, the protocol's 15 s keepalives) complete nothing, an event with no `data:` line dispatches nothing (the framing's own rule), and the `id:` value persists to the next dispatched event the same way, which is what carries the sequence number of an id-only block forward.
|
|
1960
|
+
*/
|
|
1961
|
+
declare function createSseParser(): {
|
|
1962
|
+
readonly write: (text: string) => readonly SseParsedEvent[];
|
|
1963
|
+
};
|
|
1964
|
+
/**
|
|
1965
|
+
* One parsed SSE event as the protocol's envelope, or undefined when the event is not a client event this half reads: a block under any other event name, or data that is not one JSON object carrying the fields the door relies on (`event_type`, `sequence_num`, `source`). An envelope the door cannot read is one it knows nothing about, never a failure: the stream stays up and the next event is read on its own merits.
|
|
1966
|
+
*/
|
|
1967
|
+
declare function parseRcStreamEnvelope(parsed: SseParsedEvent): RcStreamEnvelope | undefined;
|
|
1968
|
+
/** One answer from the API host the presence call dials: the status and the whole body. Presence answers one small JSON object, never a stream, so the body needs no cap of its own. */
|
|
1969
|
+
interface RcPresenceAnswer {
|
|
1970
|
+
readonly status: number;
|
|
1971
|
+
readonly body: string;
|
|
1972
|
+
}
|
|
1973
|
+
/** One answer from the API host the stream dial opens: the status and the body's chunks as they arrive. On a success the chunks are the live stream (consumed incrementally, never buffered); the production dial returns an already-drained empty iterable for any non-2xx answer, whose body is one small error document. */
|
|
1974
|
+
interface RcStreamAnswer {
|
|
1975
|
+
readonly status: number;
|
|
1976
|
+
readonly chunks: AsyncIterable<Uint8Array>;
|
|
1977
|
+
}
|
|
1978
|
+
/**
|
|
1979
|
+
* The one network effect the client read stream performs, injected so the attachment logic runs against fakes: announce a client's presence, and open the read stream. Production dials the real API host over the door's interception-proof agent; tests redirect to a local stand-in. `resume` names the documented resume pair's value: present only when the door has seen events for the session already, it sends `from_sequence_num` as a query parameter and `Last-Event-ID` as a header together.
|
|
1980
|
+
*/
|
|
1981
|
+
interface RcStreamDial {
|
|
1982
|
+
readonly announcePresence: (sessionId: string, headers: Readonly<Record<string, string>>, clientId: string) => Promise<RcPresenceAnswer>;
|
|
1983
|
+
readonly openStream: (sessionId: string, headers: Readonly<Record<string, string>>, resume: {
|
|
1984
|
+
readonly fromSequenceNum: number;
|
|
1985
|
+
} | undefined, signal: AbortSignal) => Promise<RcStreamAnswer>;
|
|
1986
|
+
}
|
|
1987
|
+
/** The fan-out every stream event is handed to: the tracker files what it recognises, and each subscriber receives the event beside it. */
|
|
1988
|
+
interface RcEventFanout {
|
|
1989
|
+
/** Delivers one event to every subscriber listening for its session (or for every session), synchronously, in publication order. */
|
|
1990
|
+
readonly publish: (event: RcStreamEvent) => void;
|
|
1991
|
+
/** Adds one listener, told every event whose session it matches; `undefined` listens to every session. Returns the detach function. */
|
|
1992
|
+
readonly subscribe: (session: string | undefined, listener: (event: RcStreamEvent) => void) => () => void;
|
|
1993
|
+
}
|
|
1994
|
+
/** Creates the fan-out: plain synchronous listener sets, one per session plus one for every-session listeners. Delivery is synchronous so the tracker's filing (which rides the same publish) and every subscriber observe the same order; a subscriber that cannot keep up is bounded where it is bridged to a pull (the typed API's subscription), not here. */
|
|
1995
|
+
declare function createRcEventFanout(): RcEventFanout;
|
|
1996
|
+
/** Everything the attachment hub needs, injected so its decisions run against fakes in unit tests. */
|
|
1997
|
+
interface RcStreamHubDeps {
|
|
1998
|
+
readonly now: () => number;
|
|
1999
|
+
/** The tracker's credential accessor: the OAuth-kind bearer and protocol headers the attachment replays, exactly as the write path does. */
|
|
2000
|
+
readonly credentialOf: (sessionId: string) => RcObservedCredential | undefined;
|
|
2001
|
+
/** The tracker's swept session list: an attachment whose session has expired is dropped, exactly when the tracker itself gives up on it. */
|
|
2002
|
+
readonly trackedSessions: () => readonly string[];
|
|
2003
|
+
/** Files one envelope with the tracker: advances the session's sequence cursor and births or retires pending control requests, exactly as an observed event-batch body does. */
|
|
2004
|
+
readonly fileStreamEvent: (sessionId: string, event: RcStreamEnvelope) => void;
|
|
2005
|
+
/** Reads the session's sequence cursor: the highest number the door has seen, from the stream or from its own confirmed writes. */
|
|
2006
|
+
readonly sequenceNumOf: (sessionId: string) => number | undefined;
|
|
2007
|
+
readonly dial: RcStreamDial;
|
|
2008
|
+
readonly fanout: RcEventFanout;
|
|
2009
|
+
/** Mints the stable client id one session's attachment announces: a v4 UUID or better in production. Stable means it survives reconnects, so the host sees one client, not a new one per drop. */
|
|
2010
|
+
readonly newClientId: () => string;
|
|
2011
|
+
/** How long a failed attachment backs off; production passes `RC_STREAM_BACKOFF_MS`, tests pass small values so a backoff is reached in milliseconds. */
|
|
2012
|
+
readonly backoffMs: number;
|
|
2013
|
+
readonly sleep: (ms: number) => Promise<void>;
|
|
2014
|
+
/** The door's log, for attachment lifecycle lines only: never an event payload, never a credential. */
|
|
2015
|
+
readonly log?: (line: string) => void;
|
|
2016
|
+
}
|
|
2017
|
+
/** The door's client read stream attachment: one stream per tracked session, fanned out to every subscriber. */
|
|
2018
|
+
interface RcStreamHub {
|
|
2019
|
+
/** Reconciles the attachments against the tracker: attaches a stream to every tracked session whose OAuth credential is known, and drops an attachment whose session has expired or lost its credential. Idempotent, synchronous and total (never throws): the door calls it after every observed Remote Control exchange, so an attachment follows the session it belongs to without any polling of its own. */
|
|
2020
|
+
readonly reconcile: () => void;
|
|
2021
|
+
/** Stops every attachment and frees their dials. */
|
|
2022
|
+
readonly close: () => void;
|
|
2023
|
+
}
|
|
2024
|
+
/** Creates the attachment hub. One per door process; everything it holds dies with it. */
|
|
2025
|
+
declare function createRcStreamHub(deps: RcStreamHubDeps): RcStreamHub;
|
|
2026
|
+
|
|
1879
2027
|
/** Where the Remote Control inject path dials: the API host's own address by default, over TLS with the door's interception-proof agent (real-name DNS resolution and the pf-exempt source-port range), so an injected event cannot be looped back into the door's own transparent surface. A test redirects the dial at a local stand-in presenting the host's name, exactly as the forwarding targets are redirected. */
|
|
1880
2028
|
interface RcDialTarget {
|
|
1881
2029
|
readonly host: string;
|
|
@@ -1891,6 +2039,7 @@ interface RcDialTarget {
|
|
|
1891
2039
|
* The real `RcEventDial`: one keep-alive TLS agent of the door's own exempt kind, so every injected event rides the same interception-proof dials the door's forwarded traffic does. The dial only ever reads small JSON answers (an event write's result, or an error), never a stream.
|
|
1892
2040
|
*/
|
|
1893
2041
|
declare function realRcEventDial(target?: RcDialTarget): RcEventDial;
|
|
2042
|
+
declare function realRcStreamDial(target?: RcDialTarget): RcStreamDial;
|
|
1894
2043
|
declare function realConnectEffects(): ConnectEffects;
|
|
1895
2044
|
|
|
1896
2045
|
/**
|
|
@@ -1966,6 +2115,225 @@ declare function frontDoorRcControl(transport: RcControlTransport, token: string
|
|
|
1966
2115
|
/** The filesystem operations headroom coordination needs: the same shape as `FarmFs`, injected so every decision over state, sessions, and the start lock runs against an in-memory fake in tests. */
|
|
1967
2116
|
type HeadroomFs = Pick<FarmFs, "mkdirp" | "mkdirPrivate" | "readFileUtf8" | "writeFileUtf8" | "writeFilePrivate" | "writeFileExclusive" | "readdir" | "removeRecursive">;
|
|
1968
2117
|
|
|
2118
|
+
/** What an `lstat` (which never follows symlinks) reports about one path, narrowed to what authenticating the socket needs. */
|
|
2119
|
+
interface SocketPathStat {
|
|
2120
|
+
readonly kind: "dir" | "socket" | "symlink" | "other";
|
|
2121
|
+
/** The owning user id. */
|
|
2122
|
+
readonly uid: number;
|
|
2123
|
+
/** The permission bits, without the file type bits. */
|
|
2124
|
+
readonly mode: number;
|
|
2125
|
+
}
|
|
2126
|
+
/** The platform facts and the one filesystem call the socket checks need, injected so every refusal is unit-testable without a real socket, directory or second user. */
|
|
2127
|
+
interface HeadroomSocketTrustPorts {
|
|
2128
|
+
/** `process.platform` in the real implementation. */
|
|
2129
|
+
readonly platform: string;
|
|
2130
|
+
/** This process's user id. Only called on a platform with unix sockets, which all have POSIX user ids. */
|
|
2131
|
+
readonly currentUid: () => number;
|
|
2132
|
+
/** Stats one path without following symlinks, or returns undefined when nothing is there. */
|
|
2133
|
+
readonly lstat: (target: string) => SocketPathStat | undefined;
|
|
2134
|
+
}
|
|
2135
|
+
|
|
2136
|
+
/**
|
|
2137
|
+
* A secondary pre-pipeline surface the listener answers under one path prefix: the typed Remote Control API. The listener owns only the dispatch (the prefix and the not-matched 404); the handle itself is whatever the door built, so this file stays independent of the API framework behind it.
|
|
2138
|
+
*/
|
|
2139
|
+
interface PrePipelineApi {
|
|
2140
|
+
/** The path prefix every request of this surface arrives under, outside the routed URL space. */
|
|
2141
|
+
readonly pathPrefix: string;
|
|
2142
|
+
/** Serves one request, resolving with whether a procedure under the prefix matched; the listener answers the 404 itself when one did not. */
|
|
2143
|
+
readonly handle: (request: IncomingMessage, response: ServerResponse) => Promise<{
|
|
2144
|
+
readonly matched: boolean;
|
|
2145
|
+
}>;
|
|
2146
|
+
}
|
|
2147
|
+
|
|
2148
|
+
/**
|
|
2149
|
+
* The Remote Control operations as a typed oRPC API, so programmatic consumers (automation, a mobile or web client, another of this user's tools) get a generated type-safe client instead of hand-rolled HTTP. One procedure per existing operation, each wrapping the same operation the bespoke token-gated routes wrap (the routes stay: the CLI uses them), with inputs and outputs validating through the Zod schemas of `rcSchemas.ts`, which the operations' own values must satisfy, so contract and behaviour share one schema source and cannot drift apart silently.
|
|
2150
|
+
*
|
|
2151
|
+
* Mounted on the provider listener beside the bespoke namespace, authenticated by the same per-generation owner-only control token as a Bearer credential: a fresh random value per door start, written owner-only under the front door's state directory, and checked in constant time like every other capability the door accepts. `rc.subscribe` streams the client attachment's fan-out: every event the door's held stream produced, SSE-framed by oRPC's event iterator, each carrying its sequence number as the SSE event id so a consumer's own reconnect can resume exactly as the door's does.
|
|
2152
|
+
*/
|
|
2153
|
+
/** The one path prefix the typed API is mounted under, answered before the routed pipeline like the bespoke control routes are. */
|
|
2154
|
+
declare const RC_ORPC_PATH_PREFIX = "/__agent-shim/orpc";
|
|
2155
|
+
/** Everything the typed API needs: the same operations the bespoke control routes take, the fan-out its subscription reads, and the token both surfaces demand. */
|
|
2156
|
+
interface RcApiDeps {
|
|
2157
|
+
/** This generation's control token: the value the door wrote owner-only for its callers to present. */
|
|
2158
|
+
readonly expectedToken: string;
|
|
2159
|
+
/** The observed sessions as the tracker lists them. */
|
|
2160
|
+
readonly list: () => readonly RcSessionSummary[];
|
|
2161
|
+
/** The observed sessions as the tracker reports their status, filtered to one when named. */
|
|
2162
|
+
readonly statusOf: (sessionId?: string) => readonly RcSessionStatus[];
|
|
2163
|
+
/** The control requests awaiting an answer, filtered to one session when named. */
|
|
2164
|
+
readonly pendingOf: (sessionId?: string) => readonly RcPendingRequestSummary[];
|
|
2165
|
+
/** The inject operation, already wired to the tracker and the door's API-host dial. */
|
|
2166
|
+
readonly inject: (sessionId: string, text: string) => Promise<RcEventWriteResult>;
|
|
2167
|
+
/** The answer operation, already wired to the tracker and the door's API-host dial. */
|
|
2168
|
+
readonly answer: (sessionId: string, requestId: string, decision: RcAnswerDecision) => Promise<RcEventWriteResult>;
|
|
2169
|
+
/** The interrupt operation, already wired to the tracker and the door's API-host dial. */
|
|
2170
|
+
readonly interrupt: (sessionId: string) => Promise<RcEventWriteResult>;
|
|
2171
|
+
/** The set-model operation, already wired to the tracker and the door's API-host dial. */
|
|
2172
|
+
readonly setModel: (sessionId: string, model: string) => Promise<RcEventWriteResult>;
|
|
2173
|
+
/** The set-permission-mode operation, already wired to the tracker and the door's API-host dial. */
|
|
2174
|
+
readonly setPermissionMode: (sessionId: string, mode: RcPermissionMode) => Promise<RcEventWriteResult>;
|
|
2175
|
+
/** The client attachment's fan-out, whose events the subscription yields. */
|
|
2176
|
+
readonly fanout: RcEventFanout;
|
|
2177
|
+
}
|
|
2178
|
+
/** Builds the typed API's router: one procedure per operation, every one behind the control-token middleware. */
|
|
2179
|
+
declare function createRcApiRouter(deps: RcApiDeps): {
|
|
2180
|
+
rc: {
|
|
2181
|
+
list: _orpc_server.DecoratedProcedure<_orpc_server.MergedInitialContext<{
|
|
2182
|
+
readonly headers: IncomingHttpHeaders;
|
|
2183
|
+
} & Record<never, never>, {
|
|
2184
|
+
readonly headers: IncomingHttpHeaders;
|
|
2185
|
+
}, {
|
|
2186
|
+
readonly headers: IncomingHttpHeaders;
|
|
2187
|
+
}>, any, Schema<unknown, unknown>, zod.ZodObject<{
|
|
2188
|
+
sessions: zod.ZodReadonly<zod.ZodArray<zod.ZodObject<{
|
|
2189
|
+
id: zod.ZodString;
|
|
2190
|
+
createdAt: zod.ZodNumber;
|
|
2191
|
+
lastSeenAt: zod.ZodNumber;
|
|
2192
|
+
}, zod_v4_core.$strict>>>;
|
|
2193
|
+
}, zod_v4_core.$strict>, Record<never, never>, Record<never, never>>;
|
|
2194
|
+
status: _orpc_server.DecoratedProcedure<_orpc_server.MergedInitialContext<{
|
|
2195
|
+
readonly headers: IncomingHttpHeaders;
|
|
2196
|
+
} & Record<never, never>, {
|
|
2197
|
+
readonly headers: IncomingHttpHeaders;
|
|
2198
|
+
}, {
|
|
2199
|
+
readonly headers: IncomingHttpHeaders;
|
|
2200
|
+
}>, any, zod.ZodObject<{
|
|
2201
|
+
session: zod.ZodOptional<zod.ZodString>;
|
|
2202
|
+
}, zod_v4_core.$strict>, zod.ZodObject<{
|
|
2203
|
+
statuses: zod.ZodReadonly<zod.ZodArray<zod.ZodObject<{
|
|
2204
|
+
workerState: zod.ZodOptional<zod.ZodObject<{
|
|
2205
|
+
value: zod.ZodString;
|
|
2206
|
+
observedAt: zod.ZodNumber;
|
|
2207
|
+
}, zod_v4_core.$strict>>;
|
|
2208
|
+
workerIdleSeconds: zod.ZodOptional<zod.ZodObject<{
|
|
2209
|
+
value: zod.ZodNumber;
|
|
2210
|
+
observedAt: zod.ZodNumber;
|
|
2211
|
+
}, zod_v4_core.$strict>>;
|
|
2212
|
+
pending: zod.ZodReadonly<zod.ZodArray<zod.ZodObject<{
|
|
2213
|
+
sessionId: zod.ZodString;
|
|
2214
|
+
requestId: zod.ZodString;
|
|
2215
|
+
type: zod.ZodString;
|
|
2216
|
+
summary: zod.ZodString;
|
|
2217
|
+
observedAt: zod.ZodNumber;
|
|
2218
|
+
}, zod_v4_core.$strict>>>;
|
|
2219
|
+
id: zod.ZodString;
|
|
2220
|
+
createdAt: zod.ZodNumber;
|
|
2221
|
+
lastSeenAt: zod.ZodNumber;
|
|
2222
|
+
}, zod_v4_core.$strict>>>;
|
|
2223
|
+
}, zod_v4_core.$strict>, Record<never, never>, Record<never, never>>;
|
|
2224
|
+
pending: _orpc_server.DecoratedProcedure<_orpc_server.MergedInitialContext<{
|
|
2225
|
+
readonly headers: IncomingHttpHeaders;
|
|
2226
|
+
} & Record<never, never>, {
|
|
2227
|
+
readonly headers: IncomingHttpHeaders;
|
|
2228
|
+
}, {
|
|
2229
|
+
readonly headers: IncomingHttpHeaders;
|
|
2230
|
+
}>, any, zod.ZodObject<{
|
|
2231
|
+
session: zod.ZodOptional<zod.ZodString>;
|
|
2232
|
+
}, zod_v4_core.$strict>, zod.ZodObject<{
|
|
2233
|
+
pending: zod.ZodReadonly<zod.ZodArray<zod.ZodObject<{
|
|
2234
|
+
sessionId: zod.ZodString;
|
|
2235
|
+
requestId: zod.ZodString;
|
|
2236
|
+
type: zod.ZodString;
|
|
2237
|
+
summary: zod.ZodString;
|
|
2238
|
+
observedAt: zod.ZodNumber;
|
|
2239
|
+
}, zod_v4_core.$strict>>>;
|
|
2240
|
+
}, zod_v4_core.$strict>, Record<never, never>, Record<never, never>>;
|
|
2241
|
+
send: _orpc_server.DecoratedProcedure<_orpc_server.MergedInitialContext<{
|
|
2242
|
+
readonly headers: IncomingHttpHeaders;
|
|
2243
|
+
} & Record<never, never>, {
|
|
2244
|
+
readonly headers: IncomingHttpHeaders;
|
|
2245
|
+
}, {
|
|
2246
|
+
readonly headers: IncomingHttpHeaders;
|
|
2247
|
+
}>, any, zod.ZodObject<{
|
|
2248
|
+
session: zod.ZodString;
|
|
2249
|
+
text: zod.ZodString;
|
|
2250
|
+
}, zod_v4_core.$strict>, zod.ZodObject<{
|
|
2251
|
+
session: zod.ZodString;
|
|
2252
|
+
sequenceNums: zod.ZodReadonly<zod.ZodArray<zod.ZodNumber>>;
|
|
2253
|
+
}, zod_v4_core.$strict>, Record<never, never>, Record<never, never>>;
|
|
2254
|
+
answer: _orpc_server.DecoratedProcedure<_orpc_server.MergedInitialContext<{
|
|
2255
|
+
readonly headers: IncomingHttpHeaders;
|
|
2256
|
+
} & Record<never, never>, {
|
|
2257
|
+
readonly headers: IncomingHttpHeaders;
|
|
2258
|
+
}, {
|
|
2259
|
+
readonly headers: IncomingHttpHeaders;
|
|
2260
|
+
}>, any, zod.ZodObject<{
|
|
2261
|
+
session: zod.ZodString;
|
|
2262
|
+
request: zod.ZodString;
|
|
2263
|
+
approve: zod.ZodBoolean;
|
|
2264
|
+
text: zod.ZodOptional<zod.ZodString>;
|
|
2265
|
+
}, zod_v4_core.$strict>, zod.ZodObject<{
|
|
2266
|
+
session: zod.ZodString;
|
|
2267
|
+
request: zod.ZodString;
|
|
2268
|
+
sequenceNums: zod.ZodReadonly<zod.ZodArray<zod.ZodNumber>>;
|
|
2269
|
+
}, zod_v4_core.$strict>, Record<never, never>, Record<never, never>>;
|
|
2270
|
+
interrupt: _orpc_server.DecoratedProcedure<_orpc_server.MergedInitialContext<{
|
|
2271
|
+
readonly headers: IncomingHttpHeaders;
|
|
2272
|
+
} & Record<never, never>, {
|
|
2273
|
+
readonly headers: IncomingHttpHeaders;
|
|
2274
|
+
}, {
|
|
2275
|
+
readonly headers: IncomingHttpHeaders;
|
|
2276
|
+
}>, any, zod.ZodObject<{
|
|
2277
|
+
session: zod.ZodString;
|
|
2278
|
+
}, zod_v4_core.$strict>, zod.ZodObject<{
|
|
2279
|
+
session: zod.ZodString;
|
|
2280
|
+
sequenceNums: zod.ZodReadonly<zod.ZodArray<zod.ZodNumber>>;
|
|
2281
|
+
}, zod_v4_core.$strict>, Record<never, never>, Record<never, never>>;
|
|
2282
|
+
setModel: _orpc_server.DecoratedProcedure<_orpc_server.MergedInitialContext<{
|
|
2283
|
+
readonly headers: IncomingHttpHeaders;
|
|
2284
|
+
} & Record<never, never>, {
|
|
2285
|
+
readonly headers: IncomingHttpHeaders;
|
|
2286
|
+
}, {
|
|
2287
|
+
readonly headers: IncomingHttpHeaders;
|
|
2288
|
+
}>, any, zod.ZodObject<{
|
|
2289
|
+
session: zod.ZodString;
|
|
2290
|
+
model: zod.ZodString;
|
|
2291
|
+
}, zod_v4_core.$strict>, zod.ZodObject<{
|
|
2292
|
+
session: zod.ZodString;
|
|
2293
|
+
sequenceNums: zod.ZodReadonly<zod.ZodArray<zod.ZodNumber>>;
|
|
2294
|
+
}, zod_v4_core.$strict>, Record<never, never>, Record<never, never>>;
|
|
2295
|
+
setPermissionMode: _orpc_server.DecoratedProcedure<_orpc_server.MergedInitialContext<{
|
|
2296
|
+
readonly headers: IncomingHttpHeaders;
|
|
2297
|
+
} & Record<never, never>, {
|
|
2298
|
+
readonly headers: IncomingHttpHeaders;
|
|
2299
|
+
}, {
|
|
2300
|
+
readonly headers: IncomingHttpHeaders;
|
|
2301
|
+
}>, any, zod.ZodObject<{
|
|
2302
|
+
session: zod.ZodString;
|
|
2303
|
+
mode: zod.ZodEnum<{
|
|
2304
|
+
default: "default";
|
|
2305
|
+
acceptEdits: "acceptEdits";
|
|
2306
|
+
bypassPermissions: "bypassPermissions";
|
|
2307
|
+
plan: "plan";
|
|
2308
|
+
dontAsk: "dontAsk";
|
|
2309
|
+
auto: "auto";
|
|
2310
|
+
}>;
|
|
2311
|
+
}, zod_v4_core.$strict>, zod.ZodObject<{
|
|
2312
|
+
session: zod.ZodString;
|
|
2313
|
+
sequenceNums: zod.ZodReadonly<zod.ZodArray<zod.ZodNumber>>;
|
|
2314
|
+
}, zod_v4_core.$strict>, Record<never, never>, Record<never, never>>;
|
|
2315
|
+
subscribe: _orpc_server.DecoratedProcedure<_orpc_server.MergedInitialContext<{
|
|
2316
|
+
readonly headers: IncomingHttpHeaders;
|
|
2317
|
+
} & Record<never, never>, {
|
|
2318
|
+
readonly headers: IncomingHttpHeaders;
|
|
2319
|
+
}, {
|
|
2320
|
+
readonly headers: IncomingHttpHeaders;
|
|
2321
|
+
}>, any, zod.ZodObject<{
|
|
2322
|
+
session: zod.ZodOptional<zod.ZodString>;
|
|
2323
|
+
}, zod_v4_core.$strict>, any, Record<never, never>, Record<never, never>>;
|
|
2324
|
+
};
|
|
2325
|
+
};
|
|
2326
|
+
/** The typed API's router, as the CLI-side client's own type is derived from it. */
|
|
2327
|
+
type RcApiRouter = ReturnType<typeof createRcApiRouter>;
|
|
2328
|
+
/**
|
|
2329
|
+
* Builds the typed API's node handler, already bound to its mount prefix and context: the pre-pipeline surface the provider listener hands every request under `RC_ORPC_PATH_PREFIX`, answering with `matched: false` for a path under the prefix that names no procedure (which the listener itself answers as a 404). Request bodies are bounded by the same protocol cap the bespoke routes apply.
|
|
2330
|
+
*/
|
|
2331
|
+
declare function createRcApiNodeHandler(deps: RcApiDeps): PrePipelineApi;
|
|
2332
|
+
/** The typed API's client as the `frontdoor rc` verbs use it: every call presents the control token, over TLS trusting only the CA file the door's own state names. */
|
|
2333
|
+
type RcApiClient = RouterClient<RcApiRouter>;
|
|
2334
|
+
/** Builds the typed API's client for the door's provider listener: the same address, CA and per-generation control token the bespoke control client uses. */
|
|
2335
|
+
declare function frontDoorRcApiClient(port: number, ca: string, token: string): RcApiClient;
|
|
2336
|
+
|
|
1969
2337
|
/** The outcome of authenticating the listener a front-door state file names. */
|
|
1970
2338
|
type ListenerVerdict = {
|
|
1971
2339
|
readonly ok: true;
|
|
@@ -2417,24 +2785,6 @@ declare function ensureHeadroom(params: {
|
|
|
2417
2785
|
/** The token-saving settings of the `headroom` config block, without its install and lifecycle fields (`source`, `idleShutdownMinutes`). */
|
|
2418
2786
|
type HeadroomSettings = Pick<HeadroomGlobalConfig, "mode" | "targetRatio" | "ccr" | "rolloutChannel" | "interceptToolResults" | "readMaturation">;
|
|
2419
2787
|
|
|
2420
|
-
/** What an `lstat` (which never follows symlinks) reports about one path, narrowed to what authenticating the socket needs. */
|
|
2421
|
-
interface SocketPathStat {
|
|
2422
|
-
readonly kind: "dir" | "socket" | "symlink" | "other";
|
|
2423
|
-
/** The owning user id. */
|
|
2424
|
-
readonly uid: number;
|
|
2425
|
-
/** The permission bits, without the file type bits. */
|
|
2426
|
-
readonly mode: number;
|
|
2427
|
-
}
|
|
2428
|
-
/** The platform facts and the one filesystem call the socket checks need, injected so every refusal is unit-testable without a real socket, directory or second user. */
|
|
2429
|
-
interface HeadroomSocketTrustPorts {
|
|
2430
|
-
/** `process.platform` in the real implementation. */
|
|
2431
|
-
readonly platform: string;
|
|
2432
|
-
/** This process's user id. Only called on a platform with unix sockets, which all have POSIX user ids. */
|
|
2433
|
-
readonly currentUid: () => number;
|
|
2434
|
-
/** Stats one path without following symlinks, or returns undefined when nothing is there. */
|
|
2435
|
-
readonly lstat: (target: string) => SocketPathStat | undefined;
|
|
2436
|
-
}
|
|
2437
|
-
|
|
2438
2788
|
/** Everything the supervisor needs to run the daemon, resolved from the global config and the filesystem before it starts. */
|
|
2439
2789
|
interface HeadroomSupervisorConfig {
|
|
2440
2790
|
/** The install spec as configured (`headroom.source`), already defaulted. */
|
|
@@ -2962,6 +3312,14 @@ declare function updateDirectoryRule(paths: LayoutPaths, rulePath: string, optio
|
|
|
2962
3312
|
/** Removes the directory rule for `rulePath`. Throws `DirectoryRuleNotFoundError` when no rule matches that exact path. */
|
|
2963
3313
|
declare function removeDirectoryRule(paths: LayoutPaths, rulePath: string): void;
|
|
2964
3314
|
|
|
3315
|
+
/** Where a pinned Claude Code version came from, strongest first: the launch's own flag, then the environment, then the cascade. */
|
|
3316
|
+
type ClaudeVersionSource = "flag" | "environment" | "cascade";
|
|
3317
|
+
/** The pinned version a launch runs, and which of the three forms named it. */
|
|
3318
|
+
interface PinnedClaudeVersion {
|
|
3319
|
+
readonly version: string;
|
|
3320
|
+
readonly source: ClaudeVersionSource;
|
|
3321
|
+
}
|
|
3322
|
+
|
|
2965
3323
|
/** Which precedence rule produced an identity decision. */
|
|
2966
3324
|
type IdentityDecisionSource =
|
|
2967
3325
|
/** `CLAUDE_CONFIG_DIR` was already set: identity resolution is skipped entirely and the real binary uses whatever it already points to. */
|
|
@@ -3086,6 +3444,8 @@ interface RunCheckParams {
|
|
|
3086
3444
|
readonly platform: string;
|
|
3087
3445
|
/** The provider a launch here would route through (`launch.provider` in the cascade), when one is selected. */
|
|
3088
3446
|
readonly provider?: CheckProviderInput;
|
|
3447
|
+
/** The Claude Code versions installed here, oldest first. Omit to leave the Claude Code version out of the report; with it, `check` says which version a launch here runs and whether a pin is installed. */
|
|
3448
|
+
readonly installedClaudeVersions?: readonly string[];
|
|
3089
3449
|
/** Where cached credentials live. Omit to skip reporting a credential cache's age; with it, a block that caches reports whether it holds an entry, how old it is and whether it has expired, never the token. */
|
|
3090
3450
|
readonly credentialCache?: CredentialCacheEnv;
|
|
3091
3451
|
}
|
|
@@ -3103,6 +3463,16 @@ interface CheckReport {
|
|
|
3103
3463
|
readonly keychain?: KeychainLookupResult;
|
|
3104
3464
|
readonly settingsExposure: readonly SettingsExposureReport[];
|
|
3105
3465
|
readonly credential: CredentialReport;
|
|
3466
|
+
/** The Claude Code version a launch here would run, when the installed versions were given. */
|
|
3467
|
+
readonly claudeVersion?: ClaudeVersionReport;
|
|
3468
|
+
}
|
|
3469
|
+
/** Which Claude Code version a launch would run: the pin and where it comes from, with whether it is installed, or the highest installed version when nothing pins one. */
|
|
3470
|
+
interface ClaudeVersionReport {
|
|
3471
|
+
readonly pinned?: PinnedClaudeVersion & {
|
|
3472
|
+
readonly installed: boolean;
|
|
3473
|
+
};
|
|
3474
|
+
readonly highestInstalled?: string;
|
|
3475
|
+
readonly installed: readonly string[];
|
|
3106
3476
|
}
|
|
3107
3477
|
/**
|
|
3108
3478
|
* Resolves the full cascade for one directory/identity and reports everything `agent-shim check` documents: every entry's resolved state and which layer/condition decided it, any ambiguous `history/projects/` encoding in scope, and the three always-on diagnostics (ambient-credential exposure, macOS Keychain service name, settings-secrets exposure).
|
|
@@ -3161,6 +3531,12 @@ interface DiscoveredClaudeBinary {
|
|
|
3161
3531
|
/** The version string, when discovered via the versions directory. */
|
|
3162
3532
|
version?: string;
|
|
3163
3533
|
}
|
|
3534
|
+
/** What a launch asks binary discovery for: nothing (the highest installed version) or an exact version. */
|
|
3535
|
+
interface ClaudeBinaryRequest {
|
|
3536
|
+
readonly version?: string;
|
|
3537
|
+
}
|
|
3538
|
+
/** Discovers the real `claude` binary to spawn, for the version a launch asked for. Injected into the launcher so it never reads the filesystem or PATH itself. */
|
|
3539
|
+
type ClaudeBinaryResolver = (request?: Readonly<ClaudeBinaryRequest>) => DiscoveredClaudeBinary;
|
|
3164
3540
|
|
|
3165
3541
|
type DoctorSeverity = "pass" | "warn" | "fail";
|
|
3166
3542
|
type DoctorSection = "ambient-credential" | "binary-discovery" | "claude-shim" | "path-resolution" | "legacy-name" | "config-profile" | "identity" | "pool" | "provider" | "keychain" | "directory-rules" | "global-config" | "categories-local" | "active-identity" | "headroom";
|
|
@@ -3222,6 +3598,8 @@ interface DoctorPathResolution {
|
|
|
3222
3598
|
/** Everything `runDoctor` needs, all of it already loaded/injected — nothing in `runDoctor` itself reads a file, shells out, or touches the farm. */
|
|
3223
3599
|
interface RunDoctorParams {
|
|
3224
3600
|
readonly env: Readonly<Record<string, string | undefined>>;
|
|
3601
|
+
/** The Claude Code versions installed here, oldest first. Omit to skip checking that a pinned version (`launch.claudeVersion`) is installed; with it, a profile, directory rule or global config pinning a version that is not installed is a warning. */
|
|
3602
|
+
readonly installedClaudeVersions?: readonly string[];
|
|
3225
3603
|
/** Where cached credentials live. Omit to leave a credential cache's age out of the identity and provider findings; with it, a block that caches reports whether it holds an entry, how old it is and whether it has expired, never the token. */
|
|
3226
3604
|
readonly credentialCache?: CredentialCacheEnv;
|
|
3227
3605
|
readonly identities: readonly DoctorIdentityInput[];
|
|
@@ -3319,7 +3697,7 @@ interface PrepareLaunchParams {
|
|
|
3319
3697
|
readonly proc: ProcPort;
|
|
3320
3698
|
readonly log: LogPort;
|
|
3321
3699
|
/** Discovers the real `claude` binary to spawn. Injected so `runLauncher` never depends on `src/versionDiscovery.ts`'s own filesystem/PATH inputs directly — the caller (`src/cli.ts`) wires the real discovery, tests wire a fake that returns a fixed path. */
|
|
3322
|
-
readonly resolveClaudeBinary:
|
|
3700
|
+
readonly resolveClaudeBinary: ClaudeBinaryResolver;
|
|
3323
3701
|
/** An identity pinned to `$PWD` by a directory rule. Accepted as an already-resolved value — the rules-loading code that produces it lands in Phase 4/5. */
|
|
3324
3702
|
readonly directoryPinnedIdentity?: string;
|
|
3325
3703
|
/** A directory rule's `configProfile` selection for `$PWD`. Accepted as an already-resolved value for the same reason. */
|
|
@@ -3387,5 +3765,5 @@ interface PrepareClaudeLaunchOptions {
|
|
|
3387
3765
|
*/
|
|
3388
3766
|
declare function prepareClaudeLaunch(options: PrepareClaudeLaunchOptions): LaunchPlan;
|
|
3389
3767
|
|
|
3390
|
-
export { AMBIENT_CREDENTIAL_VARS, CONNECT_INTERCEPT_HOST, CONNECT_INTERCEPT_HOSTS, CONNECT_LIMITS, CONTROL_PATH_PREFIX, CategoryClassificationOverlaySchema, CategoryClassificationSchema, CategoryMapSchema, CliError, ConfigProfileSchema, CredentialCacheSchema, CredentialSchema, CredentialSourceSchema, DirectoryRuleAlreadyExistsError, DirectoryRuleMissingTargetError, DirectoryRuleNotFoundError, DirectoryRuleSchema, DirectoryRulesSchema, EXIT_FAILURE, EXIT_USAGE, EntryValueSchema, FARM_MANIFEST_FILENAME, FrontDoorStartError, GlobalConfigSchema, HeadroomStartError, IdentityAlreadyExistsError, IdentityNotFoundError, IdentitySchema, InvalidCategoryNameError, InvalidIdentityNameError, InvalidProviderNameError, LaunchRefusedError, LegacyProviderFileError, PROMPT_CACHE_TTL_MS, PlanClassSchema, PoolNameSchema, PoolNotFoundError, PoolPickReportSchema, PoolSchema, PortableConfigSchema, ProfileAlreadyExistsError, ProfileNotFoundError, ProviderAlreadyExistsError, ProviderKindMismatchError, ProviderNotFoundError, ProviderSchema, RC_IDLE_EXPIRY_MS, RC_PENDING_DEADLINE_MS, RC_PERMISSION_MODES, RC_REQUEST_PARSE_CAP_BYTES, RC_SESSIONS_PATH_PREFIX, ROUTED_PATH_PREFIX, UsageError, UsageSnapshotError, UsageSnapshotSchema, WhenSchema, addDirectoryRule, addIdentity, addPool, addProvider, answerRcControlRequest, buildEntryFacts, buildLayoutPaths, buildRcControlResponsePayload, buildRcEventWriteBody, buildRcInterruptPayload, buildRcSetModelPayload, buildRcSetPermissionModePayload, buildRcUserMessagePayload, carryOver, checkReportHasWarnings, checkReportToJson, collectCheckReport, collectDoctorReport, collectPoolPick, createLeafCache, createProfile, createRcControlHandler, createRcSessionTracker, describeProviderEndpoint, detectAmbientCredential, effectiveWindow, ensureCa, ensureFrontDoor, ensureHeadroom, evaluateAmbientCredentialGuard, evaluateWhen, formatAmbientCredentialGuardMessage, formatCheckReport, formatDoctorReport, forwardableHeaders, frontDoorRcControl, generateCa, identityExists, injectRcUserMessage, interruptRcSession, isIdentityDirectoryName, isInterceptedHost, isRcPermissionMode, listDirectoryRules, listIdentities, listProfiles, listProviders, listUsageSnapshots, matchBranch, mintLeaf, observingRoutedRoute, parseConnectTarget, planOf, prepareClaudeLaunch, prepareLaunch, profileExists, providerExists, rankPool, rcEventWriteResultFromAnswer, rcObserverAsPassthrough, readActiveIdentity, readDirectoryRules, readFarmManifest, readGlobalConfig, readIdentity, readPools, readProfile, readProvider, readUsageSnapshot, realConnectCertStore, realConnectEffects, realRcControlTransport, realRcEventDial, recoverFarm, recoveryDiagnostics, removeDirectoryRule, removeIdentity, removePool, removeProfile, removeProvider, requirePool, resolveAgentShimHome, resolveClaudeHome, resolveDecisions, resolveLayoutPaths, resolveSupervisorConfig, resyncFarm, runCheck, runDoctor, runFrontDoorSupervisor, runSupervisor, servedByPipeline, setAllowAmbientCredential, setDefaultConfigProfile, setGlobalDefaultProfile, setIdentityCredential, setPool, setProfileCategories, setProfileEntries, setProfileLaunchFlags, setProfileMetadata, setRcSessionModel, setRcSessionPermissionMode, snapshotPath, startConnectServer, topLevelNames, updateDirectoryRule, updateProvider, useIdentity, writeDirectoryRules };
|
|
3391
|
-
export type { AddDirectoryRuleOptions, AddProviderInput, AmbientCredentialDetection, AmbientCredentialGuardResult, AmbientCredentialVar, BuildEntryFactsParams, CaMaterial, Candidate, CarryOverParams, CarryOverResult, CategoryMap, CheckReport, CollectCheckReportParams, CollectDoctorReportParams, CompiledRule, ConditionContext, ConfigProfile, ConnectCertStore, ConnectEffects, ConnectLimits, ConnectServerConfig, ConnectServerHandle, ConnectTarget, Credential, CredentialSource, Decision, Diagnostic, DirectoryRule, DirectoryRules, DoctorReport, EffectiveWindow, EliminatedRule, EnsureFrontDoorPorts, EnsureHeadroomPorts, EntryFact, EntryFacts, EntryValue, EvaluateAmbientCredentialGuardParams, FlattenedCascade, FrontDoorRcControl, FrontDoorSupervisorPorts, GlobalConfig, HeadroomSupervisorConfig, Identity, IdentityCredentialChange, IdentityListEntry, IdentityListing, InjectedCredential, LaunchPlan, Layer, LayerId, LayoutPaths, LeafCert, PlanClass, Pool, PoolMember, PoolPickReport, PoolRanking, PortableConfig, PrepareClaudeLaunchOptions, PrepareLaunchParams, ProfileListEntry, Provider, ProviderListEntry, RankPoolInput, RcAnswerDecision, RcAnswerDeps, RcControlAnswer, RcControlHandlerDeps, RcControlRequestDeps, RcControlTransport, RcDialAnswer, RcDialTarget, RcEventDial, RcEventWriteResult, RcExchangeObserver, RcInjectDeps, RcObservedCredential, RcObservedRequest, RcPendingRequestSummary, RcPermissionMode, RcSessionStatus, RcSessionSummary, RcSessionTracker, RcSessionTrackerDeps, RcWorkerFact, RcWriteHeaders, RecoverFarmParams, RecoveryResult, ResolveDecisionsInput, ResolvedState, ResyncFarmParams, ResyncFarmResult, RunCheckParams, RunDoctorParams, RunFrontDoorSupervisorOptions, RunSupervisorOptions, StickyPick, SupervisorPorts, UnreadableIdentityListEntry, UpdateDirectoryRuleOptions, UpdateProviderInput, UsageReadFs, UsageSnapshot, WhenCondition, WhenEvaluation };
|
|
3768
|
+
export { AMBIENT_CREDENTIAL_VARS, CONNECT_INTERCEPT_HOST, CONNECT_INTERCEPT_HOSTS, CONNECT_LIMITS, CONTROL_PATH_PREFIX, CategoryClassificationOverlaySchema, CategoryClassificationSchema, CategoryMapSchema, CliError, ConfigProfileSchema, CredentialCacheSchema, CredentialSchema, CredentialSourceSchema, DirectoryRuleAlreadyExistsError, DirectoryRuleMissingTargetError, DirectoryRuleNotFoundError, DirectoryRuleSchema, DirectoryRulesSchema, EXIT_FAILURE, EXIT_USAGE, EntryValueSchema, FARM_MANIFEST_FILENAME, FrontDoorStartError, GlobalConfigSchema, HeadroomStartError, IdentityAlreadyExistsError, IdentityNotFoundError, IdentitySchema, InvalidCategoryNameError, InvalidIdentityNameError, InvalidProviderNameError, LaunchRefusedError, LegacyProviderFileError, PROMPT_CACHE_TTL_MS, PlanClassSchema, PoolNameSchema, PoolNotFoundError, PoolPickReportSchema, PoolSchema, PortableConfigSchema, ProfileAlreadyExistsError, ProfileNotFoundError, ProviderAlreadyExistsError, ProviderKindMismatchError, ProviderNotFoundError, ProviderSchema, RC_IDLE_EXPIRY_MS, RC_ORPC_PATH_PREFIX, RC_PENDING_DEADLINE_MS, RC_PERMISSION_MODES, RC_REQUEST_PARSE_CAP_BYTES, RC_SESSIONS_PATH_PREFIX, RC_STREAM_BACKOFF_MS, ROUTED_PATH_PREFIX, RcPermissionModeSchema, RcStreamEnvelopeSchema, RcStreamEventSchema, UsageError, UsageSnapshotError, UsageSnapshotSchema, WhenSchema, addDirectoryRule, addIdentity, addPool, addProvider, answerRcControlRequest, buildEntryFacts, buildLayoutPaths, buildRcControlResponsePayload, buildRcEventWriteBody, buildRcInterruptPayload, buildRcSetModelPayload, buildRcSetPermissionModePayload, buildRcUserMessagePayload, carryOver, checkReportHasWarnings, checkReportToJson, collectCheckReport, collectDoctorReport, collectPoolPick, createLeafCache, createProfile, createRcApiNodeHandler, createRcApiRouter, createRcControlHandler, createRcEventFanout, createRcSessionTracker, createRcStreamHub, createSseParser, describeProviderEndpoint, detectAmbientCredential, effectiveWindow, ensureCa, ensureFrontDoor, ensureHeadroom, evaluateAmbientCredentialGuard, evaluateWhen, formatAmbientCredentialGuardMessage, formatCheckReport, formatDoctorReport, forwardableHeaders, frontDoorRcApiClient, frontDoorRcControl, generateCa, identityExists, injectRcUserMessage, interruptRcSession, isIdentityDirectoryName, isInterceptedHost, isRcPermissionMode, listDirectoryRules, listIdentities, listProfiles, listProviders, listUsageSnapshots, matchBranch, mintLeaf, observingRoutedRoute, parseConnectTarget, parseRcStreamEnvelope, planOf, prepareClaudeLaunch, prepareLaunch, profileExists, providerExists, rankPool, rcEventWriteResultFromAnswer, rcObserverAsPassthrough, readActiveIdentity, readDirectoryRules, readFarmManifest, readGlobalConfig, readIdentity, readPools, readProfile, readProvider, readUsageSnapshot, realConnectCertStore, realConnectEffects, realRcControlTransport, realRcEventDial, realRcStreamDial, recoverFarm, recoveryDiagnostics, removeDirectoryRule, removeIdentity, removePool, removeProfile, removeProvider, requirePool, resolveAgentShimHome, resolveClaudeHome, resolveDecisions, resolveLayoutPaths, resolveSupervisorConfig, resyncFarm, runCheck, runDoctor, runFrontDoorSupervisor, runSupervisor, servedByPipeline, setAllowAmbientCredential, setDefaultConfigProfile, setGlobalDefaultProfile, setIdentityCredential, setPool, setProfileCategories, setProfileEntries, setProfileLaunchFlags, setProfileMetadata, setRcSessionModel, setRcSessionPermissionMode, snapshotPath, startConnectServer, topLevelNames, updateDirectoryRule, updateProvider, useIdentity, writeDirectoryRules };
|
|
3769
|
+
export type { AddDirectoryRuleOptions, AddProviderInput, AmbientCredentialDetection, AmbientCredentialGuardResult, AmbientCredentialVar, BuildEntryFactsParams, CaMaterial, Candidate, CarryOverParams, CarryOverResult, CategoryMap, CheckReport, CollectCheckReportParams, CollectDoctorReportParams, CompiledRule, ConditionContext, ConfigProfile, ConnectCertStore, ConnectEffects, ConnectLimits, ConnectServerConfig, ConnectServerHandle, ConnectTarget, Credential, CredentialSource, Decision, Diagnostic, DirectoryRule, DirectoryRules, DoctorReport, EffectiveWindow, EliminatedRule, EnsureFrontDoorPorts, EnsureHeadroomPorts, EntryFact, EntryFacts, EntryValue, EvaluateAmbientCredentialGuardParams, FlattenedCascade, FrontDoorRcControl, FrontDoorSupervisorPorts, GlobalConfig, HeadroomSupervisorConfig, Identity, IdentityCredentialChange, IdentityListEntry, IdentityListing, InjectedCredential, LaunchPlan, Layer, LayerId, LayoutPaths, LeafCert, PlanClass, Pool, PoolMember, PoolPickReport, PoolRanking, PortableConfig, PrepareClaudeLaunchOptions, PrepareLaunchParams, ProfileListEntry, Provider, ProviderListEntry, RankPoolInput, RcAnswerDecision, RcAnswerDeps, RcApiClient, RcApiDeps, RcApiRouter, RcControlAnswer, RcControlHandlerDeps, RcControlRequestDeps, RcControlTransport, RcDialAnswer, RcDialTarget, RcEventDial, RcEventFanout, RcEventWriteResult, RcExchangeObserver, RcInjectDeps, RcObservedCredential, RcObservedRequest, RcPendingRequestSummary, RcPermissionMode, RcPresenceAnswer, RcSessionStatus, RcSessionSummary, RcSessionTracker, RcSessionTrackerDeps, RcStreamAnswer, RcStreamDial, RcStreamEnvelope, RcStreamEvent, RcStreamHub, RcStreamHubDeps, RcWorkerFact, RcWriteHeaders, RecoverFarmParams, RecoveryResult, ResolveDecisionsInput, ResolvedState, ResyncFarmParams, ResyncFarmResult, RunCheckParams, RunDoctorParams, RunFrontDoorSupervisorOptions, RunSupervisorOptions, SseParsedEvent, StickyPick, SupervisorPorts, UnreadableIdentityListEntry, UpdateDirectoryRuleOptions, UpdateProviderInput, UsageReadFs, UsageSnapshot, WhenCondition, WhenEvaluation };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-shim",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.10.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>",
|
|
@@ -50,6 +50,8 @@
|
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
52
|
"@clack/prompts": "^1.8.0",
|
|
53
|
+
"@orpc/client": "1.15.4",
|
|
54
|
+
"@orpc/server": "1.15.4",
|
|
53
55
|
"commander": "^15.0.0",
|
|
54
56
|
"cosmiconfig": "^10.0.1",
|
|
55
57
|
"picomatch": "^4.0.7",
|