@termfleet/core 0.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/agent-launch.d.ts +78 -0
- package/dist/agent-launch.js +247 -0
- package/dist/agent-session-id.d.ts +10 -0
- package/dist/agent-session-id.js +36 -0
- package/dist/agent-session-index-client.d.ts +7 -0
- package/dist/agent-session-index-client.js +86 -0
- package/dist/agent-session-index-worker.d.ts +1 -0
- package/dist/agent-session-index-worker.js +20 -0
- package/dist/agent-session-index.d.ts +34 -0
- package/dist/agent-session-index.js +527 -0
- package/dist/agent-session-tail.d.ts +33 -0
- package/dist/agent-session-tail.js +184 -0
- package/dist/agent-session-watcher.d.ts +36 -0
- package/dist/agent-session-watcher.js +194 -0
- package/dist/agent-session.d.ts +380 -0
- package/dist/agent-session.js +1688 -0
- package/dist/background-runner.d.ts +3 -0
- package/dist/background-runner.js +55 -0
- package/dist/boot-queue.d.ts +35 -0
- package/dist/boot-queue.js +66 -0
- package/dist/build-info.d.ts +5 -0
- package/dist/build-info.js +38 -0
- package/dist/collab/canvas-doc.d.ts +47 -0
- package/dist/collab/canvas-doc.js +83 -0
- package/dist/contracts/auth.d.ts +77 -0
- package/dist/contracts/auth.js +1 -0
- package/dist/contracts/canvas.d.ts +34 -0
- package/dist/contracts/canvas.js +76 -0
- package/dist/contracts/console-layout.d.ts +39 -0
- package/dist/contracts/console-layout.js +135 -0
- package/dist/contracts/files.d.ts +38 -0
- package/dist/contracts/files.js +37 -0
- package/dist/contracts/provider-url.d.ts +3 -0
- package/dist/contracts/provider-url.js +49 -0
- package/dist/contracts/registry.d.ts +58 -0
- package/dist/contracts/registry.js +285 -0
- package/dist/launch-trace.d.ts +6 -0
- package/dist/launch-trace.js +33 -0
- package/dist/lib/errors.d.ts +1 -0
- package/dist/lib/errors.js +5 -0
- package/dist/lib/exec.d.ts +13 -0
- package/dist/lib/exec.js +134 -0
- package/dist/local-providers.d.ts +32 -0
- package/dist/local-providers.js +184 -0
- package/dist/local-tunnel.d.ts +6 -0
- package/dist/local-tunnel.js +258 -0
- package/dist/provider-access-token.d.ts +11 -0
- package/dist/provider-access-token.js +77 -0
- package/dist/provider-client.d.ts +152 -0
- package/dist/provider-client.js +666 -0
- package/dist/provider-url-resolver.d.ts +16 -0
- package/dist/provider-url-resolver.js +37 -0
- package/dist/registry-client.d.ts +93 -0
- package/dist/registry-client.js +170 -0
- package/dist/registry.d.ts +56 -0
- package/dist/registry.js +406 -0
- package/dist/session-attention.d.ts +24 -0
- package/dist/session-attention.js +54 -0
- package/dist/session-lifecycle.d.ts +83 -0
- package/dist/session-lifecycle.js +658 -0
- package/dist/session-window.d.ts +3 -0
- package/dist/session-window.js +20 -0
- package/dist/terminal-client.d.ts +49 -0
- package/dist/terminal-client.js +89 -0
- package/dist/types.d.ts +155 -0
- package/dist/types.js +21 -0
- package/package.json +26 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { normalizeProviderOrigin } from "./contracts/provider-url.js";
|
|
2
|
+
// A provider access token: a short-lived, org-scoped bearer the registry mints (only
|
|
3
|
+
// for a user entitled to the provider's owning org) and a provider trusts in place of
|
|
4
|
+
// a bare session. Shared by the standalone registry and the Cloud Worker so the wire
|
|
5
|
+
// format and verification are identical. HS256 over Web Crypto (available in Node 20+
|
|
6
|
+
// and Workers). The registry holds the signing secret; a provider verifies via the
|
|
7
|
+
// registry's /provider-tokens/verify endpoint (it never holds the secret).
|
|
8
|
+
// Short-lived by design: a leaked token is only useful for minutes, and the browser/
|
|
9
|
+
// CLI re-mints transparently. Shared so the worker and standalone registry agree.
|
|
10
|
+
export const PROVIDER_ACCESS_TOKEN_DURATION_MS = 10 * 60 * 1000;
|
|
11
|
+
export async function signProviderAccessToken(payload, secret) {
|
|
12
|
+
const signingInput = `${base64UrlJson({ alg: "HS256", typ: "TFPT" })}.${base64UrlJson(payload)}`;
|
|
13
|
+
return `${signingInput}.${await hmacSha256(signingInput, secret)}`;
|
|
14
|
+
}
|
|
15
|
+
// Verifies signature, structure, and audience and returns the payload. Throws on any
|
|
16
|
+
// malformation/forgery. Expiry is the caller's to check (it owns the clock + the
|
|
17
|
+
// error shape). Constant-time signature compare.
|
|
18
|
+
export async function verifyProviderAccessTokenPayload(token, secret) {
|
|
19
|
+
if (!token) {
|
|
20
|
+
throw new Error("Provider access token is required.");
|
|
21
|
+
}
|
|
22
|
+
const parts = token.split(".");
|
|
23
|
+
if (parts.length !== 3 || !parts[0] || !parts[1] || !parts[2]) {
|
|
24
|
+
throw new Error("Provider access token is malformed.");
|
|
25
|
+
}
|
|
26
|
+
const signingInput = `${parts[0]}.${parts[1]}`;
|
|
27
|
+
if (!constantTimeEqual(parts[2], await hmacSha256(signingInput, secret))) {
|
|
28
|
+
throw new Error("Provider access token signature is invalid.");
|
|
29
|
+
}
|
|
30
|
+
const payload = JSON.parse(base64UrlDecode(parts[1]));
|
|
31
|
+
if (payload.aud !== "termfleet-provider"
|
|
32
|
+
|| typeof payload.provider !== "string"
|
|
33
|
+
|| typeof payload.sub !== "string"
|
|
34
|
+
|| typeof payload.exp !== "number"
|
|
35
|
+
|| typeof payload.iat !== "number"
|
|
36
|
+
|| (payload.org !== undefined && typeof payload.org !== "string")) {
|
|
37
|
+
throw new Error("Provider access token payload is malformed.");
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
aud: payload.aud,
|
|
41
|
+
exp: payload.exp,
|
|
42
|
+
iat: payload.iat,
|
|
43
|
+
...(payload.org ? { org: payload.org } : {}),
|
|
44
|
+
provider: normalizeProviderOrigin(payload.provider),
|
|
45
|
+
sub: payload.sub
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function base64UrlJson(value) {
|
|
49
|
+
return base64UrlEncodeBytes(new TextEncoder().encode(JSON.stringify(value)));
|
|
50
|
+
}
|
|
51
|
+
function base64UrlEncodeBytes(bytes) {
|
|
52
|
+
let binary = "";
|
|
53
|
+
for (const byte of bytes) {
|
|
54
|
+
binary += String.fromCharCode(byte);
|
|
55
|
+
}
|
|
56
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
|
|
57
|
+
}
|
|
58
|
+
function base64UrlDecode(value) {
|
|
59
|
+
const padded = value.replace(/-/g, "+").replace(/_/g, "/").padEnd(Math.ceil(value.length / 4) * 4, "=");
|
|
60
|
+
const binary = atob(padded);
|
|
61
|
+
return new TextDecoder().decode(new Uint8Array([...binary].map((char) => char.charCodeAt(0))));
|
|
62
|
+
}
|
|
63
|
+
async function hmacSha256(value, secret) {
|
|
64
|
+
const key = await crypto.subtle.importKey("raw", new TextEncoder().encode(secret), { hash: "SHA-256", name: "HMAC" }, false, ["sign"]);
|
|
65
|
+
const signature = await crypto.subtle.sign("HMAC", key, new TextEncoder().encode(value));
|
|
66
|
+
return [...new Uint8Array(signature)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
67
|
+
}
|
|
68
|
+
function constantTimeEqual(left, right) {
|
|
69
|
+
if (left.length !== right.length) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
let mismatch = 0;
|
|
73
|
+
for (let index = 0; index < left.length; index += 1) {
|
|
74
|
+
mismatch |= left.charCodeAt(index) ^ right.charCodeAt(index);
|
|
75
|
+
}
|
|
76
|
+
return mismatch === 0;
|
|
77
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import type { AgentWindowCreateOptions, AgentWindowCreateResult } from "./agent-launch.js";
|
|
2
|
+
import type { AgentProvider, AgentSessionIndexPage } from "./agent-session-index.js";
|
|
3
|
+
import type { AgentSessionDetails } from "./agent-session.js";
|
|
4
|
+
import type { AuthSessionResource, AuthSignInResponse } from "./contracts/auth.js";
|
|
5
|
+
import type { ProviderDirectoryList, ProviderFileStat, ProviderFileWriteResult } from "./contracts/files.js";
|
|
6
|
+
import type { RegistryProviderRecord } from "./contracts/registry.js";
|
|
7
|
+
import type { LifecycleSnapshot } from "./session-lifecycle.js";
|
|
8
|
+
import type { Bounds, OrphanSessionPruneResult, ProviderHealth, ProviderRef, ProviderSnapshot, TerminalEffectKind, TerminalThemeProfile } from "./types.js";
|
|
9
|
+
import { type Socket } from "socket.io-client";
|
|
10
|
+
import { type ProviderUrlResolver } from "./provider-url-resolver.js";
|
|
11
|
+
export type DockerWorkerStartOptions = Partial<RegistryProviderRecord> & {
|
|
12
|
+
terminalThemeProfile?: TerminalThemeProfile;
|
|
13
|
+
};
|
|
14
|
+
export type ProviderSettingsUpdate = {
|
|
15
|
+
terminalThemeProfile?: TerminalThemeProfile;
|
|
16
|
+
};
|
|
17
|
+
type CommandAck<T> = {
|
|
18
|
+
ok?: boolean;
|
|
19
|
+
error?: string;
|
|
20
|
+
result?: T;
|
|
21
|
+
snapshot?: ProviderSnapshot;
|
|
22
|
+
};
|
|
23
|
+
export type ProviderClientOptions = {
|
|
24
|
+
authToken?: () => string | undefined;
|
|
25
|
+
urlResolver?: ProviderUrlResolver;
|
|
26
|
+
};
|
|
27
|
+
export declare class ProviderClient {
|
|
28
|
+
readonly ref: ProviderRef;
|
|
29
|
+
private readonly authToken?;
|
|
30
|
+
private readonly urls;
|
|
31
|
+
private readonly apiBase;
|
|
32
|
+
private socket?;
|
|
33
|
+
private readonly agentSubscriptions;
|
|
34
|
+
private agentListenersSocket?;
|
|
35
|
+
constructor(ref: ProviderRef, options?: ProviderClientOptions);
|
|
36
|
+
health(): Promise<ProviderHealth>;
|
|
37
|
+
snapshot(): Promise<ProviderSnapshot>;
|
|
38
|
+
updateProviderSettings(settings: ProviderSettingsUpdate): Promise<{
|
|
39
|
+
result: unknown;
|
|
40
|
+
snapshot?: ProviderSnapshot;
|
|
41
|
+
}>;
|
|
42
|
+
lifecycle(): Promise<LifecycleSnapshot>;
|
|
43
|
+
pruneOrphanSessions(): Promise<OrphanSessionPruneResult>;
|
|
44
|
+
registryProviders(options?: {
|
|
45
|
+
authToken?: string;
|
|
46
|
+
}): Promise<RegistryProviderRecord[]>;
|
|
47
|
+
registerLocalProvider(provider: RegistryProviderRecord): Promise<RegistryProviderRecord>;
|
|
48
|
+
unregisterLocalProvider(baseUrl: string): Promise<RegistryProviderRecord>;
|
|
49
|
+
registerSharedProvider(provider: RegistryProviderRecord, options: {
|
|
50
|
+
authToken: string;
|
|
51
|
+
}): Promise<RegistryProviderRecord>;
|
|
52
|
+
unregisterSharedProvider(baseUrl: string, options: {
|
|
53
|
+
authToken: string;
|
|
54
|
+
}): Promise<RegistryProviderRecord>;
|
|
55
|
+
startDockerWorker(options?: DockerWorkerStartOptions): Promise<RegistryProviderRecord>;
|
|
56
|
+
startLocalProvider(options: {
|
|
57
|
+
kind: "iterm" | "virtual-tmux" | "wezterm";
|
|
58
|
+
label?: string;
|
|
59
|
+
}): Promise<RegistryProviderRecord>;
|
|
60
|
+
signInToRegistry(identifier: string, password: string): Promise<AuthSignInResponse>;
|
|
61
|
+
registrySession(authToken: string): Promise<AuthSessionResource>;
|
|
62
|
+
signOutOfRegistry(authToken: string): Promise<unknown>;
|
|
63
|
+
switchRegistryOrganization(organizationId: string, options: {
|
|
64
|
+
authToken: string;
|
|
65
|
+
}): Promise<AuthSessionResource>;
|
|
66
|
+
captureTerminal(terminalId: string, lines?: number, options?: {
|
|
67
|
+
preserveEscapes?: boolean;
|
|
68
|
+
}): Promise<{
|
|
69
|
+
content: string;
|
|
70
|
+
}>;
|
|
71
|
+
getAgentSession(agent: AgentProvider, sessionId: string, options?: {
|
|
72
|
+
cwd?: string;
|
|
73
|
+
}): Promise<AgentSessionDetails>;
|
|
74
|
+
getAgentSubagentSession(sessionId: string, agentId: string): Promise<AgentSessionDetails>;
|
|
75
|
+
listAgentSessions(options?: {
|
|
76
|
+
cursor?: string | null;
|
|
77
|
+
limit?: number;
|
|
78
|
+
query?: string;
|
|
79
|
+
}): Promise<AgentSessionIndexPage>;
|
|
80
|
+
connect(): Socket;
|
|
81
|
+
disconnect(): void;
|
|
82
|
+
onSnapshot(handler: (snapshot: ProviderSnapshot) => void): () => void;
|
|
83
|
+
onAgentSession(sessionId: string, handlers: {
|
|
84
|
+
error?: (message: string) => void;
|
|
85
|
+
update: (details: AgentSessionDetails) => void;
|
|
86
|
+
}, options?: {
|
|
87
|
+
cwd?: string;
|
|
88
|
+
}): () => void;
|
|
89
|
+
private wireAgentSessionListeners;
|
|
90
|
+
private subscribeAgentSession;
|
|
91
|
+
createWindow<T = unknown>(options?: {
|
|
92
|
+
cwd?: string;
|
|
93
|
+
filesystemId?: string;
|
|
94
|
+
kind?: "terminal" | "folder" | "file" | "iframe";
|
|
95
|
+
name?: string;
|
|
96
|
+
path?: string;
|
|
97
|
+
terminalId?: string;
|
|
98
|
+
src?: string;
|
|
99
|
+
}): Promise<CommandAck<T>>;
|
|
100
|
+
createAgentWindow(options: AgentWindowCreateOptions, clientOptions?: {
|
|
101
|
+
timeoutMs?: number;
|
|
102
|
+
}): Promise<CommandAck<AgentWindowCreateResult>>;
|
|
103
|
+
moveWindow<T = unknown>(id: number, bounds: Bounds): Promise<CommandAck<T>>;
|
|
104
|
+
closeWindow<T = unknown>(id: number): Promise<CommandAck<T>>;
|
|
105
|
+
sendToSession<T = unknown>(agentSessionId: string, data: string, options?: {
|
|
106
|
+
submitMode?: "retry" | "single";
|
|
107
|
+
}): Promise<CommandAck<T>>;
|
|
108
|
+
closeSession<T = unknown>(agentSessionId: string): Promise<CommandAck<T>>;
|
|
109
|
+
resizeDisplay<T = Bounds>(bounds: Bounds): Promise<CommandAck<T>>;
|
|
110
|
+
sendTerminalInput<T = unknown>(terminalId: string, data: string, options?: {
|
|
111
|
+
breakGlass?: boolean;
|
|
112
|
+
submitMode?: "retry" | "single";
|
|
113
|
+
}): Promise<CommandAck<T>>;
|
|
114
|
+
sendLine<T = unknown>(terminalId: string, line: string, options?: {
|
|
115
|
+
breakGlass?: boolean;
|
|
116
|
+
submitMode?: "retry" | "single";
|
|
117
|
+
}): Promise<CommandAck<T>>;
|
|
118
|
+
setTerminalEffect<T = unknown>(terminalId: string, kind: TerminalEffectKind, options?: {
|
|
119
|
+
durationMs?: number;
|
|
120
|
+
}): Promise<CommandAck<T>>;
|
|
121
|
+
listDirectory(terminalId: string, path: string): Promise<ProviderDirectoryList>;
|
|
122
|
+
listDirectoryByFilesystem(filesystemId: string, path: string): Promise<ProviderDirectoryList>;
|
|
123
|
+
readFile(terminalId: string, path: string): Promise<Buffer>;
|
|
124
|
+
readFileByFilesystem(filesystemId: string, path: string): Promise<Buffer>;
|
|
125
|
+
statFile(terminalId: string, path: string): Promise<ProviderFileStat>;
|
|
126
|
+
statFileByFilesystem(filesystemId: string, path: string): Promise<ProviderFileStat>;
|
|
127
|
+
writeFile(terminalId: string, path: string, data: Buffer, options?: {
|
|
128
|
+
mkdirs?: boolean;
|
|
129
|
+
mode?: string;
|
|
130
|
+
}): Promise<ProviderFileWriteResult>;
|
|
131
|
+
writeFileByFilesystem(filesystemId: string, path: string, data: Buffer, options?: {
|
|
132
|
+
mkdirs?: boolean;
|
|
133
|
+
mode?: string;
|
|
134
|
+
}): Promise<ProviderFileWriteResult>;
|
|
135
|
+
private postJson;
|
|
136
|
+
private patchJson;
|
|
137
|
+
private writeJson;
|
|
138
|
+
private command;
|
|
139
|
+
private fetchProviderUrl;
|
|
140
|
+
private readAuthToken;
|
|
141
|
+
}
|
|
142
|
+
export declare function providerRefFromUrl(value: string, label?: string): ProviderRef;
|
|
143
|
+
export declare function resolveMachineId(record: {
|
|
144
|
+
baseUrl: string;
|
|
145
|
+
instanceId?: string;
|
|
146
|
+
}): string;
|
|
147
|
+
export declare function machineLayoutKeyForId(machineId: string): string;
|
|
148
|
+
export declare function machineLayoutKey(record: {
|
|
149
|
+
baseUrl: string;
|
|
150
|
+
instanceId?: string;
|
|
151
|
+
}): string;
|
|
152
|
+
export {};
|