@abaigram/abai-stub 0.0.0-stage → 0.2.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/LICENSE +21 -0
- package/README.md +22 -2
- package/dist/audit.d.ts +102 -0
- package/dist/audit.d.ts.map +1 -0
- package/dist/audit.js +196 -0
- package/dist/audit.js.map +1 -0
- package/dist/cells/fit.d.ts +6 -0
- package/dist/cells/fit.d.ts.map +1 -0
- package/dist/cells/fit.js +44 -0
- package/dist/cells/fit.js.map +1 -0
- package/dist/content.d.ts +17 -0
- package/dist/content.d.ts.map +1 -0
- package/dist/content.js +71 -0
- package/dist/content.js.map +1 -0
- package/dist/endpoint.d.ts +90 -0
- package/dist/endpoint.d.ts.map +1 -0
- package/dist/endpoint.js +804 -0
- package/dist/endpoint.js.map +1 -0
- package/dist/entry.d.ts +36 -0
- package/dist/entry.d.ts.map +1 -0
- package/dist/entry.js +409 -0
- package/dist/entry.js.map +1 -0
- package/dist/env.d.ts +38 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +69 -0
- package/dist/env.js.map +1 -0
- package/dist/harness-binding.d.ts +235 -0
- package/dist/harness-binding.d.ts.map +1 -0
- package/dist/harness-binding.js +618 -0
- package/dist/harness-binding.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/manifest/index.d.ts +3 -0
- package/dist/manifest/index.d.ts.map +1 -0
- package/dist/manifest/index.js +3 -0
- package/dist/manifest/index.js.map +1 -0
- package/dist/manifest/manifest.d.ts +177 -0
- package/dist/manifest/manifest.d.ts.map +1 -0
- package/dist/manifest/manifest.js +452 -0
- package/dist/manifest/manifest.js.map +1 -0
- package/dist/manifest/render.d.ts +6 -0
- package/dist/manifest/render.d.ts.map +1 -0
- package/dist/manifest/render.js +39 -0
- package/dist/manifest/render.js.map +1 -0
- package/dist/null-harness.d.ts +32 -0
- package/dist/null-harness.d.ts.map +1 -0
- package/dist/null-harness.js +162 -0
- package/dist/null-harness.js.map +1 -0
- package/dist/program.d.ts +255 -0
- package/dist/program.d.ts.map +1 -0
- package/dist/program.js +898 -0
- package/dist/program.js.map +1 -0
- package/dist/region.d.ts +72 -0
- package/dist/region.d.ts.map +1 -0
- package/dist/region.js +93 -0
- package/dist/region.js.map +1 -0
- package/dist/registry.d.ts +60 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +105 -0
- package/dist/registry.js.map +1 -0
- package/dist/wire/descriptor.d.ts +38 -0
- package/dist/wire/descriptor.d.ts.map +1 -0
- package/dist/wire/descriptor.js +144 -0
- package/dist/wire/descriptor.js.map +1 -0
- package/dist/wire/framing.d.ts +11 -0
- package/dist/wire/framing.d.ts.map +1 -0
- package/dist/wire/framing.js +42 -0
- package/dist/wire/framing.js.map +1 -0
- package/dist/wire/index.d.ts +4 -0
- package/dist/wire/index.d.ts.map +1 -0
- package/dist/wire/index.js +4 -0
- package/dist/wire/index.js.map +1 -0
- package/dist/wire/protocol.d.ts +257 -0
- package/dist/wire/protocol.d.ts.map +1 -0
- package/dist/wire/protocol.js +17 -0
- package/dist/wire/protocol.js.map +1 -0
- package/package.json +36 -5
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/** Discovery record a program with a wire endpoint writes next to its socket. */
|
|
2
|
+
export interface WireDescriptor {
|
|
3
|
+
pid: number;
|
|
4
|
+
socket: string;
|
|
5
|
+
cwd: string;
|
|
6
|
+
/** The program's name; "unknown" when a foreign descriptor has none. */
|
|
7
|
+
name: string;
|
|
8
|
+
mode: string;
|
|
9
|
+
/** ISO timestamp. */
|
|
10
|
+
startedAt: string;
|
|
11
|
+
}
|
|
12
|
+
/** Longest socket path accepted (macOS sun_path is 104 bytes including the NUL). */
|
|
13
|
+
export declare const MAX_SOCKET_PATH_BYTES = 103;
|
|
14
|
+
/** Path of the descriptor file for a pid. */
|
|
15
|
+
export declare function descriptorPath(runDir: string, pid: number): string;
|
|
16
|
+
/** Default Unix socket path for a pid. */
|
|
17
|
+
export declare function defaultSocketPath(runDir: string, pid: number): string;
|
|
18
|
+
/** Throw when a socket path exceeds MAX_SOCKET_PATH_BYTES. */
|
|
19
|
+
export declare function assertSocketPathLength(socketPath: string): void;
|
|
20
|
+
/** Create the run dir with mode 0o700 (tightening an existing one) and return it. */
|
|
21
|
+
export declare function ensureRunDir(runDir: string): string;
|
|
22
|
+
/** True when the path exists and is a Unix socket. */
|
|
23
|
+
export declare function isSocketFile(path: string): boolean;
|
|
24
|
+
/** True when a process with this pid exists (including ones we may not signal). */
|
|
25
|
+
export declare function isPidAlive(pid: number): boolean;
|
|
26
|
+
/** Atomically write a descriptor file (mode 0o600) via a temp file and rename. */
|
|
27
|
+
export declare function writeDescriptor(runDir: string, descriptor: WireDescriptor): void;
|
|
28
|
+
/**
|
|
29
|
+
* Read all valid descriptors in filename order; a missing dir yields []. A
|
|
30
|
+
* descriptor needs a numeric `pid` and a string `socket`; extra fields (a
|
|
31
|
+
* foreign program's) are kept, and a missing `name` reads as "unknown".
|
|
32
|
+
*/
|
|
33
|
+
export declare function readDescriptors(runDir: string): WireDescriptor[];
|
|
34
|
+
/** Remove a descriptor file; a missing file is not an error. */
|
|
35
|
+
export declare function removeDescriptor(runDir: string, pid: number): void;
|
|
36
|
+
/** Delete descriptors (and their sockets) of dead processes; return the live descriptors. */
|
|
37
|
+
export declare function pruneDescriptors(runDir: string): WireDescriptor[];
|
|
38
|
+
//# sourceMappingURL=descriptor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"descriptor.d.ts","sourceRoot":"","sources":["../../src/wire/descriptor.ts"],"names":[],"mappings":"AAeA,iFAAiF;AACjF,MAAM,WAAW,cAAc;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,qBAAqB;IACrB,SAAS,EAAE,MAAM,CAAC;CAClB;AAED,oFAAoF;AACpF,eAAO,MAAM,qBAAqB,MAAM,CAAC;AAEzC,6CAA6C;AAC7C,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAElE;AAED,0CAA0C;AAC1C,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAErE;AAED,8DAA8D;AAC9D,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAK/D;AAED,qFAAqF;AACrF,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAInD;AAED,sDAAsD;AACtD,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAMlD;AAED,mFAAmF;AACnF,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAS/C;AAED,kFAAkF;AAClF,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,cAAc,GAAG,IAAI,CAchF;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,EAAE,CA6BhE;AAED,gEAAgE;AAChE,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAOlE;AAED,6FAA6F;AAC7F,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,EAAE,CAuBjE","sourcesContent":["// Discovery records for the wire endpoint: a program writes one next to its\n// socket in a run directory, and a client finds the program through it.\nimport { Buffer } from \"node:buffer\";\nimport {\n\tchmodSync,\n\tlstatSync,\n\tmkdirSync,\n\treaddirSync,\n\treadFileSync,\n\trenameSync,\n\tunlinkSync,\n\twriteFileSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\n\n/** Discovery record a program with a wire endpoint writes next to its socket. */\nexport interface WireDescriptor {\n\tpid: number;\n\tsocket: string;\n\tcwd: string;\n\t/** The program's name; \"unknown\" when a foreign descriptor has none. */\n\tname: string;\n\tmode: string;\n\t/** ISO timestamp. */\n\tstartedAt: string;\n}\n\n/** Longest socket path accepted (macOS sun_path is 104 bytes including the NUL). */\nexport const MAX_SOCKET_PATH_BYTES = 103;\n\n/** Path of the descriptor file for a pid. */\nexport function descriptorPath(runDir: string, pid: number): string {\n\treturn join(runDir, `${pid}.json`);\n}\n\n/** Default Unix socket path for a pid. */\nexport function defaultSocketPath(runDir: string, pid: number): string {\n\treturn join(runDir, `${pid}.sock`);\n}\n\n/** Throw when a socket path exceeds MAX_SOCKET_PATH_BYTES. */\nexport function assertSocketPathLength(socketPath: string): void {\n\tconst bytes = Buffer.byteLength(socketPath);\n\tif (bytes > MAX_SOCKET_PATH_BYTES) {\n\t\tthrow new Error(`socket path is too long (${bytes} bytes, max ${MAX_SOCKET_PATH_BYTES}): ${socketPath}`);\n\t}\n}\n\n/** Create the run dir with mode 0o700 (tightening an existing one) and return it. */\nexport function ensureRunDir(runDir: string): string {\n\tmkdirSync(runDir, { recursive: true, mode: 0o700 });\n\tchmodSync(runDir, 0o700);\n\treturn runDir;\n}\n\n/** True when the path exists and is a Unix socket. */\nexport function isSocketFile(path: string): boolean {\n\ttry {\n\t\treturn lstatSync(path).isSocket();\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/** True when a process with this pid exists (including ones we may not signal). */\nexport function isPidAlive(pid: number): boolean {\n\ttry {\n\t\tprocess.kill(pid, 0);\n\t\treturn true;\n\t} catch (error) {\n\t\tconst code = (error as NodeJS.ErrnoException).code;\n\t\tif (code === \"EPERM\") return true;\n\t\treturn false;\n\t}\n}\n\n/** Atomically write a descriptor file (mode 0o600) via a temp file and rename. */\nexport function writeDescriptor(runDir: string, descriptor: WireDescriptor): void {\n\tconst target = descriptorPath(runDir, descriptor.pid);\n\tconst tmp = `${target}.${process.pid}.tmp`;\n\ttry {\n\t\twriteFileSync(tmp, `${JSON.stringify(descriptor)}\\n`, { mode: 0o600 });\n\t\trenameSync(tmp, target);\n\t} catch (error) {\n\t\ttry {\n\t\t\tunlinkSync(tmp);\n\t\t} catch {\n\t\t\t// ignore\n\t\t}\n\t\tthrow error;\n\t}\n}\n\n/**\n * Read all valid descriptors in filename order; a missing dir yields []. A\n * descriptor needs a numeric `pid` and a string `socket`; extra fields (a\n * foreign program's) are kept, and a missing `name` reads as \"unknown\".\n */\nexport function readDescriptors(runDir: string): WireDescriptor[] {\n\tlet names: string[];\n\ttry {\n\t\tnames = readdirSync(runDir);\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") return [];\n\t\tthrow error;\n\t}\n\tconst result: WireDescriptor[] = [];\n\tfor (const name of names.filter((n) => n.endsWith(\".json\")).sort()) {\n\t\tlet parsed: unknown;\n\t\ttry {\n\t\t\tparsed = JSON.parse(readFileSync(join(runDir, name), \"utf8\"));\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t\tif (\n\t\t\ttypeof parsed !== \"object\" ||\n\t\t\tparsed === null ||\n\t\t\ttypeof (parsed as { pid?: unknown }).pid !== \"number\" ||\n\t\t\ttypeof (parsed as { socket?: unknown }).socket !== \"string\"\n\t\t) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst record = parsed as WireDescriptor;\n\t\tif (typeof record.name !== \"string\") record.name = \"unknown\";\n\t\tresult.push(record);\n\t}\n\treturn result;\n}\n\n/** Remove a descriptor file; a missing file is not an error. */\nexport function removeDescriptor(runDir: string, pid: number): void {\n\ttry {\n\t\tunlinkSync(descriptorPath(runDir, pid));\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") return;\n\t\tthrow error;\n\t}\n}\n\n/** Delete descriptors (and their sockets) of dead processes; return the live descriptors. */\nexport function pruneDescriptors(runDir: string): WireDescriptor[] {\n\tconst live: WireDescriptor[] = [];\n\tfor (const descriptor of readDescriptors(runDir)) {\n\t\tif (isPidAlive(descriptor.pid)) {\n\t\t\tlive.push(descriptor);\n\t\t\tcontinue;\n\t\t}\n\t\ttry {\n\t\t\tunlinkSync(descriptorPath(runDir, descriptor.pid));\n\t\t} catch {\n\t\t\t// ignore\n\t\t}\n\t\t// Only a default-path socket is known to belong to the dead pid. An explicit\n\t\t// path may have been reclaimed by a live process since, so prune never touches it.\n\t\tif (descriptor.socket === defaultSocketPath(runDir, descriptor.pid) && isSocketFile(descriptor.socket)) {\n\t\t\ttry {\n\t\t\t\tunlinkSync(descriptor.socket);\n\t\t\t} catch {\n\t\t\t\t// ignore\n\t\t\t}\n\t\t}\n\t}\n\treturn live;\n}\n"]}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
// Discovery records for the wire endpoint: a program writes one next to its
|
|
2
|
+
// socket in a run directory, and a client finds the program through it.
|
|
3
|
+
import { Buffer } from "node:buffer";
|
|
4
|
+
import { chmodSync, lstatSync, mkdirSync, readdirSync, readFileSync, renameSync, unlinkSync, writeFileSync, } from "node:fs";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
/** Longest socket path accepted (macOS sun_path is 104 bytes including the NUL). */
|
|
7
|
+
export const MAX_SOCKET_PATH_BYTES = 103;
|
|
8
|
+
/** Path of the descriptor file for a pid. */
|
|
9
|
+
export function descriptorPath(runDir, pid) {
|
|
10
|
+
return join(runDir, `${pid}.json`);
|
|
11
|
+
}
|
|
12
|
+
/** Default Unix socket path for a pid. */
|
|
13
|
+
export function defaultSocketPath(runDir, pid) {
|
|
14
|
+
return join(runDir, `${pid}.sock`);
|
|
15
|
+
}
|
|
16
|
+
/** Throw when a socket path exceeds MAX_SOCKET_PATH_BYTES. */
|
|
17
|
+
export function assertSocketPathLength(socketPath) {
|
|
18
|
+
const bytes = Buffer.byteLength(socketPath);
|
|
19
|
+
if (bytes > MAX_SOCKET_PATH_BYTES) {
|
|
20
|
+
throw new Error(`socket path is too long (${bytes} bytes, max ${MAX_SOCKET_PATH_BYTES}): ${socketPath}`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/** Create the run dir with mode 0o700 (tightening an existing one) and return it. */
|
|
24
|
+
export function ensureRunDir(runDir) {
|
|
25
|
+
mkdirSync(runDir, { recursive: true, mode: 0o700 });
|
|
26
|
+
chmodSync(runDir, 0o700);
|
|
27
|
+
return runDir;
|
|
28
|
+
}
|
|
29
|
+
/** True when the path exists and is a Unix socket. */
|
|
30
|
+
export function isSocketFile(path) {
|
|
31
|
+
try {
|
|
32
|
+
return lstatSync(path).isSocket();
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/** True when a process with this pid exists (including ones we may not signal). */
|
|
39
|
+
export function isPidAlive(pid) {
|
|
40
|
+
try {
|
|
41
|
+
process.kill(pid, 0);
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
const code = error.code;
|
|
46
|
+
if (code === "EPERM")
|
|
47
|
+
return true;
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/** Atomically write a descriptor file (mode 0o600) via a temp file and rename. */
|
|
52
|
+
export function writeDescriptor(runDir, descriptor) {
|
|
53
|
+
const target = descriptorPath(runDir, descriptor.pid);
|
|
54
|
+
const tmp = `${target}.${process.pid}.tmp`;
|
|
55
|
+
try {
|
|
56
|
+
writeFileSync(tmp, `${JSON.stringify(descriptor)}\n`, { mode: 0o600 });
|
|
57
|
+
renameSync(tmp, target);
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
try {
|
|
61
|
+
unlinkSync(tmp);
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
// ignore
|
|
65
|
+
}
|
|
66
|
+
throw error;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Read all valid descriptors in filename order; a missing dir yields []. A
|
|
71
|
+
* descriptor needs a numeric `pid` and a string `socket`; extra fields (a
|
|
72
|
+
* foreign program's) are kept, and a missing `name` reads as "unknown".
|
|
73
|
+
*/
|
|
74
|
+
export function readDescriptors(runDir) {
|
|
75
|
+
let names;
|
|
76
|
+
try {
|
|
77
|
+
names = readdirSync(runDir);
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
if (error.code === "ENOENT")
|
|
81
|
+
return [];
|
|
82
|
+
throw error;
|
|
83
|
+
}
|
|
84
|
+
const result = [];
|
|
85
|
+
for (const name of names.filter((n) => n.endsWith(".json")).sort()) {
|
|
86
|
+
let parsed;
|
|
87
|
+
try {
|
|
88
|
+
parsed = JSON.parse(readFileSync(join(runDir, name), "utf8"));
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
if (typeof parsed !== "object" ||
|
|
94
|
+
parsed === null ||
|
|
95
|
+
typeof parsed.pid !== "number" ||
|
|
96
|
+
typeof parsed.socket !== "string") {
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
const record = parsed;
|
|
100
|
+
if (typeof record.name !== "string")
|
|
101
|
+
record.name = "unknown";
|
|
102
|
+
result.push(record);
|
|
103
|
+
}
|
|
104
|
+
return result;
|
|
105
|
+
}
|
|
106
|
+
/** Remove a descriptor file; a missing file is not an error. */
|
|
107
|
+
export function removeDescriptor(runDir, pid) {
|
|
108
|
+
try {
|
|
109
|
+
unlinkSync(descriptorPath(runDir, pid));
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
if (error.code === "ENOENT")
|
|
113
|
+
return;
|
|
114
|
+
throw error;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/** Delete descriptors (and their sockets) of dead processes; return the live descriptors. */
|
|
118
|
+
export function pruneDescriptors(runDir) {
|
|
119
|
+
const live = [];
|
|
120
|
+
for (const descriptor of readDescriptors(runDir)) {
|
|
121
|
+
if (isPidAlive(descriptor.pid)) {
|
|
122
|
+
live.push(descriptor);
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
try {
|
|
126
|
+
unlinkSync(descriptorPath(runDir, descriptor.pid));
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
// ignore
|
|
130
|
+
}
|
|
131
|
+
// Only a default-path socket is known to belong to the dead pid. An explicit
|
|
132
|
+
// path may have been reclaimed by a live process since, so prune never touches it.
|
|
133
|
+
if (descriptor.socket === defaultSocketPath(runDir, descriptor.pid) && isSocketFile(descriptor.socket)) {
|
|
134
|
+
try {
|
|
135
|
+
unlinkSync(descriptor.socket);
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
// ignore
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return live;
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=descriptor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"descriptor.js","sourceRoot":"","sources":["../../src/wire/descriptor.ts"],"names":[],"mappings":"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","sourcesContent":["// Discovery records for the wire endpoint: a program writes one next to its\n// socket in a run directory, and a client finds the program through it.\nimport { Buffer } from \"node:buffer\";\nimport {\n\tchmodSync,\n\tlstatSync,\n\tmkdirSync,\n\treaddirSync,\n\treadFileSync,\n\trenameSync,\n\tunlinkSync,\n\twriteFileSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\n\n/** Discovery record a program with a wire endpoint writes next to its socket. */\nexport interface WireDescriptor {\n\tpid: number;\n\tsocket: string;\n\tcwd: string;\n\t/** The program's name; \"unknown\" when a foreign descriptor has none. */\n\tname: string;\n\tmode: string;\n\t/** ISO timestamp. */\n\tstartedAt: string;\n}\n\n/** Longest socket path accepted (macOS sun_path is 104 bytes including the NUL). */\nexport const MAX_SOCKET_PATH_BYTES = 103;\n\n/** Path of the descriptor file for a pid. */\nexport function descriptorPath(runDir: string, pid: number): string {\n\treturn join(runDir, `${pid}.json`);\n}\n\n/** Default Unix socket path for a pid. */\nexport function defaultSocketPath(runDir: string, pid: number): string {\n\treturn join(runDir, `${pid}.sock`);\n}\n\n/** Throw when a socket path exceeds MAX_SOCKET_PATH_BYTES. */\nexport function assertSocketPathLength(socketPath: string): void {\n\tconst bytes = Buffer.byteLength(socketPath);\n\tif (bytes > MAX_SOCKET_PATH_BYTES) {\n\t\tthrow new Error(`socket path is too long (${bytes} bytes, max ${MAX_SOCKET_PATH_BYTES}): ${socketPath}`);\n\t}\n}\n\n/** Create the run dir with mode 0o700 (tightening an existing one) and return it. */\nexport function ensureRunDir(runDir: string): string {\n\tmkdirSync(runDir, { recursive: true, mode: 0o700 });\n\tchmodSync(runDir, 0o700);\n\treturn runDir;\n}\n\n/** True when the path exists and is a Unix socket. */\nexport function isSocketFile(path: string): boolean {\n\ttry {\n\t\treturn lstatSync(path).isSocket();\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/** True when a process with this pid exists (including ones we may not signal). */\nexport function isPidAlive(pid: number): boolean {\n\ttry {\n\t\tprocess.kill(pid, 0);\n\t\treturn true;\n\t} catch (error) {\n\t\tconst code = (error as NodeJS.ErrnoException).code;\n\t\tif (code === \"EPERM\") return true;\n\t\treturn false;\n\t}\n}\n\n/** Atomically write a descriptor file (mode 0o600) via a temp file and rename. */\nexport function writeDescriptor(runDir: string, descriptor: WireDescriptor): void {\n\tconst target = descriptorPath(runDir, descriptor.pid);\n\tconst tmp = `${target}.${process.pid}.tmp`;\n\ttry {\n\t\twriteFileSync(tmp, `${JSON.stringify(descriptor)}\\n`, { mode: 0o600 });\n\t\trenameSync(tmp, target);\n\t} catch (error) {\n\t\ttry {\n\t\t\tunlinkSync(tmp);\n\t\t} catch {\n\t\t\t// ignore\n\t\t}\n\t\tthrow error;\n\t}\n}\n\n/**\n * Read all valid descriptors in filename order; a missing dir yields []. A\n * descriptor needs a numeric `pid` and a string `socket`; extra fields (a\n * foreign program's) are kept, and a missing `name` reads as \"unknown\".\n */\nexport function readDescriptors(runDir: string): WireDescriptor[] {\n\tlet names: string[];\n\ttry {\n\t\tnames = readdirSync(runDir);\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") return [];\n\t\tthrow error;\n\t}\n\tconst result: WireDescriptor[] = [];\n\tfor (const name of names.filter((n) => n.endsWith(\".json\")).sort()) {\n\t\tlet parsed: unknown;\n\t\ttry {\n\t\t\tparsed = JSON.parse(readFileSync(join(runDir, name), \"utf8\"));\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t\tif (\n\t\t\ttypeof parsed !== \"object\" ||\n\t\t\tparsed === null ||\n\t\t\ttypeof (parsed as { pid?: unknown }).pid !== \"number\" ||\n\t\t\ttypeof (parsed as { socket?: unknown }).socket !== \"string\"\n\t\t) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst record = parsed as WireDescriptor;\n\t\tif (typeof record.name !== \"string\") record.name = \"unknown\";\n\t\tresult.push(record);\n\t}\n\treturn result;\n}\n\n/** Remove a descriptor file; a missing file is not an error. */\nexport function removeDescriptor(runDir: string, pid: number): void {\n\ttry {\n\t\tunlinkSync(descriptorPath(runDir, pid));\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") return;\n\t\tthrow error;\n\t}\n}\n\n/** Delete descriptors (and their sockets) of dead processes; return the live descriptors. */\nexport function pruneDescriptors(runDir: string): WireDescriptor[] {\n\tconst live: WireDescriptor[] = [];\n\tfor (const descriptor of readDescriptors(runDir)) {\n\t\tif (isPidAlive(descriptor.pid)) {\n\t\t\tlive.push(descriptor);\n\t\t\tcontinue;\n\t\t}\n\t\ttry {\n\t\t\tunlinkSync(descriptorPath(runDir, descriptor.pid));\n\t\t} catch {\n\t\t\t// ignore\n\t\t}\n\t\t// Only a default-path socket is known to belong to the dead pid. An explicit\n\t\t// path may have been reclaimed by a live process since, so prune never touches it.\n\t\tif (descriptor.socket === defaultSocketPath(runDir, descriptor.pid) && isSocketFile(descriptor.socket)) {\n\t\t\ttry {\n\t\t\t\tunlinkSync(descriptor.socket);\n\t\t\t} catch {\n\t\t\t\t// ignore\n\t\t\t}\n\t\t}\n\t}\n\treturn live;\n}\n"]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Readable } from "node:stream";
|
|
2
|
+
/** The default line cap on both ends: a large payload fits. */
|
|
3
|
+
export declare const DEFAULT_MAX_LINE_BYTES: number;
|
|
4
|
+
/**
|
|
5
|
+
* LF-only line reader with a byte cap. Modeled on `attachJsonlLineReader`
|
|
6
|
+
* Chunks stay
|
|
7
|
+
* buffers and only the newest one is scanned for the newline, so a large
|
|
8
|
+
* line costs one concatenation instead of a rescan per chunk.
|
|
9
|
+
*/
|
|
10
|
+
export declare function attachCappedLineReader(socket: Readable, maxLineBytes: number, onLine: (line: string) => void, onOverflow: () => void): () => void;
|
|
11
|
+
//# sourceMappingURL=framing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"framing.d.ts","sourceRoot":"","sources":["../../src/wire/framing.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,+DAA+D;AAC/D,eAAO,MAAM,sBAAsB,QAAmB,CAAC;AAEvD;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACrC,MAAM,EAAE,QAAQ,EAChB,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,EAC9B,UAAU,EAAE,MAAM,IAAI,GACpB,MAAM,IAAI,CA8BZ","sourcesContent":["// Line framing for the wire protocol.\nimport type { Readable } from \"node:stream\";\n\n/** The default line cap on both ends: a large payload fits. */\nexport const DEFAULT_MAX_LINE_BYTES = 64 * 1024 * 1024;\n\n/**\n * LF-only line reader with a byte cap. Modeled on `attachJsonlLineReader`\n * Chunks stay\n * buffers and only the newest one is scanned for the newline, so a large\n * line costs one concatenation instead of a rescan per chunk.\n */\nexport function attachCappedLineReader(\n\tsocket: Readable,\n\tmaxLineBytes: number,\n\tonLine: (line: string) => void,\n\tonOverflow: () => void,\n): () => void {\n\tlet chunks: Buffer[] = [];\n\tlet pendingBytes = 0;\n\tconst onData = (data: string | Buffer) => {\n\t\tlet chunk = typeof data === \"string\" ? Buffer.from(data, \"utf8\") : data;\n\t\twhile (true) {\n\t\t\tconst newlineIndex = chunk.indexOf(10);\n\t\t\tif (newlineIndex === -1) break;\n\t\t\tconst head = chunk.subarray(0, newlineIndex);\n\t\t\tconst line = (chunks.length === 0 ? head : Buffer.concat([...chunks, head])).toString(\"utf8\");\n\t\t\tchunks = [];\n\t\t\tpendingBytes = 0;\n\t\t\tchunk = chunk.subarray(newlineIndex + 1);\n\t\t\tonLine(line.endsWith(\"\\r\") ? line.slice(0, -1) : line);\n\t\t\tif (socket.destroyed) return;\n\t\t}\n\t\tif (chunk.length > 0) {\n\t\t\tchunks.push(chunk);\n\t\t\tpendingBytes += chunk.length;\n\t\t\tif (pendingBytes > maxLineBytes) {\n\t\t\t\tchunks = [];\n\t\t\t\tpendingBytes = 0;\n\t\t\t\tonOverflow();\n\t\t\t}\n\t\t}\n\t};\n\tsocket.on(\"data\", onData);\n\treturn () => {\n\t\tsocket.off(\"data\", onData);\n\t};\n}\n"]}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/** The default line cap on both ends: a large payload fits. */
|
|
2
|
+
export const DEFAULT_MAX_LINE_BYTES = 64 * 1024 * 1024;
|
|
3
|
+
/**
|
|
4
|
+
* LF-only line reader with a byte cap. Modeled on `attachJsonlLineReader`
|
|
5
|
+
* Chunks stay
|
|
6
|
+
* buffers and only the newest one is scanned for the newline, so a large
|
|
7
|
+
* line costs one concatenation instead of a rescan per chunk.
|
|
8
|
+
*/
|
|
9
|
+
export function attachCappedLineReader(socket, maxLineBytes, onLine, onOverflow) {
|
|
10
|
+
let chunks = [];
|
|
11
|
+
let pendingBytes = 0;
|
|
12
|
+
const onData = (data) => {
|
|
13
|
+
let chunk = typeof data === "string" ? Buffer.from(data, "utf8") : data;
|
|
14
|
+
while (true) {
|
|
15
|
+
const newlineIndex = chunk.indexOf(10);
|
|
16
|
+
if (newlineIndex === -1)
|
|
17
|
+
break;
|
|
18
|
+
const head = chunk.subarray(0, newlineIndex);
|
|
19
|
+
const line = (chunks.length === 0 ? head : Buffer.concat([...chunks, head])).toString("utf8");
|
|
20
|
+
chunks = [];
|
|
21
|
+
pendingBytes = 0;
|
|
22
|
+
chunk = chunk.subarray(newlineIndex + 1);
|
|
23
|
+
onLine(line.endsWith("\r") ? line.slice(0, -1) : line);
|
|
24
|
+
if (socket.destroyed)
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (chunk.length > 0) {
|
|
28
|
+
chunks.push(chunk);
|
|
29
|
+
pendingBytes += chunk.length;
|
|
30
|
+
if (pendingBytes > maxLineBytes) {
|
|
31
|
+
chunks = [];
|
|
32
|
+
pendingBytes = 0;
|
|
33
|
+
onOverflow();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
socket.on("data", onData);
|
|
38
|
+
return () => {
|
|
39
|
+
socket.off("data", onData);
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=framing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"framing.js","sourceRoot":"","sources":["../../src/wire/framing.ts"],"names":[],"mappings":"AAGA,+DAA+D;AAC/D,MAAM,CAAC,MAAM,sBAAsB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AAEvD;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CACrC,MAAgB,EAChB,YAAoB,EACpB,MAA8B,EAC9B,UAAsB,EACT;IACb,IAAI,MAAM,GAAa,EAAE,CAAC;IAC1B,IAAI,YAAY,GAAG,CAAC,CAAC;IACrB,MAAM,MAAM,GAAG,CAAC,IAAqB,EAAE,EAAE,CAAC;QACzC,IAAI,KAAK,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACxE,OAAO,IAAI,EAAE,CAAC;YACb,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YACvC,IAAI,YAAY,KAAK,CAAC,CAAC;gBAAE,MAAM;YAC/B,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC;YAC7C,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YAC9F,MAAM,GAAG,EAAE,CAAC;YACZ,YAAY,GAAG,CAAC,CAAC;YACjB,KAAK,GAAG,KAAK,CAAC,QAAQ,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC;YACzC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YACvD,IAAI,MAAM,CAAC,SAAS;gBAAE,OAAO;QAC9B,CAAC;QACD,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACnB,YAAY,IAAI,KAAK,CAAC,MAAM,CAAC;YAC7B,IAAI,YAAY,GAAG,YAAY,EAAE,CAAC;gBACjC,MAAM,GAAG,EAAE,CAAC;gBACZ,YAAY,GAAG,CAAC,CAAC;gBACjB,UAAU,EAAE,CAAC;YACd,CAAC;QACF,CAAC;IAAA,CACD,CAAC;IACF,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1B,OAAO,GAAG,EAAE,CAAC;QACZ,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAA,CAC3B,CAAC;AAAA,CACF","sourcesContent":["// Line framing for the wire protocol.\nimport type { Readable } from \"node:stream\";\n\n/** The default line cap on both ends: a large payload fits. */\nexport const DEFAULT_MAX_LINE_BYTES = 64 * 1024 * 1024;\n\n/**\n * LF-only line reader with a byte cap. Modeled on `attachJsonlLineReader`\n * Chunks stay\n * buffers and only the newest one is scanned for the newline, so a large\n * line costs one concatenation instead of a rescan per chunk.\n */\nexport function attachCappedLineReader(\n\tsocket: Readable,\n\tmaxLineBytes: number,\n\tonLine: (line: string) => void,\n\tonOverflow: () => void,\n): () => void {\n\tlet chunks: Buffer[] = [];\n\tlet pendingBytes = 0;\n\tconst onData = (data: string | Buffer) => {\n\t\tlet chunk = typeof data === \"string\" ? Buffer.from(data, \"utf8\") : data;\n\t\twhile (true) {\n\t\t\tconst newlineIndex = chunk.indexOf(10);\n\t\t\tif (newlineIndex === -1) break;\n\t\t\tconst head = chunk.subarray(0, newlineIndex);\n\t\t\tconst line = (chunks.length === 0 ? head : Buffer.concat([...chunks, head])).toString(\"utf8\");\n\t\t\tchunks = [];\n\t\t\tpendingBytes = 0;\n\t\t\tchunk = chunk.subarray(newlineIndex + 1);\n\t\t\tonLine(line.endsWith(\"\\r\") ? line.slice(0, -1) : line);\n\t\t\tif (socket.destroyed) return;\n\t\t}\n\t\tif (chunk.length > 0) {\n\t\t\tchunks.push(chunk);\n\t\t\tpendingBytes += chunk.length;\n\t\t\tif (pendingBytes > maxLineBytes) {\n\t\t\t\tchunks = [];\n\t\t\t\tpendingBytes = 0;\n\t\t\t\tonOverflow();\n\t\t\t}\n\t\t}\n\t};\n\tsocket.on(\"data\", onData);\n\treturn () => {\n\t\tsocket.off(\"data\", onData);\n\t};\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/wire/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC","sourcesContent":["export * from \"./descriptor.ts\";\nexport * from \"./framing.ts\";\nexport * from \"./protocol.ts\";\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/wire/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC","sourcesContent":["export * from \"./descriptor.ts\";\nexport * from \"./framing.ts\";\nexport * from \"./protocol.ts\";\n"]}
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import type { Manifest } from "../manifest/manifest.ts";
|
|
2
|
+
export declare const PROTOCOL_VERSION = 1;
|
|
3
|
+
/**
|
|
4
|
+
* The extensions a TypeScript stub speaks beyond the v1 core, named in
|
|
5
|
+
* `hello.abai.extensions` so a client speaks each only when it is offered:
|
|
6
|
+
* `consent` (consent stated on a request or hook answer), `content` (the
|
|
7
|
+
* install, use and turn slots on `get_content`), `turns` (turns and
|
|
8
|
+
* touchpoints as messages), `call_codes` (a code beside every error),
|
|
9
|
+
* `defaults` (a `hook_response` whose `result` is null asks the program to
|
|
10
|
+
* apply the decision's default, audited as a default; a v1-core host has no
|
|
11
|
+
* such answer, so the client sends it the manifest default instead),
|
|
12
|
+
* `lifecycle` (the `lifecycle {op}` command of section 5.5 and a cause on
|
|
13
|
+
* `turn_end`), `messages` (the `record_message` command: the harness hands
|
|
14
|
+
* the stub one message sent or received over the run's network for the
|
|
15
|
+
* audit log, section 10).
|
|
16
|
+
*/
|
|
17
|
+
export declare const EXTENSIONS: readonly ["consent", "content", "turns", "call_codes", "defaults", "lifecycle", "messages"];
|
|
18
|
+
export type Extension = (typeof EXTENSIONS)[number];
|
|
19
|
+
/** Why a request failed, in the capability error vocabulary (the `call_codes` extension). */
|
|
20
|
+
export type WireErrorCode = "unknown" | "forbidden" | "denied" | "invalid" | "timeout" | "error";
|
|
21
|
+
/** The abai identity of the program, in `hello`. */
|
|
22
|
+
export interface HelloAbai {
|
|
23
|
+
name: string;
|
|
24
|
+
abaigrammar: string;
|
|
25
|
+
modes: string[];
|
|
26
|
+
audit: {
|
|
27
|
+
path: string;
|
|
28
|
+
failed: string | null;
|
|
29
|
+
};
|
|
30
|
+
/** Wire extensions beyond the v1 core; absent means none. */
|
|
31
|
+
extensions?: string[];
|
|
32
|
+
}
|
|
33
|
+
export interface HelloMessage {
|
|
34
|
+
type: "hello";
|
|
35
|
+
protocol: number;
|
|
36
|
+
pid: number;
|
|
37
|
+
/** The program's own version string, when it has one. */
|
|
38
|
+
version?: string;
|
|
39
|
+
cwd: string;
|
|
40
|
+
/** A directory the program calls its own (arx-06's agent dir); absent for most programs. */
|
|
41
|
+
agentDir?: string;
|
|
42
|
+
mode: string;
|
|
43
|
+
/** What this host offers: hooks and commands policy does not forbid. */
|
|
44
|
+
capabilities: {
|
|
45
|
+
hooks: string[];
|
|
46
|
+
commands: string[];
|
|
47
|
+
};
|
|
48
|
+
/** Sequence number of the last event the host counted. */
|
|
49
|
+
lastSeq: number;
|
|
50
|
+
/** This connection's id (`k1`, `k2`, ...), as the audit log names it. */
|
|
51
|
+
connection: string;
|
|
52
|
+
abai: HelloAbai;
|
|
53
|
+
}
|
|
54
|
+
export type WireEvent = {
|
|
55
|
+
type: string;
|
|
56
|
+
} & Record<string, unknown>;
|
|
57
|
+
export interface EventMessage {
|
|
58
|
+
type: "event";
|
|
59
|
+
seq: number;
|
|
60
|
+
ts: number;
|
|
61
|
+
event: WireEvent;
|
|
62
|
+
/** A sized field was cut to its declared max. An additive field; a v1-core client ignores it. */
|
|
63
|
+
truncated?: boolean;
|
|
64
|
+
}
|
|
65
|
+
/** A `snapshot` message some hosts send; parsed, its shape is the host's. */
|
|
66
|
+
export type LooseSnapshotMessage = {
|
|
67
|
+
type: "snapshot";
|
|
68
|
+
} & Record<string, unknown>;
|
|
69
|
+
/** An event that could not be serialized was dropped; the program continues. */
|
|
70
|
+
export interface SerializeErrorMessage {
|
|
71
|
+
type: "serialize_error";
|
|
72
|
+
seq: number;
|
|
73
|
+
ts: number;
|
|
74
|
+
eventType: string;
|
|
75
|
+
error: string;
|
|
76
|
+
}
|
|
77
|
+
export type WireResponse = {
|
|
78
|
+
type: "response";
|
|
79
|
+
id?: string;
|
|
80
|
+
command: string;
|
|
81
|
+
success: true;
|
|
82
|
+
data?: unknown;
|
|
83
|
+
} | {
|
|
84
|
+
type: "response";
|
|
85
|
+
id?: string;
|
|
86
|
+
command: string;
|
|
87
|
+
success: false;
|
|
88
|
+
error: string;
|
|
89
|
+
code?: WireErrorCode;
|
|
90
|
+
};
|
|
91
|
+
/** Extension `turns`: the program gives the harness a turn; `turn_end` hands control back. */
|
|
92
|
+
export interface TurnMessage {
|
|
93
|
+
type: "turn";
|
|
94
|
+
id: string;
|
|
95
|
+
name: string;
|
|
96
|
+
/** How long the program waits before the turn ends on its own. */
|
|
97
|
+
timeoutMs: number;
|
|
98
|
+
content?: string;
|
|
99
|
+
}
|
|
100
|
+
/** Extension `turns`: a program-initiated `install` or `session`; `touchpoint_end` returns it. */
|
|
101
|
+
export interface TouchpointMessage {
|
|
102
|
+
type: "touchpoint";
|
|
103
|
+
id: string;
|
|
104
|
+
kind: "install" | "session";
|
|
105
|
+
content?: string;
|
|
106
|
+
}
|
|
107
|
+
/** Interceptable hook round trip. Only sent to the connection holding the hook. */
|
|
108
|
+
export interface HookMessage {
|
|
109
|
+
type: "hook";
|
|
110
|
+
id: string;
|
|
111
|
+
hook: string;
|
|
112
|
+
timeoutMs: number;
|
|
113
|
+
payload: unknown;
|
|
114
|
+
}
|
|
115
|
+
export interface HookTimeoutMessage {
|
|
116
|
+
type: "hook_timeout";
|
|
117
|
+
hook: string;
|
|
118
|
+
id: string;
|
|
119
|
+
}
|
|
120
|
+
/** The claimant's claims were dropped by the host (three consecutive timeouts). */
|
|
121
|
+
export interface HookClaimsReleasedMessage {
|
|
122
|
+
type: "hook_claims_released";
|
|
123
|
+
reason: string;
|
|
124
|
+
hooks: string[];
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* A hook could not be served: the payload was not serializable (no `hook`
|
|
128
|
+
* message was sent for this id) or the claimant's result failed validation.
|
|
129
|
+
* The run continued as if the hook were unclaimed.
|
|
130
|
+
*/
|
|
131
|
+
export interface HookRejectedMessage {
|
|
132
|
+
type: "hook_rejected";
|
|
133
|
+
id: string;
|
|
134
|
+
hook: string;
|
|
135
|
+
error: string;
|
|
136
|
+
}
|
|
137
|
+
export type ServerMessage = HelloMessage | EventMessage | LooseSnapshotMessage | SerializeErrorMessage | WireResponse | HookMessage | HookTimeoutMessage | HookClaimsReleasedMessage | HookRejectedMessage | TurnMessage | TouchpointMessage;
|
|
138
|
+
/**
|
|
139
|
+
* Per-connection event filter. `include` restricts the stream to the listed
|
|
140
|
+
* event types; `exclude` drops the listed types. A `subscribe` request
|
|
141
|
+
* replaces the whole filter, so an omitted `exclude` means no exclusions.
|
|
142
|
+
*/
|
|
143
|
+
export interface SubscriptionFilter {
|
|
144
|
+
include?: string[];
|
|
145
|
+
exclude?: string[];
|
|
146
|
+
}
|
|
147
|
+
/** The library's commands: the connection's own, the stub's, and the cells channel. */
|
|
148
|
+
export type LibraryCommand = {
|
|
149
|
+
type: "ping";
|
|
150
|
+
} | ({
|
|
151
|
+
type: "subscribe";
|
|
152
|
+
} & SubscriptionFilter) | {
|
|
153
|
+
type: "claim_hooks";
|
|
154
|
+
hooks: string[];
|
|
155
|
+
timeoutMs?: number;
|
|
156
|
+
} | {
|
|
157
|
+
type: "release_hooks";
|
|
158
|
+
hooks?: string[];
|
|
159
|
+
} | {
|
|
160
|
+
type: "get_manifest";
|
|
161
|
+
} | {
|
|
162
|
+
type: "get_content";
|
|
163
|
+
} | {
|
|
164
|
+
type: "get_audit";
|
|
165
|
+
limit?: number;
|
|
166
|
+
} | {
|
|
167
|
+
type: "get_cells";
|
|
168
|
+
} | {
|
|
169
|
+
type: "set_cell";
|
|
170
|
+
name: string;
|
|
171
|
+
value: unknown;
|
|
172
|
+
} | {
|
|
173
|
+
type: "lifecycle";
|
|
174
|
+
op: string;
|
|
175
|
+
};
|
|
176
|
+
/**
|
|
177
|
+
* Every command a client can send: the library commands, plus any capability
|
|
178
|
+
* call sent as `{ type: <capability name>, ...params }`. The advertised list
|
|
179
|
+
* is the host's (`hello.capabilities.commands`).
|
|
180
|
+
*/
|
|
181
|
+
export type WireCommand = LibraryCommand | ({
|
|
182
|
+
type: string;
|
|
183
|
+
} & Record<string, unknown>);
|
|
184
|
+
/** Consent stated for an act whose policy is `confirm` (abaigrammar section 10); the `consent` extension. */
|
|
185
|
+
export type WireConsent = "approved" | "auto" | "denied";
|
|
186
|
+
export interface RequestMessage {
|
|
187
|
+
type: "request";
|
|
188
|
+
id: string;
|
|
189
|
+
command: WireCommand;
|
|
190
|
+
/** The agent's stated reason for an act of control; written to the audit log. */
|
|
191
|
+
reason?: string;
|
|
192
|
+
/** Extension `consent`: ignored by a v1-core host. */
|
|
193
|
+
consent?: WireConsent;
|
|
194
|
+
}
|
|
195
|
+
export interface HookResponseMessage {
|
|
196
|
+
type: "hook_response";
|
|
197
|
+
id: string;
|
|
198
|
+
result: unknown;
|
|
199
|
+
/** The agent's stated reason for its answer; written to the audit log. */
|
|
200
|
+
reason?: string;
|
|
201
|
+
/** Extension `consent`: ignored by a v1-core host. */
|
|
202
|
+
consent?: WireConsent;
|
|
203
|
+
}
|
|
204
|
+
/** Extension `turns`: the harness is done with a turn. `cause` says why the agent did nothing with it (`budget`). */
|
|
205
|
+
export interface TurnEndMessage {
|
|
206
|
+
type: "turn_end";
|
|
207
|
+
id: string;
|
|
208
|
+
cause?: string;
|
|
209
|
+
}
|
|
210
|
+
/** Extension `turns`: the harness is done with a touchpoint. */
|
|
211
|
+
export interface TouchpointEndMessage {
|
|
212
|
+
type: "touchpoint_end";
|
|
213
|
+
id: string;
|
|
214
|
+
}
|
|
215
|
+
export type ClientMessage = RequestMessage | HookResponseMessage | TurnEndMessage | TouchpointEndMessage;
|
|
216
|
+
/** `get_cells`: every cell's value (sized ones cut to their max) and the host's event sequence number. */
|
|
217
|
+
export interface GetCellsData {
|
|
218
|
+
seq: number;
|
|
219
|
+
cells: Record<string, unknown>;
|
|
220
|
+
}
|
|
221
|
+
/** `set_cell`: the knob and the value that landed (it may be clamped). */
|
|
222
|
+
export interface SetCellData {
|
|
223
|
+
name: string;
|
|
224
|
+
value: unknown;
|
|
225
|
+
}
|
|
226
|
+
/** `get_manifest`: the effective manifest of this running host. */
|
|
227
|
+
export interface GetManifestData {
|
|
228
|
+
manifest: Manifest;
|
|
229
|
+
}
|
|
230
|
+
/** `get_content`: the content slots the stub embeds (abaigrammar section 8). A v1-core host sends `identity` only. */
|
|
231
|
+
export interface GetContentData {
|
|
232
|
+
identity: string;
|
|
233
|
+
install?: string;
|
|
234
|
+
use?: string;
|
|
235
|
+
turns?: Record<string, string>;
|
|
236
|
+
}
|
|
237
|
+
/** `lifecycle {op: "status"}`: what the stub knows of its own process. */
|
|
238
|
+
export interface LifecycleStatusData {
|
|
239
|
+
pid: number;
|
|
240
|
+
name: string;
|
|
241
|
+
mode: string;
|
|
242
|
+
cwd: string;
|
|
243
|
+
startedAt: string;
|
|
244
|
+
connections: number;
|
|
245
|
+
paused: boolean;
|
|
246
|
+
/** A launcher handed this program its connection, so the full lifecycle is available to it. */
|
|
247
|
+
launched: boolean;
|
|
248
|
+
}
|
|
249
|
+
/** `get_audit`: the log's location and state, and its last records. */
|
|
250
|
+
export interface GetAuditData {
|
|
251
|
+
path: string;
|
|
252
|
+
failed: string | null;
|
|
253
|
+
records: unknown[];
|
|
254
|
+
/** More records exist than were returned. */
|
|
255
|
+
truncated: boolean;
|
|
256
|
+
}
|
|
257
|
+
//# sourceMappingURL=protocol.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/wire/protocol.ts"],"names":[],"mappings":"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","sourcesContent":["// abai wire protocol v1 (abaigrammar section 6.3): LF-framed JSON lines over a\n// local socket. The core is the generic part of arx-06's supervisor protocol,\n// unchanged, so a running arx-06 is a sidecar target; extensions are\n// advertised in hello.abai.extensions.\nimport type { Manifest } from \"../manifest/manifest.ts\";\n\nexport const PROTOCOL_VERSION = 1;\n\n/**\n * The extensions a TypeScript stub speaks beyond the v1 core, named in\n * `hello.abai.extensions` so a client speaks each only when it is offered:\n * `consent` (consent stated on a request or hook answer), `content` (the\n * install, use and turn slots on `get_content`), `turns` (turns and\n * touchpoints as messages), `call_codes` (a code beside every error),\n * `defaults` (a `hook_response` whose `result` is null asks the program to\n * apply the decision's default, audited as a default; a v1-core host has no\n * such answer, so the client sends it the manifest default instead),\n * `lifecycle` (the `lifecycle {op}` command of section 5.5 and a cause on\n * `turn_end`), `messages` (the `record_message` command: the harness hands\n * the stub one message sent or received over the run's network for the\n * audit log, section 10).\n */\nexport const EXTENSIONS = [\"consent\", \"content\", \"turns\", \"call_codes\", \"defaults\", \"lifecycle\", \"messages\"] as const;\nexport type Extension = (typeof EXTENSIONS)[number];\n\n/** Why a request failed, in the capability error vocabulary (the `call_codes` extension). */\nexport type WireErrorCode = \"unknown\" | \"forbidden\" | \"denied\" | \"invalid\" | \"timeout\" | \"error\";\n\n// ---------------------------------------------------------------------------\n// Server -> client\n// ---------------------------------------------------------------------------\n\n/** The abai identity of the program, in `hello`. */\nexport interface HelloAbai {\n\tname: string;\n\tabaigrammar: string;\n\tmodes: string[];\n\taudit: { path: string; failed: string | null };\n\t/** Wire extensions beyond the v1 core; absent means none. */\n\textensions?: string[];\n}\n\nexport interface HelloMessage {\n\ttype: \"hello\";\n\tprotocol: number;\n\tpid: number;\n\t/** The program's own version string, when it has one. */\n\tversion?: string;\n\tcwd: string;\n\t/** A directory the program calls its own (arx-06's agent dir); absent for most programs. */\n\tagentDir?: string;\n\tmode: string;\n\t/** What this host offers: hooks and commands policy does not forbid. */\n\tcapabilities: { hooks: string[]; commands: string[] };\n\t/** Sequence number of the last event the host counted. */\n\tlastSeq: number;\n\t/** This connection's id (`k1`, `k2`, ...), as the audit log names it. */\n\tconnection: string;\n\tabai: HelloAbai;\n}\n\nexport type WireEvent = { type: string } & Record<string, unknown>;\n\nexport interface EventMessage {\n\ttype: \"event\";\n\tseq: number;\n\tts: number;\n\tevent: WireEvent;\n\t/** A sized field was cut to its declared max. An additive field; a v1-core client ignores it. */\n\ttruncated?: boolean;\n}\n\n/** A `snapshot` message some hosts send; parsed, its shape is the host's. */\nexport type LooseSnapshotMessage = { type: \"snapshot\" } & Record<string, unknown>;\n\n/** An event that could not be serialized was dropped; the program continues. */\nexport interface SerializeErrorMessage {\n\ttype: \"serialize_error\";\n\tseq: number;\n\tts: number;\n\teventType: string;\n\terror: string;\n}\n\nexport type WireResponse =\n\t| { type: \"response\"; id?: string; command: string; success: true; data?: unknown }\n\t| { type: \"response\"; id?: string; command: string; success: false; error: string; code?: WireErrorCode };\n\n/** Extension `turns`: the program gives the harness a turn; `turn_end` hands control back. */\nexport interface TurnMessage {\n\ttype: \"turn\";\n\tid: string;\n\tname: string;\n\t/** How long the program waits before the turn ends on its own. */\n\ttimeoutMs: number;\n\tcontent?: string;\n}\n\n/** Extension `turns`: a program-initiated `install` or `session`; `touchpoint_end` returns it. */\nexport interface TouchpointMessage {\n\ttype: \"touchpoint\";\n\tid: string;\n\tkind: \"install\" | \"session\";\n\tcontent?: string;\n}\n\n/** Interceptable hook round trip. Only sent to the connection holding the hook. */\nexport interface HookMessage {\n\ttype: \"hook\";\n\tid: string;\n\thook: string;\n\ttimeoutMs: number;\n\tpayload: unknown;\n}\n\nexport interface HookTimeoutMessage {\n\ttype: \"hook_timeout\";\n\thook: string;\n\tid: string;\n}\n\n/** The claimant's claims were dropped by the host (three consecutive timeouts). */\nexport interface HookClaimsReleasedMessage {\n\ttype: \"hook_claims_released\";\n\treason: string;\n\thooks: string[];\n}\n\n/**\n * A hook could not be served: the payload was not serializable (no `hook`\n * message was sent for this id) or the claimant's result failed validation.\n * The run continued as if the hook were unclaimed.\n */\nexport interface HookRejectedMessage {\n\ttype: \"hook_rejected\";\n\tid: string;\n\thook: string;\n\terror: string;\n}\n\nexport type ServerMessage =\n\t| HelloMessage\n\t| EventMessage\n\t| LooseSnapshotMessage\n\t| SerializeErrorMessage\n\t| WireResponse\n\t| HookMessage\n\t| HookTimeoutMessage\n\t| HookClaimsReleasedMessage\n\t| HookRejectedMessage\n\t| TurnMessage\n\t| TouchpointMessage;\n\n// ---------------------------------------------------------------------------\n// Client -> server\n// ---------------------------------------------------------------------------\n\n/**\n * Per-connection event filter. `include` restricts the stream to the listed\n * event types; `exclude` drops the listed types. A `subscribe` request\n * replaces the whole filter, so an omitted `exclude` means no exclusions.\n */\nexport interface SubscriptionFilter {\n\tinclude?: string[];\n\texclude?: string[];\n}\n\n/** The library's commands: the connection's own, the stub's, and the cells channel. */\nexport type LibraryCommand =\n\t// connection\n\t| { type: \"ping\" }\n\t| ({ type: \"subscribe\" } & SubscriptionFilter)\n\t| { type: \"claim_hooks\"; hooks: string[]; timeoutMs?: number }\n\t| { type: \"release_hooks\"; hooks?: string[] }\n\t// library\n\t| { type: \"get_manifest\" }\n\t| { type: \"get_content\" }\n\t| { type: \"get_audit\"; limit?: number }\n\t// cells (abaigrammar section 5.2)\n\t| { type: \"get_cells\" }\n\t| { type: \"set_cell\"; name: string; value: unknown }\n\t// lifecycle (abaigrammar section 5.5), the `lifecycle` extension: status always, pause and resume for a\n\t// cooperative pause, stop for the declared stop handler; start and restart are the launcher's own\n\t| { type: \"lifecycle\"; op: string };\n\n/**\n * Every command a client can send: the library commands, plus any capability\n * call sent as `{ type: <capability name>, ...params }`. The advertised list\n * is the host's (`hello.capabilities.commands`).\n */\nexport type WireCommand = LibraryCommand | ({ type: string } & Record<string, unknown>);\n\n/** Consent stated for an act whose policy is `confirm` (abaigrammar section 10); the `consent` extension. */\nexport type WireConsent = \"approved\" | \"auto\" | \"denied\";\n\nexport interface RequestMessage {\n\ttype: \"request\";\n\tid: string;\n\tcommand: WireCommand;\n\t/** The agent's stated reason for an act of control; written to the audit log. */\n\treason?: string;\n\t/** Extension `consent`: ignored by a v1-core host. */\n\tconsent?: WireConsent;\n}\n\nexport interface HookResponseMessage {\n\ttype: \"hook_response\";\n\tid: string;\n\tresult: unknown;\n\t/** The agent's stated reason for its answer; written to the audit log. */\n\treason?: string;\n\t/** Extension `consent`: ignored by a v1-core host. */\n\tconsent?: WireConsent;\n}\n\n/** Extension `turns`: the harness is done with a turn. `cause` says why the agent did nothing with it (`budget`). */\nexport interface TurnEndMessage {\n\ttype: \"turn_end\";\n\tid: string;\n\tcause?: string;\n}\n\n/** Extension `turns`: the harness is done with a touchpoint. */\nexport interface TouchpointEndMessage {\n\ttype: \"touchpoint_end\";\n\tid: string;\n}\n\nexport type ClientMessage = RequestMessage | HookResponseMessage | TurnEndMessage | TouchpointEndMessage;\n\n// ---------------------------------------------------------------------------\n// Response data of the library commands\n// ---------------------------------------------------------------------------\n\n/** `get_cells`: every cell's value (sized ones cut to their max) and the host's event sequence number. */\nexport interface GetCellsData {\n\tseq: number;\n\tcells: Record<string, unknown>;\n}\n\n/** `set_cell`: the knob and the value that landed (it may be clamped). */\nexport interface SetCellData {\n\tname: string;\n\tvalue: unknown;\n}\n\n/** `get_manifest`: the effective manifest of this running host. */\nexport interface GetManifestData {\n\tmanifest: Manifest;\n}\n\n/** `get_content`: the content slots the stub embeds (abaigrammar section 8). A v1-core host sends `identity` only. */\nexport interface GetContentData {\n\tidentity: string;\n\tinstall?: string;\n\tuse?: string;\n\tturns?: Record<string, string>;\n}\n\n/** `lifecycle {op: \"status\"}`: what the stub knows of its own process. */\nexport interface LifecycleStatusData {\n\tpid: number;\n\tname: string;\n\tmode: string;\n\tcwd: string;\n\tstartedAt: string;\n\tconnections: number;\n\tpaused: boolean;\n\t/** A launcher handed this program its connection, so the full lifecycle is available to it. */\n\tlaunched: boolean;\n}\n\n/** `get_audit`: the log's location and state, and its last records. */\nexport interface GetAuditData {\n\tpath: string;\n\tfailed: string | null;\n\trecords: unknown[];\n\t/** More records exist than were returned. */\n\ttruncated: boolean;\n}\n"]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export const PROTOCOL_VERSION = 1;
|
|
2
|
+
/**
|
|
3
|
+
* The extensions a TypeScript stub speaks beyond the v1 core, named in
|
|
4
|
+
* `hello.abai.extensions` so a client speaks each only when it is offered:
|
|
5
|
+
* `consent` (consent stated on a request or hook answer), `content` (the
|
|
6
|
+
* install, use and turn slots on `get_content`), `turns` (turns and
|
|
7
|
+
* touchpoints as messages), `call_codes` (a code beside every error),
|
|
8
|
+
* `defaults` (a `hook_response` whose `result` is null asks the program to
|
|
9
|
+
* apply the decision's default, audited as a default; a v1-core host has no
|
|
10
|
+
* such answer, so the client sends it the manifest default instead),
|
|
11
|
+
* `lifecycle` (the `lifecycle {op}` command of section 5.5 and a cause on
|
|
12
|
+
* `turn_end`), `messages` (the `record_message` command: the harness hands
|
|
13
|
+
* the stub one message sent or received over the run's network for the
|
|
14
|
+
* audit log, section 10).
|
|
15
|
+
*/
|
|
16
|
+
export const EXTENSIONS = ["consent", "content", "turns", "call_codes", "defaults", "lifecycle", "messages"];
|
|
17
|
+
//# sourceMappingURL=protocol.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../src/wire/protocol.ts"],"names":[],"mappings":"AAMA,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAElC;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,CAAU,CAAC","sourcesContent":["// abai wire protocol v1 (abaigrammar section 6.3): LF-framed JSON lines over a\n// local socket. The core is the generic part of arx-06's supervisor protocol,\n// unchanged, so a running arx-06 is a sidecar target; extensions are\n// advertised in hello.abai.extensions.\nimport type { Manifest } from \"../manifest/manifest.ts\";\n\nexport const PROTOCOL_VERSION = 1;\n\n/**\n * The extensions a TypeScript stub speaks beyond the v1 core, named in\n * `hello.abai.extensions` so a client speaks each only when it is offered:\n * `consent` (consent stated on a request or hook answer), `content` (the\n * install, use and turn slots on `get_content`), `turns` (turns and\n * touchpoints as messages), `call_codes` (a code beside every error),\n * `defaults` (a `hook_response` whose `result` is null asks the program to\n * apply the decision's default, audited as a default; a v1-core host has no\n * such answer, so the client sends it the manifest default instead),\n * `lifecycle` (the `lifecycle {op}` command of section 5.5 and a cause on\n * `turn_end`), `messages` (the `record_message` command: the harness hands\n * the stub one message sent or received over the run's network for the\n * audit log, section 10).\n */\nexport const EXTENSIONS = [\"consent\", \"content\", \"turns\", \"call_codes\", \"defaults\", \"lifecycle\", \"messages\"] as const;\nexport type Extension = (typeof EXTENSIONS)[number];\n\n/** Why a request failed, in the capability error vocabulary (the `call_codes` extension). */\nexport type WireErrorCode = \"unknown\" | \"forbidden\" | \"denied\" | \"invalid\" | \"timeout\" | \"error\";\n\n// ---------------------------------------------------------------------------\n// Server -> client\n// ---------------------------------------------------------------------------\n\n/** The abai identity of the program, in `hello`. */\nexport interface HelloAbai {\n\tname: string;\n\tabaigrammar: string;\n\tmodes: string[];\n\taudit: { path: string; failed: string | null };\n\t/** Wire extensions beyond the v1 core; absent means none. */\n\textensions?: string[];\n}\n\nexport interface HelloMessage {\n\ttype: \"hello\";\n\tprotocol: number;\n\tpid: number;\n\t/** The program's own version string, when it has one. */\n\tversion?: string;\n\tcwd: string;\n\t/** A directory the program calls its own (arx-06's agent dir); absent for most programs. */\n\tagentDir?: string;\n\tmode: string;\n\t/** What this host offers: hooks and commands policy does not forbid. */\n\tcapabilities: { hooks: string[]; commands: string[] };\n\t/** Sequence number of the last event the host counted. */\n\tlastSeq: number;\n\t/** This connection's id (`k1`, `k2`, ...), as the audit log names it. */\n\tconnection: string;\n\tabai: HelloAbai;\n}\n\nexport type WireEvent = { type: string } & Record<string, unknown>;\n\nexport interface EventMessage {\n\ttype: \"event\";\n\tseq: number;\n\tts: number;\n\tevent: WireEvent;\n\t/** A sized field was cut to its declared max. An additive field; a v1-core client ignores it. */\n\ttruncated?: boolean;\n}\n\n/** A `snapshot` message some hosts send; parsed, its shape is the host's. */\nexport type LooseSnapshotMessage = { type: \"snapshot\" } & Record<string, unknown>;\n\n/** An event that could not be serialized was dropped; the program continues. */\nexport interface SerializeErrorMessage {\n\ttype: \"serialize_error\";\n\tseq: number;\n\tts: number;\n\teventType: string;\n\terror: string;\n}\n\nexport type WireResponse =\n\t| { type: \"response\"; id?: string; command: string; success: true; data?: unknown }\n\t| { type: \"response\"; id?: string; command: string; success: false; error: string; code?: WireErrorCode };\n\n/** Extension `turns`: the program gives the harness a turn; `turn_end` hands control back. */\nexport interface TurnMessage {\n\ttype: \"turn\";\n\tid: string;\n\tname: string;\n\t/** How long the program waits before the turn ends on its own. */\n\ttimeoutMs: number;\n\tcontent?: string;\n}\n\n/** Extension `turns`: a program-initiated `install` or `session`; `touchpoint_end` returns it. */\nexport interface TouchpointMessage {\n\ttype: \"touchpoint\";\n\tid: string;\n\tkind: \"install\" | \"session\";\n\tcontent?: string;\n}\n\n/** Interceptable hook round trip. Only sent to the connection holding the hook. */\nexport interface HookMessage {\n\ttype: \"hook\";\n\tid: string;\n\thook: string;\n\ttimeoutMs: number;\n\tpayload: unknown;\n}\n\nexport interface HookTimeoutMessage {\n\ttype: \"hook_timeout\";\n\thook: string;\n\tid: string;\n}\n\n/** The claimant's claims were dropped by the host (three consecutive timeouts). */\nexport interface HookClaimsReleasedMessage {\n\ttype: \"hook_claims_released\";\n\treason: string;\n\thooks: string[];\n}\n\n/**\n * A hook could not be served: the payload was not serializable (no `hook`\n * message was sent for this id) or the claimant's result failed validation.\n * The run continued as if the hook were unclaimed.\n */\nexport interface HookRejectedMessage {\n\ttype: \"hook_rejected\";\n\tid: string;\n\thook: string;\n\terror: string;\n}\n\nexport type ServerMessage =\n\t| HelloMessage\n\t| EventMessage\n\t| LooseSnapshotMessage\n\t| SerializeErrorMessage\n\t| WireResponse\n\t| HookMessage\n\t| HookTimeoutMessage\n\t| HookClaimsReleasedMessage\n\t| HookRejectedMessage\n\t| TurnMessage\n\t| TouchpointMessage;\n\n// ---------------------------------------------------------------------------\n// Client -> server\n// ---------------------------------------------------------------------------\n\n/**\n * Per-connection event filter. `include` restricts the stream to the listed\n * event types; `exclude` drops the listed types. A `subscribe` request\n * replaces the whole filter, so an omitted `exclude` means no exclusions.\n */\nexport interface SubscriptionFilter {\n\tinclude?: string[];\n\texclude?: string[];\n}\n\n/** The library's commands: the connection's own, the stub's, and the cells channel. */\nexport type LibraryCommand =\n\t// connection\n\t| { type: \"ping\" }\n\t| ({ type: \"subscribe\" } & SubscriptionFilter)\n\t| { type: \"claim_hooks\"; hooks: string[]; timeoutMs?: number }\n\t| { type: \"release_hooks\"; hooks?: string[] }\n\t// library\n\t| { type: \"get_manifest\" }\n\t| { type: \"get_content\" }\n\t| { type: \"get_audit\"; limit?: number }\n\t// cells (abaigrammar section 5.2)\n\t| { type: \"get_cells\" }\n\t| { type: \"set_cell\"; name: string; value: unknown }\n\t// lifecycle (abaigrammar section 5.5), the `lifecycle` extension: status always, pause and resume for a\n\t// cooperative pause, stop for the declared stop handler; start and restart are the launcher's own\n\t| { type: \"lifecycle\"; op: string };\n\n/**\n * Every command a client can send: the library commands, plus any capability\n * call sent as `{ type: <capability name>, ...params }`. The advertised list\n * is the host's (`hello.capabilities.commands`).\n */\nexport type WireCommand = LibraryCommand | ({ type: string } & Record<string, unknown>);\n\n/** Consent stated for an act whose policy is `confirm` (abaigrammar section 10); the `consent` extension. */\nexport type WireConsent = \"approved\" | \"auto\" | \"denied\";\n\nexport interface RequestMessage {\n\ttype: \"request\";\n\tid: string;\n\tcommand: WireCommand;\n\t/** The agent's stated reason for an act of control; written to the audit log. */\n\treason?: string;\n\t/** Extension `consent`: ignored by a v1-core host. */\n\tconsent?: WireConsent;\n}\n\nexport interface HookResponseMessage {\n\ttype: \"hook_response\";\n\tid: string;\n\tresult: unknown;\n\t/** The agent's stated reason for its answer; written to the audit log. */\n\treason?: string;\n\t/** Extension `consent`: ignored by a v1-core host. */\n\tconsent?: WireConsent;\n}\n\n/** Extension `turns`: the harness is done with a turn. `cause` says why the agent did nothing with it (`budget`). */\nexport interface TurnEndMessage {\n\ttype: \"turn_end\";\n\tid: string;\n\tcause?: string;\n}\n\n/** Extension `turns`: the harness is done with a touchpoint. */\nexport interface TouchpointEndMessage {\n\ttype: \"touchpoint_end\";\n\tid: string;\n}\n\nexport type ClientMessage = RequestMessage | HookResponseMessage | TurnEndMessage | TouchpointEndMessage;\n\n// ---------------------------------------------------------------------------\n// Response data of the library commands\n// ---------------------------------------------------------------------------\n\n/** `get_cells`: every cell's value (sized ones cut to their max) and the host's event sequence number. */\nexport interface GetCellsData {\n\tseq: number;\n\tcells: Record<string, unknown>;\n}\n\n/** `set_cell`: the knob and the value that landed (it may be clamped). */\nexport interface SetCellData {\n\tname: string;\n\tvalue: unknown;\n}\n\n/** `get_manifest`: the effective manifest of this running host. */\nexport interface GetManifestData {\n\tmanifest: Manifest;\n}\n\n/** `get_content`: the content slots the stub embeds (abaigrammar section 8). A v1-core host sends `identity` only. */\nexport interface GetContentData {\n\tidentity: string;\n\tinstall?: string;\n\tuse?: string;\n\tturns?: Record<string, string>;\n}\n\n/** `lifecycle {op: \"status\"}`: what the stub knows of its own process. */\nexport interface LifecycleStatusData {\n\tpid: number;\n\tname: string;\n\tmode: string;\n\tcwd: string;\n\tstartedAt: string;\n\tconnections: number;\n\tpaused: boolean;\n\t/** A launcher handed this program its connection, so the full lifecycle is available to it. */\n\tlaunched: boolean;\n}\n\n/** `get_audit`: the log's location and state, and its last records. */\nexport interface GetAuditData {\n\tpath: string;\n\tfailed: string | null;\n\trecords: unknown[];\n\t/** More records exist than were returned. */\n\ttruncated: boolean;\n}\n"]}
|