@cello-protocol/daemon 0.0.3 → 0.0.5

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.
Files changed (153) hide show
  1. package/dist/agent-loader.d.ts +41 -0
  2. package/dist/agent-loader.d.ts.map +1 -0
  3. package/dist/agent-loader.js +94 -0
  4. package/dist/agent-loader.js.map +1 -0
  5. package/dist/bin/cello-daemon.d.ts +13 -0
  6. package/dist/bin/cello-daemon.d.ts.map +1 -0
  7. package/dist/bin/cello-daemon.js +170 -0
  8. package/dist/bin/cello-daemon.js.map +1 -0
  9. package/dist/cello-node-transport-dialer.d.ts +59 -0
  10. package/dist/cello-node-transport-dialer.d.ts.map +1 -0
  11. package/dist/cello-node-transport-dialer.js +108 -0
  12. package/dist/cello-node-transport-dialer.js.map +1 -0
  13. package/dist/challenge-verifier.d.ts +12 -0
  14. package/dist/challenge-verifier.d.ts.map +1 -0
  15. package/dist/challenge-verifier.js +11 -0
  16. package/dist/challenge-verifier.js.map +1 -0
  17. package/dist/connect-or-start.d.ts +25 -0
  18. package/dist/connect-or-start.d.ts.map +1 -0
  19. package/dist/connect-or-start.js +117 -0
  20. package/dist/connect-or-start.js.map +1 -0
  21. package/dist/content-park-client.d.ts +49 -0
  22. package/dist/content-park-client.d.ts.map +1 -0
  23. package/dist/content-park-client.js +196 -0
  24. package/dist/content-park-client.js.map +1 -0
  25. package/dist/daemon.d.ts +65 -0
  26. package/dist/daemon.d.ts.map +1 -0
  27. package/dist/daemon.js +3202 -0
  28. package/dist/daemon.js.map +1 -0
  29. package/dist/directory-bootstrap.d.ts +55 -0
  30. package/dist/directory-bootstrap.d.ts.map +1 -0
  31. package/dist/directory-bootstrap.js +102 -0
  32. package/dist/directory-bootstrap.js.map +1 -0
  33. package/dist/file-manifest-provider.d.ts +18 -0
  34. package/dist/file-manifest-provider.d.ts.map +1 -0
  35. package/dist/file-manifest-provider.js +72 -0
  36. package/dist/file-manifest-provider.js.map +1 -0
  37. package/dist/index.d.ts +18 -0
  38. package/dist/index.d.ts.map +1 -0
  39. package/dist/index.js +18 -0
  40. package/dist/index.js.map +1 -0
  41. package/dist/ipc-client.d.ts +31 -0
  42. package/dist/ipc-client.d.ts.map +1 -0
  43. package/dist/ipc-client.js +112 -0
  44. package/dist/ipc-client.js.map +1 -0
  45. package/dist/ipc-server.d.ts +49 -0
  46. package/dist/ipc-server.d.ts.map +1 -0
  47. package/dist/ipc-server.js +268 -0
  48. package/dist/ipc-server.js.map +1 -0
  49. package/dist/lock-file.d.ts +27 -0
  50. package/dist/lock-file.d.ts.map +1 -0
  51. package/dist/lock-file.js +84 -0
  52. package/dist/lock-file.js.map +1 -0
  53. package/dist/manifest-loader.d.ts +33 -0
  54. package/dist/manifest-loader.d.ts.map +1 -0
  55. package/dist/manifest-loader.js +70 -0
  56. package/dist/manifest-loader.js.map +1 -0
  57. package/dist/manifest-poll-scheduler.d.ts +31 -0
  58. package/dist/manifest-poll-scheduler.d.ts.map +1 -0
  59. package/dist/manifest-poll-scheduler.js +59 -0
  60. package/dist/manifest-poll-scheduler.js.map +1 -0
  61. package/dist/manifest-version-store-file.d.ts +18 -0
  62. package/dist/manifest-version-store-file.d.ts.map +1 -0
  63. package/dist/manifest-version-store-file.js +40 -0
  64. package/dist/manifest-version-store-file.js.map +1 -0
  65. package/dist/manifest-version-store.d.ts +14 -0
  66. package/dist/manifest-version-store.d.ts.map +1 -0
  67. package/dist/manifest-version-store.js +13 -0
  68. package/dist/manifest-version-store.js.map +1 -0
  69. package/dist/network-directory-node.d.ts +94 -0
  70. package/dist/network-directory-node.d.ts.map +1 -0
  71. package/dist/network-directory-node.js +626 -0
  72. package/dist/network-directory-node.js.map +1 -0
  73. package/dist/nonce-dedup.d.ts +68 -0
  74. package/dist/nonce-dedup.d.ts.map +1 -0
  75. package/dist/nonce-dedup.js +204 -0
  76. package/dist/nonce-dedup.js.map +1 -0
  77. package/dist/notification-dispatcher.d.ts +65 -0
  78. package/dist/notification-dispatcher.d.ts.map +1 -0
  79. package/dist/notification-dispatcher.js +138 -0
  80. package/dist/notification-dispatcher.js.map +1 -0
  81. package/dist/registration-context.d.ts +69 -0
  82. package/dist/registration-context.d.ts.map +1 -0
  83. package/dist/registration-context.js +118 -0
  84. package/dist/registration-context.js.map +1 -0
  85. package/dist/registration-manager.d.ts +72 -0
  86. package/dist/registration-manager.d.ts.map +1 -0
  87. package/dist/registration-manager.js +267 -0
  88. package/dist/registration-manager.js.map +1 -0
  89. package/dist/registration-persistence.d.ts +131 -0
  90. package/dist/registration-persistence.d.ts.map +1 -0
  91. package/dist/registration-persistence.js +233 -0
  92. package/dist/registration-persistence.js.map +1 -0
  93. package/dist/retry-queue.d.ts +144 -0
  94. package/dist/retry-queue.d.ts.map +1 -0
  95. package/dist/retry-queue.js +444 -0
  96. package/dist/retry-queue.js.map +1 -0
  97. package/dist/seal-frontier-verify.d.ts +58 -0
  98. package/dist/seal-frontier-verify.d.ts.map +1 -0
  99. package/dist/seal-frontier-verify.js +87 -0
  100. package/dist/seal-frontier-verify.js.map +1 -0
  101. package/dist/seal-legibility-tbs.d.ts +25 -0
  102. package/dist/seal-legibility-tbs.d.ts.map +1 -0
  103. package/dist/seal-legibility-tbs.js +78 -0
  104. package/dist/seal-legibility-tbs.js.map +1 -0
  105. package/dist/seal-upgrade.d.ts +90 -0
  106. package/dist/seal-upgrade.d.ts.map +1 -0
  107. package/dist/seal-upgrade.js +178 -0
  108. package/dist/seal-upgrade.js.map +1 -0
  109. package/dist/session-assignment-parser.d.ts +22 -0
  110. package/dist/session-assignment-parser.d.ts.map +1 -0
  111. package/dist/session-assignment-parser.js +139 -0
  112. package/dist/session-assignment-parser.js.map +1 -0
  113. package/dist/session-ceremony.d.ts +156 -0
  114. package/dist/session-ceremony.d.ts.map +1 -0
  115. package/dist/session-ceremony.js +447 -0
  116. package/dist/session-ceremony.js.map +1 -0
  117. package/dist/session-connection-gater.d.ts +91 -0
  118. package/dist/session-connection-gater.d.ts.map +1 -0
  119. package/dist/session-connection-gater.js +146 -0
  120. package/dist/session-connection-gater.js.map +1 -0
  121. package/dist/session-node-manager.d.ts +585 -0
  122. package/dist/session-node-manager.d.ts.map +1 -0
  123. package/dist/session-node-manager.js +2609 -0
  124. package/dist/session-node-manager.js.map +1 -0
  125. package/dist/session-relay-client.d.ts +101 -0
  126. package/dist/session-relay-client.d.ts.map +1 -0
  127. package/dist/session-relay-client.js +520 -0
  128. package/dist/session-relay-client.js.map +1 -0
  129. package/dist/session-tree.d.ts +80 -0
  130. package/dist/session-tree.d.ts.map +1 -0
  131. package/dist/session-tree.js +123 -0
  132. package/dist/session-tree.js.map +1 -0
  133. package/dist/signaling-connect.d.ts +83 -0
  134. package/dist/signaling-connect.d.ts.map +1 -0
  135. package/dist/signaling-connect.js +266 -0
  136. package/dist/signaling-connect.js.map +1 -0
  137. package/dist/transcript-cipher.d.ts +31 -0
  138. package/dist/transcript-cipher.d.ts.map +1 -0
  139. package/dist/transcript-cipher.js +74 -0
  140. package/dist/transcript-cipher.js.map +1 -0
  141. package/dist/transport-composition.d.ts +31 -0
  142. package/dist/transport-composition.d.ts.map +1 -0
  143. package/dist/transport-composition.js +55 -0
  144. package/dist/transport-composition.js.map +1 -0
  145. package/dist/transport-selector.d.ts +189 -0
  146. package/dist/transport-selector.d.ts.map +1 -0
  147. package/dist/transport-selector.js +195 -0
  148. package/dist/transport-selector.js.map +1 -0
  149. package/dist/types.d.ts +265 -0
  150. package/dist/types.d.ts.map +1 -0
  151. package/dist/types.js +33 -0
  152. package/dist/types.js.map +1 -0
  153. package/package.json +4 -4
