@scotthuang/agent-knock-knock-pi 0.1.0-poc.1

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/lib/ipc.js ADDED
@@ -0,0 +1,255 @@
1
+ import { timingSafeEqual } from "node:crypto";
2
+ import fs from "node:fs";
3
+ import net from "node:net";
4
+ import { CALLBACK_MAX_REQUEST_BYTES as CALLBACK_BODY_LIMIT_BYTES, CALLBACK_MAX_RESPONSE_BYTES, CALLBACK_SOCKET_ENV, CALLBACK_TIMEOUT_MS, CALLBACK_TOKEN_ENV, } from "./constants.js";
5
+ export { CALLBACK_MAX_RESPONSE_BYTES, CALLBACK_SOCKET_ENV, CALLBACK_TIMEOUT_MS, CALLBACK_TOKEN_ENV, };
6
+ export const CALLBACK_MAX_BODY_BYTES = CALLBACK_BODY_LIMIT_BYTES;
7
+ export const CALLBACK_MAX_REQUEST_BYTES = CALLBACK_MAX_BODY_BYTES + 64 * 1024;
8
+ /** Host an authenticated, one-frame-per-connection Pi callback transport. */
9
+ export function createCallbackIpcServer(options) {
10
+ let state = "idle";
11
+ const sockets = new Set();
12
+ const server = net.createServer((socket) => {
13
+ sockets.add(socket);
14
+ socket.setTimeout(CALLBACK_TIMEOUT_MS, () => socket.destroy());
15
+ socket.once("close", () => sockets.delete(socket));
16
+ socket.once("error", () => undefined);
17
+ void handleConnection(socket, options);
18
+ });
19
+ return {
20
+ start() {
21
+ if (state === "running")
22
+ return Promise.resolve();
23
+ if (state !== "idle") {
24
+ return Promise.reject(new Error("Pi callback IPC server cannot be restarted"));
25
+ }
26
+ if (!options.socketPath || !options.token) {
27
+ state = "stopped";
28
+ return Promise.reject(new Error("Pi callback IPC configuration is invalid"));
29
+ }
30
+ state = "starting";
31
+ return new Promise((resolve, reject) => {
32
+ const failed = (error) => {
33
+ state = "stopped";
34
+ reject(error);
35
+ };
36
+ server.once("error", failed);
37
+ server.listen(options.socketPath, () => {
38
+ server.off("error", failed);
39
+ server.on("error", () => undefined);
40
+ try {
41
+ fs.chmodSync(options.socketPath, 0o600);
42
+ }
43
+ catch (error) {
44
+ state = "stopped";
45
+ server.close(() => reject(error));
46
+ return;
47
+ }
48
+ state = "running";
49
+ resolve();
50
+ });
51
+ });
52
+ },
53
+ async stop() {
54
+ if (state === "stopped")
55
+ return;
56
+ state = "stopped";
57
+ for (const socket of sockets)
58
+ socket.destroy();
59
+ if (server.listening) {
60
+ await new Promise((resolve) => server.close(() => resolve()));
61
+ }
62
+ await fs.promises.rm(options.socketPath, { force: true }).catch(() => undefined);
63
+ },
64
+ };
65
+ }
66
+ /** Send one authenticated request from the short-lived Profile helper. */
67
+ export function sendCallbackOverIpc(options) {
68
+ const frame = `${JSON.stringify(options.request)}\n`;
69
+ if (Buffer.byteLength(frame, "utf8") > CALLBACK_MAX_REQUEST_BYTES) {
70
+ return Promise.reject(new Error("Pi callback IPC request exceeded its limit"));
71
+ }
72
+ return new Promise((resolve, reject) => {
73
+ const socket = net.createConnection(options.socketPath);
74
+ let settled = false;
75
+ const finish = (callback) => {
76
+ if (settled)
77
+ return;
78
+ settled = true;
79
+ socket.destroy();
80
+ callback();
81
+ };
82
+ socket.setTimeout(CALLBACK_TIMEOUT_MS, () => {
83
+ finish(() => reject(new Error("Pi callback IPC timed out")));
84
+ });
85
+ socket.once("error", () => {
86
+ finish(() => reject(new Error("Pi callback IPC unavailable")));
87
+ });
88
+ socket.once("connect", () => socket.write(frame));
89
+ readFrame(socket, CALLBACK_MAX_RESPONSE_BYTES).then((value) => {
90
+ const response = parseWireResponse(value);
91
+ if (!response) {
92
+ finish(() => reject(new Error("Pi callback IPC response was invalid")));
93
+ return;
94
+ }
95
+ finish(() => resolve(response));
96
+ }, () => {
97
+ finish(() => reject(new Error("Pi callback IPC response was incomplete")));
98
+ });
99
+ });
100
+ }
101
+ async function handleConnection(socket, options) {
102
+ try {
103
+ const frame = await readFrame(socket, CALLBACK_MAX_REQUEST_BYTES);
104
+ const request = parseWireRequest(frame);
105
+ if (!request) {
106
+ socket.destroy();
107
+ return;
108
+ }
109
+ if (!sameSecret(request.token, options.token)) {
110
+ writeFrame(socket, {
111
+ deliveryId: request.deliveryId,
112
+ messageId: request.messageId,
113
+ status: "rejected",
114
+ errorCode: "callback_authentication_failed",
115
+ });
116
+ return;
117
+ }
118
+ const acknowledgement = await options.routes.deliver(request);
119
+ writeFrame(socket, {
120
+ deliveryId: acknowledgement.request.delivery_id,
121
+ messageId: acknowledgement.request.message_id,
122
+ status: acknowledgement.result.status,
123
+ ...(acknowledgement.result.acceptance_id
124
+ ? { acceptanceId: acknowledgement.result.acceptance_id }
125
+ : {}),
126
+ ...(acknowledgement.result.error_code
127
+ ? { errorCode: acknowledgement.result.error_code }
128
+ : {}),
129
+ });
130
+ }
131
+ catch {
132
+ socket.destroy();
133
+ }
134
+ }
135
+ function readFrame(socket, maxBytes) {
136
+ return new Promise((resolve, reject) => {
137
+ const chunks = [];
138
+ let bytes = 0;
139
+ let settled = false;
140
+ const cleanup = () => {
141
+ socket.off("data", onData);
142
+ socket.off("end", onEnd);
143
+ socket.off("close", onClose);
144
+ socket.off("error", onError);
145
+ };
146
+ const finish = (error, value) => {
147
+ if (settled)
148
+ return;
149
+ settled = true;
150
+ cleanup();
151
+ if (error)
152
+ reject(error);
153
+ else
154
+ resolve(value ?? "");
155
+ };
156
+ const onData = (chunk) => {
157
+ const newline = chunk.indexOf(0x0a);
158
+ const frameChunk = newline >= 0 ? chunk.subarray(0, newline) : chunk;
159
+ bytes += frameChunk.length;
160
+ if (bytes > maxBytes) {
161
+ finish(new Error("Pi callback IPC frame exceeded its limit"));
162
+ return;
163
+ }
164
+ chunks.push(frameChunk);
165
+ if (newline >= 0) {
166
+ finish(undefined, Buffer.concat(chunks, bytes).toString("utf8"));
167
+ }
168
+ };
169
+ const onEnd = () => finish(new Error("Pi callback IPC frame ended early"));
170
+ const onClose = () => finish(new Error("Pi callback IPC connection closed"));
171
+ const onError = () => finish(new Error("Pi callback IPC failed"));
172
+ socket.on("data", onData);
173
+ socket.once("end", onEnd);
174
+ socket.once("close", onClose);
175
+ socket.once("error", onError);
176
+ });
177
+ }
178
+ function writeFrame(socket, value) {
179
+ if (socket.destroyed)
180
+ return;
181
+ const frame = `${JSON.stringify(value)}\n`;
182
+ if (Buffer.byteLength(frame, "utf8") > CALLBACK_MAX_RESPONSE_BYTES) {
183
+ socket.destroy();
184
+ return;
185
+ }
186
+ socket.end(frame);
187
+ }
188
+ function parseWireRequest(value) {
189
+ let parsed;
190
+ try {
191
+ parsed = JSON.parse(value);
192
+ }
193
+ catch {
194
+ return undefined;
195
+ }
196
+ if (!isRecord(parsed))
197
+ return undefined;
198
+ const keys = [
199
+ "token",
200
+ "controllerId",
201
+ "deliveryId",
202
+ "messageId",
203
+ "idempotencyKey",
204
+ "body",
205
+ ];
206
+ if (Object.keys(parsed).length !== keys.length)
207
+ return undefined;
208
+ if (keys.some((key) => typeof parsed[key] !== "string"))
209
+ return undefined;
210
+ return parsed;
211
+ }
212
+ function parseWireResponse(value) {
213
+ let parsed;
214
+ try {
215
+ parsed = JSON.parse(value);
216
+ }
217
+ catch {
218
+ return undefined;
219
+ }
220
+ if (!isRecord(parsed))
221
+ return undefined;
222
+ const allowed = new Set([
223
+ "deliveryId",
224
+ "messageId",
225
+ "status",
226
+ "acceptanceId",
227
+ "errorCode",
228
+ ]);
229
+ if (Object.keys(parsed).some((key) => !allowed.has(key)))
230
+ return undefined;
231
+ if (typeof parsed.deliveryId !== "string" || typeof parsed.messageId !== "string") {
232
+ return undefined;
233
+ }
234
+ if (!["accepted", "retry", "rejected", "unknown"].includes(String(parsed.status))) {
235
+ return undefined;
236
+ }
237
+ if (parsed.acceptanceId !== undefined && typeof parsed.acceptanceId !== "string") {
238
+ return undefined;
239
+ }
240
+ if (parsed.errorCode !== undefined && typeof parsed.errorCode !== "string") {
241
+ return undefined;
242
+ }
243
+ if (parsed.status === "accepted" && !parsed.acceptanceId)
244
+ return undefined;
245
+ return parsed;
246
+ }
247
+ function sameSecret(left, right) {
248
+ const leftBytes = Buffer.from(left, "utf8");
249
+ const rightBytes = Buffer.from(right, "utf8");
250
+ return leftBytes.length === rightBytes.length && timingSafeEqual(leftBytes, rightBytes);
251
+ }
252
+ function isRecord(value) {
253
+ return typeof value === "object" && value !== null && !Array.isArray(value);
254
+ }
255
+ //# sourceMappingURL=ipc.js.map
package/lib/ipc.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ipc.js","sourceRoot":"","sources":["../src/ipc.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ export interface ConnectorProfileResources {
2
+ readonly instanceNonce: string;
3
+ readonly directory: string;
4
+ readonly socketPath: string;
5
+ readonly stateDirectory: string;
6
+ readonly token: string;
7
+ readonly profilePath: string;
8
+ readonly profile: Readonly<Record<string, unknown>>;
9
+ readonly fingerprint: string;
10
+ environment(controllerId: string): NodeJS.ProcessEnv;
11
+ remove(): void;
12
+ }
13
+ /** Create one Pi-runtime-private route-bound Host Profile and IPC authority. */
14
+ export declare function createConnectorProfileResources(baseEnvironment?: Readonly<NodeJS.ProcessEnv>): ConnectorProfileResources;
package/lib/profile.js ADDED
@@ -0,0 +1,160 @@
1
+ import { randomBytes } from "node:crypto";
2
+ import fs from "node:fs";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ import { createTrustedHostProfileRuntime, hostProfileRelayEnvironment, } from "@scotthuang/agent-knock-knock/host-adapter";
7
+ import { CALLBACK_MAX_RESPONSE_BYTES, CALLBACK_SOCKET_ENV, CALLBACK_TIMEOUT_MS, CALLBACK_TOKEN_ENV, CONNECTOR_STATE_DIR_ENV, CONNECTOR_VERSION, CONTROLLER_ID_ENV, PI_HOST_ID, SUPPORTED_PI_VERSION, } from "./constants.js";
8
+ const HOST_PROFILE_SCHEMA_URL = "https://raw.githubusercontent.com/scotthuang/agent-knock-knock/main/" +
9
+ "schemas/host-profile-v1.schema.json";
10
+ /** Create one Pi-runtime-private route-bound Host Profile and IPC authority. */
11
+ export function createConnectorProfileResources(baseEnvironment = process.env) {
12
+ if (process.platform === "win32") {
13
+ throw new Error("agent-knock-knock-pi POC requires a POSIX Unix socket");
14
+ }
15
+ const instanceNonce = randomBytes(12).toString("hex");
16
+ const token = randomBytes(32).toString("base64url");
17
+ const stateDirectory = resolveStateDirectory(baseEnvironment);
18
+ ensurePrivateDirectory(stateDirectory);
19
+ const directory = fs.mkdtempSync(path.join(os.tmpdir(), "akk-pi-"));
20
+ fs.chmodSync(directory, 0o700);
21
+ const socketPath = path.join(directory, "callback.sock");
22
+ const profilePath = path.join(directory, "host-profile.json");
23
+ const helperPath = fileURLToPath(new URL("./callback-helper.js", import.meta.url));
24
+ const revision = `${CONNECTOR_VERSION}-${instanceNonce}`;
25
+ const profile = Object.freeze({
26
+ $schema: HOST_PROFILE_SCHEMA_URL,
27
+ schema: "agent-knock-knock/host-profile",
28
+ version: 1,
29
+ id: "pi-native",
30
+ revision,
31
+ compatibility: {
32
+ host: PI_HOST_ID,
33
+ range: `=${SUPPORTED_PI_VERSION}`,
34
+ },
35
+ controllerContext: {
36
+ driver: "environment_v1",
37
+ sessionIdVariable: CONTROLLER_ID_ENV,
38
+ scope: "route_bound_v1",
39
+ },
40
+ callback: {
41
+ driver: "command_json_v1",
42
+ executable: process.execPath,
43
+ arguments: [
44
+ helperPath,
45
+ "--controller-id",
46
+ "${controller.session_id}",
47
+ "--delivery-id",
48
+ "${envelope.delivery_id}",
49
+ "--message-id",
50
+ "${envelope.message_id}",
51
+ "--idempotency-key",
52
+ "${envelope.idempotency_key}",
53
+ ],
54
+ stdin: "${envelope.body}",
55
+ environment: {
56
+ allow: [CALLBACK_SOCKET_ENV, CALLBACK_TOKEN_ENV],
57
+ },
58
+ timeoutMs: CALLBACK_TIMEOUT_MS,
59
+ maxOutputBytes: CALLBACK_MAX_RESPONSE_BYTES,
60
+ acknowledgement: {
61
+ disposition: {
62
+ jsonPointer: "/result/status",
63
+ mapping: {
64
+ accepted: "accepted",
65
+ retry: "retryable_failure",
66
+ rejected: "permanent_failure",
67
+ unknown: "uncertain",
68
+ },
69
+ },
70
+ acceptanceId: { jsonPointer: "/result/acceptance_id" },
71
+ acknowledgedDeliveryId: { jsonPointer: "/request/delivery_id" },
72
+ acknowledgedMessageId: { jsonPointer: "/request/message_id" },
73
+ },
74
+ },
75
+ });
76
+ try {
77
+ fs.writeFileSync(profilePath, `${JSON.stringify(profile, null, 2)}\n`, {
78
+ encoding: "utf8",
79
+ mode: 0o600,
80
+ flag: "wx",
81
+ });
82
+ }
83
+ catch (error) {
84
+ fs.rmSync(directory, { recursive: true, force: true });
85
+ throw error;
86
+ }
87
+ const environment = (controllerId) => {
88
+ if (!validIdentity(controllerId)) {
89
+ throw new Error("Pi AKK controller id is missing or invalid");
90
+ }
91
+ const base = {
92
+ ...baseEnvironment,
93
+ [CONTROLLER_ID_ENV]: controllerId,
94
+ [CALLBACK_SOCKET_ENV]: socketPath,
95
+ [CALLBACK_TOKEN_ENV]: token,
96
+ };
97
+ const runtime = createTrustedHostProfileRuntime({
98
+ selection: profilePath,
99
+ host: PI_HOST_ID,
100
+ hostVersion: SUPPORTED_PI_VERSION,
101
+ environment: base,
102
+ });
103
+ return hostProfileRelayEnvironment(runtime, base);
104
+ };
105
+ let fingerprint;
106
+ try {
107
+ const validationEnvironment = environment(`akk-pi:${instanceNonce}:profile-validation`);
108
+ const candidate = validationEnvironment.AKK_HOST_PROFILE_FINGERPRINT;
109
+ if (!candidate) {
110
+ throw new Error("AKK Host Adapter did not produce a Profile fingerprint");
111
+ }
112
+ fingerprint = candidate;
113
+ }
114
+ catch (error) {
115
+ fs.rmSync(directory, { recursive: true, force: true });
116
+ throw error;
117
+ }
118
+ let removed = false;
119
+ return Object.freeze({
120
+ instanceNonce,
121
+ directory,
122
+ socketPath,
123
+ stateDirectory,
124
+ token,
125
+ profilePath,
126
+ profile,
127
+ fingerprint,
128
+ environment,
129
+ remove() {
130
+ if (removed)
131
+ return;
132
+ removed = true;
133
+ fs.rmSync(directory, { recursive: true, force: true });
134
+ },
135
+ });
136
+ }
137
+ function resolveStateDirectory(environment) {
138
+ const configured = environment[CONNECTOR_STATE_DIR_ENV];
139
+ if (configured) {
140
+ if (!path.isAbsolute(configured)) {
141
+ throw new Error(`${CONNECTOR_STATE_DIR_ENV} must be an absolute path`);
142
+ }
143
+ return path.resolve(configured);
144
+ }
145
+ return path.join(os.homedir(), ".pi", "agent", "akk");
146
+ }
147
+ function ensurePrivateDirectory(directory) {
148
+ fs.mkdirSync(directory, { recursive: true, mode: 0o700 });
149
+ const stats = fs.lstatSync(directory);
150
+ if (!stats.isDirectory() || stats.isSymbolicLink()) {
151
+ throw new Error("Pi AKK state directory must be a real directory");
152
+ }
153
+ fs.chmodSync(directory, 0o700);
154
+ }
155
+ function validIdentity(value) {
156
+ return value.length > 0 &&
157
+ value.trim() === value &&
158
+ !/[\u0000-\u001f\u007f]/u.test(value);
159
+ }
160
+ //# sourceMappingURL=profile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile.js","sourceRoot":"","sources":["../src/profile.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,71 @@
1
+ import { CallbackInbox } from "./callback-inbox.js";
2
+ export interface CallbackRequest {
3
+ readonly controllerId: string;
4
+ readonly deliveryId: string;
5
+ readonly messageId: string;
6
+ readonly idempotencyKey: string;
7
+ readonly body: string;
8
+ }
9
+ export type CallbackStatus = "accepted" | "retry" | "rejected" | "unknown";
10
+ export interface CallbackAcknowledgement {
11
+ readonly request: {
12
+ readonly delivery_id: string;
13
+ readonly message_id: string;
14
+ };
15
+ readonly result: {
16
+ readonly status: CallbackStatus;
17
+ readonly acceptance_id?: string;
18
+ readonly error_code?: string;
19
+ };
20
+ }
21
+ /** One exact Pi session/branch runtime that may receive AKK callbacks. */
22
+ export interface PiCallbackTarget {
23
+ /** Exact object identity shared with the HostAdapter controller context. */
24
+ readonly authority: object;
25
+ readonly sessionId: string;
26
+ /** Changes when the extension runtime or explicit branch epoch changes. */
27
+ readonly runtimeGeneration: string;
28
+ /** Diagnostic-only snapshot; normal conversation messages advance the leaf. */
29
+ readonly anchorLeafId: string | null;
30
+ isLive(): boolean;
31
+ deliver(body: string, request: CallbackRequest): void | Promise<void>;
32
+ }
33
+ export interface PiCallbackRoute {
34
+ readonly controllerId: string;
35
+ readonly target: PiCallbackTarget;
36
+ readonly sessionId: string;
37
+ readonly runtimeGeneration: string;
38
+ readonly anchorLeafId: string | null;
39
+ }
40
+ /**
41
+ * Exact-object callback routing for a Pi controller incarnation.
42
+ *
43
+ * Admission is durable before an accepted ACK is returned. Delivery into Pi
44
+ * is then at-least-once across the narrow `sendMessage()`/inbox-state window,
45
+ * because Pi 0.84.4 does not expose an admission receipt for that API.
46
+ */
47
+ export declare class PiRouteTable {
48
+ private readonly inbox;
49
+ private readonly routeByAuthority;
50
+ private readonly disposedAuthorities;
51
+ private readonly routeByControllerId;
52
+ private readonly deliveryByKey;
53
+ private readonly retryTimerByKey;
54
+ private readonly retryAttemptByKey;
55
+ private readonly instanceNonce;
56
+ private nextRouteNonce;
57
+ private active;
58
+ constructor(inbox: CallbackInbox, instanceNonce?: string);
59
+ bind(target: PiCallbackTarget): PiCallbackRoute;
60
+ dispose(target: PiCallbackTarget): void;
61
+ deliver(request: CallbackRequest): Promise<CallbackAcknowledgement>;
62
+ close(): Promise<void>;
63
+ private replayPending;
64
+ private ensureDelivery;
65
+ private attemptDelivery;
66
+ private scheduleRetry;
67
+ private cancelRouteRetries;
68
+ private clearRetry;
69
+ private assertActive;
70
+ private routeIsLive;
71
+ }