@aitty/protocol 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/index.d.ts +99 -0
- package/dist/index.js +94 -0
- package/package.json +42 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
//#region packages/protocol/src/index.d.ts
|
|
2
|
+
declare const AITTY_SESSION_PATH_PREFIX = "/s/";
|
|
3
|
+
type AittyTheme = "dark" | "light" | string;
|
|
4
|
+
type AittyThemeSource = {
|
|
5
|
+
getTheme?: () => AittyTheme | undefined | Promise<AittyTheme | undefined>;
|
|
6
|
+
subscribe?: (listener: (theme: AittyTheme | undefined) => void) => AittyThemeSubscription | void;
|
|
7
|
+
};
|
|
8
|
+
type AittyThemeSubscription = (() => void) | {
|
|
9
|
+
dispose(): void;
|
|
10
|
+
};
|
|
11
|
+
type AittyRuntimeKind = "droid" | "pty";
|
|
12
|
+
type AittySessionInfo = {
|
|
13
|
+
runtimeKind: AittyRuntimeKind;
|
|
14
|
+
};
|
|
15
|
+
interface AittyPortlessOptions {
|
|
16
|
+
label?: string;
|
|
17
|
+
project?: string;
|
|
18
|
+
}
|
|
19
|
+
interface AittyPortlessIdentity {
|
|
20
|
+
label: string;
|
|
21
|
+
path: string;
|
|
22
|
+
project: string;
|
|
23
|
+
sessionId: string;
|
|
24
|
+
}
|
|
25
|
+
type AittyTerminalConnectionState = "connecting" | "open" | "reconnecting" | "superseded" | "closed" | "error";
|
|
26
|
+
type AittyTerminalOutputState = "pending" | "ready";
|
|
27
|
+
type AittyTerminalSessionPresentationState = "starting" | "live" | "reconnecting" | "superseded" | "shutdown" | "ended" | "error";
|
|
28
|
+
type AittyTerminalLoadingPresentation = {
|
|
29
|
+
message: string;
|
|
30
|
+
visible: boolean;
|
|
31
|
+
};
|
|
32
|
+
type AittyTerminalStatusSnapshot = {
|
|
33
|
+
connection: AittyTerminalConnectionState;
|
|
34
|
+
loading: AittyTerminalLoadingPresentation;
|
|
35
|
+
message: string;
|
|
36
|
+
output: AittyTerminalOutputState;
|
|
37
|
+
sessionState: AittyTerminalSessionPresentationState;
|
|
38
|
+
};
|
|
39
|
+
type AittyHelloControlFrame = {
|
|
40
|
+
cols: number;
|
|
41
|
+
replay: string;
|
|
42
|
+
rows: number;
|
|
43
|
+
type: "hello";
|
|
44
|
+
};
|
|
45
|
+
type AittyPingControlFrame = {
|
|
46
|
+
type: "ping";
|
|
47
|
+
};
|
|
48
|
+
type AittyPongControlFrame = {
|
|
49
|
+
type: "pong";
|
|
50
|
+
};
|
|
51
|
+
type AittyResizeControlFrame = {
|
|
52
|
+
cols: number;
|
|
53
|
+
rows: number;
|
|
54
|
+
type: "resize";
|
|
55
|
+
};
|
|
56
|
+
type AittyExitControlFrame = {
|
|
57
|
+
code: number | null;
|
|
58
|
+
signal: string | null;
|
|
59
|
+
type: "exit";
|
|
60
|
+
};
|
|
61
|
+
type AittyThemeControlFrame = {
|
|
62
|
+
theme: AittyTheme | null;
|
|
63
|
+
type: "theme";
|
|
64
|
+
};
|
|
65
|
+
type AittyControlFrame = AittyExitControlFrame | AittyHelloControlFrame | AittyPingControlFrame | AittyPongControlFrame | AittyResizeControlFrame | AittyThemeControlFrame;
|
|
66
|
+
declare function createAittyPortlessIdentity(options: {
|
|
67
|
+
label?: string;
|
|
68
|
+
labelFallback?: string;
|
|
69
|
+
project?: string;
|
|
70
|
+
projectFallback?: string;
|
|
71
|
+
sessionIdLength?: number;
|
|
72
|
+
token: string;
|
|
73
|
+
}): AittyPortlessIdentity;
|
|
74
|
+
declare function normalizePortlessSegment(value: string | undefined, fallback: string): string;
|
|
75
|
+
declare function normalizeAittyPortlessPathname(pathname: string): string;
|
|
76
|
+
declare function createSessionInfoBody(runtimeKind: AittyRuntimeKind): string;
|
|
77
|
+
declare function createThemeControlFrame(theme: AittyTheme | undefined): string;
|
|
78
|
+
declare function createHelloControlFrame(options: {
|
|
79
|
+
cols: number;
|
|
80
|
+
replay?: string;
|
|
81
|
+
rows: number;
|
|
82
|
+
}): string;
|
|
83
|
+
declare function createPingControlFrame(): string;
|
|
84
|
+
declare function createPongControlFrame(): string;
|
|
85
|
+
declare function createResizeControlFrame(cols: number, rows: number): string;
|
|
86
|
+
declare function createExitControlFrame(options: {
|
|
87
|
+
code: number | null;
|
|
88
|
+
signal?: string | null;
|
|
89
|
+
}): string;
|
|
90
|
+
declare function parseAittyControlFrame(data: string): AittyControlFrame | null;
|
|
91
|
+
declare function isAittyResizeControlFrame(frame: AittyControlFrame): frame is AittyResizeControlFrame;
|
|
92
|
+
declare function isValidAittyResizeDimension(value: unknown): value is number;
|
|
93
|
+
declare function normalizeTheme(theme: AittyTheme | undefined): AittyTheme | undefined;
|
|
94
|
+
declare function readThemeSource(source: AittyThemeSource | undefined): Promise<AittyTheme | undefined>;
|
|
95
|
+
declare function subscribeThemeSource(source: AittyThemeSource | undefined, listener: (theme: AittyTheme | undefined) => void): {
|
|
96
|
+
dispose(): void;
|
|
97
|
+
};
|
|
98
|
+
//#endregion
|
|
99
|
+
export { AITTY_SESSION_PATH_PREFIX, AittyControlFrame, AittyExitControlFrame, AittyHelloControlFrame, AittyPingControlFrame, AittyPongControlFrame, AittyPortlessIdentity, AittyPortlessOptions, AittyResizeControlFrame, AittyRuntimeKind, AittySessionInfo, AittyTerminalConnectionState, AittyTerminalLoadingPresentation, AittyTerminalOutputState, AittyTerminalSessionPresentationState, AittyTerminalStatusSnapshot, AittyTheme, AittyThemeControlFrame, AittyThemeSource, AittyThemeSubscription, createAittyPortlessIdentity, createExitControlFrame, createHelloControlFrame, createPingControlFrame, createPongControlFrame, createResizeControlFrame, createSessionInfoBody, createThemeControlFrame, isAittyResizeControlFrame, isValidAittyResizeDimension, normalizeAittyPortlessPathname, normalizePortlessSegment, normalizeTheme, parseAittyControlFrame, readThemeSource, subscribeThemeSource };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
//#region packages/protocol/src/index.ts
|
|
2
|
+
const AITTY_SESSION_PATH_PREFIX = "/s/";
|
|
3
|
+
function createAittyPortlessIdentity(options) {
|
|
4
|
+
const project = normalizePortlessSegment(options.project, options.projectFallback ?? "session");
|
|
5
|
+
const label = normalizePortlessSegment(options.label, options.labelFallback ?? "agent");
|
|
6
|
+
const sessionId = options.token.slice(0, Math.max(1, options.sessionIdLength ?? 8));
|
|
7
|
+
return {
|
|
8
|
+
label,
|
|
9
|
+
path: `/s/${project}/${label}-${sessionId}`,
|
|
10
|
+
project,
|
|
11
|
+
sessionId
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
function normalizePortlessSegment(value, fallback) {
|
|
15
|
+
return Array.from((value ?? "").normalize("NFKD")).filter((character) => character.charCodeAt(0) <= 127).join("").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || fallback;
|
|
16
|
+
}
|
|
17
|
+
function normalizeAittyPortlessPathname(pathname) {
|
|
18
|
+
const candidate = pathname.trim();
|
|
19
|
+
if (!candidate) throw new Error("Aitty URL pathname must be a portless session path");
|
|
20
|
+
const normalizedPathname = candidate.startsWith("/") ? candidate : `/${candidate}`;
|
|
21
|
+
if (!normalizedPathname.startsWith("/s/")) throw new Error(`Aitty URL pathname must start with /s/`);
|
|
22
|
+
return normalizedPathname;
|
|
23
|
+
}
|
|
24
|
+
function createSessionInfoBody(runtimeKind) {
|
|
25
|
+
return JSON.stringify({ runtimeKind });
|
|
26
|
+
}
|
|
27
|
+
function createThemeControlFrame(theme) {
|
|
28
|
+
return JSON.stringify({
|
|
29
|
+
theme: normalizeTheme(theme) ?? null,
|
|
30
|
+
type: "theme"
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
function createHelloControlFrame(options) {
|
|
34
|
+
return JSON.stringify({
|
|
35
|
+
cols: options.cols,
|
|
36
|
+
replay: options.replay ?? "",
|
|
37
|
+
rows: options.rows,
|
|
38
|
+
type: "hello"
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
function createPingControlFrame() {
|
|
42
|
+
return JSON.stringify({ type: "ping" });
|
|
43
|
+
}
|
|
44
|
+
function createPongControlFrame() {
|
|
45
|
+
return JSON.stringify({ type: "pong" });
|
|
46
|
+
}
|
|
47
|
+
function createResizeControlFrame(cols, rows) {
|
|
48
|
+
return JSON.stringify({
|
|
49
|
+
cols,
|
|
50
|
+
rows,
|
|
51
|
+
type: "resize"
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
function createExitControlFrame(options) {
|
|
55
|
+
return JSON.stringify({
|
|
56
|
+
code: options.code,
|
|
57
|
+
signal: options.signal ?? null,
|
|
58
|
+
type: "exit"
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
function parseAittyControlFrame(data) {
|
|
62
|
+
try {
|
|
63
|
+
const parsed = JSON.parse(data);
|
|
64
|
+
if (!parsed || typeof parsed !== "object" || !("type" in parsed)) return null;
|
|
65
|
+
if (typeof parsed.type !== "string") return null;
|
|
66
|
+
return parsed;
|
|
67
|
+
} catch {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function isAittyResizeControlFrame(frame) {
|
|
72
|
+
return frame.type === "resize" && isValidAittyResizeDimension(frame.cols) && isValidAittyResizeDimension(frame.rows);
|
|
73
|
+
}
|
|
74
|
+
function isValidAittyResizeDimension(value) {
|
|
75
|
+
return typeof value === "number" && Number.isInteger(value) && value > 0;
|
|
76
|
+
}
|
|
77
|
+
function normalizeTheme(theme) {
|
|
78
|
+
if (typeof theme !== "string") return;
|
|
79
|
+
const normalized = theme.trim();
|
|
80
|
+
return normalized.length > 0 ? normalized : void 0;
|
|
81
|
+
}
|
|
82
|
+
async function readThemeSource(source) {
|
|
83
|
+
return normalizeTheme(await source?.getTheme?.());
|
|
84
|
+
}
|
|
85
|
+
function subscribeThemeSource(source, listener) {
|
|
86
|
+
const subscription = source?.subscribe?.((theme) => {
|
|
87
|
+
listener(normalizeTheme(theme));
|
|
88
|
+
});
|
|
89
|
+
if (typeof subscription === "function") return { dispose: subscription };
|
|
90
|
+
if (subscription && typeof subscription.dispose === "function") return subscription;
|
|
91
|
+
return { dispose() {} };
|
|
92
|
+
}
|
|
93
|
+
//#endregion
|
|
94
|
+
export { AITTY_SESSION_PATH_PREFIX, createAittyPortlessIdentity, createExitControlFrame, createHelloControlFrame, createPingControlFrame, createPongControlFrame, createResizeControlFrame, createSessionInfoBody, createThemeControlFrame, isAittyResizeControlFrame, isValidAittyResizeDimension, normalizeAittyPortlessPathname, normalizePortlessSegment, normalizeTheme, parseAittyControlFrame, readThemeSource, subscribeThemeSource };
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@aitty/protocol",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Shared protocol types and helpers for aitty.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"agent",
|
|
7
|
+
"ai",
|
|
8
|
+
"browser",
|
|
9
|
+
"protocol",
|
|
10
|
+
"terminal"
|
|
11
|
+
],
|
|
12
|
+
"homepage": "https://github.com/kingsword09/aitty#readme",
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/kingsword09/aitty/issues"
|
|
15
|
+
},
|
|
16
|
+
"license": "Apache-2.0",
|
|
17
|
+
"author": "Kingsword kingsword09 <kingsword09@gmail.com>",
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/kingsword09/aitty.git",
|
|
21
|
+
"directory": "packages/protocol"
|
|
22
|
+
},
|
|
23
|
+
"type": "module",
|
|
24
|
+
"sideEffects": false,
|
|
25
|
+
"main": "./dist/index.js",
|
|
26
|
+
"types": "./dist/index.d.ts",
|
|
27
|
+
"exports": {
|
|
28
|
+
".": {
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"default": "./dist/index.js"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"dist"
|
|
35
|
+
],
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"access": "public"
|
|
38
|
+
},
|
|
39
|
+
"engines": {
|
|
40
|
+
"node": ">=20"
|
|
41
|
+
}
|
|
42
|
+
}
|