@roamcode.ai/server 1.0.23 → 1.1.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/dist/container/relay.js +1647 -0
- package/dist/health-watchdog.js +87 -0
- package/dist/index.d.ts +1770 -20
- package/dist/index.js +18037 -3840
- package/dist/managed-update-helper.js +4 -1
- package/dist/relay-start.d.ts +118 -0
- package/dist/relay-start.js +1642 -0
- package/dist/start.d.ts +504 -19
- package/dist/start.js +17261 -4824
- package/package.json +6 -5
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import * as better_sqlite3 from 'better-sqlite3';
|
|
2
2
|
import { FastifyInstance } from 'fastify';
|
|
3
|
+
import WebSocket from 'ws';
|
|
4
|
+
import { z, ZodType } from 'zod';
|
|
3
5
|
import { spawn, ChildProcess, SpawnOptions } from 'node:child_process';
|
|
4
6
|
import { EventEmitter } from 'node:events';
|
|
5
|
-
import { ZodType } from 'zod';
|
|
6
7
|
|
|
7
8
|
interface ServerConfig {
|
|
8
9
|
claudeBin: string;
|
|
@@ -138,6 +139,12 @@ declare function assertConfigAllowsStart(cfg: ServerRuntimeConfig): void;
|
|
|
138
139
|
declare function extractBearerToken(authorizationHeader: string | undefined): string | undefined;
|
|
139
140
|
interface AuthGateOptions {
|
|
140
141
|
token?: string;
|
|
142
|
+
/**
|
|
143
|
+
* Optional verifier for independently revocable credentials (for example per-device tokens). It
|
|
144
|
+
* receives the presented plaintext once; implementations should persist only a digest. A verifier
|
|
145
|
+
* failure is treated as an invalid credential and can never take the server down.
|
|
146
|
+
*/
|
|
147
|
+
verifyCredential?: (token: string) => boolean;
|
|
141
148
|
/** Consecutive failures from one client before it is locked out. Default 10. */
|
|
142
149
|
maxFailures?: number;
|
|
143
150
|
/** Lockout duration in ms. Default 60000. */
|
|
@@ -181,6 +188,7 @@ declare class AuthGate {
|
|
|
181
188
|
private readonly lockoutMs;
|
|
182
189
|
private readonly graceMs;
|
|
183
190
|
private readonly now;
|
|
191
|
+
private readonly verifyCredential?;
|
|
184
192
|
private readonly clients;
|
|
185
193
|
constructor(opts: AuthGateOptions);
|
|
186
194
|
check(presentedToken: string | undefined, clientKey: string): AuthCheckResult;
|
|
@@ -193,6 +201,10 @@ declare class AuthGate {
|
|
|
193
201
|
* slate is correct (and avoids leaving a client locked out against a token that no longer exists).
|
|
194
202
|
*/
|
|
195
203
|
rotateToken(newToken: string): void;
|
|
204
|
+
/** True only for the current host recovery credential (never a device key or grace token). */
|
|
205
|
+
isCurrentHostToken(presentedToken: string | undefined): boolean;
|
|
206
|
+
/** Security reset: replace the host credential immediately, with no previous-token grace window. */
|
|
207
|
+
resetToken(newToken: string): void;
|
|
196
208
|
/** Drop entries whose lockout has expired and whose failure count is 0 — keeps the map bounded. */
|
|
197
209
|
private sweepExpired;
|
|
198
210
|
/** TEST ONLY: number of tracked clients currently locked (lockedUntil in the future). */
|
|
@@ -319,7 +331,58 @@ declare class FsService {
|
|
|
319
331
|
pruneOlderThan(target: string, maxAgeMs: number, now?: number, recursive?: boolean): Promise<number>;
|
|
320
332
|
}
|
|
321
333
|
|
|
322
|
-
|
|
334
|
+
declare const ADAPTER_CONTRACT_VERSION: 1;
|
|
335
|
+
declare const adapterCapabilityNames: readonly ["probe", "launch", "resume", "state", "identity", "metadata", "usage", "login", "attachments", "cleanup"];
|
|
336
|
+
type AdapterCapabilityName = (typeof adapterCapabilityNames)[number];
|
|
337
|
+
type AdapterStateAuthority = "native-events" | "runtime-signals" | "pane-heuristics";
|
|
338
|
+
interface AdapterManifestV1 {
|
|
339
|
+
schemaVersion: typeof ADAPTER_CONTRACT_VERSION;
|
|
340
|
+
id: string;
|
|
341
|
+
version: string;
|
|
342
|
+
displayName: string;
|
|
343
|
+
platforms: Array<"darwin" | "linux">;
|
|
344
|
+
resumeIdentity: "optional" | "required" | "unsupported";
|
|
345
|
+
capabilities: Record<AdapterCapabilityName, boolean>;
|
|
346
|
+
stateAuthority: AdapterStateAuthority[];
|
|
347
|
+
/** JSON Schema for the adapter-owned launch options. */
|
|
348
|
+
optionSchema: Record<string, unknown>;
|
|
349
|
+
}
|
|
350
|
+
declare class AdapterManifestError extends Error {
|
|
351
|
+
constructor(message: string);
|
|
352
|
+
}
|
|
353
|
+
/** The supported, bounded JSON Schema subset shared by the server validator, generated UI, and OpenAPI. */
|
|
354
|
+
declare function validateAdapterOptionSchema(value: unknown): Record<string, unknown>;
|
|
355
|
+
declare function validateAdapterManifest(value: unknown): AdapterManifestV1;
|
|
356
|
+
/** Validate and freeze the public metadata at the adapter boundary before any lifecycle code can run. */
|
|
357
|
+
declare function defineAdapterManifest(value: AdapterManifestV1): Readonly<AdapterManifestV1>;
|
|
358
|
+
declare function publicAdapterDescriptor(manifest: AdapterManifestV1, source: "built-in" | "installed"): {
|
|
359
|
+
id: string;
|
|
360
|
+
displayName: string;
|
|
361
|
+
version: string;
|
|
362
|
+
schemaVersion: 1;
|
|
363
|
+
source: "built-in" | "installed";
|
|
364
|
+
enabled: boolean;
|
|
365
|
+
platforms: ("darwin" | "linux")[];
|
|
366
|
+
resumeIdentity: "optional" | "required" | "unsupported";
|
|
367
|
+
capabilities: {
|
|
368
|
+
state: boolean;
|
|
369
|
+
probe: boolean;
|
|
370
|
+
launch: boolean;
|
|
371
|
+
resume: boolean;
|
|
372
|
+
identity: boolean;
|
|
373
|
+
metadata: boolean;
|
|
374
|
+
usage: boolean;
|
|
375
|
+
login: boolean;
|
|
376
|
+
attachments: boolean;
|
|
377
|
+
cleanup: boolean;
|
|
378
|
+
};
|
|
379
|
+
stateAuthority: AdapterStateAuthority[];
|
|
380
|
+
optionSchema: Record<string, unknown>;
|
|
381
|
+
};
|
|
382
|
+
|
|
383
|
+
/** Public adapter identity. Built-ins are ordinary ids under the same contract; third parties are not
|
|
384
|
+
* forced through a source-code union update. Runtime validation is owned by ProviderRegistry. */
|
|
385
|
+
type ProviderId = string;
|
|
323
386
|
interface ProviderAvailability {
|
|
324
387
|
terminalAvailable: boolean;
|
|
325
388
|
metadataAvailable: boolean;
|
|
@@ -350,7 +413,22 @@ type CodexSessionOptions = {
|
|
|
350
413
|
dangerouslyBypassApprovalsAndSandbox?: boolean;
|
|
351
414
|
addDirs?: string[];
|
|
352
415
|
};
|
|
353
|
-
|
|
416
|
+
interface ProviderSessionOptions {
|
|
417
|
+
provider: ProviderId;
|
|
418
|
+
model?: string;
|
|
419
|
+
effort?: string;
|
|
420
|
+
reasoningEffort?: string;
|
|
421
|
+
permissionMode?: ClaudeSessionOptions["permissionMode"];
|
|
422
|
+
dangerouslySkip?: boolean;
|
|
423
|
+
sandbox?: CodexSessionOptions["sandbox"];
|
|
424
|
+
approvalPolicy?: CodexSessionOptions["approvalPolicy"];
|
|
425
|
+
profile?: string;
|
|
426
|
+
webSearch?: boolean;
|
|
427
|
+
dangerouslyBypassApprovalsAndSandbox?: boolean;
|
|
428
|
+
addDirs?: string[];
|
|
429
|
+
legacyArgs?: string[];
|
|
430
|
+
[key: string]: unknown;
|
|
431
|
+
}
|
|
354
432
|
type LaunchIntent = "fresh" | "resume";
|
|
355
433
|
interface ProcessSpec {
|
|
356
434
|
executable: string;
|
|
@@ -399,9 +477,11 @@ interface ProviderRuntimeMetadata {
|
|
|
399
477
|
effort?: string;
|
|
400
478
|
}
|
|
401
479
|
interface AgentProvider {
|
|
480
|
+
/** Exact public, versioned adapter contract. Optional only for legacy in-process test doubles. */
|
|
481
|
+
readonly manifest?: Readonly<AdapterManifestV1>;
|
|
402
482
|
readonly id: ProviderId;
|
|
403
483
|
readonly displayName: string;
|
|
404
|
-
readonly resumeIdentity: "optional" | "required";
|
|
484
|
+
readonly resumeIdentity: "optional" | "required" | "unsupported";
|
|
405
485
|
probe(): Promise<ProviderAvailability>;
|
|
406
486
|
buildProcess(context: ProviderProcessContext): Promise<ProcessSpec>;
|
|
407
487
|
/** Stateful parsers must be created per spawned process; providers are registry singletons. */
|
|
@@ -413,6 +493,10 @@ interface AgentProvider {
|
|
|
413
493
|
runtimeMetadata?(pane: string): ProviderRuntimeMetadata | undefined;
|
|
414
494
|
cleanup(paths: readonly string[]): void;
|
|
415
495
|
}
|
|
496
|
+
/** Installable and built-in adapters must implement this strict public shape. */
|
|
497
|
+
interface ProviderAdapterV1 extends AgentProvider {
|
|
498
|
+
readonly manifest: Readonly<AdapterManifestV1>;
|
|
499
|
+
}
|
|
416
500
|
|
|
417
501
|
interface SessionDefaults {
|
|
418
502
|
/** The provider used by the most recently created session. Absent only for legacy saved documents. */
|
|
@@ -480,6 +564,7 @@ interface StoredSessionBase {
|
|
|
480
564
|
}
|
|
481
565
|
interface StoredClaudeSession extends StoredSessionBase {
|
|
482
566
|
provider: "claude";
|
|
567
|
+
externalAdapter?: never;
|
|
483
568
|
dangerouslySkip: boolean;
|
|
484
569
|
/** The USER-chosen spawn flags the session was created with (`--model`/`--effort`/`--permission-mode`/
|
|
485
570
|
* `--dangerously-skip-permissions`/`--add-dir …`) — everything EXCEPT the ephemeral per-session
|
|
@@ -497,13 +582,24 @@ interface StoredIntegrationStatus {
|
|
|
497
582
|
}
|
|
498
583
|
interface StoredCodexSession extends StoredSessionBase {
|
|
499
584
|
provider: "codex";
|
|
585
|
+
externalAdapter?: never;
|
|
500
586
|
launchOptions: CodexSessionOptions;
|
|
501
587
|
providerSessionId?: string;
|
|
502
588
|
integrationStatus?: StoredIntegrationStatus;
|
|
503
589
|
dangerouslySkip?: never;
|
|
504
590
|
spawnArgs?: never;
|
|
505
591
|
}
|
|
506
|
-
|
|
592
|
+
interface StoredExternalSession extends StoredSessionBase {
|
|
593
|
+
provider: ProviderId;
|
|
594
|
+
/** Discriminator that keeps additive third-party rows separate from rollback-readable built-in tables. */
|
|
595
|
+
externalAdapter: true;
|
|
596
|
+
launchOptions: ProviderSessionOptions;
|
|
597
|
+
providerSessionId?: string;
|
|
598
|
+
integrationStatus?: StoredIntegrationStatus;
|
|
599
|
+
dangerouslySkip?: never;
|
|
600
|
+
spawnArgs?: never;
|
|
601
|
+
}
|
|
602
|
+
type StoredSession = StoredClaudeSession | StoredCodexSession | StoredExternalSession;
|
|
507
603
|
/** How a store is actually backed: "sqlite" (durable) or "memory-fallback" (the native module failed to
|
|
508
604
|
* load — NOT durable across restarts). Surfaced so start.ts can warn loudly + /diag can report it. */
|
|
509
605
|
type StoreMode = "sqlite" | "memory-fallback";
|
|
@@ -594,6 +690,1514 @@ declare function resolveAccessToken(opts: ResolveAccessTokenOptions): {
|
|
|
594
690
|
generated: boolean;
|
|
595
691
|
};
|
|
596
692
|
|
|
693
|
+
/** A pairing link is deliberately short-lived and can be claimed exactly once. */
|
|
694
|
+
declare const PAIRING_TTL_MS: number;
|
|
695
|
+
type DeviceScope = "direct" | "relay";
|
|
696
|
+
interface DeviceInfo {
|
|
697
|
+
id: string;
|
|
698
|
+
name: string;
|
|
699
|
+
createdAt: number;
|
|
700
|
+
lastSeenAt: number;
|
|
701
|
+
scopes: DeviceScope[];
|
|
702
|
+
/** Pinned E2E relay signing identity. Public material only; the private key never leaves the device. */
|
|
703
|
+
relayIdentityFingerprint?: string;
|
|
704
|
+
}
|
|
705
|
+
interface DeviceRelayIdentity {
|
|
706
|
+
publicKey: string;
|
|
707
|
+
fingerprint: string;
|
|
708
|
+
}
|
|
709
|
+
declare class DevicePairingError extends Error {
|
|
710
|
+
readonly code: "INVALID_RELAY_IDENTITY";
|
|
711
|
+
constructor(code: "INVALID_RELAY_IDENTITY", message: string);
|
|
712
|
+
}
|
|
713
|
+
interface PairingTicket {
|
|
714
|
+
/** One-time capability carried by the pairing URL. Never persisted in plaintext. */
|
|
715
|
+
secret: string;
|
|
716
|
+
expiresAt: number;
|
|
717
|
+
/** Exact product surfaces the resulting device credential can reach. */
|
|
718
|
+
scopes: DeviceScope[];
|
|
719
|
+
}
|
|
720
|
+
/**
|
|
721
|
+
* Relay bootstrap pre-allocates both durable ids. The token is still inert until the one-use pairing
|
|
722
|
+
* capability is claimed, but carrying it in the URL fragment makes a dropped final response recoverable:
|
|
723
|
+
* the browser can reconnect with the same credential after the host committed the claim.
|
|
724
|
+
*/
|
|
725
|
+
interface RelayPairingTicket extends PairingTicket {
|
|
726
|
+
deviceId: string;
|
|
727
|
+
token: string;
|
|
728
|
+
}
|
|
729
|
+
interface DeviceEnrollment {
|
|
730
|
+
/** The per-device bearer credential. Returned once; only its SHA-256 digest is persisted. */
|
|
731
|
+
token: string;
|
|
732
|
+
device: DeviceInfo;
|
|
733
|
+
}
|
|
734
|
+
interface DeviceStore {
|
|
735
|
+
readonly mode: "sqlite" | "memory-fallback";
|
|
736
|
+
issuePairing(now?: number, scopes?: DeviceScope[]): PairingTicket;
|
|
737
|
+
claimPairing(secret: string, name: string, now?: number, relayIdentityPublicKey?: string): DeviceEnrollment | undefined;
|
|
738
|
+
issueRelayPairing(now?: number): RelayPairingTicket;
|
|
739
|
+
pendingRelayPairing(deviceId: string, now?: number): boolean;
|
|
740
|
+
claimRelayPairing(secret: string, token: string, name: string, relayIdentityPublicKey: string, now?: number): DeviceEnrollment | undefined;
|
|
741
|
+
/** Resolve a per-device bearer credential and best-effort touch its last-seen time. */
|
|
742
|
+
authenticate(token: string, now?: number, requiredScope?: DeviceScope): DeviceInfo | undefined;
|
|
743
|
+
relayIdentity(id: string): DeviceRelayIdentity | undefined;
|
|
744
|
+
list(): DeviceInfo[];
|
|
745
|
+
rename(id: string, name: string): DeviceInfo | undefined;
|
|
746
|
+
revoke(id: string): boolean;
|
|
747
|
+
revokeAll(): number;
|
|
748
|
+
close(): void;
|
|
749
|
+
}
|
|
750
|
+
interface OpenDeviceStoreOptions {
|
|
751
|
+
/** SQLite file path. ":memory:" uses an in-process DB. */
|
|
752
|
+
dbPath: string;
|
|
753
|
+
generateSecret?: () => string;
|
|
754
|
+
generateToken?: () => string;
|
|
755
|
+
generateId?: () => string;
|
|
756
|
+
}
|
|
757
|
+
declare function normalizeDeviceScopes(value: unknown): DeviceScope[] | undefined;
|
|
758
|
+
/** Keep device labels useful in UI while refusing control characters and unbounded payloads. */
|
|
759
|
+
declare function normalizeDeviceName(value: unknown): string | undefined;
|
|
760
|
+
declare function openDeviceStore(opts: OpenDeviceStoreOptions): DeviceStore;
|
|
761
|
+
|
|
762
|
+
declare const INPUT_LEASE_TTL_MS = 30000;
|
|
763
|
+
type InputLeaseActorType = "device" | "host" | "local" | "relay";
|
|
764
|
+
interface InputLeasePrincipal {
|
|
765
|
+
actorType: InputLeaseActorType;
|
|
766
|
+
actorId: string;
|
|
767
|
+
label: string;
|
|
768
|
+
}
|
|
769
|
+
interface InputLease {
|
|
770
|
+
id: string;
|
|
771
|
+
sessionId: string;
|
|
772
|
+
holderId: string;
|
|
773
|
+
actorType: InputLeaseActorType;
|
|
774
|
+
actorId: string;
|
|
775
|
+
label: string;
|
|
776
|
+
acquiredAt: number;
|
|
777
|
+
renewedAt: number;
|
|
778
|
+
expiresAt: number;
|
|
779
|
+
revision: number;
|
|
780
|
+
}
|
|
781
|
+
type InputLeaseEvent = {
|
|
782
|
+
type: "granted";
|
|
783
|
+
lease: InputLease;
|
|
784
|
+
} | {
|
|
785
|
+
type: "renewed";
|
|
786
|
+
lease: InputLease;
|
|
787
|
+
} | {
|
|
788
|
+
type: "released" | "expired" | "revoked";
|
|
789
|
+
lease: InputLease;
|
|
790
|
+
} | {
|
|
791
|
+
type: "taken-over";
|
|
792
|
+
lease: InputLease;
|
|
793
|
+
previous: InputLease;
|
|
794
|
+
};
|
|
795
|
+
type InputLeaseAcquireResult = {
|
|
796
|
+
status: "granted" | "owned";
|
|
797
|
+
lease: InputLease;
|
|
798
|
+
} | {
|
|
799
|
+
status: "denied";
|
|
800
|
+
current: InputLease;
|
|
801
|
+
};
|
|
802
|
+
interface InputLeaseCoordinatorOptions {
|
|
803
|
+
ttlMs?: number;
|
|
804
|
+
now?: () => number;
|
|
805
|
+
generateId?: () => string;
|
|
806
|
+
scheduleExpiry?: boolean;
|
|
807
|
+
onEvent?: (event: InputLeaseEvent) => void;
|
|
808
|
+
}
|
|
809
|
+
/**
|
|
810
|
+
* Coordinates the one mutable terminal input stream shared by many read-only observers.
|
|
811
|
+
*
|
|
812
|
+
* Leases intentionally live in memory: a host restart invalidates every connection and therefore every holder.
|
|
813
|
+
* Durable audit is supplied by the caller through onEvent. Expiry, release, and confirmed takeover are explicit;
|
|
814
|
+
* merely sending input can never acquire or steal ownership.
|
|
815
|
+
*/
|
|
816
|
+
declare class InputLeaseCoordinator {
|
|
817
|
+
private readonly leases;
|
|
818
|
+
private readonly listeners;
|
|
819
|
+
private readonly timers;
|
|
820
|
+
private readonly ttlMs;
|
|
821
|
+
private readonly now;
|
|
822
|
+
private readonly generateId;
|
|
823
|
+
private readonly scheduleExpiry;
|
|
824
|
+
private readonly onEvent?;
|
|
825
|
+
private revision;
|
|
826
|
+
constructor(options?: InputLeaseCoordinatorOptions);
|
|
827
|
+
acquire(sessionId: string, holderId: string, principal: InputLeasePrincipal): InputLeaseAcquireResult;
|
|
828
|
+
takeover(sessionId: string, holderId: string, principal: InputLeasePrincipal, confirmed: boolean, authorized?: boolean): InputLeaseAcquireResult;
|
|
829
|
+
renew(sessionId: string, holderId: string, leaseId: string): InputLease | undefined;
|
|
830
|
+
canWrite(sessionId: string, holderId: string, leaseId?: string): boolean;
|
|
831
|
+
release(sessionId: string, holderId: string, leaseId?: string): boolean;
|
|
832
|
+
releaseHolder(holderId: string): number;
|
|
833
|
+
revoke(sessionId: string): boolean;
|
|
834
|
+
revokeActor(actorType: InputLeaseActorType, actorId: string): number;
|
|
835
|
+
get(sessionId: string): InputLease | undefined;
|
|
836
|
+
subscribe(sessionId: string, listener: (event: InputLeaseEvent) => void): () => void;
|
|
837
|
+
close(): void;
|
|
838
|
+
private validate;
|
|
839
|
+
private current;
|
|
840
|
+
private renewExisting;
|
|
841
|
+
private remove;
|
|
842
|
+
private schedule;
|
|
843
|
+
private emit;
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
type TeamStoreMode = "sqlite" | "memory-fallback";
|
|
847
|
+
type TeamMemberKind = "person" | "service";
|
|
848
|
+
type TeamMemberStatus = "active" | "suspended" | "removed";
|
|
849
|
+
type TeamRole = "viewer" | "operator" | "workspace-manager" | "extension-manager" | "policy-admin" | "organization-admin";
|
|
850
|
+
type TeamScopeType = "team" | "host" | "workspace";
|
|
851
|
+
type TeamPrincipalType = "device" | "host" | "local" | "relay";
|
|
852
|
+
type TeamPermission = "team:read" | "sessions:read" | "sessions:operate" | "attention:read" | "attention:manage" | "presence:read" | "presence:write" | "workspaces:manage" | "extensions:manage" | "policy:manage" | "members:manage" | "audit:read" | "fleet:read";
|
|
853
|
+
interface TeamRecord {
|
|
854
|
+
id: string;
|
|
855
|
+
name: string;
|
|
856
|
+
authorizationEnabled: boolean;
|
|
857
|
+
revision: number;
|
|
858
|
+
createdAt: number;
|
|
859
|
+
updatedAt: number;
|
|
860
|
+
}
|
|
861
|
+
interface TeamMember {
|
|
862
|
+
id: string;
|
|
863
|
+
displayName: string;
|
|
864
|
+
kind: TeamMemberKind;
|
|
865
|
+
status: TeamMemberStatus;
|
|
866
|
+
revision: number;
|
|
867
|
+
createdAt: number;
|
|
868
|
+
updatedAt: number;
|
|
869
|
+
}
|
|
870
|
+
interface TeamRoleBinding {
|
|
871
|
+
id: string;
|
|
872
|
+
memberId: string;
|
|
873
|
+
role: TeamRole;
|
|
874
|
+
scopeType: TeamScopeType;
|
|
875
|
+
scopeId?: string;
|
|
876
|
+
createdAt: number;
|
|
877
|
+
}
|
|
878
|
+
interface TeamPrincipalBinding {
|
|
879
|
+
actorType: TeamPrincipalType;
|
|
880
|
+
actorId: string;
|
|
881
|
+
memberId: string;
|
|
882
|
+
createdAt: number;
|
|
883
|
+
}
|
|
884
|
+
interface TeamAuthorizationResource {
|
|
885
|
+
hostId?: string;
|
|
886
|
+
workspaceId?: string;
|
|
887
|
+
}
|
|
888
|
+
interface TeamAuthorizationDecision {
|
|
889
|
+
allowed: boolean;
|
|
890
|
+
reason: "local-break-glass" | "not-enforced" | "unbound" | "inactive" | "role" | "missing-permission";
|
|
891
|
+
member?: TeamMember;
|
|
892
|
+
roles: TeamRole[];
|
|
893
|
+
}
|
|
894
|
+
interface TeamStore {
|
|
895
|
+
readonly mode: TeamStoreMode;
|
|
896
|
+
getTeam(): TeamRecord | null;
|
|
897
|
+
createTeam(input: {
|
|
898
|
+
name: string;
|
|
899
|
+
ownerName: string;
|
|
900
|
+
ownerPrincipal: {
|
|
901
|
+
actorType: TeamPrincipalType;
|
|
902
|
+
actorId: string;
|
|
903
|
+
};
|
|
904
|
+
}, now?: number): {
|
|
905
|
+
team: TeamRecord;
|
|
906
|
+
owner: TeamMember;
|
|
907
|
+
};
|
|
908
|
+
updateTeam(input: {
|
|
909
|
+
name?: string;
|
|
910
|
+
authorizationEnabled?: boolean;
|
|
911
|
+
}, expectedRevision: number, now?: number): TeamRecord;
|
|
912
|
+
listMembers(opts?: {
|
|
913
|
+
includeRemoved?: boolean;
|
|
914
|
+
}): TeamMember[];
|
|
915
|
+
getMember(id: string): TeamMember | undefined;
|
|
916
|
+
createMember(input: {
|
|
917
|
+
displayName: string;
|
|
918
|
+
kind?: TeamMemberKind;
|
|
919
|
+
}, now?: number): TeamMember;
|
|
920
|
+
updateMember(id: string, input: {
|
|
921
|
+
displayName?: string;
|
|
922
|
+
status?: TeamMemberStatus;
|
|
923
|
+
}, expectedRevision: number, now?: number): TeamMember | undefined;
|
|
924
|
+
listRoleBindings(memberId?: string): TeamRoleBinding[];
|
|
925
|
+
grantRole(input: {
|
|
926
|
+
memberId: string;
|
|
927
|
+
role: TeamRole;
|
|
928
|
+
scopeType?: TeamScopeType;
|
|
929
|
+
scopeId?: string;
|
|
930
|
+
}, now?: number): TeamRoleBinding;
|
|
931
|
+
revokeRole(id: string, now?: number): boolean;
|
|
932
|
+
listPrincipalBindings(memberId?: string): TeamPrincipalBinding[];
|
|
933
|
+
bindPrincipal(input: {
|
|
934
|
+
memberId: string;
|
|
935
|
+
actorType: TeamPrincipalType;
|
|
936
|
+
actorId: string;
|
|
937
|
+
}, now?: number): TeamPrincipalBinding;
|
|
938
|
+
unbindPrincipal(actorType: TeamPrincipalType, actorId: string, now?: number): boolean;
|
|
939
|
+
memberForPrincipal(actorType: TeamPrincipalType, actorId: string): TeamMember | undefined;
|
|
940
|
+
authorize(actorType: TeamPrincipalType, actorId: string, permission: TeamPermission, resource?: TeamAuthorizationResource): TeamAuthorizationDecision;
|
|
941
|
+
close(): void;
|
|
942
|
+
}
|
|
943
|
+
interface OpenTeamStoreOptions {
|
|
944
|
+
dbPath: string;
|
|
945
|
+
generateTeamId?: () => string;
|
|
946
|
+
generateMemberId?: () => string;
|
|
947
|
+
generateRoleId?: () => string;
|
|
948
|
+
loadDatabase?: () => typeof better_sqlite3;
|
|
949
|
+
}
|
|
950
|
+
declare class TeamRevisionConflictError extends Error {
|
|
951
|
+
readonly current: TeamRecord | TeamMember;
|
|
952
|
+
constructor(current: TeamRecord | TeamMember);
|
|
953
|
+
}
|
|
954
|
+
declare function openTeamStore(opts: OpenTeamStoreOptions): TeamStore;
|
|
955
|
+
declare function teamRolePermissions(role: TeamRole): readonly TeamPermission[];
|
|
956
|
+
declare function isTeamRole(value: unknown): value is TeamRole;
|
|
957
|
+
declare function isTeamScopeType(value: unknown): value is TeamScopeType;
|
|
958
|
+
|
|
959
|
+
declare const PRESENCE_TTL_MS = 45000;
|
|
960
|
+
declare const PRESENCE_HEARTBEAT_MS = 15000;
|
|
961
|
+
type PresenceMode = "viewing" | "operating";
|
|
962
|
+
interface PresenceTarget {
|
|
963
|
+
hostId: string;
|
|
964
|
+
workspaceId?: string;
|
|
965
|
+
sessionId?: string;
|
|
966
|
+
agentId?: string;
|
|
967
|
+
}
|
|
968
|
+
interface PresenceRecord extends PresenceTarget {
|
|
969
|
+
id: string;
|
|
970
|
+
memberId?: string;
|
|
971
|
+
label: string;
|
|
972
|
+
mode: PresenceMode;
|
|
973
|
+
connectedAt: number;
|
|
974
|
+
lastSeenAt: number;
|
|
975
|
+
expiresAt: number;
|
|
976
|
+
revision: number;
|
|
977
|
+
}
|
|
978
|
+
type PresenceEvent = {
|
|
979
|
+
type: "joined" | "updated" | "left" | "expired";
|
|
980
|
+
presence: PresenceRecord;
|
|
981
|
+
};
|
|
982
|
+
interface PresenceHeartbeatInput extends PresenceTarget {
|
|
983
|
+
clientId: string;
|
|
984
|
+
mode: PresenceMode;
|
|
985
|
+
memberId?: string;
|
|
986
|
+
}
|
|
987
|
+
interface PresenceCoordinatorOptions {
|
|
988
|
+
ttlMs?: number;
|
|
989
|
+
now?: () => number;
|
|
990
|
+
generateId?: () => string;
|
|
991
|
+
maxRecords?: number;
|
|
992
|
+
maxPerActor?: number;
|
|
993
|
+
scheduleExpiry?: boolean;
|
|
994
|
+
}
|
|
995
|
+
/**
|
|
996
|
+
* Ephemeral, privacy-bounded presence. No IP, bearer credential, path, prompt, or terminal data is retained.
|
|
997
|
+
* Heartbeats expire cleanly after disconnect and are capped both globally and per authenticated actor.
|
|
998
|
+
*/
|
|
999
|
+
declare class PresenceCoordinator {
|
|
1000
|
+
private readonly records;
|
|
1001
|
+
private readonly listeners;
|
|
1002
|
+
private readonly ttlMs;
|
|
1003
|
+
private readonly now;
|
|
1004
|
+
private readonly generateId;
|
|
1005
|
+
private readonly maxRecords;
|
|
1006
|
+
private readonly maxPerActor;
|
|
1007
|
+
private readonly timer?;
|
|
1008
|
+
private revision;
|
|
1009
|
+
constructor(options?: PresenceCoordinatorOptions);
|
|
1010
|
+
heartbeat(principal: InputLeasePrincipal, input: PresenceHeartbeatInput): PresenceRecord;
|
|
1011
|
+
list(filter?: Partial<PresenceTarget>): PresenceRecord[];
|
|
1012
|
+
release(principal: Pick<InputLeasePrincipal, "actorType" | "actorId">, clientId: string): boolean;
|
|
1013
|
+
releaseActor(principal: Pick<InputLeasePrincipal, "actorType" | "actorId">): number;
|
|
1014
|
+
/**
|
|
1015
|
+
* Input ownership is authoritative for the public "operating" label. When a lease ends or moves, keep the
|
|
1016
|
+
* connected observer visible but immediately downgrade stale operating heartbeats instead of waiting for TTL.
|
|
1017
|
+
*/
|
|
1018
|
+
downgradeOperating(principal: Pick<InputLeasePrincipal, "actorType" | "actorId">, sessionId: string): number;
|
|
1019
|
+
subscribe(listener: (event: PresenceEvent) => void): () => void;
|
|
1020
|
+
sweep(): number;
|
|
1021
|
+
close(): void;
|
|
1022
|
+
private enforceBounds;
|
|
1023
|
+
private evict;
|
|
1024
|
+
private publicRecord;
|
|
1025
|
+
private emit;
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
declare const RELAY_PROTOCOL_VERSION: 1;
|
|
1029
|
+
declare const RELAY_HANDSHAKE_MAX_SKEW_MS: number;
|
|
1030
|
+
declare const RELAY_CHANNEL_MAX_AGE_MS: number;
|
|
1031
|
+
declare const RELAY_CHANNEL_MAX_FRAMES = 1000000;
|
|
1032
|
+
declare const RELAY_MAX_PLAINTEXT_BYTES: number;
|
|
1033
|
+
type RelayRole = "device" | "host";
|
|
1034
|
+
type RelayDirection = "device-to-host" | "host-to-device";
|
|
1035
|
+
type RelayFrameKind = "auth" | "rpc-request" | "rpc-response" | "stream-open" | "stream-data" | "stream-control" | "close";
|
|
1036
|
+
type RelayCryptoErrorCode = "INVALID_RELAY_IDENTITY" | "INVALID_RELAY_HELLO" | "RELAY_IDENTITY_MISMATCH" | "RELAY_SIGNATURE_INVALID" | "RELAY_HANDSHAKE_EXPIRED" | "RELAY_HANDSHAKE_MISMATCH" | "RELAY_FRAME_INVALID" | "RELAY_FRAME_OUT_OF_ORDER" | "RELAY_FRAME_AUTH_FAILED" | "RELAY_FRAME_TOO_LARGE" | "RELAY_KEY_ROTATION_REQUIRED" | "RELAY_CHANNEL_CLOSED";
|
|
1037
|
+
declare class RelayCryptoError extends Error {
|
|
1038
|
+
readonly code: RelayCryptoErrorCode;
|
|
1039
|
+
constructor(code: RelayCryptoErrorCode, message: string);
|
|
1040
|
+
}
|
|
1041
|
+
interface RelayIdentity {
|
|
1042
|
+
/** Base64url-encoded SPKI DER public key. Safe to pin and exchange. */
|
|
1043
|
+
publicKey: string;
|
|
1044
|
+
/** Base64url-encoded PKCS#8 DER private key. Host persistence must use mode 0600. */
|
|
1045
|
+
privateKey: string;
|
|
1046
|
+
fingerprint: string;
|
|
1047
|
+
}
|
|
1048
|
+
interface RelayEphemeralKeyPair {
|
|
1049
|
+
publicKey: string;
|
|
1050
|
+
privateKey: string;
|
|
1051
|
+
}
|
|
1052
|
+
interface RelayHandshakeHello {
|
|
1053
|
+
v: typeof RELAY_PROTOCOL_VERSION;
|
|
1054
|
+
role: RelayRole;
|
|
1055
|
+
routeId: string;
|
|
1056
|
+
deviceId: string;
|
|
1057
|
+
sessionId: string;
|
|
1058
|
+
issuedAt: number;
|
|
1059
|
+
nonce: string;
|
|
1060
|
+
ephemeralPublicKey: string;
|
|
1061
|
+
identityFingerprint: string;
|
|
1062
|
+
signature: string;
|
|
1063
|
+
}
|
|
1064
|
+
interface RelayEncryptedFrame {
|
|
1065
|
+
v: typeof RELAY_PROTOCOL_VERSION;
|
|
1066
|
+
sessionId: string;
|
|
1067
|
+
seq: string;
|
|
1068
|
+
kind: RelayFrameKind;
|
|
1069
|
+
ciphertext: string;
|
|
1070
|
+
}
|
|
1071
|
+
interface RelayChannelOptions {
|
|
1072
|
+
role: RelayRole;
|
|
1073
|
+
localEphemeral: RelayEphemeralKeyPair;
|
|
1074
|
+
deviceHello: RelayHandshakeHello;
|
|
1075
|
+
hostHello: RelayHandshakeHello;
|
|
1076
|
+
deviceIdentityPublicKey: string;
|
|
1077
|
+
hostIdentityPublicKey: string;
|
|
1078
|
+
now?: () => number;
|
|
1079
|
+
maxAgeMs?: number;
|
|
1080
|
+
maxFrames?: number;
|
|
1081
|
+
}
|
|
1082
|
+
declare function relayIdentityFingerprint(publicKey: string): string;
|
|
1083
|
+
declare function generateRelayIdentity(): RelayIdentity;
|
|
1084
|
+
/** Validates both key encodings and proves that the persisted private key belongs to the advertised identity. */
|
|
1085
|
+
declare function validateRelayIdentity(value: unknown): RelayIdentity;
|
|
1086
|
+
declare function generateRelayEphemeralKeyPair(): RelayEphemeralKeyPair;
|
|
1087
|
+
declare function createRelayHandshakeHello(input: {
|
|
1088
|
+
role: RelayRole;
|
|
1089
|
+
routeId: string;
|
|
1090
|
+
deviceId: string;
|
|
1091
|
+
sessionId?: string;
|
|
1092
|
+
identity: RelayIdentity;
|
|
1093
|
+
ephemeral?: RelayEphemeralKeyPair;
|
|
1094
|
+
nonce?: Uint8Array;
|
|
1095
|
+
issuedAt?: number;
|
|
1096
|
+
}): {
|
|
1097
|
+
hello: RelayHandshakeHello;
|
|
1098
|
+
ephemeral: RelayEphemeralKeyPair;
|
|
1099
|
+
};
|
|
1100
|
+
declare function verifyRelayHandshakeHello(hello: RelayHandshakeHello, expected: {
|
|
1101
|
+
role: RelayRole;
|
|
1102
|
+
routeId: string;
|
|
1103
|
+
deviceId: string;
|
|
1104
|
+
sessionId: string;
|
|
1105
|
+
identityPublicKey: string;
|
|
1106
|
+
now?: number;
|
|
1107
|
+
maxSkewMs?: number;
|
|
1108
|
+
}): void;
|
|
1109
|
+
/** Small exported primitive used to pin RFC 5869 test vectors independently of the handshake. */
|
|
1110
|
+
declare function hkdfSha256(input: Uint8Array, salt: Uint8Array, info: Uint8Array, length: number): Buffer;
|
|
1111
|
+
declare class RelayCipherState {
|
|
1112
|
+
readonly sessionId: string;
|
|
1113
|
+
readonly role: RelayRole;
|
|
1114
|
+
private readonly sendKey;
|
|
1115
|
+
private readonly receiveKey;
|
|
1116
|
+
private readonly sendBaseNonce;
|
|
1117
|
+
private readonly receiveBaseNonce;
|
|
1118
|
+
private readonly now;
|
|
1119
|
+
private readonly maxAgeMs;
|
|
1120
|
+
private readonly maxFrames;
|
|
1121
|
+
private sendSequence;
|
|
1122
|
+
private receiveSequence;
|
|
1123
|
+
private closed;
|
|
1124
|
+
private readonly createdAt;
|
|
1125
|
+
private readonly sendDirection;
|
|
1126
|
+
private readonly receiveDirection;
|
|
1127
|
+
constructor(sessionId: string, role: RelayRole, sendKey: Buffer, receiveKey: Buffer, sendBaseNonce: Buffer, receiveBaseNonce: Buffer, now: () => number, maxAgeMs: number, maxFrames: number);
|
|
1128
|
+
encrypt(kind: RelayFrameKind, plaintext: Uint8Array): RelayEncryptedFrame;
|
|
1129
|
+
decrypt(frame: RelayEncryptedFrame): Buffer;
|
|
1130
|
+
needsRotation(): boolean;
|
|
1131
|
+
sequences(): {
|
|
1132
|
+
send: string;
|
|
1133
|
+
receive: string;
|
|
1134
|
+
};
|
|
1135
|
+
close(): void;
|
|
1136
|
+
private assertOpen;
|
|
1137
|
+
private assertKind;
|
|
1138
|
+
}
|
|
1139
|
+
declare function establishRelayChannel(options: RelayChannelOptions): RelayCipherState;
|
|
1140
|
+
|
|
1141
|
+
interface RelayIdentityStoreOptions {
|
|
1142
|
+
dataDir: string;
|
|
1143
|
+
generate?: () => RelayIdentity;
|
|
1144
|
+
now?: () => number;
|
|
1145
|
+
}
|
|
1146
|
+
interface DurableRelayIdentity {
|
|
1147
|
+
identity: RelayIdentity;
|
|
1148
|
+
createdAt: number;
|
|
1149
|
+
path: string;
|
|
1150
|
+
generated: boolean;
|
|
1151
|
+
}
|
|
1152
|
+
/** Loads one stable host identity or creates it once without allowing concurrent processes to overwrite it. */
|
|
1153
|
+
declare function loadOrCreateRelayIdentity(options: RelayIdentityStoreOptions): DurableRelayIdentity;
|
|
1154
|
+
|
|
1155
|
+
type RelayStoreMode = "sqlite" | "memory";
|
|
1156
|
+
interface RelayRouteRecord {
|
|
1157
|
+
id: string;
|
|
1158
|
+
label: string;
|
|
1159
|
+
hostCredentialHash: string;
|
|
1160
|
+
ownerAccountId?: string;
|
|
1161
|
+
createdAt: number;
|
|
1162
|
+
updatedAt: number;
|
|
1163
|
+
}
|
|
1164
|
+
interface RelayDeviceRouteRecord {
|
|
1165
|
+
routeId: string;
|
|
1166
|
+
deviceId: string;
|
|
1167
|
+
credentialHash: string;
|
|
1168
|
+
createdAt: number;
|
|
1169
|
+
updatedAt: number;
|
|
1170
|
+
/** Bootstrap credentials expire unless the host promotes the device after the E2E pairing claim. */
|
|
1171
|
+
expiresAt?: number;
|
|
1172
|
+
}
|
|
1173
|
+
interface PublicRelayRouteRecord {
|
|
1174
|
+
id: string;
|
|
1175
|
+
label: string;
|
|
1176
|
+
deviceCount: number;
|
|
1177
|
+
createdAt: number;
|
|
1178
|
+
updatedAt: number;
|
|
1179
|
+
}
|
|
1180
|
+
interface RelayRouteStore {
|
|
1181
|
+
readonly mode: RelayStoreMode;
|
|
1182
|
+
createRoute(input: {
|
|
1183
|
+
id?: string;
|
|
1184
|
+
label: string;
|
|
1185
|
+
hostCredentialHash: string;
|
|
1186
|
+
ownerAccountId?: string;
|
|
1187
|
+
}, now?: number): RelayRouteRecord;
|
|
1188
|
+
getRoute(id: string): RelayRouteRecord | undefined;
|
|
1189
|
+
listRoutes(now?: number): PublicRelayRouteRecord[];
|
|
1190
|
+
listRoutesByOwner(ownerAccountId: string, now?: number): PublicRelayRouteRecord[];
|
|
1191
|
+
countDevices(routeId: string, now?: number): number;
|
|
1192
|
+
rotateHostCredential(routeId: string, credentialHash: string, now?: number): boolean;
|
|
1193
|
+
deleteRoute(id: string): boolean;
|
|
1194
|
+
authenticateHost(routeId: string, credential: string): boolean;
|
|
1195
|
+
putDevice(input: {
|
|
1196
|
+
routeId: string;
|
|
1197
|
+
deviceId: string;
|
|
1198
|
+
credentialHash: string;
|
|
1199
|
+
expiresAt?: number;
|
|
1200
|
+
}, now?: number): RelayDeviceRouteRecord;
|
|
1201
|
+
getDevice(routeId: string, deviceId: string, now?: number): RelayDeviceRouteRecord | undefined;
|
|
1202
|
+
authenticateDevice(routeId: string, deviceId: string, credential: string, now?: number): boolean;
|
|
1203
|
+
revokeDevice(routeId: string, deviceId: string): boolean;
|
|
1204
|
+
close(): void;
|
|
1205
|
+
}
|
|
1206
|
+
interface OpenRelayRouteStoreOptions {
|
|
1207
|
+
dbPath: string;
|
|
1208
|
+
generateRouteId?: () => string;
|
|
1209
|
+
loadDatabase?: () => typeof better_sqlite3;
|
|
1210
|
+
}
|
|
1211
|
+
declare function relayCredentialHash(credential: string): string;
|
|
1212
|
+
declare function generateRelayCredential(prefix?: "rrh" | "rrd" | "rrp"): string;
|
|
1213
|
+
declare function openRelayRouteStore(options: OpenRelayRouteStoreOptions): RelayRouteStore;
|
|
1214
|
+
|
|
1215
|
+
type RelayAccountStoreMode = "sqlite" | "memory";
|
|
1216
|
+
type RelayAccountStatus = "active" | "suspended" | "deleted";
|
|
1217
|
+
type RelayAccountPlan = "free" | "team" | "enterprise";
|
|
1218
|
+
interface RelayAccountRecord {
|
|
1219
|
+
id: string;
|
|
1220
|
+
label: string;
|
|
1221
|
+
status: RelayAccountStatus;
|
|
1222
|
+
plan: RelayAccountPlan;
|
|
1223
|
+
maxRoutes: number;
|
|
1224
|
+
maxDevicesPerRoute: number;
|
|
1225
|
+
revision: number;
|
|
1226
|
+
createdAt: number;
|
|
1227
|
+
updatedAt: number;
|
|
1228
|
+
}
|
|
1229
|
+
interface CreateRelayAccountInput {
|
|
1230
|
+
label: string;
|
|
1231
|
+
credential: string;
|
|
1232
|
+
plan?: RelayAccountPlan;
|
|
1233
|
+
maxRoutes?: number;
|
|
1234
|
+
maxDevicesPerRoute?: number;
|
|
1235
|
+
}
|
|
1236
|
+
interface UpdateRelayAccountInput {
|
|
1237
|
+
label?: string;
|
|
1238
|
+
status?: RelayAccountStatus;
|
|
1239
|
+
plan?: RelayAccountPlan;
|
|
1240
|
+
maxRoutes?: number;
|
|
1241
|
+
maxDevicesPerRoute?: number;
|
|
1242
|
+
}
|
|
1243
|
+
interface RelayAccountStore {
|
|
1244
|
+
readonly mode: RelayAccountStoreMode;
|
|
1245
|
+
createAccount(input: CreateRelayAccountInput, now?: number): RelayAccountRecord;
|
|
1246
|
+
getAccount(id: string): RelayAccountRecord | undefined;
|
|
1247
|
+
listAccounts(options?: {
|
|
1248
|
+
includeDeleted?: boolean;
|
|
1249
|
+
}): RelayAccountRecord[];
|
|
1250
|
+
authenticate(credential: string): RelayAccountRecord | undefined;
|
|
1251
|
+
updateAccount(id: string, input: UpdateRelayAccountInput, expectedRevision: number, now?: number): RelayAccountRecord | undefined;
|
|
1252
|
+
rotateCredential(id: string, credential: string, expectedRevision: number, now?: number): RelayAccountRecord | undefined;
|
|
1253
|
+
close(): void;
|
|
1254
|
+
}
|
|
1255
|
+
interface OpenRelayAccountStoreOptions {
|
|
1256
|
+
dbPath: string;
|
|
1257
|
+
generateAccountId?: () => string;
|
|
1258
|
+
loadDatabase?: () => typeof better_sqlite3;
|
|
1259
|
+
}
|
|
1260
|
+
declare class RelayAccountRevisionConflictError extends Error {
|
|
1261
|
+
readonly current: RelayAccountRecord;
|
|
1262
|
+
constructor(current: RelayAccountRecord);
|
|
1263
|
+
}
|
|
1264
|
+
declare function relayAccountCredentialHash(credential: string): string;
|
|
1265
|
+
declare function relayAccountCredentialLookup(credential: string): string;
|
|
1266
|
+
declare function generateRelayAccountCredential(): string;
|
|
1267
|
+
declare function openRelayAccountStore(options: OpenRelayAccountStoreOptions): RelayAccountStore;
|
|
1268
|
+
|
|
1269
|
+
interface RelayDeviceProvisioner {
|
|
1270
|
+
putDevice(deviceId: string, credentialHash: string, expiresAt?: number): Promise<void>;
|
|
1271
|
+
revokeDevice(deviceId: string): Promise<void>;
|
|
1272
|
+
}
|
|
1273
|
+
interface RelayDeviceProvisionerOptions {
|
|
1274
|
+
relayUrl: string;
|
|
1275
|
+
routeId: string;
|
|
1276
|
+
hostCredential: string;
|
|
1277
|
+
request?: typeof globalThis.fetch;
|
|
1278
|
+
timeoutMs?: number;
|
|
1279
|
+
}
|
|
1280
|
+
/** Host-authenticated provisioning uses HTTPS; routing credentials never appear in URLs or logs. */
|
|
1281
|
+
declare function createRelayDeviceProvisioner(options: RelayDeviceProvisionerOptions): RelayDeviceProvisioner;
|
|
1282
|
+
|
|
1283
|
+
interface RelayPairingPackage {
|
|
1284
|
+
v: 1;
|
|
1285
|
+
label: string;
|
|
1286
|
+
relayUrl: string;
|
|
1287
|
+
routeId: string;
|
|
1288
|
+
deviceId: string;
|
|
1289
|
+
deviceCredential: string;
|
|
1290
|
+
deviceToken: string;
|
|
1291
|
+
pairingSecret: string;
|
|
1292
|
+
expiresAt: number;
|
|
1293
|
+
hostIdentityPublicKey: string;
|
|
1294
|
+
hostIdentityFingerprint: string;
|
|
1295
|
+
}
|
|
1296
|
+
interface RelayPairingBootstrap {
|
|
1297
|
+
appUrl: string;
|
|
1298
|
+
label: string;
|
|
1299
|
+
relayUrl: string;
|
|
1300
|
+
routeId: string;
|
|
1301
|
+
hostIdentityPublicKey: string;
|
|
1302
|
+
hostIdentityFingerprint: string;
|
|
1303
|
+
provisioner: RelayDeviceProvisioner;
|
|
1304
|
+
generateDeviceCredential?: () => string;
|
|
1305
|
+
}
|
|
1306
|
+
declare function normalizeRelayAppUrl(value: string): string;
|
|
1307
|
+
declare function buildRelayPairingUrl(appUrl: string, pairing: RelayPairingPackage): string;
|
|
1308
|
+
|
|
1309
|
+
declare const BLIND_RELAY_PROTOCOL_VERSION: 1;
|
|
1310
|
+
declare const BLIND_RELAY_DEFAULT_MAX_FRAME_BYTES = 1500000;
|
|
1311
|
+
declare const BLIND_RELAY_DEFAULT_MAX_QUEUE_BYTES = 4000000;
|
|
1312
|
+
declare const BLIND_RELAY_DEFAULT_MAX_CONNECTIONS_PER_ROUTE = 64;
|
|
1313
|
+
declare const BLIND_RELAY_DEFAULT_MAX_BYTES_PER_MINUTE: number;
|
|
1314
|
+
declare const BLIND_RELAY_DEFAULT_MAX_MESSAGES_PER_MINUTE = 12000;
|
|
1315
|
+
interface CreateBlindRelayOptions {
|
|
1316
|
+
rootToken: string;
|
|
1317
|
+
/** Previous provisioning capabilities accepted only during an explicit, bounded zero-downtime rotation window. */
|
|
1318
|
+
previousRootTokens?: string[];
|
|
1319
|
+
store?: RelayRouteStore;
|
|
1320
|
+
/** Optional hosted control plane. Self-hosted root-only routing remains available without it. */
|
|
1321
|
+
accountStore?: RelayAccountStore;
|
|
1322
|
+
allowedOrigins?: string[];
|
|
1323
|
+
handshakeTimeoutMs?: number;
|
|
1324
|
+
idleTimeoutMs?: number;
|
|
1325
|
+
maxFrameBytes?: number;
|
|
1326
|
+
maxQueueBytes?: number;
|
|
1327
|
+
maxConnectionsPerRoute?: number;
|
|
1328
|
+
maxBytesPerMinute?: number;
|
|
1329
|
+
maxMessagesPerMinute?: number;
|
|
1330
|
+
now?: () => number;
|
|
1331
|
+
generateChannelId?: () => string;
|
|
1332
|
+
}
|
|
1333
|
+
interface BlindRelayMetrics {
|
|
1334
|
+
activeHosts: number;
|
|
1335
|
+
activeDevices: number;
|
|
1336
|
+
acceptedConnections: number;
|
|
1337
|
+
rejectedConnections: number;
|
|
1338
|
+
forwardedFrames: number;
|
|
1339
|
+
forwardedBytes: number;
|
|
1340
|
+
droppedFrames: number;
|
|
1341
|
+
}
|
|
1342
|
+
interface BlindRelayServer {
|
|
1343
|
+
app: FastifyInstance;
|
|
1344
|
+
store: RelayRouteStore;
|
|
1345
|
+
accountStore?: RelayAccountStore;
|
|
1346
|
+
metrics(): BlindRelayMetrics;
|
|
1347
|
+
}
|
|
1348
|
+
declare function createBlindRelayServer(options: CreateBlindRelayOptions): BlindRelayServer;
|
|
1349
|
+
|
|
1350
|
+
interface StartedBlindRelay extends BlindRelayServer {
|
|
1351
|
+
url: string;
|
|
1352
|
+
}
|
|
1353
|
+
declare function startBlindRelay(env?: NodeJS.ProcessEnv): Promise<StartedBlindRelay>;
|
|
1354
|
+
declare function isRelayDirectExecution(moduleUrl: string, argv1: string | undefined, embeddedContainerBuild?: boolean): boolean;
|
|
1355
|
+
|
|
1356
|
+
/** RPC uses JSON inside an encrypted frame inside a base64 relay envelope. Larger data uses chunked streams. */
|
|
1357
|
+
declare const RELAY_RPC_MAX_BODY_BYTES: number;
|
|
1358
|
+
declare const RELAY_RPC_MAX_PATH_BYTES = 4096;
|
|
1359
|
+
type RelayRpcMethod = "GET" | "HEAD" | "POST" | "PUT" | "PATCH" | "DELETE";
|
|
1360
|
+
interface RelayRpcRequest {
|
|
1361
|
+
id: string;
|
|
1362
|
+
method: RelayRpcMethod;
|
|
1363
|
+
path: string;
|
|
1364
|
+
headers: Record<string, string>;
|
|
1365
|
+
body?: Buffer;
|
|
1366
|
+
}
|
|
1367
|
+
interface RelayRpcResponse {
|
|
1368
|
+
id: string;
|
|
1369
|
+
status: number;
|
|
1370
|
+
headers: Record<string, string>;
|
|
1371
|
+
body?: string;
|
|
1372
|
+
}
|
|
1373
|
+
declare function parseRelayRpcRequest(value: unknown): RelayRpcRequest;
|
|
1374
|
+
declare function relayRpcResponse(input: {
|
|
1375
|
+
id: string;
|
|
1376
|
+
status: number;
|
|
1377
|
+
headers: Record<string, string | string[] | number | undefined>;
|
|
1378
|
+
body?: Uint8Array;
|
|
1379
|
+
}): RelayRpcResponse;
|
|
1380
|
+
|
|
1381
|
+
type RelayHostStatus = "idle" | "connecting" | "online" | "reconnecting" | "stopped";
|
|
1382
|
+
interface RelayHostMetrics {
|
|
1383
|
+
status: RelayHostStatus;
|
|
1384
|
+
activeChannels: number;
|
|
1385
|
+
acceptedChannels: number;
|
|
1386
|
+
rejectedChannels: number;
|
|
1387
|
+
completedRequests: number;
|
|
1388
|
+
failedRequests: number;
|
|
1389
|
+
reconnects: number;
|
|
1390
|
+
activeTransfers: number;
|
|
1391
|
+
completedTransfers: number;
|
|
1392
|
+
failedTransfers: number;
|
|
1393
|
+
streamedRequestBytes: number;
|
|
1394
|
+
streamedResponseBytes: number;
|
|
1395
|
+
}
|
|
1396
|
+
interface RelayHostConnectorOptions {
|
|
1397
|
+
relayUrl: string;
|
|
1398
|
+
routeId: string;
|
|
1399
|
+
hostCredential: string;
|
|
1400
|
+
hostIdentity: RelayIdentity;
|
|
1401
|
+
devices: DeviceStore;
|
|
1402
|
+
dispatchRequest(token: string, request: RelayRpcRequest): Promise<RelayRpcResponse>;
|
|
1403
|
+
openTerminal?: RelayTerminalOpener;
|
|
1404
|
+
openHttp?: RelayHttpOpener;
|
|
1405
|
+
WebSocketClass?: typeof WebSocket;
|
|
1406
|
+
now?: () => number;
|
|
1407
|
+
random?: () => number;
|
|
1408
|
+
handshakeTimeoutMs?: number;
|
|
1409
|
+
requestTimeoutMs?: number;
|
|
1410
|
+
maxStreamRequestBytes?: number;
|
|
1411
|
+
onStatus?: (status: RelayHostStatus) => void;
|
|
1412
|
+
/** Promotes a five-minute broker bootstrap credential after the E2E pairing claim commits. */
|
|
1413
|
+
promoteDevice?: (deviceId: string, credentialHash: string) => Promise<void>;
|
|
1414
|
+
}
|
|
1415
|
+
interface RelayTerminalOpenRequest {
|
|
1416
|
+
streamId: string;
|
|
1417
|
+
sessionId: string;
|
|
1418
|
+
cols?: number;
|
|
1419
|
+
rows?: number;
|
|
1420
|
+
respawn?: "continue" | "fresh";
|
|
1421
|
+
}
|
|
1422
|
+
interface RelayTerminalHandlers {
|
|
1423
|
+
onBinary(data: Uint8Array): void;
|
|
1424
|
+
onControl(data: string): void;
|
|
1425
|
+
onClose(code: number): void;
|
|
1426
|
+
}
|
|
1427
|
+
interface RelayTerminalBridge {
|
|
1428
|
+
send(data: string): void;
|
|
1429
|
+
close(): void;
|
|
1430
|
+
}
|
|
1431
|
+
type RelayTerminalOpener = (token: string, request: RelayTerminalOpenRequest, handlers: RelayTerminalHandlers) => Promise<RelayTerminalBridge>;
|
|
1432
|
+
interface RelayHttpOpenRequest {
|
|
1433
|
+
streamId: string;
|
|
1434
|
+
method: RelayRpcRequest["method"];
|
|
1435
|
+
path: string;
|
|
1436
|
+
headers: Record<string, string>;
|
|
1437
|
+
}
|
|
1438
|
+
interface RelayHttpResponseHead {
|
|
1439
|
+
status: number;
|
|
1440
|
+
headers: Record<string, string>;
|
|
1441
|
+
}
|
|
1442
|
+
interface RelayHttpHandlers {
|
|
1443
|
+
onResponse(response: RelayHttpResponseHead): void | Promise<void>;
|
|
1444
|
+
onData(data: Uint8Array): void | Promise<void>;
|
|
1445
|
+
onEnd(): void | Promise<void>;
|
|
1446
|
+
onError(error: Error): void;
|
|
1447
|
+
}
|
|
1448
|
+
interface RelayHttpBridge {
|
|
1449
|
+
write(data: Uint8Array): Promise<void>;
|
|
1450
|
+
end(): void;
|
|
1451
|
+
close(): void;
|
|
1452
|
+
}
|
|
1453
|
+
type RelayHttpOpener = (token: string, request: RelayHttpOpenRequest, handlers: RelayHttpHandlers) => Promise<RelayHttpBridge>;
|
|
1454
|
+
interface RelayHostConnector {
|
|
1455
|
+
start(): void;
|
|
1456
|
+
stop(): Promise<void>;
|
|
1457
|
+
waitUntilReady(timeoutMs?: number): Promise<void>;
|
|
1458
|
+
closeDevice(deviceId: string): void;
|
|
1459
|
+
metrics(): RelayHostMetrics;
|
|
1460
|
+
}
|
|
1461
|
+
declare function relayConnectUrl(raw: string): string;
|
|
1462
|
+
declare function createRelayHostConnector(options: RelayHostConnectorOptions): RelayHostConnector;
|
|
1463
|
+
|
|
1464
|
+
interface RelayHostRuntimeConfig {
|
|
1465
|
+
relayUrl: string;
|
|
1466
|
+
routeId: string;
|
|
1467
|
+
hostCredential: string;
|
|
1468
|
+
hostIdentity: RelayIdentity;
|
|
1469
|
+
/** Static PWA origin used only for one-use remote pairing links. */
|
|
1470
|
+
appUrl?: string;
|
|
1471
|
+
hostLabel: string;
|
|
1472
|
+
}
|
|
1473
|
+
interface PersistedRelayHostConfig {
|
|
1474
|
+
version: 1;
|
|
1475
|
+
relayUrl: string;
|
|
1476
|
+
routeId: string;
|
|
1477
|
+
hostCredential: string;
|
|
1478
|
+
appUrl?: string;
|
|
1479
|
+
hostLabel: string;
|
|
1480
|
+
}
|
|
1481
|
+
type RelayHostConfigInput = Omit<PersistedRelayHostConfig, "version">;
|
|
1482
|
+
declare function relayHostConfigPath(dataDir: string): string;
|
|
1483
|
+
declare function readRelayHostConfig(dataDir: string): PersistedRelayHostConfig | undefined;
|
|
1484
|
+
declare function writeRelayHostConfig(dataDir: string, input: RelayHostConfigInput): PersistedRelayHostConfig;
|
|
1485
|
+
declare function removeRelayHostConfig(dataDir: string): boolean;
|
|
1486
|
+
declare function resolveRelayHostConfig(env: NodeJS.ProcessEnv, dataDir: string): RelayHostRuntimeConfig | undefined;
|
|
1487
|
+
|
|
1488
|
+
interface LoopbackRelayTerminalOptions {
|
|
1489
|
+
baseUrl(): string | undefined;
|
|
1490
|
+
issueTicket(token: string): Promise<string>;
|
|
1491
|
+
WebSocketClass?: typeof WebSocket;
|
|
1492
|
+
openTimeoutMs?: number;
|
|
1493
|
+
}
|
|
1494
|
+
declare function createLoopbackRelayTerminalOpener(options: LoopbackRelayTerminalOptions): RelayTerminalOpener;
|
|
1495
|
+
|
|
1496
|
+
interface LoopbackRelayHttpOptions {
|
|
1497
|
+
baseUrl(): string | undefined;
|
|
1498
|
+
headers(token: string, requestHeaders: Record<string, string>): Record<string, string>;
|
|
1499
|
+
idleTimeoutMs?: number;
|
|
1500
|
+
}
|
|
1501
|
+
/**
|
|
1502
|
+
* Streams an authenticated relay request through the real loopback HTTP server. This deliberately traverses
|
|
1503
|
+
* the normal auth, RBAC, rate-limit, idempotency, audit, multipart, and route hooks instead of calling file
|
|
1504
|
+
* services out of band.
|
|
1505
|
+
*/
|
|
1506
|
+
declare function createLoopbackRelayHttpOpener(options: LoopbackRelayHttpOptions): RelayHttpOpener;
|
|
1507
|
+
|
|
1508
|
+
declare const RELAY_WIRE_PROTOCOL_VERSION: 1;
|
|
1509
|
+
declare const RELAY_WIRE_MAX_ENVELOPE_BYTES = 1400000;
|
|
1510
|
+
type RelayWireEnvelope = {
|
|
1511
|
+
v: 1;
|
|
1512
|
+
t: "device-hello";
|
|
1513
|
+
hello: RelayHandshakeHello;
|
|
1514
|
+
identityPublicKey?: string;
|
|
1515
|
+
} | {
|
|
1516
|
+
v: 1;
|
|
1517
|
+
t: "host-hello";
|
|
1518
|
+
hello: RelayHandshakeHello;
|
|
1519
|
+
} | {
|
|
1520
|
+
v: 1;
|
|
1521
|
+
t: "cipher";
|
|
1522
|
+
frame: RelayEncryptedFrame;
|
|
1523
|
+
};
|
|
1524
|
+
declare function encodeRelayWireEnvelope(envelope: RelayWireEnvelope): string;
|
|
1525
|
+
declare function decodeRelayWireEnvelope(payload: unknown): RelayWireEnvelope;
|
|
1526
|
+
|
|
1527
|
+
type PolicyStoreMode = "sqlite" | "memory-fallback";
|
|
1528
|
+
type ExtensionPolicyMode = "allow-integrity" | "signed-only" | "deny";
|
|
1529
|
+
type UpdatePolicyMode = "stable-only" | "deny";
|
|
1530
|
+
interface EnterprisePolicy {
|
|
1531
|
+
enforcementEnabled: boolean;
|
|
1532
|
+
allowedHostIds: string[] | null;
|
|
1533
|
+
allowedWorkspaceIds: string[] | null;
|
|
1534
|
+
allowedProviderIds: string[] | null;
|
|
1535
|
+
allowDangerousProviderModes: boolean;
|
|
1536
|
+
allowFileTransfer: boolean;
|
|
1537
|
+
extensionMode: ExtensionPolicyMode;
|
|
1538
|
+
allowRelay: boolean;
|
|
1539
|
+
updateMode: UpdatePolicyMode;
|
|
1540
|
+
revision: number;
|
|
1541
|
+
createdAt: number;
|
|
1542
|
+
updatedAt: number;
|
|
1543
|
+
}
|
|
1544
|
+
interface EnterprisePolicyUpdate {
|
|
1545
|
+
enforcementEnabled?: boolean;
|
|
1546
|
+
allowedHostIds?: string[] | null;
|
|
1547
|
+
allowedWorkspaceIds?: string[] | null;
|
|
1548
|
+
allowedProviderIds?: string[] | null;
|
|
1549
|
+
allowDangerousProviderModes?: boolean;
|
|
1550
|
+
allowFileTransfer?: boolean;
|
|
1551
|
+
extensionMode?: ExtensionPolicyMode;
|
|
1552
|
+
allowRelay?: boolean;
|
|
1553
|
+
updateMode?: UpdatePolicyMode;
|
|
1554
|
+
}
|
|
1555
|
+
type EnterprisePolicyAction = "access" | "session.launch" | "file.transfer" | "extension.mutate" | "relay.access" | "update.mutate";
|
|
1556
|
+
interface EnterprisePolicyContext {
|
|
1557
|
+
hostId: string;
|
|
1558
|
+
workspaceId?: string;
|
|
1559
|
+
providerId?: string;
|
|
1560
|
+
dangerousProviderMode?: boolean;
|
|
1561
|
+
extensionTrust?: "signed" | "integrity";
|
|
1562
|
+
updateChannel?: "stable" | "beta" | "nightly";
|
|
1563
|
+
}
|
|
1564
|
+
interface EnterprisePolicyDecision {
|
|
1565
|
+
allowed: boolean;
|
|
1566
|
+
reason: "not-enforced" | "allowed" | "host-denied" | "workspace-denied" | "provider-denied" | "dangerous-mode-denied" | "file-transfer-denied" | "extension-denied" | "extension-signature-required" | "relay-denied" | "updates-denied" | "update-channel-denied";
|
|
1567
|
+
}
|
|
1568
|
+
interface PolicyStore {
|
|
1569
|
+
readonly mode: PolicyStoreMode;
|
|
1570
|
+
get(): EnterprisePolicy;
|
|
1571
|
+
update(input: EnterprisePolicyUpdate, expectedRevision: number, now?: number): EnterprisePolicy;
|
|
1572
|
+
close(): void;
|
|
1573
|
+
}
|
|
1574
|
+
interface OpenPolicyStoreOptions {
|
|
1575
|
+
dbPath: string;
|
|
1576
|
+
loadDatabase?: () => typeof better_sqlite3;
|
|
1577
|
+
now?: number;
|
|
1578
|
+
}
|
|
1579
|
+
declare class EnterprisePolicyRevisionConflictError extends Error {
|
|
1580
|
+
readonly current: EnterprisePolicy;
|
|
1581
|
+
constructor(current: EnterprisePolicy);
|
|
1582
|
+
}
|
|
1583
|
+
declare function evaluateEnterprisePolicy(policy: EnterprisePolicy, action: EnterprisePolicyAction, context: EnterprisePolicyContext): EnterprisePolicyDecision;
|
|
1584
|
+
declare function openPolicyStore(options: OpenPolicyStoreOptions): PolicyStore;
|
|
1585
|
+
|
|
1586
|
+
type PeerStoreMode = "sqlite" | "memory-fallback";
|
|
1587
|
+
type PeerAction = "read" | "send" | "wait" | "start" | "focus";
|
|
1588
|
+
type PeerStatus = "active" | "suspended";
|
|
1589
|
+
interface PeerRecord {
|
|
1590
|
+
id: string;
|
|
1591
|
+
label: string;
|
|
1592
|
+
remoteHostId: string;
|
|
1593
|
+
remoteVersion: string;
|
|
1594
|
+
actions: PeerAction[];
|
|
1595
|
+
allowedWorkspaceIds: string[] | null;
|
|
1596
|
+
status: PeerStatus;
|
|
1597
|
+
revision: number;
|
|
1598
|
+
createdAt: number;
|
|
1599
|
+
updatedAt: number;
|
|
1600
|
+
lastVerifiedAt: number;
|
|
1601
|
+
}
|
|
1602
|
+
interface PeerConnection extends PeerRecord {
|
|
1603
|
+
baseUrl: string;
|
|
1604
|
+
credential: string;
|
|
1605
|
+
}
|
|
1606
|
+
interface CreatePeerInput {
|
|
1607
|
+
label: string;
|
|
1608
|
+
baseUrl: string;
|
|
1609
|
+
credential: string;
|
|
1610
|
+
remoteHostId: string;
|
|
1611
|
+
remoteVersion: string;
|
|
1612
|
+
actions?: PeerAction[];
|
|
1613
|
+
allowedWorkspaceIds?: string[] | null;
|
|
1614
|
+
}
|
|
1615
|
+
interface UpdatePeerInput {
|
|
1616
|
+
label?: string;
|
|
1617
|
+
actions?: PeerAction[];
|
|
1618
|
+
allowedWorkspaceIds?: string[] | null;
|
|
1619
|
+
status?: PeerStatus;
|
|
1620
|
+
remoteVersion?: string;
|
|
1621
|
+
lastVerifiedAt?: number;
|
|
1622
|
+
}
|
|
1623
|
+
interface PeerStore {
|
|
1624
|
+
readonly mode: PeerStoreMode;
|
|
1625
|
+
list(): PeerRecord[];
|
|
1626
|
+
get(id: string): PeerRecord | undefined;
|
|
1627
|
+
connection(id: string): PeerConnection | undefined;
|
|
1628
|
+
create(input: CreatePeerInput, now?: number): PeerRecord;
|
|
1629
|
+
update(id: string, input: UpdatePeerInput, expectedRevision: number, now?: number): PeerRecord | undefined;
|
|
1630
|
+
rotateCredential(id: string, input: {
|
|
1631
|
+
credential: string;
|
|
1632
|
+
remoteVersion: string;
|
|
1633
|
+
lastVerifiedAt?: number;
|
|
1634
|
+
}, expectedRevision: number, now?: number): PeerRecord | undefined;
|
|
1635
|
+
remove(id: string): boolean;
|
|
1636
|
+
close(): void;
|
|
1637
|
+
}
|
|
1638
|
+
interface OpenPeerStoreOptions {
|
|
1639
|
+
dbPath: string;
|
|
1640
|
+
generatePeerId?: () => string;
|
|
1641
|
+
loadDatabase?: () => typeof better_sqlite3;
|
|
1642
|
+
}
|
|
1643
|
+
declare class PeerRevisionConflictError extends Error {
|
|
1644
|
+
readonly current: PeerRecord;
|
|
1645
|
+
constructor(current: PeerRecord);
|
|
1646
|
+
}
|
|
1647
|
+
declare function normalizePeerBaseUrl(value: unknown): string;
|
|
1648
|
+
declare function openPeerStore(options: OpenPeerStoreOptions): PeerStore;
|
|
1649
|
+
|
|
1650
|
+
interface VerifiedPeerIdentity {
|
|
1651
|
+
remoteHostId: string;
|
|
1652
|
+
remoteVersion: string;
|
|
1653
|
+
remoteLabel: string;
|
|
1654
|
+
protocolVersion: number;
|
|
1655
|
+
}
|
|
1656
|
+
interface PeerJsonResponse {
|
|
1657
|
+
status: number;
|
|
1658
|
+
body: unknown;
|
|
1659
|
+
}
|
|
1660
|
+
declare class PeerRequestError extends Error {
|
|
1661
|
+
readonly status?: number | undefined;
|
|
1662
|
+
readonly remoteCode?: string | undefined;
|
|
1663
|
+
constructor(message: string, status?: number | undefined, remoteCode?: string | undefined);
|
|
1664
|
+
}
|
|
1665
|
+
declare function requestPeerJson(connection: Pick<PeerConnection, "baseUrl" | "credential">, path: string, init?: {
|
|
1666
|
+
method?: "GET" | "POST";
|
|
1667
|
+
body?: unknown;
|
|
1668
|
+
idempotencyKey?: string;
|
|
1669
|
+
fetch?: typeof globalThis.fetch;
|
|
1670
|
+
timeoutMs?: number;
|
|
1671
|
+
}): Promise<PeerJsonResponse>;
|
|
1672
|
+
declare function verifyPeerConnection(input: {
|
|
1673
|
+
baseUrl: string;
|
|
1674
|
+
credential: string;
|
|
1675
|
+
localHostId: string;
|
|
1676
|
+
fetch?: typeof globalThis.fetch;
|
|
1677
|
+
}): Promise<VerifiedPeerIdentity>;
|
|
1678
|
+
|
|
1679
|
+
type CommandCenterStoreMode = "sqlite" | "memory-fallback";
|
|
1680
|
+
type WorkspaceKind = "directory" | "worktree";
|
|
1681
|
+
type AgentActivity = "blocked" | "working" | "done" | "idle" | "ended" | "unknown";
|
|
1682
|
+
type AttentionKind = "blocked" | "done" | "error" | "file" | "policy";
|
|
1683
|
+
type AttentionState = "open" | "acknowledged" | "snoozed" | "resolved";
|
|
1684
|
+
interface HostRecord {
|
|
1685
|
+
id: string;
|
|
1686
|
+
label: string;
|
|
1687
|
+
createdAt: number;
|
|
1688
|
+
updatedAt: number;
|
|
1689
|
+
}
|
|
1690
|
+
interface WorkspaceRecord {
|
|
1691
|
+
id: string;
|
|
1692
|
+
label: string;
|
|
1693
|
+
cwd: string;
|
|
1694
|
+
kind: WorkspaceKind;
|
|
1695
|
+
sortOrder: number;
|
|
1696
|
+
createdAt: number;
|
|
1697
|
+
updatedAt: number;
|
|
1698
|
+
archivedAt?: number;
|
|
1699
|
+
}
|
|
1700
|
+
interface SessionPlacement {
|
|
1701
|
+
sessionId: string;
|
|
1702
|
+
workspaceId: string;
|
|
1703
|
+
agentId: string;
|
|
1704
|
+
createdAt: number;
|
|
1705
|
+
}
|
|
1706
|
+
interface AgentRecord {
|
|
1707
|
+
id: string;
|
|
1708
|
+
sessionId: string;
|
|
1709
|
+
workspaceId: string;
|
|
1710
|
+
provider: string;
|
|
1711
|
+
activity: AgentActivity;
|
|
1712
|
+
createdAt: number;
|
|
1713
|
+
updatedAt: number;
|
|
1714
|
+
}
|
|
1715
|
+
interface AttentionItem {
|
|
1716
|
+
id: string;
|
|
1717
|
+
workspaceId: string;
|
|
1718
|
+
sessionId: string;
|
|
1719
|
+
agentId: string;
|
|
1720
|
+
kind: AttentionKind;
|
|
1721
|
+
state: AttentionState;
|
|
1722
|
+
title: string;
|
|
1723
|
+
detail?: string;
|
|
1724
|
+
urgency: number;
|
|
1725
|
+
occurrenceCount: number;
|
|
1726
|
+
createdAt: number;
|
|
1727
|
+
updatedAt: number;
|
|
1728
|
+
acknowledgedAt?: number;
|
|
1729
|
+
snoozedUntil?: number;
|
|
1730
|
+
resolvedAt?: number;
|
|
1731
|
+
}
|
|
1732
|
+
interface CommandEvent {
|
|
1733
|
+
id: number;
|
|
1734
|
+
type: string;
|
|
1735
|
+
resourceType: string;
|
|
1736
|
+
resourceId: string;
|
|
1737
|
+
payload: Record<string, unknown>;
|
|
1738
|
+
createdAt: number;
|
|
1739
|
+
}
|
|
1740
|
+
interface CommandLayoutEnvelope {
|
|
1741
|
+
document: Record<string, unknown> | null;
|
|
1742
|
+
revision: number;
|
|
1743
|
+
updatedAt?: number;
|
|
1744
|
+
}
|
|
1745
|
+
declare class CommandCenterRevisionConflictError extends Error {
|
|
1746
|
+
readonly current: CommandLayoutEnvelope;
|
|
1747
|
+
constructor(current: CommandLayoutEnvelope);
|
|
1748
|
+
}
|
|
1749
|
+
interface CreateWorkspaceInput {
|
|
1750
|
+
cwd: string;
|
|
1751
|
+
label?: string;
|
|
1752
|
+
kind?: WorkspaceKind;
|
|
1753
|
+
}
|
|
1754
|
+
interface UpdateWorkspaceInput {
|
|
1755
|
+
label?: string;
|
|
1756
|
+
sortOrder?: number;
|
|
1757
|
+
archived?: boolean;
|
|
1758
|
+
}
|
|
1759
|
+
interface UpsertAgentInput {
|
|
1760
|
+
sessionId: string;
|
|
1761
|
+
workspaceId: string;
|
|
1762
|
+
provider: string;
|
|
1763
|
+
activity: AgentActivity;
|
|
1764
|
+
createdAt: number;
|
|
1765
|
+
}
|
|
1766
|
+
interface RecordAttentionInput {
|
|
1767
|
+
workspaceId: string;
|
|
1768
|
+
sessionId: string;
|
|
1769
|
+
agentId: string;
|
|
1770
|
+
kind: AttentionKind;
|
|
1771
|
+
title: string;
|
|
1772
|
+
detail?: string;
|
|
1773
|
+
urgency?: number;
|
|
1774
|
+
/** Stable transition identity, e.g. `blocked:<sessionId>`. Only one unresolved item exists per key. */
|
|
1775
|
+
dedupeKey: string;
|
|
1776
|
+
}
|
|
1777
|
+
interface CommandCenterStore {
|
|
1778
|
+
readonly mode: CommandCenterStoreMode;
|
|
1779
|
+
getHost(): HostRecord;
|
|
1780
|
+
renameHost(label: string, now?: number): HostRecord;
|
|
1781
|
+
listWorkspaces(opts?: {
|
|
1782
|
+
includeArchived?: boolean;
|
|
1783
|
+
}): WorkspaceRecord[];
|
|
1784
|
+
getWorkspace(id: string): WorkspaceRecord | undefined;
|
|
1785
|
+
createWorkspace(input: CreateWorkspaceInput, now?: number): WorkspaceRecord;
|
|
1786
|
+
updateWorkspace(id: string, input: UpdateWorkspaceInput, now?: number): WorkspaceRecord | undefined;
|
|
1787
|
+
ensureSession(sessionId: string, cwd: string, now?: number): SessionPlacement;
|
|
1788
|
+
placementForSession(sessionId: string): SessionPlacement | undefined;
|
|
1789
|
+
removeSession(sessionId: string, now?: number): void;
|
|
1790
|
+
upsertAgent(input: UpsertAgentInput, now?: number): AgentRecord;
|
|
1791
|
+
getAgent(id: string): AgentRecord | undefined;
|
|
1792
|
+
listAgents(): AgentRecord[];
|
|
1793
|
+
recordAttention(input: RecordAttentionInput, now?: number): AttentionItem;
|
|
1794
|
+
listAttention(opts?: {
|
|
1795
|
+
includeResolved?: boolean;
|
|
1796
|
+
includeSnoozed?: boolean;
|
|
1797
|
+
now?: number;
|
|
1798
|
+
}): AttentionItem[];
|
|
1799
|
+
acknowledgeAttention(id: string, now?: number): AttentionItem | undefined;
|
|
1800
|
+
snoozeAttention(id: string, until: number, now?: number): AttentionItem | undefined;
|
|
1801
|
+
resolveAttention(id: string, now?: number): AttentionItem | undefined;
|
|
1802
|
+
resolveAttentionByDedupeKey(dedupeKey: string, now?: number): number;
|
|
1803
|
+
markSessionViewed(sessionId: string, now?: number): number;
|
|
1804
|
+
appendEvent(type: string, resourceType: string, resourceId: string, payload?: Record<string, unknown>, now?: number): CommandEvent;
|
|
1805
|
+
listEvents(afterId?: number, limit?: number): CommandEvent[];
|
|
1806
|
+
eventBounds(): {
|
|
1807
|
+
earliest: number;
|
|
1808
|
+
latest: number;
|
|
1809
|
+
};
|
|
1810
|
+
subscribeEvents(listener: (event: CommandEvent) => void): () => void;
|
|
1811
|
+
getLayout(): CommandLayoutEnvelope;
|
|
1812
|
+
putLayout(document: Record<string, unknown>, expectedRevision: number, now?: number): CommandLayoutEnvelope;
|
|
1813
|
+
close(): void;
|
|
1814
|
+
}
|
|
1815
|
+
interface OpenCommandCenterStoreOptions {
|
|
1816
|
+
dbPath: string;
|
|
1817
|
+
hostLabel?: string;
|
|
1818
|
+
generateHostId?: () => string;
|
|
1819
|
+
generateWorkspaceId?: () => string;
|
|
1820
|
+
generateAttentionId?: () => string;
|
|
1821
|
+
/** Test/embedding seam; throwing selects the non-durable in-memory fallback. */
|
|
1822
|
+
loadDatabase?: () => typeof better_sqlite3;
|
|
1823
|
+
}
|
|
1824
|
+
declare function normalizeLabel(value: unknown): string | undefined;
|
|
1825
|
+
declare function agentIdForSession(sessionId: string): string;
|
|
1826
|
+
declare function openCommandCenterStore(opts: OpenCommandCenterStoreOptions): CommandCenterStore;
|
|
1827
|
+
/** Exposed for API adapters and tests; one current RoamCode session owns one current agent. */
|
|
1828
|
+
declare const currentAgentIdForSession: typeof agentIdForSession;
|
|
1829
|
+
/** Re-exported validation keeps transport and stores on one label contract. */
|
|
1830
|
+
declare const normalizeCommandCenterLabel: typeof normalizeLabel;
|
|
1831
|
+
|
|
1832
|
+
type WorktreeErrorCode = "WORKTREE_OUTSIDE_ROOT" | "WORKTREE_INVALID_REF" | "WORKTREE_NOT_FOUND" | "WORKTREE_NOT_REGISTERED" | "WORKTREE_MAIN_PROTECTED" | "WORKTREE_DIRTY" | "WORKTREE_EXISTS" | "WORKTREE_GIT_FAILED" | "WORKTREE_TIMEOUT";
|
|
1833
|
+
declare class WorktreeError extends Error {
|
|
1834
|
+
readonly code: WorktreeErrorCode;
|
|
1835
|
+
readonly statusCode: number;
|
|
1836
|
+
constructor(code: WorktreeErrorCode, message: string, statusCode?: number);
|
|
1837
|
+
}
|
|
1838
|
+
interface WorktreeRecord {
|
|
1839
|
+
path: string;
|
|
1840
|
+
repositoryPath: string;
|
|
1841
|
+
branch?: string;
|
|
1842
|
+
head: string;
|
|
1843
|
+
dirty: boolean;
|
|
1844
|
+
changedFiles: number;
|
|
1845
|
+
isMain: boolean;
|
|
1846
|
+
}
|
|
1847
|
+
interface CreateWorktreeInput {
|
|
1848
|
+
repositoryPath: string;
|
|
1849
|
+
path: string;
|
|
1850
|
+
branch?: string;
|
|
1851
|
+
baseRef?: string;
|
|
1852
|
+
}
|
|
1853
|
+
interface CreateWorktreeResult {
|
|
1854
|
+
worktree: WorktreeRecord;
|
|
1855
|
+
created: boolean;
|
|
1856
|
+
}
|
|
1857
|
+
interface WorktreeService {
|
|
1858
|
+
inspect(path: string): Promise<WorktreeRecord>;
|
|
1859
|
+
create(input: CreateWorktreeInput): Promise<CreateWorktreeResult>;
|
|
1860
|
+
remove(path: string, force?: boolean): Promise<WorktreeRecord>;
|
|
1861
|
+
}
|
|
1862
|
+
interface CreateWorktreeServiceOptions {
|
|
1863
|
+
fsRoot: string;
|
|
1864
|
+
gitBin?: string;
|
|
1865
|
+
timeoutMs?: number;
|
|
1866
|
+
maxOutputBytes?: number;
|
|
1867
|
+
}
|
|
1868
|
+
declare function createWorktreeService(options: CreateWorktreeServiceOptions): WorktreeService;
|
|
1869
|
+
|
|
1870
|
+
type ExtensionKind = "adapter" | "plugin";
|
|
1871
|
+
type ExtensionTrust = "signed" | "integrity";
|
|
1872
|
+
declare class ExtensionError extends Error {
|
|
1873
|
+
readonly code: "EXTENSION_INVALID" | "EXTENSION_OUTSIDE_ROOT" | "EXTENSION_INTEGRITY_MISMATCH" | "EXTENSION_SIGNATURE_INVALID" | "EXTENSION_NOT_FOUND" | "EXTENSION_VERSION_NOT_FOUND" | "EXTENSION_ROLLBACK_UNAVAILABLE" | "EXTENSION_IN_USE" | "EXTENSION_PERMISSION_DENIED";
|
|
1874
|
+
readonly statusCode: number;
|
|
1875
|
+
constructor(code: "EXTENSION_INVALID" | "EXTENSION_OUTSIDE_ROOT" | "EXTENSION_INTEGRITY_MISMATCH" | "EXTENSION_SIGNATURE_INVALID" | "EXTENSION_NOT_FOUND" | "EXTENSION_VERSION_NOT_FOUND" | "EXTENSION_ROLLBACK_UNAVAILABLE" | "EXTENSION_IN_USE" | "EXTENSION_PERMISSION_DENIED", message: string, statusCode?: number);
|
|
1876
|
+
}
|
|
1877
|
+
declare const pluginPermissionSchema: z.ZodEnum<{
|
|
1878
|
+
"notifications:write": "notifications:write";
|
|
1879
|
+
"worktrees:write": "worktrees:write";
|
|
1880
|
+
"ci:read": "ci:read";
|
|
1881
|
+
"releases:read": "releases:read";
|
|
1882
|
+
"events:read": "events:read";
|
|
1883
|
+
"events:write": "events:write";
|
|
1884
|
+
}>;
|
|
1885
|
+
declare const pluginManifestSchema: z.ZodObject<{
|
|
1886
|
+
schemaVersion: z.ZodLiteral<1>;
|
|
1887
|
+
kind: z.ZodLiteral<"plugin">;
|
|
1888
|
+
id: z.ZodString;
|
|
1889
|
+
version: z.ZodString;
|
|
1890
|
+
displayName: z.ZodString;
|
|
1891
|
+
description: z.ZodString;
|
|
1892
|
+
platforms: z.ZodArray<z.ZodEnum<{
|
|
1893
|
+
darwin: "darwin";
|
|
1894
|
+
linux: "linux";
|
|
1895
|
+
}>>;
|
|
1896
|
+
minimumRoamCodeVersion: z.ZodOptional<z.ZodString>;
|
|
1897
|
+
permissions: z.ZodArray<z.ZodEnum<{
|
|
1898
|
+
"notifications:write": "notifications:write";
|
|
1899
|
+
"worktrees:write": "worktrees:write";
|
|
1900
|
+
"ci:read": "ci:read";
|
|
1901
|
+
"releases:read": "releases:read";
|
|
1902
|
+
"events:read": "events:read";
|
|
1903
|
+
"events:write": "events:write";
|
|
1904
|
+
}>>;
|
|
1905
|
+
actions: z.ZodArray<z.ZodObject<{
|
|
1906
|
+
id: z.ZodString;
|
|
1907
|
+
title: z.ZodString;
|
|
1908
|
+
description: z.ZodOptional<z.ZodString>;
|
|
1909
|
+
entrypoint: z.ZodString;
|
|
1910
|
+
args: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
1911
|
+
cwd: z.ZodDefault<z.ZodEnum<{
|
|
1912
|
+
workspace: "workspace";
|
|
1913
|
+
host: "host";
|
|
1914
|
+
explicit: "explicit";
|
|
1915
|
+
}>>;
|
|
1916
|
+
timeoutMs: z.ZodDefault<z.ZodNumber>;
|
|
1917
|
+
maxOutputBytes: z.ZodDefault<z.ZodNumber>;
|
|
1918
|
+
permissions: z.ZodDefault<z.ZodArray<z.ZodEnum<{
|
|
1919
|
+
"notifications:write": "notifications:write";
|
|
1920
|
+
"worktrees:write": "worktrees:write";
|
|
1921
|
+
"ci:read": "ci:read";
|
|
1922
|
+
"releases:read": "releases:read";
|
|
1923
|
+
"events:read": "events:read";
|
|
1924
|
+
"events:write": "events:write";
|
|
1925
|
+
}>>>;
|
|
1926
|
+
}, z.core.$strict>>;
|
|
1927
|
+
eventHooks: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
1928
|
+
event: z.ZodString;
|
|
1929
|
+
actionId: z.ZodString;
|
|
1930
|
+
}, z.core.$strict>>>;
|
|
1931
|
+
settingsSchema: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
1932
|
+
ui: z.ZodOptional<z.ZodObject<{
|
|
1933
|
+
label: z.ZodString;
|
|
1934
|
+
route: z.ZodString;
|
|
1935
|
+
}, z.core.$strict>>;
|
|
1936
|
+
}, z.core.$strict>;
|
|
1937
|
+
declare const adapterRuntimeSchema: z.ZodObject<{
|
|
1938
|
+
executable: z.ZodString;
|
|
1939
|
+
probeArgs: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
1940
|
+
probeTimeoutMs: z.ZodDefault<z.ZodNumber>;
|
|
1941
|
+
launchArgs: z.ZodArray<z.ZodString>;
|
|
1942
|
+
resumeArgs: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
1943
|
+
env: z.ZodDefault<z.ZodArray<z.ZodEnum<{
|
|
1944
|
+
HOME: "HOME";
|
|
1945
|
+
PATH: "PATH";
|
|
1946
|
+
LANG: "LANG";
|
|
1947
|
+
LC_ALL: "LC_ALL";
|
|
1948
|
+
TMPDIR: "TMPDIR";
|
|
1949
|
+
SHELL: "SHELL";
|
|
1950
|
+
}>>>;
|
|
1951
|
+
workingPatterns: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
1952
|
+
blockedPatterns: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
1953
|
+
idlePatterns: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
1954
|
+
identityPattern: z.ZodOptional<z.ZodString>;
|
|
1955
|
+
}, z.core.$strict>;
|
|
1956
|
+
type PluginPermission = z.infer<typeof pluginPermissionSchema>;
|
|
1957
|
+
type PluginManifestV1 = z.infer<typeof pluginManifestSchema>;
|
|
1958
|
+
type AdapterRuntimeV1 = z.infer<typeof adapterRuntimeSchema>;
|
|
1959
|
+
interface AdapterPackageManifestV1 {
|
|
1960
|
+
schemaVersion: 1;
|
|
1961
|
+
kind: "adapter";
|
|
1962
|
+
adapter: AdapterManifestV1;
|
|
1963
|
+
runtime: AdapterRuntimeV1;
|
|
1964
|
+
}
|
|
1965
|
+
type ExtensionManifestV1 = PluginManifestV1 | AdapterPackageManifestV1;
|
|
1966
|
+
interface ExtensionVersionRecord {
|
|
1967
|
+
kind: ExtensionKind;
|
|
1968
|
+
id: string;
|
|
1969
|
+
version: string;
|
|
1970
|
+
manifest: ExtensionManifestV1;
|
|
1971
|
+
integrity: string;
|
|
1972
|
+
trust: ExtensionTrust;
|
|
1973
|
+
signerFingerprint?: string;
|
|
1974
|
+
source: string;
|
|
1975
|
+
installedAt: number;
|
|
1976
|
+
}
|
|
1977
|
+
interface InstalledExtension {
|
|
1978
|
+
kind: ExtensionKind;
|
|
1979
|
+
id: string;
|
|
1980
|
+
enabled: boolean;
|
|
1981
|
+
currentVersion: string;
|
|
1982
|
+
previousVersion?: string;
|
|
1983
|
+
updatedAt: number;
|
|
1984
|
+
approvedPermissions: string[];
|
|
1985
|
+
current: ExtensionVersionRecord;
|
|
1986
|
+
versions: ExtensionVersionRecord[];
|
|
1987
|
+
}
|
|
1988
|
+
interface InstallExtensionInput {
|
|
1989
|
+
sourceDirectory: string;
|
|
1990
|
+
expectedIntegrity: string;
|
|
1991
|
+
signature?: string;
|
|
1992
|
+
publicKey?: string;
|
|
1993
|
+
source?: string;
|
|
1994
|
+
allowUnsigned?: boolean;
|
|
1995
|
+
}
|
|
1996
|
+
interface ExtensionManager {
|
|
1997
|
+
readonly mode: "sqlite" | "memory-fallback";
|
|
1998
|
+
list(kind?: ExtensionKind): InstalledExtension[];
|
|
1999
|
+
get(kind: ExtensionKind, id: string): InstalledExtension | undefined;
|
|
2000
|
+
packagePath(kind: ExtensionKind, id: string, version?: string): string;
|
|
2001
|
+
verify(kind: ExtensionKind, id: string, version?: string): Promise<boolean>;
|
|
2002
|
+
install(input: InstallExtensionInput): Promise<InstalledExtension>;
|
|
2003
|
+
setEnabled(kind: ExtensionKind, id: string, enabled: boolean, approvedPermissions?: string[]): InstalledExtension;
|
|
2004
|
+
rollback(kind: ExtensionKind, id: string): InstalledExtension;
|
|
2005
|
+
uninstall(kind: ExtensionKind, id: string, options?: {
|
|
2006
|
+
purgeState?: boolean;
|
|
2007
|
+
}): Promise<boolean>;
|
|
2008
|
+
close(): void;
|
|
2009
|
+
}
|
|
2010
|
+
interface OpenExtensionManagerOptions {
|
|
2011
|
+
dbPath: string;
|
|
2012
|
+
packagesDir: string;
|
|
2013
|
+
fsRoot: string;
|
|
2014
|
+
now?: () => number;
|
|
2015
|
+
loadDatabase?: () => typeof better_sqlite3;
|
|
2016
|
+
}
|
|
2017
|
+
declare function inspectExtensionPackage(sourceDirectory: string, fsRoot: string): Promise<{
|
|
2018
|
+
manifest: ExtensionManifestV1;
|
|
2019
|
+
integrity: string;
|
|
2020
|
+
}>;
|
|
2021
|
+
declare function openExtensionManager(options: OpenExtensionManagerOptions): ExtensionManager;
|
|
2022
|
+
interface MarketplaceEntry {
|
|
2023
|
+
kind: ExtensionKind;
|
|
2024
|
+
id: string;
|
|
2025
|
+
version: string;
|
|
2026
|
+
displayName: string;
|
|
2027
|
+
description: string;
|
|
2028
|
+
trust: "verified" | "community" | "local";
|
|
2029
|
+
compatibility: {
|
|
2030
|
+
platforms: Array<"darwin" | "linux">;
|
|
2031
|
+
minimumRoamCodeVersion?: string;
|
|
2032
|
+
};
|
|
2033
|
+
changelog?: string;
|
|
2034
|
+
source: string;
|
|
2035
|
+
integrity: string;
|
|
2036
|
+
signerFingerprint?: string;
|
|
2037
|
+
reportUrl?: string;
|
|
2038
|
+
}
|
|
2039
|
+
declare function parseMarketplaceIndex(value: unknown): MarketplaceEntry[];
|
|
2040
|
+
declare function searchMarketplace(entries: MarketplaceEntry[], query: string, platform?: NodeJS.Platform): MarketplaceEntry[];
|
|
2041
|
+
|
|
2042
|
+
declare class PluginRuntimeError extends Error {
|
|
2043
|
+
readonly code: "PLUGIN_NOT_FOUND" | "PLUGIN_DISABLED" | "PLUGIN_ACTION_NOT_FOUND" | "PLUGIN_PERMISSION_DENIED" | "PLUGIN_PATH_DENIED" | "PLUGIN_OUTPUT_LIMIT" | "PLUGIN_TIMEOUT" | "PLUGIN_FAILED";
|
|
2044
|
+
readonly statusCode: number;
|
|
2045
|
+
constructor(code: "PLUGIN_NOT_FOUND" | "PLUGIN_DISABLED" | "PLUGIN_ACTION_NOT_FOUND" | "PLUGIN_PERMISSION_DENIED" | "PLUGIN_PATH_DENIED" | "PLUGIN_OUTPUT_LIMIT" | "PLUGIN_TIMEOUT" | "PLUGIN_FAILED", message: string, statusCode?: number);
|
|
2046
|
+
}
|
|
2047
|
+
interface PluginRunInput {
|
|
2048
|
+
pluginId: string;
|
|
2049
|
+
actionId: string;
|
|
2050
|
+
workspacePath?: string;
|
|
2051
|
+
explicitCwd?: string;
|
|
2052
|
+
context?: Record<string, unknown>;
|
|
2053
|
+
}
|
|
2054
|
+
interface PluginRunResult {
|
|
2055
|
+
pluginId: string;
|
|
2056
|
+
pluginVersion: string;
|
|
2057
|
+
actionId: string;
|
|
2058
|
+
status: "succeeded" | "failed";
|
|
2059
|
+
exitCode: number;
|
|
2060
|
+
stdout: string;
|
|
2061
|
+
stderr: string;
|
|
2062
|
+
startedAt: number;
|
|
2063
|
+
finishedAt: number;
|
|
2064
|
+
truncated: false;
|
|
2065
|
+
}
|
|
2066
|
+
interface PluginAuditEvent {
|
|
2067
|
+
pluginId: string;
|
|
2068
|
+
pluginVersion: string;
|
|
2069
|
+
actionId: string;
|
|
2070
|
+
phase: "started" | "finished";
|
|
2071
|
+
result?: "succeeded" | "failed";
|
|
2072
|
+
exitCode?: number;
|
|
2073
|
+
durationMs?: number;
|
|
2074
|
+
}
|
|
2075
|
+
interface CreatePluginRuntimeOptions {
|
|
2076
|
+
extensions: ExtensionManager;
|
|
2077
|
+
fsRoot: string;
|
|
2078
|
+
now?: () => number;
|
|
2079
|
+
audit?: (event: PluginAuditEvent) => void;
|
|
2080
|
+
}
|
|
2081
|
+
interface PluginRuntime {
|
|
2082
|
+
run(input: PluginRunInput): Promise<PluginRunResult>;
|
|
2083
|
+
hooksFor(eventType: string): Array<{
|
|
2084
|
+
pluginId: string;
|
|
2085
|
+
actionId: string;
|
|
2086
|
+
}>;
|
|
2087
|
+
}
|
|
2088
|
+
declare function createPluginRuntime(options: CreatePluginRuntimeOptions): PluginRuntime;
|
|
2089
|
+
|
|
2090
|
+
type ControlStoreMode = "sqlite" | "memory-fallback";
|
|
2091
|
+
type AuditActorType = "host" | "device" | "local" | "automation" | "plugin" | "system";
|
|
2092
|
+
type AuditResult = "success" | "denied" | "error";
|
|
2093
|
+
interface IdempotencyRecord {
|
|
2094
|
+
actorId: string;
|
|
2095
|
+
key: string;
|
|
2096
|
+
fingerprint: string;
|
|
2097
|
+
statusCode: number;
|
|
2098
|
+
body: string;
|
|
2099
|
+
createdAt: number;
|
|
2100
|
+
expiresAt: number;
|
|
2101
|
+
}
|
|
2102
|
+
interface AuditRecord {
|
|
2103
|
+
id: number;
|
|
2104
|
+
actorType: AuditActorType;
|
|
2105
|
+
actorId: string;
|
|
2106
|
+
action: string;
|
|
2107
|
+
targetType: string;
|
|
2108
|
+
targetId?: string;
|
|
2109
|
+
result: AuditResult;
|
|
2110
|
+
metadata: Record<string, string | number | boolean | null>;
|
|
2111
|
+
createdAt: number;
|
|
2112
|
+
previousHash: string;
|
|
2113
|
+
hash: string;
|
|
2114
|
+
}
|
|
2115
|
+
type AutomationTrigger = {
|
|
2116
|
+
eventType: string;
|
|
2117
|
+
resourceType?: string;
|
|
2118
|
+
};
|
|
2119
|
+
type AutomationAction = {
|
|
2120
|
+
type: "acknowledge_attention";
|
|
2121
|
+
target: "event-resource" | string;
|
|
2122
|
+
} | {
|
|
2123
|
+
type: "resolve_attention";
|
|
2124
|
+
target: "event-resource" | string;
|
|
2125
|
+
} | {
|
|
2126
|
+
type: "snooze_attention";
|
|
2127
|
+
target: "event-resource" | string;
|
|
2128
|
+
durationMs: number;
|
|
2129
|
+
} | {
|
|
2130
|
+
type: "emit_event";
|
|
2131
|
+
eventType: string;
|
|
2132
|
+
resourceType: string;
|
|
2133
|
+
resourceId: string;
|
|
2134
|
+
};
|
|
2135
|
+
interface AutomationDefinition {
|
|
2136
|
+
id: string;
|
|
2137
|
+
name: string;
|
|
2138
|
+
enabled: boolean;
|
|
2139
|
+
trigger: AutomationTrigger;
|
|
2140
|
+
action: AutomationAction;
|
|
2141
|
+
permissions: string[];
|
|
2142
|
+
createdAt: number;
|
|
2143
|
+
updatedAt: number;
|
|
2144
|
+
}
|
|
2145
|
+
interface AutomationRun {
|
|
2146
|
+
id: number;
|
|
2147
|
+
automationId: string;
|
|
2148
|
+
eventId?: number;
|
|
2149
|
+
status: "succeeded" | "skipped" | "failed";
|
|
2150
|
+
detail?: string;
|
|
2151
|
+
createdAt: number;
|
|
2152
|
+
}
|
|
2153
|
+
interface CreateAutomationInput {
|
|
2154
|
+
name: string;
|
|
2155
|
+
enabled?: boolean;
|
|
2156
|
+
trigger: AutomationTrigger;
|
|
2157
|
+
action: AutomationAction;
|
|
2158
|
+
permissions: string[];
|
|
2159
|
+
}
|
|
2160
|
+
interface UpdateAutomationInput {
|
|
2161
|
+
name?: string;
|
|
2162
|
+
enabled?: boolean;
|
|
2163
|
+
trigger?: AutomationTrigger;
|
|
2164
|
+
action?: AutomationAction;
|
|
2165
|
+
permissions?: string[];
|
|
2166
|
+
}
|
|
2167
|
+
interface ControlStore {
|
|
2168
|
+
readonly mode: ControlStoreMode;
|
|
2169
|
+
getIdempotency(actorId: string, key: string, now?: number): IdempotencyRecord | undefined;
|
|
2170
|
+
putIdempotency(record: IdempotencyRecord): void;
|
|
2171
|
+
appendAudit(input: Omit<AuditRecord, "id" | "previousHash" | "hash">): AuditRecord;
|
|
2172
|
+
listAudit(afterId?: number, limit?: number): AuditRecord[];
|
|
2173
|
+
listAuditLatest(limit?: number): AuditRecord[];
|
|
2174
|
+
verifyAuditChain(): {
|
|
2175
|
+
valid: boolean;
|
|
2176
|
+
count: number;
|
|
2177
|
+
head: string;
|
|
2178
|
+
};
|
|
2179
|
+
listAutomations(): AutomationDefinition[];
|
|
2180
|
+
getAutomation(id: string): AutomationDefinition | undefined;
|
|
2181
|
+
createAutomation(input: CreateAutomationInput, now?: number): AutomationDefinition;
|
|
2182
|
+
updateAutomation(id: string, input: UpdateAutomationInput, now?: number): AutomationDefinition | undefined;
|
|
2183
|
+
removeAutomation(id: string): boolean;
|
|
2184
|
+
recordAutomationRun(input: Omit<AutomationRun, "id">): AutomationRun;
|
|
2185
|
+
listAutomationRuns(automationId?: string, limit?: number): AutomationRun[];
|
|
2186
|
+
close(): void;
|
|
2187
|
+
}
|
|
2188
|
+
interface OpenControlStoreOptions {
|
|
2189
|
+
dbPath: string;
|
|
2190
|
+
generateAutomationId?: () => string;
|
|
2191
|
+
loadDatabase?: () => typeof better_sqlite3;
|
|
2192
|
+
}
|
|
2193
|
+
declare function normalizeAutomationTrigger(value: unknown): AutomationTrigger | undefined;
|
|
2194
|
+
declare function normalizeAutomationAction(value: unknown): AutomationAction | undefined;
|
|
2195
|
+
declare function normalizeAutomationInput(value: unknown): CreateAutomationInput | undefined;
|
|
2196
|
+
/** Retain only coarse, bounded audit metadata; content- or credential-shaped fields are dropped. */
|
|
2197
|
+
declare function privacySafeAuditMetadata(value: Record<string, unknown> | undefined): Record<string, string | number | boolean | null>;
|
|
2198
|
+
declare function openControlStore(opts: OpenControlStoreOptions): ControlStore;
|
|
2199
|
+
declare const CONTROL_IDEMPOTENCY_TTL_MS: number;
|
|
2200
|
+
|
|
597
2201
|
/**
|
|
598
2202
|
* Origin / CSWSH (cross-site WebSocket hijacking) guard for the WS upgrade and state-changing HTTP.
|
|
599
2203
|
*
|
|
@@ -724,6 +2328,11 @@ interface WsTicketStoreOptions {
|
|
|
724
2328
|
/** Injectable ticket generator for tests. Default: 32 CSPRNG bytes, base64url. */
|
|
725
2329
|
generate?: () => string;
|
|
726
2330
|
}
|
|
2331
|
+
interface WsTicketContext {
|
|
2332
|
+
actorType: "device" | "host" | "local" | "relay";
|
|
2333
|
+
actorId: string;
|
|
2334
|
+
label: string;
|
|
2335
|
+
}
|
|
727
2336
|
/**
|
|
728
2337
|
* In-memory single-use ticket store. Deliberately NOT persisted: a ticket outliving a server restart
|
|
729
2338
|
* would defeat its 30s point, and the client just re-POSTs on reconnect. Expired entries are swept
|
|
@@ -731,20 +2340,25 @@ interface WsTicketStoreOptions {
|
|
|
731
2340
|
* a timer.
|
|
732
2341
|
*/
|
|
733
2342
|
declare class WsTicketStore {
|
|
734
|
-
/** ticket → expiry
|
|
2343
|
+
/** ticket → expiry + the authenticated principal that minted it. */
|
|
735
2344
|
private readonly tickets;
|
|
736
2345
|
private readonly ttlMs;
|
|
737
2346
|
private readonly now;
|
|
738
2347
|
private readonly generate;
|
|
739
2348
|
constructor(opts?: WsTicketStoreOptions);
|
|
740
2349
|
/** Mint a fresh single-use ticket. The response shape is exactly what POST /ws-ticket returns. */
|
|
741
|
-
issue(): {
|
|
2350
|
+
issue(context?: WsTicketContext): {
|
|
742
2351
|
ticket: string;
|
|
743
2352
|
expiresInMs: number;
|
|
744
2353
|
};
|
|
745
2354
|
/** Consume a ticket: true exactly ONCE for a live ticket; false for unknown, expired, or already-used
|
|
746
2355
|
* (the entry is deleted on first consume, so a replayed WS URL is rejected). */
|
|
747
2356
|
consume(ticket: string): boolean;
|
|
2357
|
+
/** Consume once and recover the authenticated principal bound at issuance. The wrapper object makes a
|
|
2358
|
+
* context-free legacy/test ticket distinguishable from an invalid ticket. */
|
|
2359
|
+
consumeWithContext(ticket: string): {
|
|
2360
|
+
context?: WsTicketContext;
|
|
2361
|
+
} | undefined;
|
|
748
2362
|
/** Drop expired entries so an unconsumed flood can't grow the map (lazy — no timer to leak). */
|
|
749
2363
|
private sweep;
|
|
750
2364
|
/** TEST ONLY: how many un-consumed tickets are currently held (post-sweep count). */
|
|
@@ -760,6 +2374,8 @@ interface PushSubscriptionRecord {
|
|
|
760
2374
|
auth: string;
|
|
761
2375
|
/** Optional session scope; undefined = subscribed to ALL sessions. */
|
|
762
2376
|
sessionId?: string;
|
|
2377
|
+
/** Per-device credential that created this subscription. Revocation removes its push channel too. */
|
|
2378
|
+
deviceId?: string;
|
|
763
2379
|
createdAt: number;
|
|
764
2380
|
}
|
|
765
2381
|
interface PushStore {
|
|
@@ -769,6 +2385,7 @@ interface PushStore {
|
|
|
769
2385
|
sessionId?: string;
|
|
770
2386
|
}): PushSubscriptionRecord[];
|
|
771
2387
|
remove(endpoint: string): void;
|
|
2388
|
+
removeForDevice(deviceId: string): void;
|
|
772
2389
|
close(): void;
|
|
773
2390
|
}
|
|
774
2391
|
interface OpenPushStoreOptions {
|
|
@@ -1498,10 +3115,45 @@ declare function capturePane(opts: CaptureOptions): Promise<string>;
|
|
|
1498
3115
|
|
|
1499
3116
|
declare class ProviderRegistry {
|
|
1500
3117
|
private readonly byId;
|
|
3118
|
+
private readonly manifests;
|
|
3119
|
+
private readonly sources;
|
|
3120
|
+
private readonly enabled;
|
|
1501
3121
|
constructor(providers: readonly AgentProvider[]);
|
|
3122
|
+
register(provider: AgentProvider, source?: "built-in" | "installed", enabled?: boolean): void;
|
|
3123
|
+
setEnabled(id: ProviderId, enabled: boolean): void;
|
|
3124
|
+
isEnabled(id: ProviderId): boolean;
|
|
3125
|
+
source(id: ProviderId): "built-in" | "installed" | undefined;
|
|
3126
|
+
unregisterInstalled(id: ProviderId): void;
|
|
1502
3127
|
get(id: ProviderId): AgentProvider;
|
|
1503
3128
|
list(): AgentProvider[];
|
|
3129
|
+
listEnabled(): AgentProvider[];
|
|
3130
|
+
manifest(id: ProviderId): Readonly<AdapterManifestV1>;
|
|
3131
|
+
descriptors(): {
|
|
3132
|
+
enabled: boolean;
|
|
3133
|
+
id: string;
|
|
3134
|
+
displayName: string;
|
|
3135
|
+
version: string;
|
|
3136
|
+
schemaVersion: 1;
|
|
3137
|
+
source: "built-in" | "installed";
|
|
3138
|
+
platforms: ("darwin" | "linux")[];
|
|
3139
|
+
resumeIdentity: "optional" | "required" | "unsupported";
|
|
3140
|
+
capabilities: {
|
|
3141
|
+
state: boolean;
|
|
3142
|
+
probe: boolean;
|
|
3143
|
+
launch: boolean;
|
|
3144
|
+
resume: boolean;
|
|
3145
|
+
identity: boolean;
|
|
3146
|
+
metadata: boolean;
|
|
3147
|
+
usage: boolean;
|
|
3148
|
+
login: boolean;
|
|
3149
|
+
attachments: boolean;
|
|
3150
|
+
cleanup: boolean;
|
|
3151
|
+
};
|
|
3152
|
+
stateAuthority: AdapterStateAuthority[];
|
|
3153
|
+
optionSchema: Record<string, unknown>;
|
|
3154
|
+
}[];
|
|
1504
3155
|
}
|
|
3156
|
+
type ReturnTypeOfDescriptors = ReturnType<ProviderRegistry["descriptors"]>;
|
|
1505
3157
|
|
|
1506
3158
|
interface CodexSpawnLease {
|
|
1507
3159
|
readonly started: Promise<void>;
|
|
@@ -1643,6 +3295,11 @@ interface TerminalManagerDeps {
|
|
|
1643
3295
|
* are). Same never-throw contract.
|
|
1644
3296
|
*/
|
|
1645
3297
|
onFinished?: (id: string, wasAttached: boolean) => void;
|
|
3298
|
+
/** Every semantic state transition, including ones observed while a browser is attached. Used by the
|
|
3299
|
+
* command-center event/attention layer; a failure is isolated from terminal state. */
|
|
3300
|
+
onActivityChanged?: (id: string, previous: PaneStatus, current: PaneStatus, attached: boolean) => void;
|
|
3301
|
+
/** A client focused/attached this terminal. Done-unseen attention can become seen; blocked attention stays. */
|
|
3302
|
+
onViewed?: (id: string) => void;
|
|
1646
3303
|
/**
|
|
1647
3304
|
* Capture a tmux session's CURRENT rendered pane as plain text (READ-ONLY). Injected for tests; in
|
|
1648
3305
|
* production it defaults to a real `capture-pane -p` on {@link TMUX_SOCKET}. Drives {@link refreshActivity},
|
|
@@ -1655,15 +3312,8 @@ interface TerminalManagerDeps {
|
|
|
1655
3312
|
type CreateTerminalOptions = {
|
|
1656
3313
|
id: string;
|
|
1657
3314
|
cwd: string;
|
|
1658
|
-
provider:
|
|
1659
|
-
options:
|
|
1660
|
-
cols?: number;
|
|
1661
|
-
rows?: number;
|
|
1662
|
-
} | {
|
|
1663
|
-
id: string;
|
|
1664
|
-
cwd: string;
|
|
1665
|
-
provider: "codex";
|
|
1666
|
-
options: CodexSessionOptions;
|
|
3315
|
+
provider: ProviderId;
|
|
3316
|
+
options: ProviderSessionOptions;
|
|
1667
3317
|
cols?: number;
|
|
1668
3318
|
rows?: number;
|
|
1669
3319
|
};
|
|
@@ -1680,6 +3330,7 @@ declare class TerminalManager {
|
|
|
1680
3330
|
private readonly providers;
|
|
1681
3331
|
private attachConfig?;
|
|
1682
3332
|
constructor(deps: TerminalManagerDeps);
|
|
3333
|
+
private notifyActivityChanged;
|
|
1683
3334
|
/** Late-bound (after listen(), which resolves the loopback port) — same config the chat SessionManager
|
|
1684
3335
|
* gets. When set, each terminal's claude is spawned with `--mcp-config` so send_image/send_file work. */
|
|
1685
3336
|
setAttachConfig(attach: AttachSpawnOptions | undefined): void;
|
|
@@ -2125,8 +3776,24 @@ declare class CodexLatestService {
|
|
|
2125
3776
|
|
|
2126
3777
|
interface CreateServerDeps {
|
|
2127
3778
|
store?: SessionStore;
|
|
3779
|
+
/** Durable per-device credentials + one-time pairing sessions. start.ts supplies a SQLite store. */
|
|
3780
|
+
deviceStore?: DeviceStore;
|
|
3781
|
+
/** Durable host/workspace/agent/attention/event state. start.ts supplies a SQLite store. */
|
|
3782
|
+
commandStore?: CommandCenterStore;
|
|
3783
|
+
/** Durable idempotency, privacy-safe audit, and automation definitions/runs. */
|
|
3784
|
+
controlStore?: ControlStore;
|
|
3785
|
+
/** Guarded git worktree lifecycle, confined to FS_ROOT and injectable for isolated tests. */
|
|
3786
|
+
worktreeService?: WorktreeService;
|
|
3787
|
+
/** Durable verified adapter/plugin package inventory. start.ts supplies a SQLite-backed manager. */
|
|
3788
|
+
extensionManager?: ExtensionManager;
|
|
3789
|
+
/** Bounded, permissioned plugin subprocess boundary. */
|
|
3790
|
+
pluginRuntime?: PluginRuntime;
|
|
3791
|
+
/** Optional immutable marketplace index; local extension installation never depends on it. */
|
|
3792
|
+
marketplaceEntries?: MarketplaceEntry[];
|
|
2128
3793
|
/** Absolute path to the built PWA (packages/web/dist). When set, the server also serves the UI. */
|
|
2129
3794
|
webDir?: string;
|
|
3795
|
+
/** Per-process boot identity returned as a response header for the out-of-process managed watchdog. */
|
|
3796
|
+
healthInstanceId?: string;
|
|
2130
3797
|
pushStore?: PushStore;
|
|
2131
3798
|
/** VAPID public key exposed at GET /push/vapid for the browser subscription. */
|
|
2132
3799
|
vapidPublicKey?: string;
|
|
@@ -2216,13 +3883,49 @@ interface CreateServerDeps {
|
|
|
2216
3883
|
* store is built when omitted.
|
|
2217
3884
|
*/
|
|
2218
3885
|
wsTickets?: WsTicketStore;
|
|
3886
|
+
/** One-writer/many-observer terminal input coordinator. Injectable for deterministic multi-client tests. */
|
|
3887
|
+
inputLeases?: InputLeaseCoordinator;
|
|
3888
|
+
/** Team policy seam: direct local mode permits confirmed takeover; enterprise policy can deny it here. */
|
|
3889
|
+
authorizeInputTakeover?: (principal: InputLeasePrincipal, sessionId: string) => boolean;
|
|
3890
|
+
/** Optional policy seam for acquiring/writing input. Team RBAC is applied in addition when enabled. */
|
|
3891
|
+
authorizeInputWrite?: (principal: InputLeasePrincipal, sessionId: string) => boolean;
|
|
3892
|
+
/** Durable team membership and role assignments. start.ts supplies SQLite; tests may inject memory. */
|
|
3893
|
+
teamStore?: TeamStore;
|
|
3894
|
+
/** Durable organization policy. Disabled by default; enforced uniformly when explicitly enabled. */
|
|
3895
|
+
policyStore?: PolicyStore;
|
|
3896
|
+
/** Durable, explicitly scoped host-to-host API connections. Raw peer credentials never leave this store. */
|
|
3897
|
+
peerStore?: PeerStore;
|
|
3898
|
+
/** Isolated outbound peer transport; injectable so tests never contact developer or production hosts. */
|
|
3899
|
+
peerFetch?: typeof globalThis.fetch;
|
|
3900
|
+
/** Ephemeral, bounded presence heartbeats. */
|
|
3901
|
+
presence?: PresenceCoordinator;
|
|
3902
|
+
/** Advertises and enforces that this host has an outbound blind-relay transport configured. */
|
|
3903
|
+
relayEnabled?: boolean;
|
|
3904
|
+
/** Optional hosted/self-hosted bootstrap; absent means relay works for already-provisioned devices only. */
|
|
3905
|
+
relayPairing?: RelayPairingBootstrap;
|
|
3906
|
+
/** Late-bound host connector hook so device revocation closes relay channels immediately. */
|
|
3907
|
+
onDeviceRevoked?: (deviceId: string) => void;
|
|
2219
3908
|
}
|
|
2220
3909
|
interface CreateServerResult {
|
|
2221
3910
|
app: FastifyInstance;
|
|
2222
3911
|
authGate: AuthGate;
|
|
3912
|
+
/** Issue a five-minute, one-use pairing capability without exposing the host's master token. */
|
|
3913
|
+
issuePairing(): PairingTicket;
|
|
3914
|
+
/** Internal E2E-relay bridge. It authenticates relay-scoped devices through the exact normal route hooks. */
|
|
3915
|
+
dispatchRelayRequest(token: string, request: RelayRpcRequest): Promise<RelayRpcResponse>;
|
|
3916
|
+
/** Issues a relay-principal terminal ticket without exposing the bridge's process-local capability. */
|
|
3917
|
+
issueRelayTerminalTicket(token: string): Promise<string>;
|
|
3918
|
+
/** Process-local loopback headers for streamed relay HTTP. Never expose these outside this server process. */
|
|
3919
|
+
relayLoopbackHeaders(token: string, headers?: Record<string, string>): Record<string, string>;
|
|
2223
3920
|
/** Exposed so startServer can late-bind the MCP attach config (after listen() resolves the port) —
|
|
2224
3921
|
* this is what gives the terminal's claude send_image/send_file. */
|
|
2225
3922
|
terminalManager: TerminalManager;
|
|
3923
|
+
/** Exposed for relay/team composition and isolated ownership tests. */
|
|
3924
|
+
inputLeases: InputLeaseCoordinator;
|
|
3925
|
+
teamStore: TeamStore;
|
|
3926
|
+
policyStore: PolicyStore;
|
|
3927
|
+
peerStore: PeerStore;
|
|
3928
|
+
presence: PresenceCoordinator;
|
|
2226
3929
|
/** False when tmux/node-pty is unavailable → terminal sessions are disabled (startServer warns loudly). */
|
|
2227
3930
|
terminalAvailable: boolean;
|
|
2228
3931
|
}
|
|
@@ -2351,8 +4054,41 @@ declare function startServer(env?: NodeJS.ProcessEnv): Promise<CreateServerResul
|
|
|
2351
4054
|
url: string;
|
|
2352
4055
|
token?: string;
|
|
2353
4056
|
tokenGenerated: boolean;
|
|
4057
|
+
relayHost?: RelayHostConnector;
|
|
2354
4058
|
}>;
|
|
2355
4059
|
|
|
4060
|
+
interface ProcessLifecycleTarget {
|
|
4061
|
+
once(event: string, listener: (...args: unknown[]) => void): unknown;
|
|
4062
|
+
off(event: string, listener: (...args: unknown[]) => void): unknown;
|
|
4063
|
+
exit(code: number): never | void;
|
|
4064
|
+
}
|
|
4065
|
+
interface ProcessLifecycleOptions {
|
|
4066
|
+
/** Close only on an intentional signal. Fatal errors exit immediately because process state is unknown. */
|
|
4067
|
+
close: () => void | Promise<unknown>;
|
|
4068
|
+
target?: ProcessLifecycleTarget;
|
|
4069
|
+
log?: (message: string) => void;
|
|
4070
|
+
shutdownTimeoutMs?: number;
|
|
4071
|
+
setTimer?: typeof setTimeout;
|
|
4072
|
+
clearTimer?: typeof clearTimeout;
|
|
4073
|
+
}
|
|
4074
|
+
interface ProcessLifecycleHandle {
|
|
4075
|
+
dispose(): void;
|
|
4076
|
+
}
|
|
4077
|
+
/**
|
|
4078
|
+
* Keep fatal diagnostics useful without copying bearer credentials, pairing links, or a maintainer's absolute
|
|
4079
|
+
* home path into service logs. The summary deliberately uses Error.message rather than the full stack.
|
|
4080
|
+
*/
|
|
4081
|
+
declare function safeProcessErrorSummary(reason: unknown, home?: string): string;
|
|
4082
|
+
/**
|
|
4083
|
+
* Own the process boundary for the always-on server.
|
|
4084
|
+
*
|
|
4085
|
+
* Intentional SIGTERM/SIGINT gets a bounded graceful close. An uncaught exception or unhandled rejection is
|
|
4086
|
+
* different: Node cannot promise that application state remains valid, so the process exits non-zero immediately
|
|
4087
|
+
* and lets launchd/systemd restart it. Keeping a possibly-corrupt process alive is how a listener can remain bound
|
|
4088
|
+
* while every HTTP request stalls indefinitely.
|
|
4089
|
+
*/
|
|
4090
|
+
declare function installProcessLifecycle(options: ProcessLifecycleOptions): ProcessLifecycleHandle;
|
|
4091
|
+
|
|
2356
4092
|
/** Terminal mode needs BOTH a tmux binary and a loadable node-pty. Injectable for tests. */
|
|
2357
4093
|
declare function detectTerminalSupport(deps?: {
|
|
2358
4094
|
hasTmux?: () => boolean;
|
|
@@ -2435,9 +4171,23 @@ declare function enableService(record: ServiceRecord): {
|
|
|
2435
4171
|
declare class ProviderOptionsError extends ProviderError {
|
|
2436
4172
|
constructor(message: string);
|
|
2437
4173
|
}
|
|
2438
|
-
declare function parseProviderOptions(provider: ProviderId, raw: unknown): ProviderSessionOptions;
|
|
4174
|
+
declare function parseProviderOptions(provider: ProviderId, raw: unknown, optionSchema?: Record<string, unknown>): ProviderSessionOptions;
|
|
2439
4175
|
declare function parseLegacyClaudeArgs(args: readonly string[]): ClaudeSessionOptions;
|
|
2440
4176
|
|
|
4177
|
+
interface CreateInstalledAdapterProviderOptions {
|
|
4178
|
+
extensions: ExtensionManager;
|
|
4179
|
+
adapterId: string;
|
|
4180
|
+
env?: NodeJS.ProcessEnv;
|
|
4181
|
+
}
|
|
4182
|
+
declare function createInstalledAdapterProvider(options: CreateInstalledAdapterProviderOptions): ProviderAdapterV1;
|
|
4183
|
+
|
|
4184
|
+
type JsonObject = Record<string, unknown>;
|
|
4185
|
+
interface OpenApiBuildOptions {
|
|
4186
|
+
serverVersion: string;
|
|
4187
|
+
adapters: ReturnTypeOfDescriptors;
|
|
4188
|
+
}
|
|
4189
|
+
declare function buildOpenApiDocument(options: OpenApiBuildOptions): JsonObject;
|
|
4190
|
+
|
|
2441
4191
|
interface CreateClaudeProviderOptions {
|
|
2442
4192
|
claudeBin: string;
|
|
2443
4193
|
env?: NodeJS.ProcessEnv;
|
|
@@ -2445,7 +4195,7 @@ interface CreateClaudeProviderOptions {
|
|
|
2445
4195
|
getAttach?: () => AttachSpawnOptions | undefined;
|
|
2446
4196
|
probe?: () => Promise<ProviderAvailability>;
|
|
2447
4197
|
}
|
|
2448
|
-
declare function createClaudeProvider(options: CreateClaudeProviderOptions):
|
|
4198
|
+
declare function createClaudeProvider(options: CreateClaudeProviderOptions): ProviderAdapterV1;
|
|
2449
4199
|
|
|
2450
4200
|
interface CreateCodexProviderOptions {
|
|
2451
4201
|
codexBin: string;
|
|
@@ -2458,7 +4208,7 @@ interface CreateCodexProviderOptions {
|
|
|
2458
4208
|
}
|
|
2459
4209
|
type CodexAttachContext = Pick<AttachSpawnOptions, "baseUrl" | "token" | "mcpScriptPath">;
|
|
2460
4210
|
declare function buildCodexArgs(context: ProviderProcessContext, attach?: CodexAttachContext): string[];
|
|
2461
|
-
declare function createCodexProvider(options: CreateCodexProviderOptions):
|
|
4211
|
+
declare function createCodexProvider(options: CreateCodexProviderOptions): ProviderAdapterV1;
|
|
2462
4212
|
|
|
2463
4213
|
declare const CODEX_EXECUTABLE_PROBE_TIMEOUT_MS = 5000;
|
|
2464
4214
|
declare const OPENAI_CODE_SIGNING_TEAM_ID = "2DC432GLL2";
|
|
@@ -2512,4 +4262,4 @@ declare function codexClassifierVersionWarning(codexVersion: string | undefined)
|
|
|
2512
4262
|
|
|
2513
4263
|
declare const SERVER_PACKAGE = "@roamcode.ai/server";
|
|
2514
4264
|
|
|
2515
|
-
export { API_PATH_DENYLIST, type AgentProvider, type AttachSpawnOptions, type AuthCheckResult, AuthGate, type AuthGateOptions, type Bar, CHECK_CACHE_MS, CLASSIFIER_TESTED_UP_TO, CLAUDE_LATEST_CACHE_MS, CLAUDE_VERSION_CACHE_MS, CLAUDE_VERSION_TIMEOUT_MS, CODEX_CLASSIFIER_TESTED_UP_TO, CODEX_EXECUTABLE_PROBE_TIMEOUT_MS, CODEX_OSC_MAX_CARRY, type CaptureOptions, type ChangelogEntry, type ClaudeAuthDeps, ClaudeAuthService, type ClaudeAuthStatus, type ClaudeAvailability, type ClaudeLatestDeps, ClaudeLatestService, type ClaudeMetadataRunner, ClaudeMetadataService, type ClaudeModelCatalogItem, type ClaudeSessionOptions, type ClaudeVersionProbe, type CodexAccount, CodexAppServerClient, type CodexAppServerClientOptions, type CodexDeviceLogin, type CodexExecutableDeps, type CodexExecutableProbe, type CodexExecutableResolution, type CodexInstallProvenance, CodexLatestService, type CodexLoginCompletion, type CodexLoginStatus, type CodexMetadataDiagnostics, type CodexMetadataRpc, CodexMetadataService, type CodexMetadataServiceOptions, type CodexModel, type CodexOscParser, type CodexProfileClientLifecycle, type CodexSessionOptions, type CodexSpawnLease, type CodexThreadInventoryEntry, type CodexThreadPersistence, CodexThreadResolver, type CodexThreadResolverOptions, type CodexUsage, type CodexVersionInfo, type CreateClaudeProviderOptions, type CreateCodexProfileClientLifecycleOptions, type CreateCodexProviderOptions, type CreatePushDispatcherDeps, type CreateServerDeps, type CreateServerResult, type CreateWebPushSendOptions, type DirEntry, type DirListing, type DirSearchResult, FETCH_TIMEOUT_MS, type FetchLatest, type FetchManifest, type FetchReleases, FsError, type FsErrorCode, FsService, type FsServiceOptions, type GitHubRelease, type HooksSettingsDocument, type IPty, type InstallServiceContext, type InstallServiceResult, type InstallationKind, type LaunchIntent, type ManagedInstallOptions, type ManagedInstallResult, type ManagedInstallStatus, type ManagedPaths, type McpConfigDocument, type ModelWeekBar, OPENAI_CODE_SIGNING_TEAM_ID, type OpenPushStoreOptions, type OpenSessionStoreOptions, type OriginCheckOptions, type PaneStatus, type ProcessSpec, type ProviderAvailability, ProviderError, type ProviderId, ProviderOptionsError, type ProviderProcessContext, ProviderRegistry, type ProviderRuntimeSignal, type ProviderRuntimeSignalParser, type ProviderSessionOptions, type PtySpawn, type PushDispatcher, type PushEvent, type PushEventKind, type PushPayload, type PushRecipient, type PushSendFn, type PushStore, type PushSubscriptionRecord, RUNNING_BUILD, RUNNING_VERSION, type RateLimitDecision, RateLimiter, type RateLimiterOptions, type RegisterStaticOptions, type ReleaseRecord, type RenderLaunchdOptions, type RenderSystemdOptions, type ResolveAccessTokenOptions, type ResolveCodexExecutableOptions, type ResolveCodexThreadOptions, type ResolveVapidKeysOptions, type RunClaudeVersion, type RunUsage, SEARCH_MAX_DEPTH, SEARCH_MAX_DIRS, SEARCH_MAX_RESULTS, SERVER_PACKAGE, SHELL_PATH_ALLOWLIST, type ServerConfig, type ServerRuntimeConfig, type ServiceRecord, type SessionDefaults, SessionDefaultsConflictError, type SessionFileDirection, type SessionFileKind, type SessionFileStorage, type SessionStore, type StoreMode, type StoredSession, type StoredSessionDefaults, type StoredSessionFile, type StoredStatus, TerminalManager, type TerminalManagerDeps, type TerminalMeta, TerminalProcess, type TerminalProcessOptions, type TerminalSub, USAGE_CACHE_MS, USAGE_TIMEOUT_MS, type UpdateAction, type UpdateState, type UpdateStatus, Updater, type UpdaterDeps, type UpdaterFs, type UsageInfo, UsageService, type UsageServiceDeps, type VapidKeys, type VersionInfo, WS_TICKET_TTL_MS, WsTicketStore, type WsTicketStoreOptions, assertConfigAllowsStart, buildCodexArgs, buildHooksSettingsDocument, buildMcpConfigDocument, buildPushPayload, buildServicePath, capturePane, classifierVersionWarning, classifyCodexPane, classifyPaneStatus, claudePreflightWarning, codexClassifierVersionWarning, compareVersions, computeBuildDrift, computeInstallDrift, createClaudeAuthService, createClaudeLatestService, createClaudeMetadataRunner, createClaudeProvider, createClaudeVersionProbe, createCodexOscParser, createCodexProfileClientLifecycle, createCodexProvider, createCodexThreadInventory, createCodexThreadPersistence, createPushDispatcher, createServer, createUpdater, createUsageRunner, createUsageService, createWebPushSend, defaultFetchManifest, defaultFetchReleases, defaultProbeCodexExecutable, defaultRunClaudeVersion, defaultUpdaterFs, detectTerminalSupport, enableService, ensureDataDir, extractBearerToken, extractLoginUrl, generateAccessToken, hasEncodedSep, hookAuthFileContent, hookAuthPathFor, hooksSettingsPathFor, installManagedRelease, installService, isCodexProfileClientLifecycle, isLoopbackAddress, isNewerMajorMinor, isOriginAllowed, isPublicForRequest, isPublicPath, isShellPath, isStableVersion, listTmuxSessions, loadConfig, loadServerConfig, looksLikeAssetRequest, managedPaths, mcpConfigPathFor, migrateServiceToLauncher, normalizeOrigin, normalizeProviderAvailability, normalizeRelease, normalizeSessionDefaults, openPushStore, openSessionStore, parseAllowedOrigins, parseAuthStatus, parseClaudeVersion, parseCodexOscNotifications, parseCodexVersion, parseLegacyClaudeArgs, parseNpmLatest, parseProviderOptions, parseReleaseNotes, parseUsage, pathForGate, persistAccessToken, providerPreflightWarning, readActiveVersion, readPreviousVersion, readServiceRecord, registerStatic, relativeWhen, renderLaunchdPlist, renderManagedLauncher, renderSystemdUnit, resetCodexThreadResolutionCoordinatorForTests, resolveAccessToken, resolveCodexExecutable, resolveDataDir, resolveInstallRoot, resolveVapidKeys, restartService, runClaudePreflight, runProviderPreflight, stableReleases, startServer, tmuxSessionName, writeManagedLauncher };
|
|
4265
|
+
export { ADAPTER_CONTRACT_VERSION, API_PATH_DENYLIST, type AdapterCapabilityName, AdapterManifestError, type AdapterManifestV1, type AdapterPackageManifestV1, type AdapterRuntimeV1, type AdapterStateAuthority, type AgentActivity, type AgentProvider, type AgentRecord, type AttachSpawnOptions, type AttentionItem, type AttentionKind, type AttentionState, type AuditActorType, type AuditRecord, type AuditResult, type AuthCheckResult, AuthGate, type AuthGateOptions, type AutomationAction, type AutomationDefinition, type AutomationRun, type AutomationTrigger, BLIND_RELAY_DEFAULT_MAX_BYTES_PER_MINUTE, BLIND_RELAY_DEFAULT_MAX_CONNECTIONS_PER_ROUTE, BLIND_RELAY_DEFAULT_MAX_FRAME_BYTES, BLIND_RELAY_DEFAULT_MAX_MESSAGES_PER_MINUTE, BLIND_RELAY_DEFAULT_MAX_QUEUE_BYTES, BLIND_RELAY_PROTOCOL_VERSION, type Bar, type BlindRelayMetrics, type BlindRelayServer, CHECK_CACHE_MS, CLASSIFIER_TESTED_UP_TO, CLAUDE_LATEST_CACHE_MS, CLAUDE_VERSION_CACHE_MS, CLAUDE_VERSION_TIMEOUT_MS, CODEX_CLASSIFIER_TESTED_UP_TO, CODEX_EXECUTABLE_PROBE_TIMEOUT_MS, CODEX_OSC_MAX_CARRY, CONTROL_IDEMPOTENCY_TTL_MS, type CaptureOptions, type ChangelogEntry, type ClaudeAuthDeps, ClaudeAuthService, type ClaudeAuthStatus, type ClaudeAvailability, type ClaudeLatestDeps, ClaudeLatestService, type ClaudeMetadataRunner, ClaudeMetadataService, type ClaudeModelCatalogItem, type ClaudeSessionOptions, type ClaudeVersionProbe, type CodexAccount, CodexAppServerClient, type CodexAppServerClientOptions, type CodexDeviceLogin, type CodexExecutableDeps, type CodexExecutableProbe, type CodexExecutableResolution, type CodexInstallProvenance, CodexLatestService, type CodexLoginCompletion, type CodexLoginStatus, type CodexMetadataDiagnostics, type CodexMetadataRpc, CodexMetadataService, type CodexMetadataServiceOptions, type CodexModel, type CodexOscParser, type CodexProfileClientLifecycle, type CodexSessionOptions, type CodexSpawnLease, type CodexThreadInventoryEntry, type CodexThreadPersistence, CodexThreadResolver, type CodexThreadResolverOptions, type CodexUsage, type CodexVersionInfo, CommandCenterRevisionConflictError, type CommandCenterStore, type CommandCenterStoreMode, type CommandEvent, type CommandLayoutEnvelope, type ControlStore, type ControlStoreMode, type CreateAutomationInput, type CreateBlindRelayOptions, type CreateClaudeProviderOptions, type CreateCodexProfileClientLifecycleOptions, type CreateCodexProviderOptions, type CreateInstalledAdapterProviderOptions, type CreatePeerInput, type CreatePluginRuntimeOptions, type CreatePushDispatcherDeps, type CreateRelayAccountInput, type CreateServerDeps, type CreateServerResult, type CreateWebPushSendOptions, type CreateWorktreeInput, type CreateWorktreeResult, type CreateWorktreeServiceOptions, type DeviceEnrollment, type DeviceInfo, DevicePairingError, type DeviceRelayIdentity, type DeviceScope, type DeviceStore, type DirEntry, type DirListing, type DirSearchResult, type DurableRelayIdentity, type EnterprisePolicy, type EnterprisePolicyAction, type EnterprisePolicyContext, type EnterprisePolicyDecision, EnterprisePolicyRevisionConflictError, type EnterprisePolicyUpdate, ExtensionError, type ExtensionKind, type ExtensionManager, type ExtensionManifestV1, type ExtensionPolicyMode, type ExtensionTrust, type ExtensionVersionRecord, FETCH_TIMEOUT_MS, type FetchLatest, type FetchManifest, type FetchReleases, FsError, type FsErrorCode, FsService, type FsServiceOptions, type GitHubRelease, type HooksSettingsDocument, type HostRecord, INPUT_LEASE_TTL_MS, type IPty, type IdempotencyRecord, type InputLease, type InputLeaseAcquireResult, type InputLeaseActorType, InputLeaseCoordinator, type InputLeaseCoordinatorOptions, type InputLeaseEvent, type InputLeasePrincipal, type InstallExtensionInput, type InstallServiceContext, type InstallServiceResult, type InstallationKind, type InstalledExtension, type LaunchIntent, type LoopbackRelayHttpOptions, type LoopbackRelayTerminalOptions, type ManagedInstallOptions, type ManagedInstallResult, type ManagedInstallStatus, type ManagedPaths, type MarketplaceEntry, type McpConfigDocument, type ModelWeekBar, OPENAI_CODE_SIGNING_TEAM_ID, type OpenApiBuildOptions, type OpenCommandCenterStoreOptions, type OpenControlStoreOptions, type OpenDeviceStoreOptions, type OpenExtensionManagerOptions, type OpenPeerStoreOptions, type OpenPolicyStoreOptions, type OpenPushStoreOptions, type OpenRelayAccountStoreOptions, type OpenRelayRouteStoreOptions, type OpenSessionStoreOptions, type OpenTeamStoreOptions, type OriginCheckOptions, PAIRING_TTL_MS, PRESENCE_HEARTBEAT_MS, PRESENCE_TTL_MS, type PairingTicket, type PaneStatus, type PeerAction, type PeerConnection, type PeerJsonResponse, type PeerRecord, PeerRequestError, PeerRevisionConflictError, type PeerStatus, type PeerStore, type PeerStoreMode, type PersistedRelayHostConfig, type PluginAuditEvent, type PluginManifestV1, type PluginPermission, type PluginRunInput, type PluginRunResult, type PluginRuntime, PluginRuntimeError, type PolicyStore, type PolicyStoreMode, PresenceCoordinator, type PresenceCoordinatorOptions, type PresenceEvent, type PresenceHeartbeatInput, type PresenceMode, type PresenceRecord, type PresenceTarget, type ProcessLifecycleHandle, type ProcessLifecycleOptions, type ProcessLifecycleTarget, type ProcessSpec, type ProviderAdapterV1, type ProviderAvailability, ProviderError, type ProviderId, ProviderOptionsError, type ProviderProcessContext, ProviderRegistry, type ProviderRuntimeSignal, type ProviderRuntimeSignalParser, type ProviderSessionOptions, type PtySpawn, type PublicRelayRouteRecord, type PushDispatcher, type PushEvent, type PushEventKind, type PushPayload, type PushRecipient, type PushSendFn, type PushStore, type PushSubscriptionRecord, RELAY_CHANNEL_MAX_AGE_MS, RELAY_CHANNEL_MAX_FRAMES, RELAY_HANDSHAKE_MAX_SKEW_MS, RELAY_MAX_PLAINTEXT_BYTES, RELAY_PROTOCOL_VERSION, RELAY_RPC_MAX_BODY_BYTES, RELAY_RPC_MAX_PATH_BYTES, RELAY_WIRE_MAX_ENVELOPE_BYTES, RELAY_WIRE_PROTOCOL_VERSION, RUNNING_BUILD, RUNNING_VERSION, type RateLimitDecision, RateLimiter, type RateLimiterOptions, type RegisterStaticOptions, type RelayAccountPlan, type RelayAccountRecord, RelayAccountRevisionConflictError, type RelayAccountStatus, type RelayAccountStore, type RelayAccountStoreMode, type RelayChannelOptions, RelayCipherState, RelayCryptoError, type RelayCryptoErrorCode, type RelayDeviceProvisioner, type RelayDeviceProvisionerOptions, type RelayDeviceRouteRecord, type RelayDirection, type RelayEncryptedFrame, type RelayEphemeralKeyPair, type RelayFrameKind, type RelayHandshakeHello, type RelayHostConfigInput, type RelayHostConnector, type RelayHostConnectorOptions, type RelayHostMetrics, type RelayHostRuntimeConfig, type RelayHostStatus, type RelayHttpBridge, type RelayHttpHandlers, type RelayHttpOpenRequest, type RelayHttpOpener, type RelayHttpResponseHead, type RelayIdentity, type RelayIdentityStoreOptions, type RelayPairingBootstrap, type RelayPairingPackage, type RelayRole, type RelayRouteRecord, type RelayRouteStore, type RelayRpcMethod, type RelayRpcRequest, type RelayRpcResponse, type RelayStoreMode, type RelayTerminalBridge, type RelayTerminalHandlers, type RelayTerminalOpenRequest, type RelayTerminalOpener, type RelayWireEnvelope, type ReleaseRecord, type RenderLaunchdOptions, type RenderSystemdOptions, type ResolveAccessTokenOptions, type ResolveCodexExecutableOptions, type ResolveCodexThreadOptions, type ResolveVapidKeysOptions, type ReturnTypeOfDescriptors, type RunClaudeVersion, type RunUsage, SEARCH_MAX_DEPTH, SEARCH_MAX_DIRS, SEARCH_MAX_RESULTS, SERVER_PACKAGE, SHELL_PATH_ALLOWLIST, type ServerConfig, type ServerRuntimeConfig, type ServiceRecord, type SessionDefaults, SessionDefaultsConflictError, type SessionFileDirection, type SessionFileKind, type SessionFileStorage, type SessionPlacement, type SessionStore, type StartedBlindRelay, type StoreMode, type StoredExternalSession, type StoredSession, type StoredSessionDefaults, type StoredSessionFile, type StoredStatus, type TeamAuthorizationDecision, type TeamAuthorizationResource, type TeamMember, type TeamMemberKind, type TeamMemberStatus, type TeamPermission, type TeamPrincipalBinding, type TeamPrincipalType, type TeamRecord, TeamRevisionConflictError, type TeamRole, type TeamRoleBinding, type TeamScopeType, type TeamStore, type TeamStoreMode, TerminalManager, type TerminalManagerDeps, type TerminalMeta, TerminalProcess, type TerminalProcessOptions, type TerminalSub, USAGE_CACHE_MS, USAGE_TIMEOUT_MS, type UpdateAction, type UpdateAutomationInput, type UpdatePeerInput, type UpdatePolicyMode, type UpdateRelayAccountInput, type UpdateState, type UpdateStatus, Updater, type UpdaterDeps, type UpdaterFs, type UsageInfo, UsageService, type UsageServiceDeps, type VapidKeys, type VerifiedPeerIdentity, type VersionInfo, WS_TICKET_TTL_MS, type WorkspaceKind, type WorkspaceRecord, WorktreeError, type WorktreeErrorCode, type WorktreeRecord, type WorktreeService, type WsTicketContext, WsTicketStore, type WsTicketStoreOptions, adapterCapabilityNames, assertConfigAllowsStart, buildCodexArgs, buildHooksSettingsDocument, buildMcpConfigDocument, buildOpenApiDocument, buildPushPayload, buildRelayPairingUrl, buildServicePath, capturePane, classifierVersionWarning, classifyCodexPane, classifyPaneStatus, claudePreflightWarning, codexClassifierVersionWarning, compareVersions, computeBuildDrift, computeInstallDrift, createBlindRelayServer, createClaudeAuthService, createClaudeLatestService, createClaudeMetadataRunner, createClaudeProvider, createClaudeVersionProbe, createCodexOscParser, createCodexProfileClientLifecycle, createCodexProvider, createCodexThreadInventory, createCodexThreadPersistence, createInstalledAdapterProvider, createLoopbackRelayHttpOpener, createLoopbackRelayTerminalOpener, createPluginRuntime, createPushDispatcher, createRelayDeviceProvisioner, createRelayHandshakeHello, createRelayHostConnector, createServer, createUpdater, createUsageRunner, createUsageService, createWebPushSend, createWorktreeService, currentAgentIdForSession, decodeRelayWireEnvelope, defaultFetchManifest, defaultFetchReleases, defaultProbeCodexExecutable, defaultRunClaudeVersion, defaultUpdaterFs, defineAdapterManifest, detectTerminalSupport, enableService, encodeRelayWireEnvelope, ensureDataDir, establishRelayChannel, evaluateEnterprisePolicy, extractBearerToken, extractLoginUrl, generateAccessToken, generateRelayAccountCredential, generateRelayCredential, generateRelayEphemeralKeyPair, generateRelayIdentity, hasEncodedSep, hkdfSha256, hookAuthFileContent, hookAuthPathFor, hooksSettingsPathFor, inspectExtensionPackage, installManagedRelease, installProcessLifecycle, installService, isCodexProfileClientLifecycle, isLoopbackAddress, isNewerMajorMinor, isOriginAllowed, isPublicForRequest, isPublicPath, isRelayDirectExecution, isShellPath, isStableVersion, isTeamRole, isTeamScopeType, listTmuxSessions, loadConfig, loadOrCreateRelayIdentity, loadServerConfig, looksLikeAssetRequest, managedPaths, mcpConfigPathFor, migrateServiceToLauncher, normalizeAutomationAction, normalizeAutomationInput, normalizeAutomationTrigger, normalizeCommandCenterLabel, normalizeDeviceName, normalizeDeviceScopes, normalizeOrigin, normalizePeerBaseUrl, normalizeProviderAvailability, normalizeRelayAppUrl, normalizeRelease, normalizeSessionDefaults, openCommandCenterStore, openControlStore, openDeviceStore, openExtensionManager, openPeerStore, openPolicyStore, openPushStore, openRelayAccountStore, openRelayRouteStore, openSessionStore, openTeamStore, parseAllowedOrigins, parseAuthStatus, parseClaudeVersion, parseCodexOscNotifications, parseCodexVersion, parseLegacyClaudeArgs, parseMarketplaceIndex, parseNpmLatest, parseProviderOptions, parseRelayRpcRequest, parseReleaseNotes, parseUsage, pathForGate, persistAccessToken, privacySafeAuditMetadata, providerPreflightWarning, publicAdapterDescriptor, readActiveVersion, readPreviousVersion, readRelayHostConfig, readServiceRecord, registerStatic, relativeWhen, relayAccountCredentialHash, relayAccountCredentialLookup, relayConnectUrl, relayCredentialHash, relayHostConfigPath, relayIdentityFingerprint, relayRpcResponse, removeRelayHostConfig, renderLaunchdPlist, renderManagedLauncher, renderSystemdUnit, requestPeerJson, resetCodexThreadResolutionCoordinatorForTests, resolveAccessToken, resolveCodexExecutable, resolveDataDir, resolveInstallRoot, resolveRelayHostConfig, resolveVapidKeys, restartService, runClaudePreflight, runProviderPreflight, safeProcessErrorSummary, searchMarketplace, stableReleases, startBlindRelay, startServer, teamRolePermissions, tmuxSessionName, validateAdapterManifest, validateAdapterOptionSchema, validateRelayIdentity, verifyPeerConnection, verifyRelayHandshakeHello, writeManagedLauncher, writeRelayHostConfig };
|