peerllm-host-cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (190) hide show
  1. package/LICENSE +19 -0
  2. package/README.md +83 -0
  3. package/dist/cli/commands/agreement.d.ts +3 -0
  4. package/dist/cli/commands/agreement.d.ts.map +1 -0
  5. package/dist/cli/commands/agreement.js +151 -0
  6. package/dist/cli/commands/agreement.js.map +1 -0
  7. package/dist/cli/commands/config.d.ts +3 -0
  8. package/dist/cli/commands/config.d.ts.map +1 -0
  9. package/dist/cli/commands/config.js +163 -0
  10. package/dist/cli/commands/config.js.map +1 -0
  11. package/dist/cli/commands/diagnostics.d.ts +3 -0
  12. package/dist/cli/commands/diagnostics.d.ts.map +1 -0
  13. package/dist/cli/commands/diagnostics.js +131 -0
  14. package/dist/cli/commands/diagnostics.js.map +1 -0
  15. package/dist/cli/commands/doctor.d.ts +3 -0
  16. package/dist/cli/commands/doctor.d.ts.map +1 -0
  17. package/dist/cli/commands/doctor.js +349 -0
  18. package/dist/cli/commands/doctor.js.map +1 -0
  19. package/dist/cli/commands/events.d.ts +3 -0
  20. package/dist/cli/commands/events.d.ts.map +1 -0
  21. package/dist/cli/commands/events.js +51 -0
  22. package/dist/cli/commands/events.js.map +1 -0
  23. package/dist/cli/commands/host.d.ts +3 -0
  24. package/dist/cli/commands/host.d.ts.map +1 -0
  25. package/dist/cli/commands/host.js +252 -0
  26. package/dist/cli/commands/host.js.map +1 -0
  27. package/dist/cli/commands/login.d.ts +3 -0
  28. package/dist/cli/commands/login.d.ts.map +1 -0
  29. package/dist/cli/commands/login.js +51 -0
  30. package/dist/cli/commands/login.js.map +1 -0
  31. package/dist/cli/commands/logout.d.ts +3 -0
  32. package/dist/cli/commands/logout.d.ts.map +1 -0
  33. package/dist/cli/commands/logout.js +28 -0
  34. package/dist/cli/commands/logout.js.map +1 -0
  35. package/dist/cli/commands/logs.d.ts +3 -0
  36. package/dist/cli/commands/logs.d.ts.map +1 -0
  37. package/dist/cli/commands/logs.js +157 -0
  38. package/dist/cli/commands/logs.js.map +1 -0
  39. package/dist/cli/commands/models.d.ts +3 -0
  40. package/dist/cli/commands/models.d.ts.map +1 -0
  41. package/dist/cli/commands/models.js +227 -0
  42. package/dist/cli/commands/models.js.map +1 -0
  43. package/dist/cli/commands/register.d.ts +3 -0
  44. package/dist/cli/commands/register.d.ts.map +1 -0
  45. package/dist/cli/commands/register.js +48 -0
  46. package/dist/cli/commands/register.js.map +1 -0
  47. package/dist/cli/commands/restart.d.ts +3 -0
  48. package/dist/cli/commands/restart.d.ts.map +1 -0
  49. package/dist/cli/commands/restart.js +66 -0
  50. package/dist/cli/commands/restart.js.map +1 -0
  51. package/dist/cli/commands/service.d.ts +3 -0
  52. package/dist/cli/commands/service.d.ts.map +1 -0
  53. package/dist/cli/commands/service.js +194 -0
  54. package/dist/cli/commands/service.js.map +1 -0
  55. package/dist/cli/commands/setup.d.ts +3 -0
  56. package/dist/cli/commands/setup.d.ts.map +1 -0
  57. package/dist/cli/commands/setup.js +242 -0
  58. package/dist/cli/commands/setup.js.map +1 -0
  59. package/dist/cli/commands/start.d.ts +3 -0
  60. package/dist/cli/commands/start.d.ts.map +1 -0
  61. package/dist/cli/commands/start.js +125 -0
  62. package/dist/cli/commands/start.js.map +1 -0
  63. package/dist/cli/commands/status.d.ts +3 -0
  64. package/dist/cli/commands/status.d.ts.map +1 -0
  65. package/dist/cli/commands/status.js +76 -0
  66. package/dist/cli/commands/status.js.map +1 -0
  67. package/dist/cli/commands/stop.d.ts +3 -0
  68. package/dist/cli/commands/stop.d.ts.map +1 -0
  69. package/dist/cli/commands/stop.js +46 -0
  70. package/dist/cli/commands/stop.js.map +1 -0
  71. package/dist/cli/commands/subscription.d.ts +3 -0
  72. package/dist/cli/commands/subscription.d.ts.map +1 -0
  73. package/dist/cli/commands/subscription.js +342 -0
  74. package/dist/cli/commands/subscription.js.map +1 -0
  75. package/dist/cli/exit-codes.d.ts +12 -0
  76. package/dist/cli/exit-codes.d.ts.map +1 -0
  77. package/dist/cli/exit-codes.js +11 -0
  78. package/dist/cli/exit-codes.js.map +1 -0
  79. package/dist/cli/format.d.ts +8 -0
  80. package/dist/cli/format.d.ts.map +1 -0
  81. package/dist/cli/format.js +22 -0
  82. package/dist/cli/format.js.map +1 -0
  83. package/dist/cli/index.d.ts +3 -0
  84. package/dist/cli/index.d.ts.map +1 -0
  85. package/dist/cli/index.js +88 -0
  86. package/dist/cli/index.js.map +1 -0
  87. package/dist/cli/ipc-client.d.ts +20 -0
  88. package/dist/cli/ipc-client.d.ts.map +1 -0
  89. package/dist/cli/ipc-client.js +101 -0
  90. package/dist/cli/ipc-client.js.map +1 -0
  91. package/dist/cli/prompts.d.ts +5 -0
  92. package/dist/cli/prompts.d.ts.map +1 -0
  93. package/dist/cli/prompts.js +68 -0
  94. package/dist/cli/prompts.js.map +1 -0
  95. package/dist/cli/services.d.ts +18 -0
  96. package/dist/cli/services.d.ts.map +1 -0
  97. package/dist/cli/services.js +16 -0
  98. package/dist/cli/services.js.map +1 -0
  99. package/dist/core/auth.d.ts +24 -0
  100. package/dist/core/auth.d.ts.map +1 -0
  101. package/dist/core/auth.js +111 -0
  102. package/dist/core/auth.js.map +1 -0
  103. package/dist/core/backend-client.d.ts +33 -0
  104. package/dist/core/backend-client.d.ts.map +1 -0
  105. package/dist/core/backend-client.js +79 -0
  106. package/dist/core/backend-client.js.map +1 -0
  107. package/dist/core/config.d.ts +21 -0
  108. package/dist/core/config.d.ts.map +1 -0
  109. package/dist/core/config.js +98 -0
  110. package/dist/core/config.js.map +1 -0
  111. package/dist/core/events.d.ts +23 -0
  112. package/dist/core/events.d.ts.map +1 -0
  113. package/dist/core/events.js +15 -0
  114. package/dist/core/events.js.map +1 -0
  115. package/dist/core/fs-lock.d.ts +13 -0
  116. package/dist/core/fs-lock.d.ts.map +1 -0
  117. package/dist/core/fs-lock.js +52 -0
  118. package/dist/core/fs-lock.js.map +1 -0
  119. package/dist/core/jsonrpc.d.ts +55 -0
  120. package/dist/core/jsonrpc.d.ts.map +1 -0
  121. package/dist/core/jsonrpc.js +59 -0
  122. package/dist/core/jsonrpc.js.map +1 -0
  123. package/dist/core/logger.d.ts +28 -0
  124. package/dist/core/logger.d.ts.map +1 -0
  125. package/dist/core/logger.js +80 -0
  126. package/dist/core/logger.js.map +1 -0
  127. package/dist/core/model-info.d.ts +11 -0
  128. package/dist/core/model-info.d.ts.map +1 -0
  129. package/dist/core/model-info.js +137 -0
  130. package/dist/core/model-info.js.map +1 -0
  131. package/dist/core/models-fs.d.ts +6 -0
  132. package/dist/core/models-fs.d.ts.map +1 -0
  133. package/dist/core/models-fs.js +21 -0
  134. package/dist/core/models-fs.js.map +1 -0
  135. package/dist/core/orchestrator.d.ts +42 -0
  136. package/dist/core/orchestrator.d.ts.map +1 -0
  137. package/dist/core/orchestrator.js +304 -0
  138. package/dist/core/orchestrator.js.map +1 -0
  139. package/dist/core/paths.d.ts +17 -0
  140. package/dist/core/paths.d.ts.map +1 -0
  141. package/dist/core/paths.js +51 -0
  142. package/dist/core/paths.js.map +1 -0
  143. package/dist/core/redact.d.ts +3 -0
  144. package/dist/core/redact.d.ts.map +1 -0
  145. package/dist/core/redact.js +27 -0
  146. package/dist/core/redact.js.map +1 -0
  147. package/dist/core/secrets.d.ts +12 -0
  148. package/dist/core/secrets.d.ts.map +1 -0
  149. package/dist/core/secrets.js +66 -0
  150. package/dist/core/secrets.js.map +1 -0
  151. package/dist/core/shared-runner.d.ts +70 -0
  152. package/dist/core/shared-runner.d.ts.map +1 -0
  153. package/dist/core/shared-runner.js +450 -0
  154. package/dist/core/shared-runner.js.map +1 -0
  155. package/dist/core/subscription.d.ts +53 -0
  156. package/dist/core/subscription.d.ts.map +1 -0
  157. package/dist/core/subscription.js +117 -0
  158. package/dist/core/subscription.js.map +1 -0
  159. package/dist/daemon/index.d.ts +3 -0
  160. package/dist/daemon/index.d.ts.map +1 -0
  161. package/dist/daemon/index.js +22 -0
  162. package/dist/daemon/index.js.map +1 -0
  163. package/dist/daemon/ipc-server.d.ts +33 -0
  164. package/dist/daemon/ipc-server.d.ts.map +1 -0
  165. package/dist/daemon/ipc-server.js +202 -0
  166. package/dist/daemon/ipc-server.js.map +1 -0
  167. package/dist/daemon/methods.d.ts +17 -0
  168. package/dist/daemon/methods.d.ts.map +1 -0
  169. package/dist/daemon/methods.js +68 -0
  170. package/dist/daemon/methods.js.map +1 -0
  171. package/dist/daemon/pid-lock.d.ts +10 -0
  172. package/dist/daemon/pid-lock.d.ts.map +1 -0
  173. package/dist/daemon/pid-lock.js +45 -0
  174. package/dist/daemon/pid-lock.js.map +1 -0
  175. package/dist/daemon/run.d.ts +19 -0
  176. package/dist/daemon/run.d.ts.map +1 -0
  177. package/dist/daemon/run.js +182 -0
  178. package/dist/daemon/run.js.map +1 -0
  179. package/dist/shared/config-types.d.ts +27 -0
  180. package/dist/shared/config-types.d.ts.map +1 -0
  181. package/dist/shared/config-types.js +13 -0
  182. package/dist/shared/config-types.js.map +1 -0
  183. package/dist/shared/protocol.d.ts +43 -0
  184. package/dist/shared/protocol.d.ts.map +1 -0
  185. package/dist/shared/protocol.js +11 -0
  186. package/dist/shared/protocol.js.map +1 -0
  187. package/package.json +70 -0
  188. package/templates/launchd/com.peerllm.host.plist +25 -0
  189. package/templates/systemd/peerllm-host.service +17 -0
  190. package/templates/windows/install-service.ps1 +29 -0
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env node
2
+ import { runDaemon } from "./run.js";
3
+ const args = process.argv.slice(2);
4
+ const configDirIdx = args.indexOf("--config-dir");
5
+ const configDir = configDirIdx >= 0 ? args[configDirIdx + 1] : undefined;
6
+ const cliVersion = process.env["npm_package_version"] ?? "0.1.0";
7
+ async function main() {
8
+ try {
9
+ const daemon = await runDaemon({ configDir, cliVersion });
10
+ process.stdout.write(`peerllm-hostd: listening on ${daemon.state.paths.ipcEndpoint}\n`);
11
+ process.stdout.write(`peerllm-hostd: pid ${daemon.state.pid}\n`);
12
+ await daemon.whenStopped;
13
+ process.exit(0);
14
+ }
15
+ catch (err) {
16
+ const e = err;
17
+ process.stderr.write(`peerllm-hostd: ${e.message}\n`);
18
+ process.exit(e.exitCode ?? 1);
19
+ }
20
+ }
21
+ void main();
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/daemon/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAErC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,YAAY,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAEzE,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,IAAI,OAAO,CAAC;AAEjE,KAAK,UAAU,IAAI;IACjB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC,CAAC;QAC1D,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,+BAA+B,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,IAAI,CAAC,CAAC;QACxF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,sBAAsB,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC;QACjE,MAAM,MAAM,CAAC,WAAW,CAAC;QACzB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,GAAG,GAAoC,CAAC;QAC/C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC;QACtD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC;IAChC,CAAC;AACH,CAAC;AAED,KAAK,IAAI,EAAE,CAAC"}
@@ -0,0 +1,33 @@
1
+ import { type Socket } from "node:net";
2
+ import { DaemonEventBus } from "../core/events.js";
3
+ export type MethodHandler = (params: unknown, ctx: MethodContext) => Promise<unknown> | unknown;
4
+ export interface MethodContext {
5
+ closeConnection: () => void;
6
+ closeServer: () => Promise<void>;
7
+ sendNotification: (method: string, params: unknown) => void;
8
+ socket: Socket;
9
+ }
10
+ export interface IpcServerOptions {
11
+ endpoint: string;
12
+ methods: Record<string, MethodHandler>;
13
+ onShutdownRequested: () => Promise<void> | void;
14
+ events?: DaemonEventBus;
15
+ }
16
+ export declare class IpcServer {
17
+ private readonly opts;
18
+ private server;
19
+ private readonly sockets;
20
+ private readonly subscriptions;
21
+ private readonly busListenerOffs;
22
+ constructor(opts: IpcServerOptions);
23
+ private attachEventBus;
24
+ private broadcast;
25
+ private subscribe;
26
+ private unsubscribeAll;
27
+ listen(): Promise<void>;
28
+ close(): Promise<void>;
29
+ private handleConnection;
30
+ private handleMessage;
31
+ private writeError;
32
+ }
33
+ //# sourceMappingURL=ipc-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ipc-server.d.ts","sourceRoot":"","sources":["../../src/daemon/ipc-server.ts"],"names":[],"mappings":"AACA,OAAO,EAA6B,KAAK,MAAM,EAAE,MAAM,UAAU,CAAC;AAGlE,OAAO,EAAE,cAAc,EAA6C,MAAM,mBAAmB,CAAC;AAU9F,MAAM,MAAM,aAAa,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;AAEhG,MAAM,WAAW,aAAa;IAC5B,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAC5D,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACvC,mBAAmB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAChD,MAAM,CAAC,EAAE,cAAc,CAAC;CACzB;AAID,qBAAa,SAAS;IAMR,OAAO,CAAC,QAAQ,CAAC,IAAI;IALjC,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;IAC7C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAuC;IACrE,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAyB;gBAE5B,IAAI,EAAE,gBAAgB;IAInD,OAAO,CAAC,cAAc;IAUtB,OAAO,CAAC,SAAS;IAiBjB,OAAO,CAAC,SAAS;IASjB,OAAO,CAAC,cAAc;IAIhB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAsBvB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAkB5B,OAAO,CAAC,gBAAgB;YAsBV,aAAa;IAuF3B,OAAO,CAAC,UAAU;CAanB"}
@@ -0,0 +1,202 @@
1
+ import { chmodSync, existsSync, unlinkSync } from "node:fs";
2
+ import { createServer } from "node:net";
3
+ import { platform } from "node:os";
4
+ import { isRequest, LineFramer, RPC_ERROR, RpcError, } from "../core/jsonrpc.js";
5
+ export class IpcServer {
6
+ opts;
7
+ server;
8
+ sockets = new Set();
9
+ subscriptions = new Map();
10
+ busListenerOffs = [];
11
+ constructor(opts) {
12
+ this.opts = opts;
13
+ if (opts.events)
14
+ this.attachEventBus(opts.events);
15
+ }
16
+ attachEventBus(bus) {
17
+ const names = ["hostStats", "orchestratorStatus", "log"];
18
+ for (const name of names) {
19
+ const off = bus.on(name, (payload) => {
20
+ this.broadcast(name, payload);
21
+ });
22
+ this.busListenerOffs.push(off);
23
+ }
24
+ }
25
+ broadcast(name, payload) {
26
+ const notification = JSON.stringify({
27
+ jsonrpc: "2.0",
28
+ method: `event:${name}`,
29
+ params: payload,
30
+ });
31
+ for (const [socket, filters] of this.subscriptions.entries()) {
32
+ if (filters.has("*") || filters.has(name)) {
33
+ try {
34
+ socket.write(notification + "\n");
35
+ }
36
+ catch {
37
+ // Socket dead — cleanup happens on close.
38
+ }
39
+ }
40
+ }
41
+ }
42
+ subscribe(socket, filter) {
43
+ let set = this.subscriptions.get(socket);
44
+ if (!set) {
45
+ set = new Set();
46
+ this.subscriptions.set(socket, set);
47
+ }
48
+ set.add(filter);
49
+ }
50
+ unsubscribeAll(socket) {
51
+ this.subscriptions.delete(socket);
52
+ }
53
+ async listen() {
54
+ if (platform() !== "win32" && existsSync(this.opts.endpoint)) {
55
+ unlinkSync(this.opts.endpoint);
56
+ }
57
+ return new Promise((resolveListen, rejectListen) => {
58
+ const server = createServer((socket) => this.handleConnection(socket));
59
+ server.on("error", rejectListen);
60
+ server.listen(this.opts.endpoint, () => {
61
+ if (platform() !== "win32") {
62
+ try {
63
+ chmodSync(this.opts.endpoint, 0o600);
64
+ }
65
+ catch {
66
+ // socket may have been removed concurrently; ignore
67
+ }
68
+ }
69
+ this.server = server;
70
+ resolveListen();
71
+ });
72
+ });
73
+ }
74
+ async close() {
75
+ for (const off of this.busListenerOffs)
76
+ off();
77
+ this.busListenerOffs.length = 0;
78
+ this.subscriptions.clear();
79
+ for (const s of this.sockets)
80
+ s.destroy();
81
+ this.sockets.clear();
82
+ const server = this.server;
83
+ if (!server)
84
+ return;
85
+ await new Promise((resolveClose) => server.close(() => resolveClose()));
86
+ if (platform() !== "win32") {
87
+ try {
88
+ unlinkSync(this.opts.endpoint);
89
+ }
90
+ catch {
91
+ // already gone
92
+ }
93
+ }
94
+ }
95
+ handleConnection(socket) {
96
+ this.sockets.add(socket);
97
+ socket.setEncoding("utf8");
98
+ const framer = new LineFramer();
99
+ socket.on("data", (chunk) => {
100
+ for (const line of framer.push(chunk)) {
101
+ void this.handleMessage(socket, line);
102
+ }
103
+ });
104
+ socket.on("close", () => {
105
+ this.sockets.delete(socket);
106
+ this.unsubscribeAll(socket);
107
+ });
108
+ socket.on("error", () => {
109
+ this.sockets.delete(socket);
110
+ this.unsubscribeAll(socket);
111
+ });
112
+ }
113
+ async handleMessage(socket, line) {
114
+ let msg;
115
+ try {
116
+ msg = JSON.parse(line);
117
+ }
118
+ catch {
119
+ this.writeError(socket, null, RPC_ERROR.parseError, "invalid JSON");
120
+ return;
121
+ }
122
+ if (typeof msg !== "object" || msg === null) {
123
+ this.writeError(socket, null, RPC_ERROR.invalidRequest, "expected object");
124
+ return;
125
+ }
126
+ const rec = msg;
127
+ if (rec["jsonrpc"] !== "2.0" || typeof rec["method"] !== "string") {
128
+ this.writeError(socket, null, RPC_ERROR.invalidRequest, "missing jsonrpc/method");
129
+ return;
130
+ }
131
+ if (!isRequest(rec)) {
132
+ return;
133
+ }
134
+ const id = rec["id"];
135
+ const method = rec["method"];
136
+ const params = rec["params"];
137
+ const ctx = {
138
+ closeConnection: () => socket.end(),
139
+ closeServer: () => this.opts.onShutdownRequested(),
140
+ sendNotification: (notificationMethod, notificationParams) => {
141
+ const note = JSON.stringify({
142
+ jsonrpc: "2.0",
143
+ method: notificationMethod,
144
+ params: notificationParams,
145
+ });
146
+ socket.write(note + "\n");
147
+ },
148
+ socket,
149
+ };
150
+ // Built-in subscription methods — handled by the server, not user methods.
151
+ if (method === "events.subscribe") {
152
+ const p = (params ?? {});
153
+ const filter = p.filter && p.filter.length > 0 ? p.filter : "*";
154
+ this.subscribe(socket, filter);
155
+ const response = {
156
+ jsonrpc: "2.0",
157
+ id,
158
+ result: { subscribed: true, filter },
159
+ };
160
+ socket.write(JSON.stringify(response) + "\n");
161
+ return;
162
+ }
163
+ if (method === "events.unsubscribe") {
164
+ this.unsubscribeAll(socket);
165
+ const response = {
166
+ jsonrpc: "2.0",
167
+ id,
168
+ result: { unsubscribed: true },
169
+ };
170
+ socket.write(JSON.stringify(response) + "\n");
171
+ return;
172
+ }
173
+ const handler = this.opts.methods[method];
174
+ if (!handler) {
175
+ this.writeError(socket, id, RPC_ERROR.methodNotFound, `unknown method '${method}'`);
176
+ return;
177
+ }
178
+ try {
179
+ const result = await handler(params, ctx);
180
+ const response = { jsonrpc: "2.0", id, result };
181
+ socket.write(JSON.stringify(response) + "\n");
182
+ }
183
+ catch (err) {
184
+ if (err instanceof RpcError) {
185
+ socket.write(JSON.stringify(err.toJSON(id)) + "\n");
186
+ }
187
+ else {
188
+ const message = err instanceof Error ? err.message : String(err);
189
+ this.writeError(socket, id, RPC_ERROR.internalError, message);
190
+ }
191
+ }
192
+ }
193
+ writeError(socket, id, code, message) {
194
+ const err = {
195
+ jsonrpc: "2.0",
196
+ id,
197
+ error: { code, message },
198
+ };
199
+ socket.write(JSON.stringify(err) + "\n");
200
+ }
201
+ }
202
+ //# sourceMappingURL=ipc-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ipc-server.js","sourceRoot":"","sources":["../../src/daemon/ipc-server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { ConfigService } from "../core/config.js";
2
+ import type { OrchestratorService, OrchestratorStatus } from "../core/orchestrator.js";
3
+ import type { ResolvedPaths } from "../core/paths.js";
4
+ import type { SecretsService } from "../core/secrets.js";
5
+ import type { MethodHandler } from "./ipc-server.js";
6
+ export interface DaemonState {
7
+ pid: number;
8
+ startedAt: Date;
9
+ cliVersion: string;
10
+ paths: ResolvedPaths;
11
+ config: ConfigService;
12
+ secrets: SecretsService;
13
+ orchestrator: OrchestratorService | null;
14
+ getOrchestratorStatus: () => OrchestratorStatus;
15
+ }
16
+ export declare function buildMethodRegistry(state: DaemonState): Record<string, MethodHandler>;
17
+ //# sourceMappingURL=methods.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"methods.d.ts","sourceRoot":"","sources":["../../src/daemon/methods.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,KAAK,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AACvF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAiB,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEpE,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,IAAI,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,aAAa,CAAC;IACrB,MAAM,EAAE,aAAa,CAAC;IACtB,OAAO,EAAE,cAAc,CAAC;IACxB,YAAY,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACzC,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;CACjD;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAwErF"}
@@ -0,0 +1,68 @@
1
+ import { METHOD, MIN_CLIENT_VERSION, PROTOCOL_VERSION, } from "../shared/protocol.js";
2
+ export function buildMethodRegistry(state) {
3
+ return {
4
+ [METHOD.protocolVersion]: async () => ({
5
+ version: PROTOCOL_VERSION,
6
+ minClientVersion: MIN_CLIENT_VERSION,
7
+ }),
8
+ [METHOD.getStatus]: async () => {
9
+ const config = await state.config.load();
10
+ const refreshToken = await state.secrets.get("refreshToken");
11
+ const uptimeSeconds = Math.floor((Date.now() - state.startedAt.getTime()) / 1000);
12
+ return {
13
+ daemon: {
14
+ pid: state.pid,
15
+ startedAt: state.startedAt.toISOString(),
16
+ uptimeSeconds,
17
+ version: state.cliVersion,
18
+ protocolVersion: PROTOCOL_VERSION,
19
+ },
20
+ config: {
21
+ path: state.paths.configFile,
22
+ schemaVersion: config.schemaVersion,
23
+ hostId: config.hostId,
24
+ hostName: config.hostName,
25
+ },
26
+ auth: {
27
+ loggedIn: Boolean(refreshToken),
28
+ userId: config.userId,
29
+ agreementAccepted: Boolean(config.agreementAccepted),
30
+ agreementVersion: config.agreementVersion,
31
+ },
32
+ orchestrator: { status: state.getOrchestratorStatus() },
33
+ };
34
+ },
35
+ [METHOD.shutdown]: async (_params, ctx) => {
36
+ // Defer close so the response has time to flush over the socket
37
+ // before we tear down. Microtask isn't enough — the OS may not have
38
+ // pushed the bytes onto the wire yet.
39
+ setTimeout(() => {
40
+ void ctx.closeServer();
41
+ }, 50);
42
+ return { acknowledged: true };
43
+ },
44
+ [METHOD.configReload]: async () => {
45
+ // ConfigService reads from disk on every load() — there's no cache to
46
+ // invalidate. We acknowledge so callers can wait for the daemon to
47
+ // pick up new fields on its next read.
48
+ return { reloaded: true };
49
+ },
50
+ [METHOD.hostRename]: async (params) => {
51
+ const p = (params ?? {});
52
+ if (typeof p.hostName !== "string" || p.hostName.length === 0) {
53
+ throw new Error("hostName is required");
54
+ }
55
+ const hostName = p.hostName;
56
+ await state.config.update((c) => ({ ...c, hostName }));
57
+ if (state.orchestrator) {
58
+ await state.orchestrator.updateHostName(hostName);
59
+ }
60
+ return { hostName };
61
+ },
62
+ [METHOD.modelsState]: async () => {
63
+ const stats = state.orchestrator?.getRunnerStats() ?? null;
64
+ return { loaded: stats };
65
+ },
66
+ };
67
+ }
68
+ //# sourceMappingURL=methods.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"methods.js","sourceRoot":"","sources":["../../src/daemon/methods.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export declare class DaemonAlreadyRunningError extends Error {
2
+ readonly pidFile: string;
3
+ readonly pid: number;
4
+ constructor(pidFile: string, pid: number);
5
+ }
6
+ export interface PidLock {
7
+ release(): Promise<void>;
8
+ }
9
+ export declare function acquirePidLock(pidFile: string): Promise<PidLock>;
10
+ //# sourceMappingURL=pid-lock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pid-lock.d.ts","sourceRoot":"","sources":["../../src/daemon/pid-lock.ts"],"names":[],"mappings":"AAGA,qBAAa,yBAA0B,SAAQ,KAAK;aACtB,OAAO,EAAE,MAAM;aAAkB,GAAG,EAAE,MAAM;gBAA5C,OAAO,EAAE,MAAM,EAAkB,GAAG,EAAE,MAAM;CAGzE;AAWD,MAAM,WAAW,OAAO;IACtB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED,wBAAsB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAuBtE"}
@@ -0,0 +1,45 @@
1
+ import { mkdir, readFile, unlink, writeFile } from "node:fs/promises";
2
+ import { dirname } from "node:path";
3
+ export class DaemonAlreadyRunningError extends Error {
4
+ pidFile;
5
+ pid;
6
+ constructor(pidFile, pid) {
7
+ super(`daemon already running (pid ${pid}; ${pidFile})`);
8
+ this.pidFile = pidFile;
9
+ this.pid = pid;
10
+ }
11
+ }
12
+ function pidIsAlive(pid) {
13
+ try {
14
+ process.kill(pid, 0);
15
+ return true;
16
+ }
17
+ catch (err) {
18
+ return err.code === "EPERM";
19
+ }
20
+ }
21
+ export async function acquirePidLock(pidFile) {
22
+ await mkdir(dirname(pidFile), { recursive: true });
23
+ try {
24
+ const existing = await readFile(pidFile, "utf8");
25
+ const otherPid = Number.parseInt(existing.trim(), 10);
26
+ if (Number.isFinite(otherPid) && pidIsAlive(otherPid)) {
27
+ throw new DaemonAlreadyRunningError(pidFile, otherPid);
28
+ }
29
+ // Stale file from a crashed previous run; clean it up.
30
+ await unlink(pidFile).catch(() => undefined);
31
+ }
32
+ catch (err) {
33
+ if (err instanceof DaemonAlreadyRunningError)
34
+ throw err;
35
+ if (err.code !== "ENOENT")
36
+ throw err;
37
+ }
38
+ await writeFile(pidFile, String(process.pid), { flag: "wx", mode: 0o600 });
39
+ return {
40
+ release: async () => {
41
+ await unlink(pidFile).catch(() => undefined);
42
+ },
43
+ };
44
+ }
45
+ //# sourceMappingURL=pid-lock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pid-lock.js","sourceRoot":"","sources":["../../src/daemon/pid-lock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACtE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,MAAM,OAAO,yBAA0B,SAAQ,KAAK;IACtB;IAAiC;IAA7D,YAA4B,OAAe,EAAkB,GAAW;QACtE,KAAK,CAAC,+BAA+B,GAAG,KAAK,OAAO,GAAG,CAAC,CAAC;QAD/B,YAAO,GAAP,OAAO,CAAQ;QAAkB,QAAG,GAAH,GAAG,CAAQ;IAExE,CAAC;CACF;AAED,SAAS,UAAU,CAAC,GAAW;IAC7B,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACrB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAQ,GAA6B,CAAC,IAAI,KAAK,OAAO,CAAC;IACzD,CAAC;AACH,CAAC;AAMD,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAAe;IAClD,MAAM,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEnD,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACjD,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;QACtD,IAAI,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YACtD,MAAM,IAAI,yBAAyB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QACzD,CAAC;QACD,uDAAuD;QACvD,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;IAC/C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,yBAAyB;YAAE,MAAM,GAAG,CAAC;QACxD,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ;YAAE,MAAM,GAAG,CAAC;IAClE,CAAC;IAED,MAAM,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAE3E,OAAO;QACL,OAAO,EAAE,KAAK,IAAI,EAAE;YAClB,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC/C,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,19 @@
1
+ import { type DaemonState } from "./methods.js";
2
+ export interface RunDaemonOptions {
3
+ configDir?: string | undefined;
4
+ cliVersion: string;
5
+ foreground?: boolean;
6
+ }
7
+ export interface RunningDaemon {
8
+ stop(): Promise<void>;
9
+ whenStopped: Promise<void>;
10
+ state: DaemonState;
11
+ }
12
+ declare class StartupError extends Error {
13
+ readonly exitCode: number;
14
+ readonly hint?: string | undefined;
15
+ constructor(message: string, exitCode: number, hint?: string | undefined);
16
+ }
17
+ export declare function runDaemon(opts: RunDaemonOptions): Promise<RunningDaemon>;
18
+ export { StartupError };
19
+ //# sourceMappingURL=run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/daemon/run.ts"],"names":[],"mappings":"AAUA,OAAO,EAAuB,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAGrE,MAAM,WAAW,gBAAgB;IAC/B,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,WAAW,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,KAAK,EAAE,WAAW,CAAC;CACpB;AAED,cAAM,YAAa,SAAQ,KAAK;aACe,QAAQ,EAAE,MAAM;aAAkB,IAAI,CAAC,EAAE,MAAM;gBAAhF,OAAO,EAAE,MAAM,EAAkB,QAAQ,EAAE,MAAM,EAAkB,IAAI,CAAC,EAAE,MAAM,YAAA;CAG7F;AA4FD,wBAAsB,SAAS,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,aAAa,CAAC,CAsH9E;AAED,OAAO,EAAE,YAAY,EAAE,CAAC"}
@@ -0,0 +1,182 @@
1
+ import { AuthService } from "../core/auth.js";
2
+ import { BackendClient, BackendError } from "../core/backend-client.js";
3
+ import { createConfigService } from "../core/config.js";
4
+ import { DaemonEventBus } from "../core/events.js";
5
+ import { initGlobalLogger } from "../core/logger.js";
6
+ import { OrchestratorService } from "../core/orchestrator.js";
7
+ import { resolvePaths } from "../core/paths.js";
8
+ import { SecretsService } from "../core/secrets.js";
9
+ import { SubscriptionService } from "../core/subscription.js";
10
+ import { IpcServer } from "./ipc-server.js";
11
+ import { buildMethodRegistry } from "./methods.js";
12
+ import { acquirePidLock, DaemonAlreadyRunningError } from "./pid-lock.js";
13
+ class StartupError extends Error {
14
+ exitCode;
15
+ hint;
16
+ constructor(message, exitCode, hint) {
17
+ super(message);
18
+ this.exitCode = exitCode;
19
+ this.hint = hint;
20
+ }
21
+ }
22
+ async function verifyPreconditions(config, secrets, backend, subscription) {
23
+ const cfg = await config.load();
24
+ const refreshToken = await secrets.get("refreshToken");
25
+ if (!refreshToken) {
26
+ throw new StartupError("not authenticated", 4, "Log in first: peerllm-host login");
27
+ }
28
+ if (!cfg.agreementAccepted) {
29
+ throw new StartupError("host agreement not accepted", 5, "Accept the agreement: peerllm-host agreement accept");
30
+ }
31
+ if (!cfg.hostId) {
32
+ throw new StartupError("no host is registered", 5, "Register a host: peerllm-host host create");
33
+ }
34
+ // Confirm approval before opening the SignalR connection.
35
+ try {
36
+ const host = await backend.request({
37
+ method: "GET",
38
+ path: `/api/hosts/${cfg.hostId}`,
39
+ });
40
+ if (host.isApproved === false) {
41
+ throw new StartupError("host is not yet approved", 5, "Hosts are typically approved within 24–48 hours. Check back later.");
42
+ }
43
+ }
44
+ catch (err) {
45
+ if (err instanceof StartupError)
46
+ throw err;
47
+ if (err instanceof BackendError && err.status >= 500) {
48
+ // Backend is temporarily down — let connect() retry handle it.
49
+ return;
50
+ }
51
+ throw new StartupError(`host approval check failed: ${err.message}`, 1);
52
+ }
53
+ // Subscription gate — hosts cannot serve traffic without an active subscription.
54
+ try {
55
+ const check = await subscription.hostIsActive(cfg.hostId);
56
+ if (!check.subscribed) {
57
+ if (check.pending) {
58
+ throw new StartupError("subscription pending PayPal approval", 5, "Complete PayPal checkout, or rerun: peerllm-host subscription start");
59
+ }
60
+ throw new StartupError("this host is not subscribed", 5, "Start a subscription: peerllm-host subscription start");
61
+ }
62
+ }
63
+ catch (err) {
64
+ if (err instanceof StartupError)
65
+ throw err;
66
+ if (err instanceof BackendError && err.status >= 500) {
67
+ // Backend transiently unreachable — let the orchestrator's own checks gate.
68
+ return;
69
+ }
70
+ throw new StartupError(`subscription check failed: ${err.message}`, 1);
71
+ }
72
+ }
73
+ export async function runDaemon(opts) {
74
+ const paths = resolvePaths({ configDirOverride: opts.configDir });
75
+ const config = createConfigService({ configDirOverride: opts.configDir });
76
+ const secrets = new SecretsService(paths);
77
+ const events = new DaemonEventBus();
78
+ initGlobalLogger({
79
+ logsDir: paths.logsDir,
80
+ prefix: "host",
81
+ minLevel: process.env["PEERLLM_LOG_LEVEL"] ?? "info",
82
+ stderrSink: Boolean(opts.foreground),
83
+ fileSink: true,
84
+ });
85
+ const backend = new BackendClient();
86
+ const auth = new AuthService(backend, secrets, config);
87
+ const subscription = new SubscriptionService(backend, auth);
88
+ await verifyPreconditions(config, secrets, backend, subscription);
89
+ // Refresh the access token now so the orchestrator handshake doesn't race
90
+ // against the first inbound prompt.
91
+ await auth.getValidAccessToken();
92
+ let pidLock;
93
+ try {
94
+ pidLock = await acquirePidLock(paths.pidFile);
95
+ }
96
+ catch (err) {
97
+ if (err instanceof DaemonAlreadyRunningError) {
98
+ const e = new Error(err.message);
99
+ e.exitCode = 6;
100
+ throw e;
101
+ }
102
+ throw err;
103
+ }
104
+ let orchestratorStatus = "disconnected";
105
+ events.on("orchestratorStatus", (e) => {
106
+ orchestratorStatus = e.status;
107
+ });
108
+ const orchestrator = new OrchestratorService({
109
+ paths,
110
+ config,
111
+ events,
112
+ cliVersion: opts.cliVersion,
113
+ });
114
+ const state = {
115
+ pid: process.pid,
116
+ startedAt: new Date(),
117
+ cliVersion: opts.cliVersion,
118
+ paths,
119
+ config,
120
+ secrets,
121
+ orchestrator,
122
+ getOrchestratorStatus: () => orchestratorStatus,
123
+ };
124
+ let stopping = false;
125
+ let resolveStopped;
126
+ const whenStopped = new Promise((res) => {
127
+ resolveStopped = res;
128
+ });
129
+ const ipc = new IpcServer({
130
+ endpoint: paths.ipcEndpoint,
131
+ methods: buildMethodRegistry(state),
132
+ onShutdownRequested: () => shutdown(),
133
+ events,
134
+ });
135
+ async function shutdown() {
136
+ if (stopping)
137
+ return;
138
+ stopping = true;
139
+ try {
140
+ await orchestrator.disconnect();
141
+ }
142
+ catch (err) {
143
+ // Swallow — we're shutting down anyway, but record for diagnostics.
144
+ events.emit("log", {
145
+ level: "warn",
146
+ message: `orchestrator disconnect error: ${err.message}`,
147
+ timestamp: new Date().toISOString(),
148
+ });
149
+ }
150
+ try {
151
+ await ipc.close();
152
+ }
153
+ finally {
154
+ await pidLock.release();
155
+ resolveStopped();
156
+ }
157
+ }
158
+ const signalHandler = (sig) => {
159
+ void shutdown().then(() => {
160
+ process.removeListener(sig, signalHandler);
161
+ });
162
+ };
163
+ process.on("SIGINT", signalHandler);
164
+ process.on("SIGTERM", signalHandler);
165
+ await ipc.listen();
166
+ // Orchestrator connect is async and non-blocking — daemon stays up even
167
+ // while reconnects retry in the background.
168
+ orchestrator.connect().catch((err) => {
169
+ events.emit("log", {
170
+ level: "error",
171
+ message: `orchestrator initial connect failed: ${err.message}`,
172
+ timestamp: new Date().toISOString(),
173
+ });
174
+ });
175
+ return {
176
+ stop: shutdown,
177
+ whenStopped,
178
+ state,
179
+ };
180
+ }
181
+ export { StartupError };
182
+ //# sourceMappingURL=run.js.map