@@ -0,0 +1,112 @@
1
+ /**
2
+ * IPC client for connecting to the CELLO daemon.
3
+ *
4
+ * Pseudocode:
5
+ * 1. connectToDaemon(socketPath):
6
+ * a. Create net.Socket
7
+ * b. Connect to Unix domain socket
8
+ * c. Return IpcClient with send(method, params) → Promise<result>
9
+ *
10
+ * 2. send(method, params):
11
+ * a. Generate unique request ID
12
+ * b. Write JSON + newline to socket
13
+ * c. Wait for response with matching ID
14
+ * d. Return result or throw error
15
+ */
16
+ import { createConnection } from "node:net";
17
+ import { randomUUID } from "node:crypto";
18
+ export class IpcError extends Error {
19
+ code;
20
+ guidance;
21
+ constructor(code, message, guidance) {
22
+ super(message);
23
+ this.name = "IpcError";
24
+ this.code = code;
25
+ this.guidance = guidance;
26
+ }
27
+ }
28
+ export function connectToDaemon(socketPath, opts) {
29
+ return new Promise((resolve, reject) => {
30
+ const socket = createConnection(socketPath);
31
+ const pending = new Map();
32
+ let buffer = "";
33
+ let notificationHandler = null;
34
+ const client = {
35
+ send(method, params) {
36
+ return new Promise((res, rej) => {
37
+ if (socket.destroyed) {
38
+ rej(new Error("Socket closed"));
39
+ return;
40
+ }
41
+ const id = randomUUID();
42
+ pending.set(id, { resolve: res, reject: rej });
43
+ const request = { id, method, params };
44
+ socket.write(JSON.stringify(request) + "\n");
45
+ });
46
+ },
47
+ close() {
48
+ socket.end();
49
+ },
50
+ onNotification(handler) {
51
+ notificationHandler = handler;
52
+ },
53
+ };
54
+ socket.on("connect", () => {
55
+ resolve(client);
56
+ });
57
+ socket.on("error", (err) => {
58
+ reject(err);
59
+ for (const [, p] of pending) {
60
+ p.reject(err);
61
+ }
62
+ pending.clear();
63
+ });
64
+ socket.on("data", (chunk) => {
65
+ buffer += chunk.toString("utf-8");
66
+ let newlineIdx;
67
+ while ((newlineIdx = buffer.indexOf("\n")) !== -1) {
68
+ const line = buffer.slice(0, newlineIdx);
69
+ buffer = buffer.slice(newlineIdx + 1);
70
+ if (line.trim().length === 0)
71
+ continue;
72
+ try {
73
+ const frame = JSON.parse(line);
74
+ // Notifications have a "notification" field — they are server-initiated
75
+ // and never correlate to a request.
76
+ if ("notification" in frame) {
77
+ if (notificationHandler) {
78
+ notificationHandler(frame);
79
+ }
80
+ continue;
81
+ }
82
+ // Regular response — correlate by id
83
+ const response = frame;
84
+ const p = pending.get(response.id);
85
+ if (p) {
86
+ pending.delete(response.id);
87
+ if ("error" in response) {
88
+ const errResp = response;
89
+ p.reject(new IpcError(errResp.error.code, errResp.error.message, errResp.error.guidance));
90
+ }
91
+ else {
92
+ p.resolve(response.result);
93
+ }
94
+ }
95
+ }
96
+ catch (err) {
97
+ const msg = err instanceof Error ? err.message : String(err);
98
+ if (opts?.onFrameError) {
99
+ opts.onFrameError(msg);
100
+ }
101
+ }
102
+ }
103
+ });
104
+ socket.on("close", () => {
105
+ for (const [, p] of pending) {
106
+ p.reject(new Error("Connection closed"));
107
+ }
108
+ pending.clear();
109
+ });
110
+ });
111
+ }
112
+ //# sourceMappingURL=ipc-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ipc-client.js","sourceRoot":"","sources":["../src/ipc-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * IPC server for the CELLO daemon.
3
+ *
4
+ * Pseudocode:
5
+ * 1. createIpcServer(config, handlers):
6
+ * a. Create net.Server bound to Unix domain socket
7
+ * b. Set socket permissions to 0o600 (SI-001: owner-only access)
8
+ * c. On connection:
9
+ * - Check connectionCount < maxConnections (16)
10
+ * - If limit reached, send error frame and close
11
+ * - Otherwise, increment counter, assign connectionId
12
+ * - Log daemon.ipc.connected
13
+ * - Set up newline-delimited JSON parser on the socket
14
+ * - For each parsed request, dispatch to handler map
15
+ * - On close, decrement counter, log daemon.ipc.disconnected
16
+ * d. Return server handle with start() and stop() methods
17
+ *
18
+ * 2. IPC framing: JSON-newline-delimited
19
+ * - Each message is a single JSON object followed by \n
20
+ * - Requests: {id: string, method: string, params?: object}
21
+ * - Responses: {id: string, result: any} or {id: string, error: {code, message, guidance}}
22
+ *
23
+ * 3. Graceful shutdown:
24
+ * a. Stop accepting new connections
25
+ * b. Wait for in-flight requests to complete (with timeout)
26
+ * c. Send shutdown frame to all connected clients
27
+ * d. Close all connections
28
+ * e. Unlink socket file
29
+ */
30
+ import type { Logger, IpcNotification } from "./types.js";
31
+ export type IpcHandler = (params: Record<string, unknown> | undefined, connectionId: string) => Promise<unknown>;
32
+ export interface IpcServerConfig {
33
+ socketPath: string;
34
+ maxConnections: number;
35
+ logger: Logger;
36
+ }
37
+ export type IpcDisconnectHandler = (connectionId: string) => void;
38
+ export interface IpcServer {
39
+ start(): Promise<void>;
40
+ stop(): Promise<void>;
41
+ getConnectionCount(): number;
42
+ onDisconnect(handler: IpcDisconnectHandler): void;
43
+ /** Write a notification to a specific connection. Returns false on write failure. */
44
+ sendNotification(connectionId: string, notification: IpcNotification): boolean;
45
+ /** Return all active connection IDs. */
46
+ getConnectionIds(): string[];
47
+ }
48
+ export declare function createIpcServer(config: IpcServerConfig, handlers: Map<string, IpcHandler>): IpcServer;
49
+ //# sourceMappingURL=ipc-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ipc-server.d.ts","sourceRoot":"","sources":["../src/ipc-server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAKH,OAAO,KAAK,EAAE,MAAM,EAA2B,eAAe,EAAE,MAAM,YAAY,CAAC;AAEnF,MAAM,MAAM,UAAU,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAAE,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAEjH,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,oBAAoB,GAAG,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;AAElE,MAAM,WAAW,SAAS;IACxB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,kBAAkB,IAAI,MAAM,CAAC;IAC7B,YAAY,CAAC,OAAO,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAClD,qFAAqF;IACrF,gBAAgB,CAAC,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,eAAe,GAAG,OAAO,CAAC;IAC/E,wCAAwC;IACxC,gBAAgB,IAAI,MAAM,EAAE,CAAC;CAC9B;AASD,wBAAgB,eAAe,CAC7B,MAAM,EAAE,eAAe,EACvB,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,GAChC,SAAS,CAyPX"}
@@ -0,0 +1,268 @@
1
+ /**
2
+ * IPC server for the CELLO daemon.
3
+ *
4
+ * Pseudocode:
5
+ * 1. createIpcServer(config, handlers):
6
+ * a. Create net.Server bound to Unix domain socket
7
+ * b. Set socket permissions to 0o600 (SI-001: owner-only access)
8
+ * c. On connection:
9
+ * - Check connectionCount < maxConnections (16)
10
+ * - If limit reached, send error frame and close
11
+ * - Otherwise, increment counter, assign connectionId
12
+ * - Log daemon.ipc.connected
13
+ * - Set up newline-delimited JSON parser on the socket
14
+ * - For each parsed request, dispatch to handler map
15
+ * - On close, decrement counter, log daemon.ipc.disconnected
16
+ * d. Return server handle with start() and stop() methods
17
+ *
18
+ * 2. IPC framing: JSON-newline-delimited
19
+ * - Each message is a single JSON object followed by \n
20
+ * - Requests: {id: string, method: string, params?: object}
21
+ * - Responses: {id: string, result: any} or {id: string, error: {code, message, guidance}}
22
+ *
23
+ * 3. Graceful shutdown:
24
+ * a. Stop accepting new connections
25
+ * b. Wait for in-flight requests to complete (with timeout)
26
+ * c. Send shutdown frame to all connected clients
27
+ * d. Close all connections
28
+ * e. Unlink socket file
29
+ */
30
+ import { createServer } from "node:net";
31
+ import { chmod, unlink } from "node:fs/promises";
32
+ import { randomUUID } from "node:crypto";
33
+ export function createIpcServer(config, handlers) {
34
+ const { socketPath, maxConnections, logger } = config;
35
+ let server = null;
36
+ const connections = new Map();
37
+ let stopping = false;
38
+ let disconnectHandler = null;
39
+ function handleConnection(socket) {
40
+ if (stopping) {
41
+ socket.destroy();
42
+ return;
43
+ }
44
+ if (connections.size >= maxConnections) {
45
+ logger.warn("daemon.ipc.connection.limit.reached", {
46
+ currentCount: connections.size,
47
+ maxCount: maxConnections,
48
+ });
49
+ // Destroy immediately — the client has no pending requests to correlate
50
+ // an error response against. Client's connectToDaemon() will reject with
51
+ // a socket error, which is the correct signal.
52
+ socket.destroy();
53
+ return;
54
+ }
55
+ const connectionId = randomUUID();
56
+ const conn = { id: connectionId, socket, inFlightCount: 0, shutdownReason: null };
57
+ connections.set(connectionId, conn);
58
+ logger.info("daemon.ipc.accepted", { connectionId });
59
+ // CELLO-M7-MSG-001: the IPC buffer cap MUST exceed the application content cap
60
+ // (MAX_CONTENT_BYTES = 1 MB) plus the JSON request envelope, or a max-size
61
+ // cello_send message would trip this overflow and the connection would be killed
62
+ // BEFORE cello_send's content_too_large check could run — turning a clean,
63
+ // recoverable "content_too_large" into a fatal connection drop, and making even a
64
+ // VALID 1 MB message unsendable. 4 MB matches the it-length-prefixed transport
65
+ // default (IT_LENGTH_PREFIX_DEFAULT_MAX) so the IPC, app-cap, and transport layers
66
+ // are coherent: content up to the 1 MB cap always traverses IPC, oversize content
67
+ // reaches cello_send and is rejected with content_too_large, and only a payload
68
+ // beyond the transport frame is a hard stop. Must stay in sync with the matching
69
+ // constant in adapter-claude-code/src/ipc-proxy.ts.
70
+ const MAX_BUFFER_SIZE = 4 * 1024 * 1024; // 4MB per connection (> 1MB content cap + envelope)
71
+ let buffer = "";
72
+ socket.on("data", (chunk) => {
73
+ buffer += chunk.toString("utf-8");
74
+ if (buffer.length > MAX_BUFFER_SIZE) {
75
+ logger.warn("daemon.ipc.buffer.overflow", { connectionId, bufferSize: buffer.length });
76
+ buffer = "";
77
+ socket.removeAllListeners("data");
78
+ socket.destroy();
79
+ return;
80
+ }
81
+ let newlineIdx;
82
+ while ((newlineIdx = buffer.indexOf("\n")) !== -1) {
83
+ const line = buffer.slice(0, newlineIdx);
84
+ buffer = buffer.slice(newlineIdx + 1);
85
+ if (line.trim().length === 0)
86
+ continue;
87
+ handleMessage(conn, line);
88
+ }
89
+ });
90
+ socket.on("close", () => {
91
+ connections.delete(connectionId);
92
+ const reason = conn.shutdownReason || "client_closed";
93
+ logger.info("daemon.ipc.disconnected", { connectionId, reason });
94
+ if (disconnectHandler)
95
+ disconnectHandler(connectionId);
96
+ });
97
+ // Set shutdownReason so the 'close' handler (which always fires after 'error') logs it.
98
+ // Do NOT call disconnectHandler or log here — 'close' fires immediately after 'error'.
99
+ socket.on("error", (err) => {
100
+ conn.shutdownReason = err.message;
101
+ });
102
+ }
103
+ function handleMessage(conn, line) {
104
+ let request;
105
+ try {
106
+ request = JSON.parse(line);
107
+ }
108
+ catch {
109
+ // Cannot recover the request ID from unparseable input.
110
+ // Close the connection — client's pending promises will all reject
111
+ // with "Connection closed", which correctly propagates the failure.
112
+ logger.warn("daemon.ipc.parse.error", { connectionId: conn.id });
113
+ conn.socket.destroy();
114
+ return;
115
+ }
116
+ if (!request.id || !request.method) {
117
+ // If id is missing/falsy, we can't correlate an error response.
118
+ // Close the connection rather than sending an unmatchable frame.
119
+ logger.warn("daemon.ipc.invalid.request", { connectionId: conn.id, hasId: !!request.id, hasMethod: !!request.method });
120
+ conn.socket.destroy();
121
+ return;
122
+ }
123
+ const handler = handlers.get(request.method);
124
+ if (!handler) {
125
+ const errorResp = {
126
+ id: request.id,
127
+ error: {
128
+ code: "method_not_found",
129
+ message: `Unknown method: ${request.method}`,
130
+ guidance: `Unknown IPC method '${request.method}'. Check that cello-mcp and the daemon are the same version. Run 'cello status' to verify the daemon is running.`,
131
+ },
132
+ };
133
+ conn.socket.write(JSON.stringify(errorResp) + "\n");
134
+ return;
135
+ }
136
+ conn.inFlightCount++;
137
+ Promise.resolve(handler(request.params, conn.id))
138
+ .then((result) => {
139
+ try {
140
+ const resp = { id: request.id, result };
141
+ conn.socket.write(JSON.stringify(resp) + "\n");
142
+ }
143
+ catch {
144
+ // Socket closed before response could be written
145
+ }
146
+ })
147
+ .catch((err) => {
148
+ try {
149
+ const resp = {
150
+ id: request.id,
151
+ error: {
152
+ code: "internal_error",
153
+ message: err instanceof Error ? err.message : String(err),
154
+ guidance: "An unexpected error occurred. Check daemon logs for details.",
155
+ },
156
+ };
157
+ conn.socket.write(JSON.stringify(resp) + "\n");
158
+ }
159
+ catch {
160
+ // Socket closed before error could be written
161
+ }
162
+ })
163
+ .finally(() => {
164
+ conn.inFlightCount--;
165
+ });
166
+ }
167
+ return {
168
+ async start() {
169
+ // Remove stale socket file if it exists
170
+ try {
171
+ await unlink(socketPath);
172
+ }
173
+ catch (err) {
174
+ if (err.code !== "ENOENT") {
175
+ throw err;
176
+ }
177
+ }
178
+ server = createServer(handleConnection);
179
+ await new Promise((resolve, reject) => {
180
+ server.on("error", (err) => {
181
+ reject(err);
182
+ });
183
+ server.listen(socketPath, () => {
184
+ resolve();
185
+ });
186
+ });
187
+ // SI-001: Set socket permissions to owner-only
188
+ await chmod(socketPath, 0o600);
189
+ },
190
+ async stop() {
191
+ stopping = true;
192
+ if (!server)
193
+ return;
194
+ // Wait for in-flight requests to complete (max 5 seconds)
195
+ const deadline = Date.now() + 5000;
196
+ let totalInFlight = 0;
197
+ while (Date.now() < deadline) {
198
+ totalInFlight = 0;
199
+ for (const conn of connections.values()) {
200
+ totalInFlight += conn.inFlightCount;
201
+ }
202
+ if (totalInFlight === 0)
203
+ break;
204
+ await new Promise((r) => setTimeout(r, 50));
205
+ }
206
+ if (totalInFlight > 0) {
207
+ logger.warn("daemon.ipc.shutdown.timeout", { abandonedRequests: totalInFlight });
208
+ }
209
+ // Send shutdown notification to all connected clients.
210
+ // Uses IpcNotification shape — distinct from IpcResponse so clients
211
+ // never confuse it with a response to their request.
212
+ const shutdownNotification = { notification: "shutdown" };
213
+ const shutdownFrame = JSON.stringify(shutdownNotification) + "\n";
214
+ for (const conn of connections.values()) {
215
+ try {
216
+ conn.shutdownReason = "daemon_shutdown";
217
+ conn.socket.write(shutdownFrame);
218
+ conn.socket.end();
219
+ }
220
+ catch {
221
+ // Connection may already be closed
222
+ }
223
+ }
224
+ // Close server and remove socket
225
+ await new Promise((resolve) => {
226
+ server.close(() => resolve());
227
+ });
228
+ try {
229
+ await unlink(socketPath);
230
+ }
231
+ catch (err) {
232
+ if (err.code !== "ENOENT") {
233
+ logger.warn("daemon.ipc.socket.unlink.failed", {
234
+ socketPath,
235
+ error: err instanceof Error ? err.message : String(err),
236
+ });
237
+ }
238
+ }
239
+ server = null;
240
+ },
241
+ getConnectionCount() {
242
+ return connections.size;
243
+ },
244
+ onDisconnect(handler) {
245
+ disconnectHandler = handler;
246
+ },
247
+ sendNotification(connectionId, notification) {
248
+ const conn = connections.get(connectionId);
249
+ if (!conn)
250
+ return false;
251
+ try {
252
+ const frame = JSON.stringify(notification) + "\n";
253
+ return conn.socket.write(frame);
254
+ }
255
+ catch (err) {
256
+ logger.debug("daemon.ipc.notification.write.failed", {
257
+ connectionId,
258
+ error: err instanceof Error ? err.message : String(err),
259
+ });
260
+ return false;
261
+ }
262
+ },
263
+ getConnectionIds() {
264
+ return Array.from(connections.keys());
265
+ },
266
+ };
267
+ }
268
+ //# sourceMappingURL=ipc-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ipc-server.js","sourceRoot":"","sources":["../src/ipc-server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Lock file management for the CELLO daemon.
3
+ *
4
+ * Pseudocode:
5
+ * 1. acquireLock(path, content):
6
+ * - Write JSON content to path.tmp atomically
7
+ * - Rename path.tmp → path (atomic on POSIX)
8
+ * - Return true on success
9
+ *
10
+ * 2. readLock(path):
11
+ * - Read file, parse JSON
12
+ * - Validate shape: {pid: number, socketPath: string, version: string}
13
+ * - Return parsed content or null if missing/invalid
14
+ *
15
+ * 3. isProcessAlive(pid):
16
+ * - process.kill(pid, 0) — signal 0 checks existence without killing
17
+ * - Return true if no error thrown
18
+ *
19
+ * 4. removeLock(path):
20
+ * - Unlink the file, ignoring ENOENT
21
+ */
22
+ import type { LockFileContent, Logger } from "./types.js";
23
+ export declare function readLock(lockPath: string): Promise<LockFileContent | null>;
24
+ export declare function acquireLock(lockPath: string, content: LockFileContent): Promise<void>;
25
+ export declare function removeLock(lockPath: string, logger: Logger): Promise<void>;
26
+ export declare function isProcessAlive(pid: number): boolean;
27
+ //# sourceMappingURL=lock-file.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lock-file.d.ts","sourceRoot":"","sources":["../src/lock-file.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAE1D,wBAAsB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAwBhF;AAED,wBAAsB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAU3F;AAED,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAWhF;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAOnD"}
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Lock file management for the CELLO daemon.
3
+ *
4
+ * Pseudocode:
5
+ * 1. acquireLock(path, content):
6
+ * - Write JSON content to path.tmp atomically
7
+ * - Rename path.tmp → path (atomic on POSIX)
8
+ * - Return true on success
9
+ *
10
+ * 2. readLock(path):
11
+ * - Read file, parse JSON
12
+ * - Validate shape: {pid: number, socketPath: string, version: string}
13
+ * - Return parsed content or null if missing/invalid
14
+ *
15
+ * 3. isProcessAlive(pid):
16
+ * - process.kill(pid, 0) — signal 0 checks existence without killing
17
+ * - Return true if no error thrown
18
+ *
19
+ * 4. removeLock(path):
20
+ * - Unlink the file, ignoring ENOENT
21
+ */
22
+ import { readFile, writeFile, rename, unlink } from "node:fs/promises";
23
+ export async function readLock(lockPath) {
24
+ let raw;
25
+ try {
26
+ raw = await readFile(lockPath, "utf-8");
27
+ }
28
+ catch (err) {
29
+ if (err.code === "ENOENT") {
30
+ return null;
31
+ }
32
+ throw err;
33
+ }
34
+ try {
35
+ const parsed = JSON.parse(raw);
36
+ if (typeof parsed.pid !== "number" ||
37
+ typeof parsed.socketPath !== "string" ||
38
+ typeof parsed.version !== "string") {
39
+ return null;
40
+ }
41
+ return { pid: parsed.pid, socketPath: parsed.socketPath, version: parsed.version };
42
+ }
43
+ catch {
44
+ return null;
45
+ }
46
+ }
47
+ export async function acquireLock(lockPath, content) {
48
+ const tmpPath = lockPath + ".tmp";
49
+ const json = JSON.stringify(content, null, 2) + "\n";
50
+ await writeFile(tmpPath, json, { mode: 0o600 });
51
+ try {
52
+ await rename(tmpPath, lockPath);
53
+ }
54
+ catch (err) {
55
+ try {
56
+ await unlink(tmpPath);
57
+ }
58
+ catch { /* best-effort cleanup */ }
59
+ throw err;
60
+ }
61
+ }
62
+ export async function removeLock(lockPath, logger) {
63
+ try {
64
+ await unlink(lockPath);
65
+ }
66
+ catch (err) {
67
+ if (err.code !== "ENOENT") {
68
+ logger.warn("daemon.lock.remove.failed", {
69
+ lockPath,
70
+ error: err instanceof Error ? err.message : String(err),
71
+ });
72
+ }
73
+ }
74
+ }
75
+ export function isProcessAlive(pid) {
76
+ try {
77
+ process.kill(pid, 0);
78
+ return true;
79
+ }
80
+ catch {
81
+ return false;
82
+ }
83
+ }
84
+ //# sourceMappingURL=lock-file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lock-file.js","sourceRoot":"","sources":["../src/lock-file.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAGvE,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,QAAgB;IAC7C,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC1C,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACrD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAA4B,CAAC;QAC1D,IACE,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ;YAC9B,OAAO,MAAM,CAAC,UAAU,KAAK,QAAQ;YACrC,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,EAClC,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;IACrF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,QAAgB,EAAE,OAAwB;IAC1E,MAAM,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;IAClC,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC;IACrD,MAAM,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAChD,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAClC,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,IAAI,CAAC;YAAC,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,yBAAyB,CAAC,CAAC;QAClE,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,QAAgB,EAAE,MAAc;IAC/D,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;IACzB,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACrD,MAAM,CAAC,IAAI,CAAC,2BAA2B,EAAE;gBACvC,QAAQ;gBACR,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;aACxD,CAAC,CAAC;QACL,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACrB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * M7-MANIFEST-002 — FileManifestProvider: production IManifestProvider implementation.
3
+ *
4
+ * Reads the bundled consortium-manifest.json from the package root, parses it,
5
+ * verifies the threshold signatures, and caches the result for subsequent calls
6
+ * to getCurrentManifest().
7
+ *
8
+ * Tests use TestManifestProvider (from @cello-protocol/transport) which
9
+ * takes a pre-built ConsortiumManifest and skips file read and signature verification.
10
+ *
11
+ * Crypto reference: RFC 8032 (Ed25519 threshold signature verification via verifyManifest).
12
+ */
13
+ import type { ConsortiumManifest } from "@cello-protocol/protocol-types";
14
+ import type { IManifestProvider } from "@cello-protocol/transport";
15
+ /**
16
+ * FileManifestProvider — reads consortium-manifest.json from the package root.
17
+ *
18
+ * Pseudocode:
19
+ * loadAndVerify(rootKeys, threshold):
20
+ * 1. Read consortium-manifest.json from the package root (same directory as this file).
21
+ * 2. Parse as JSON — throw on parse failure.
22
+ * 3. Call verifyManifest(parsed, rootKeys, threshold) — RFC 8032 Ed25519 threshold check.
23
+ * 4. If ok: cache the manifest, return it.
24
+ * 5. If not ok: throw Error with reason from verifyManifest diagnostics.
25
+ */
26
+ export declare class FileManifestProvider implements IManifestProvider {
27
+ #private;
28
+ constructor(manifestPath?: string);
29
+ loadAndVerify(rootKeys: readonly string[], threshold: number): Promise<ConsortiumManifest>;
30
+ getCurrentManifest(): ConsortiumManifest | null;
31
+ updateManifest(manifest: ConsortiumManifest): void;
32
+ }
33
+ //# sourceMappingURL=manifest-loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest-loader.d.ts","sourceRoot":"","sources":["../src/manifest-loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAOH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAEnE;;;;;;;;;;GAUG;AACH,qBAAa,oBAAqB,YAAW,iBAAiB;;gBAIhD,YAAY,CAAC,EAAE,MAAM;IAQ3B,aAAa,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAmChG,kBAAkB,IAAI,kBAAkB,GAAG,IAAI;IAI/C,cAAc,CAAC,QAAQ,EAAE,kBAAkB,GAAG,IAAI;CAGnD"}