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,101 @@
1
+ import { createConnection } from "node:net";
2
+ import { LineFramer } from "../core/jsonrpc.js";
3
+ export class DaemonUnreachableError extends Error {
4
+ constructor(endpoint, cause) {
5
+ super(`daemon not reachable at ${endpoint}: ${cause.message ?? cause}`);
6
+ }
7
+ }
8
+ export class IpcClient {
9
+ endpoint;
10
+ socket;
11
+ nextId = 1;
12
+ pending = new Map();
13
+ framer = new LineFramer();
14
+ notificationHandler;
15
+ constructor(endpoint) {
16
+ this.endpoint = endpoint;
17
+ }
18
+ onNotification(handler) {
19
+ this.notificationHandler = handler;
20
+ }
21
+ async connect(timeoutMs = 2000) {
22
+ await new Promise((resolveConn, rejectConn) => {
23
+ const socket = createConnection(this.endpoint);
24
+ const timer = setTimeout(() => {
25
+ socket.destroy();
26
+ rejectConn(new DaemonUnreachableError(this.endpoint, new Error("connect timeout")));
27
+ }, timeoutMs);
28
+ socket.once("connect", () => {
29
+ clearTimeout(timer);
30
+ socket.setEncoding("utf8");
31
+ socket.on("data", (chunk) => this.onData(chunk));
32
+ socket.on("close", () => this.onClose());
33
+ socket.on("error", () => this.onClose());
34
+ this.socket = socket;
35
+ resolveConn();
36
+ });
37
+ socket.once("error", (err) => {
38
+ clearTimeout(timer);
39
+ rejectConn(new DaemonUnreachableError(this.endpoint, err));
40
+ });
41
+ });
42
+ }
43
+ async call(method, params) {
44
+ const socket = this.socket;
45
+ if (!socket)
46
+ throw new Error("ipc client not connected");
47
+ const id = this.nextId++;
48
+ const request = { jsonrpc: "2.0", id, method, params };
49
+ return new Promise((resolveCall, rejectCall) => {
50
+ this.pending.set(id, {
51
+ resolve: (v) => resolveCall(v),
52
+ reject: rejectCall,
53
+ });
54
+ socket.write(JSON.stringify(request) + "\n");
55
+ });
56
+ }
57
+ close() {
58
+ this.socket?.end();
59
+ this.socket = undefined;
60
+ }
61
+ onData(chunk) {
62
+ for (const line of this.framer.push(chunk)) {
63
+ let msg;
64
+ try {
65
+ msg = JSON.parse(line);
66
+ }
67
+ catch {
68
+ continue;
69
+ }
70
+ // Notifications: method present, no id (or id is null).
71
+ if (typeof msg.method === "string" && (msg.id === undefined || msg.id === null)) {
72
+ this.notificationHandler?.(msg.method, msg.params);
73
+ continue;
74
+ }
75
+ const id = msg.id;
76
+ if (id === null || id === undefined)
77
+ continue;
78
+ const entry = this.pending.get(id);
79
+ if (!entry)
80
+ continue;
81
+ this.pending.delete(id);
82
+ if ("error" in msg) {
83
+ const err = new Error(msg.error.message);
84
+ err.code = msg.error.code;
85
+ err.hint = msg.error.data?.hint;
86
+ entry.reject(err);
87
+ }
88
+ else {
89
+ entry.resolve(msg.result);
90
+ }
91
+ }
92
+ }
93
+ onClose() {
94
+ const err = new Error("daemon closed connection");
95
+ for (const entry of this.pending.values())
96
+ entry.reject(err);
97
+ this.pending.clear();
98
+ this.socket = undefined;
99
+ }
100
+ }
101
+ //# sourceMappingURL=ipc-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ipc-client.js","sourceRoot":"","sources":["../../src/cli/ipc-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAe,MAAM,UAAU,CAAC;AAEzD,OAAO,EAAE,UAAU,EAA0C,MAAM,oBAAoB,CAAC;AAExF,MAAM,OAAO,sBAAuB,SAAQ,KAAK;IAC/C,YAAY,QAAgB,EAAE,KAAc;QAC1C,KAAK,CAAC,2BAA2B,QAAQ,KAAM,KAAe,CAAC,OAAO,IAAI,KAAK,EAAE,CAAC,CAAC;IACrF,CAAC;CACF;AAID,MAAM,OAAO,SAAS;IAUS;IATrB,MAAM,CAAqB;IAC3B,MAAM,GAAG,CAAC,CAAC;IACF,OAAO,GAAG,IAAI,GAAG,EAG/B,CAAC;IACa,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;IACnC,mBAAmB,CAAkC;IAE7D,YAA6B,QAAgB;QAAhB,aAAQ,GAAR,QAAQ,CAAQ;IAAG,CAAC;IAEjD,cAAc,CAAC,OAA4B;QACzC,IAAI,CAAC,mBAAmB,GAAG,OAAO,CAAC;IACrC,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,SAAS,GAAG,IAAI;QAC5B,MAAM,IAAI,OAAO,CAAO,CAAC,WAAW,EAAE,UAAU,EAAE,EAAE;YAClD,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC/C,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;gBAC5B,MAAM,CAAC,OAAO,EAAE,CAAC;gBACjB,UAAU,CAAC,IAAI,sBAAsB,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;YACtF,CAAC,EAAE,SAAS,CAAC,CAAC;YAEd,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE;gBAC1B,YAAY,CAAC,KAAK,CAAC,CAAC;gBACpB,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;gBAC3B,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;gBACzD,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;gBACzC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;gBACzC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;gBACrB,WAAW,EAAE,CAAC;YAChB,CAAC,CAAC,CAAC;YAEH,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;gBAC3B,YAAY,CAAC,KAAK,CAAC,CAAC;gBACpB,UAAU,CAAC,IAAI,sBAAsB,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC;YAC7D,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,IAAI,CAAI,MAAc,EAAE,MAAgB;QAC5C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC3B,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;QACzD,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,EAAE,OAAO,EAAE,KAAc,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;QAEhE,OAAO,IAAI,OAAO,CAAI,CAAC,WAAW,EAAE,UAAU,EAAE,EAAE;YAChD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE;gBACnB,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,CAAM,CAAC;gBACnC,MAAM,EAAE,UAAU;aACnB,CAAC,CAAC;YACH,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;QAC/C,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK;QACH,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC;QACnB,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;IAC1B,CAAC;IAEO,MAAM,CAAC,KAAa;QAC1B,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3C,IAAI,GAGH,CAAC;YACF,IAAI,CAAC;gBACH,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAe,CAAC;YACvC,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;YAED,wDAAwD;YACxD,IAAI,OAAO,GAAG,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,GAAG,CAAC,EAAE,KAAK,SAAS,IAAI,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;gBAChF,IAAI,CAAC,mBAAmB,EAAE,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;gBACnD,SAAS;YACX,CAAC;YAED,MAAM,EAAE,GAAG,GAAG,CAAC,EAAE,CAAC;YAClB,IAAI,EAAE,KAAK,IAAI,IAAI,EAAE,KAAK,SAAS;gBAAE,SAAS;YAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAY,CAAC,CAAC;YAC7C,IAAI,CAAC,KAAK;gBAAE,SAAS;YACrB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAY,CAAC,CAAC;YAClC,IAAI,OAAO,IAAI,GAAG,EAAE,CAAC;gBACnB,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAGtC,CAAC;gBACF,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;gBAC1B,GAAG,CAAC,IAAI,GAAI,GAAG,CAAC,KAAK,CAAC,IAAsC,EAAE,IAAI,CAAC;gBACnE,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACpB,CAAC;iBAAM,CAAC;gBACN,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAC5B,CAAC;QACH,CAAC;IACH,CAAC;IAEO,OAAO;QACb,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;QAClD,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE;YAAE,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;IAC1B,CAAC;CACF"}
@@ -0,0 +1,5 @@
1
+ export declare function prompt(question: string): Promise<string>;
2
+ export declare function promptPassword(question: string): Promise<string>;
3
+ export declare function readStdinUntilEnd(): Promise<string>;
4
+ export declare function promptYesNo(question: string, defaultYes?: boolean): Promise<boolean>;
5
+ //# sourceMappingURL=prompts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/cli/prompts.ts"],"names":[],"mappings":"AASA,wBAAsB,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAe9D;AAED,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA+BtE;AAED,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC,CAMzD;AAED,wBAAsB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,UAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,CAKxF"}
@@ -0,0 +1,68 @@
1
+ import { createInterface } from "node:readline";
2
+ import { EXIT } from "./exit-codes.js";
3
+ import { printError } from "./format.js";
4
+ function isTTY() {
5
+ return Boolean(process.stdin.isTTY && process.stdout.isTTY);
6
+ }
7
+ export async function prompt(question) {
8
+ if (!isTTY()) {
9
+ printError(`interactive prompt required but stdin is not a TTY`, {
10
+ hint: "Run this command in an interactive terminal, or use the non-interactive flags.",
11
+ });
12
+ process.exit(EXIT.userError);
13
+ }
14
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
15
+ try {
16
+ return await new Promise((resolve) => {
17
+ rl.question(question, (answer) => resolve(answer));
18
+ });
19
+ }
20
+ finally {
21
+ rl.close();
22
+ }
23
+ }
24
+ export async function promptPassword(question) {
25
+ if (!isTTY()) {
26
+ printError(`interactive password prompt required but stdin is not a TTY`, {
27
+ hint: "Pipe the password via --password-stdin instead.",
28
+ });
29
+ process.exit(EXIT.userError);
30
+ }
31
+ const rl = createInterface({
32
+ input: process.stdin,
33
+ output: process.stdout,
34
+ });
35
+ const muted = (s) => {
36
+ if (s.startsWith(question)) {
37
+ process.stdout.write(question);
38
+ }
39
+ };
40
+ rl._writeToOutput = muted;
41
+ try {
42
+ const answer = await new Promise((resolve) => {
43
+ rl.question(question, (input) => {
44
+ process.stdout.write("\n");
45
+ resolve(input);
46
+ });
47
+ });
48
+ return answer;
49
+ }
50
+ finally {
51
+ rl.close();
52
+ }
53
+ }
54
+ export async function readStdinUntilEnd() {
55
+ const chunks = [];
56
+ for await (const chunk of process.stdin) {
57
+ chunks.push(chunk);
58
+ }
59
+ return Buffer.concat(chunks).toString("utf8").replace(/\r?\n$/, "");
60
+ }
61
+ export async function promptYesNo(question, defaultYes = false) {
62
+ const suffix = defaultYes ? " [Y/n] " : " [y/N] ";
63
+ const answer = (await prompt(question + suffix)).trim().toLowerCase();
64
+ if (!answer)
65
+ return defaultYes;
66
+ return answer === "y" || answer === "yes";
67
+ }
68
+ //# sourceMappingURL=prompts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../src/cli/prompts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import { AuthService } from "../core/auth.js";
2
+ import { BackendClient } from "../core/backend-client.js";
3
+ import { ConfigService } from "../core/config.js";
4
+ import { type ResolvedPaths } from "../core/paths.js";
5
+ import { SecretsService } from "../core/secrets.js";
6
+ import { SubscriptionService } from "../core/subscription.js";
7
+ export interface ClientServices {
8
+ paths: ResolvedPaths;
9
+ config: ConfigService;
10
+ secrets: SecretsService;
11
+ backend: BackendClient;
12
+ auth: AuthService;
13
+ subscription: SubscriptionService;
14
+ }
15
+ export declare function buildClientServices(opts?: {
16
+ configDir?: string;
17
+ }): ClientServices;
18
+ //# sourceMappingURL=services.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"services.d.ts","sourceRoot":"","sources":["../../src/cli/services.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAgB,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAE9D,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,aAAa,CAAC;IACrB,MAAM,EAAE,aAAa,CAAC;IACtB,OAAO,EAAE,cAAc,CAAC;IACxB,OAAO,EAAE,aAAa,CAAC;IACvB,IAAI,EAAE,WAAW,CAAC;IAClB,YAAY,EAAE,mBAAmB,CAAC;CACnC;AAED,wBAAgB,mBAAmB,CAAC,IAAI,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,cAAc,CAQrF"}
@@ -0,0 +1,16 @@
1
+ import { AuthService } from "../core/auth.js";
2
+ import { BackendClient } from "../core/backend-client.js";
3
+ import { ConfigService } from "../core/config.js";
4
+ import { resolvePaths } from "../core/paths.js";
5
+ import { SecretsService } from "../core/secrets.js";
6
+ import { SubscriptionService } from "../core/subscription.js";
7
+ export function buildClientServices(opts = {}) {
8
+ const paths = resolvePaths({ configDirOverride: opts.configDir });
9
+ const config = new ConfigService(paths);
10
+ const secrets = new SecretsService(paths);
11
+ const backend = new BackendClient();
12
+ const auth = new AuthService(backend, secrets, config);
13
+ const subscription = new SubscriptionService(backend, auth);
14
+ return { paths, config, secrets, backend, auth, subscription };
15
+ }
16
+ //# sourceMappingURL=services.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"services.js","sourceRoot":"","sources":["../../src/cli/services.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAsB,MAAM,kBAAkB,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAW9D,MAAM,UAAU,mBAAmB,CAAC,OAA+B,EAAE;IACnE,MAAM,KAAK,GAAG,YAAY,CAAC,EAAE,iBAAiB,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;IAClE,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC,KAAK,CAAC,CAAC;IACxC,MAAM,OAAO,GAAG,IAAI,cAAc,CAAC,KAAK,CAAC,CAAC;IAC1C,MAAM,OAAO,GAAG,IAAI,aAAa,EAAE,CAAC;IACpC,MAAM,IAAI,GAAG,IAAI,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IACvD,MAAM,YAAY,GAAG,IAAI,mBAAmB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAC5D,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;AACjE,CAAC"}
@@ -0,0 +1,24 @@
1
+ import { BackendClient } from "./backend-client.js";
2
+ import type { ConfigService } from "./config.js";
3
+ import type { SecretsService } from "./secrets.js";
4
+ export declare class AuthService {
5
+ private readonly client;
6
+ private readonly secrets;
7
+ private readonly config;
8
+ private accessToken;
9
+ private tokenExpiresAt;
10
+ private refreshInFlight;
11
+ private consecutiveRefreshFailures;
12
+ constructor(client: BackendClient, secrets: SecretsService, config: ConfigService);
13
+ login(email: string, password: string): Promise<{
14
+ userId: string | undefined;
15
+ }>;
16
+ register(email: string, password: string): Promise<void>;
17
+ logout(): Promise<void>;
18
+ getValidAccessToken(): Promise<string | null>;
19
+ hasRefreshToken(): Promise<boolean>;
20
+ private refresh;
21
+ private setAccessToken;
22
+ private fetchUserIdFromMe;
23
+ }
24
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/core/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAyB,MAAM,qBAAqB,CAAC;AAC3E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAoBnD,qBAAa,WAAW;IAOpB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM;IARzB,OAAO,CAAC,WAAW,CAAqB;IACxC,OAAO,CAAC,cAAc,CAAmB;IACzC,OAAO,CAAC,eAAe,CAAqC;IAC5D,OAAO,CAAC,0BAA0B,CAAK;gBAGpB,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,aAAa;IAGlC,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC;IAsB/E,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQxD,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAMvB,mBAAmB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAa7C,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC;YAK3B,OAAO;IAkCrB,OAAO,CAAC,cAAc;YAKR,iBAAiB;CAYhC"}
@@ -0,0 +1,111 @@
1
+ import { NotAuthenticatedError } from "./backend-client.js";
2
+ import { getLogger } from "./logger.js";
3
+ export class AuthService {
4
+ client;
5
+ secrets;
6
+ config;
7
+ accessToken;
8
+ tokenExpiresAt;
9
+ refreshInFlight;
10
+ consecutiveRefreshFailures = 0;
11
+ constructor(client, secrets, config) {
12
+ this.client = client;
13
+ this.secrets = secrets;
14
+ this.config = config;
15
+ }
16
+ async login(email, password) {
17
+ const result = await this.client.request({
18
+ method: "POST",
19
+ path: "/auth/login",
20
+ body: { email, password },
21
+ });
22
+ await this.secrets.set("refreshToken", result.refreshToken);
23
+ this.setAccessToken(result.accessToken, result.expiresIn ?? 3600);
24
+ let userId = result.userId;
25
+ if (!userId) {
26
+ userId = (await this.fetchUserIdFromMe(result.accessToken)) ?? undefined;
27
+ }
28
+ if (userId) {
29
+ await this.config.update((c) => ({ ...c, userId }));
30
+ }
31
+ return { userId };
32
+ }
33
+ async register(email, password) {
34
+ await this.client.request({
35
+ method: "POST",
36
+ path: "/auth/register",
37
+ body: { email, password },
38
+ });
39
+ }
40
+ async logout() {
41
+ this.accessToken = undefined;
42
+ this.tokenExpiresAt = undefined;
43
+ await this.secrets.clear("refreshToken");
44
+ }
45
+ async getValidAccessToken() {
46
+ if (this.accessToken && this.tokenExpiresAt && this.tokenExpiresAt > new Date()) {
47
+ return this.accessToken;
48
+ }
49
+ if (!this.refreshInFlight) {
50
+ this.refreshInFlight = this.refresh().finally(() => {
51
+ this.refreshInFlight = undefined;
52
+ });
53
+ }
54
+ return this.refreshInFlight;
55
+ }
56
+ async hasRefreshToken() {
57
+ const token = await this.secrets.get("refreshToken");
58
+ return Boolean(token);
59
+ }
60
+ async refresh() {
61
+ const refreshToken = await this.secrets.get("refreshToken");
62
+ if (!refreshToken)
63
+ return null;
64
+ try {
65
+ const result = await this.client.request({
66
+ method: "POST",
67
+ path: "/auth/refresh",
68
+ body: { refreshToken },
69
+ });
70
+ this.setAccessToken(result.accessToken, result.expiresIn ?? 3600);
71
+ this.consecutiveRefreshFailures = 0;
72
+ if (result.refreshToken && result.refreshToken !== refreshToken) {
73
+ await this.secrets.set("refreshToken", result.refreshToken);
74
+ }
75
+ return result.accessToken;
76
+ }
77
+ catch (err) {
78
+ if (err instanceof NotAuthenticatedError || err.status === 400) {
79
+ this.consecutiveRefreshFailures++;
80
+ // The Electron app's threshold: 3 consecutive rejections means the token
81
+ // is permanently dead (server expiry, password change, revoke).
82
+ if (this.consecutiveRefreshFailures >= 3) {
83
+ getLogger().warn("refresh token permanently rejected; clearing");
84
+ await this.secrets.clear("refreshToken");
85
+ }
86
+ }
87
+ else {
88
+ getLogger().error("token refresh failed", err.message);
89
+ }
90
+ return null;
91
+ }
92
+ }
93
+ setAccessToken(token, expiresIn) {
94
+ this.accessToken = token;
95
+ this.tokenExpiresAt = new Date(Date.now() + expiresIn * 1000);
96
+ }
97
+ async fetchUserIdFromMe(accessToken) {
98
+ try {
99
+ const me = await this.client.request({
100
+ method: "GET",
101
+ path: "/auth/me",
102
+ bearerToken: accessToken,
103
+ });
104
+ return me.userId ?? me.id;
105
+ }
106
+ catch {
107
+ return undefined;
108
+ }
109
+ }
110
+ }
111
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/core/auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ export declare const DEFAULT_ORCHESTRATOR_URL = "https://api.peerllm.com";
2
+ export declare class BackendError extends Error {
3
+ readonly status: number;
4
+ readonly body: unknown;
5
+ readonly code?: string | undefined;
6
+ constructor(message: string, status: number, body: unknown, code?: string | undefined);
7
+ }
8
+ export declare class AgreementRequiredError extends BackendError {
9
+ readonly latestVersion: number | undefined;
10
+ readonly agreementId: string | undefined;
11
+ constructor(latestVersion: number | undefined, agreementId: string | undefined, message: string);
12
+ }
13
+ export declare class NotAuthenticatedError extends BackendError {
14
+ constructor(message?: string);
15
+ }
16
+ export interface BackendRequest {
17
+ method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
18
+ path: string;
19
+ body?: unknown;
20
+ bearerToken?: string;
21
+ headers?: Record<string, string>;
22
+ }
23
+ export interface BackendClientOptions {
24
+ baseUrl?: string;
25
+ userAgent?: string;
26
+ }
27
+ export declare class BackendClient {
28
+ private readonly baseUrl;
29
+ private readonly userAgent;
30
+ constructor(opts?: BackendClientOptions);
31
+ request<T = unknown>(req: BackendRequest): Promise<T>;
32
+ }
33
+ //# sourceMappingURL=backend-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backend-client.d.ts","sourceRoot":"","sources":["../../src/core/backend-client.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,wBAAwB,4BAA4B,CAAC;AAElE,qBAAa,YAAa,SAAQ,KAAK;aAGnB,MAAM,EAAE,MAAM;aACd,IAAI,EAAE,OAAO;aACb,IAAI,CAAC,EAAE,MAAM;gBAH7B,OAAO,EAAE,MAAM,EACC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,OAAO,EACb,IAAI,CAAC,EAAE,MAAM,YAAA;CAIhC;AAED,qBAAa,sBAAuB,SAAQ,YAAY;aAEpC,aAAa,EAAE,MAAM,GAAG,SAAS;aACjC,WAAW,EAAE,MAAM,GAAG,SAAS;gBAD/B,aAAa,EAAE,MAAM,GAAG,SAAS,EACjC,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/C,OAAO,EAAE,MAAM;CAIlB;AAED,qBAAa,qBAAsB,SAAQ,YAAY;gBACzC,OAAO,SAAsB;CAG1C;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,OAAO,CAAC;IACpD,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAEvB,IAAI,GAAE,oBAAyB;IAKrC,OAAO,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,CAAC,CAAC;CAmD5D"}
@@ -0,0 +1,79 @@
1
+ export const DEFAULT_ORCHESTRATOR_URL = "https://api.peerllm.com";
2
+ export class BackendError extends Error {
3
+ status;
4
+ body;
5
+ code;
6
+ constructor(message, status, body, code) {
7
+ super(message);
8
+ this.status = status;
9
+ this.body = body;
10
+ this.code = code;
11
+ }
12
+ }
13
+ export class AgreementRequiredError extends BackendError {
14
+ latestVersion;
15
+ agreementId;
16
+ constructor(latestVersion, agreementId, message) {
17
+ super(message, 403, { latestVersion, agreementId }, "AgreementRequired");
18
+ this.latestVersion = latestVersion;
19
+ this.agreementId = agreementId;
20
+ }
21
+ }
22
+ export class NotAuthenticatedError extends BackendError {
23
+ constructor(message = "Not authenticated") {
24
+ super(message, 401, undefined, "NotAuthenticated");
25
+ }
26
+ }
27
+ export class BackendClient {
28
+ baseUrl;
29
+ userAgent;
30
+ constructor(opts = {}) {
31
+ this.baseUrl = opts.baseUrl ?? DEFAULT_ORCHESTRATOR_URL;
32
+ this.userAgent = opts.userAgent ?? `peerllm-host-cli`;
33
+ }
34
+ async request(req) {
35
+ const headers = {
36
+ "Content-Type": "application/json",
37
+ Accept: "application/json",
38
+ "User-Agent": this.userAgent,
39
+ ...req.headers,
40
+ };
41
+ if (req.bearerToken) {
42
+ headers["Authorization"] = `Bearer ${req.bearerToken}`;
43
+ }
44
+ const url = `${this.baseUrl}${req.path}`;
45
+ let response;
46
+ try {
47
+ response = await fetch(url, {
48
+ method: req.method,
49
+ headers,
50
+ body: req.body === undefined ? undefined : JSON.stringify(req.body),
51
+ });
52
+ }
53
+ catch (err) {
54
+ throw new BackendError(`network error: ${err.message}`, 0, undefined);
55
+ }
56
+ if (response.ok) {
57
+ if (response.status === 204)
58
+ return undefined;
59
+ const text = await response.text();
60
+ return (text ? JSON.parse(text) : undefined);
61
+ }
62
+ let parsed;
63
+ try {
64
+ parsed = (await response.json());
65
+ }
66
+ catch {
67
+ parsed = {};
68
+ }
69
+ if (response.status === 403 && parsed.error === "AgreementRequired") {
70
+ throw new AgreementRequiredError(parsed.latestVersion, parsed.agreementId, parsed.message ?? "You must accept the latest host agreement before proceeding.");
71
+ }
72
+ if (response.status === 401) {
73
+ throw new NotAuthenticatedError(parsed.error ?? parsed.message ?? "Not authenticated");
74
+ }
75
+ const message = parsed.error ?? parsed.message ?? `request failed (HTTP ${response.status})`;
76
+ throw new BackendError(message, response.status, parsed);
77
+ }
78
+ }
79
+ //# sourceMappingURL=backend-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backend-client.js","sourceRoot":"","sources":["../../src/core/backend-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import { type HostConfig } from "../shared/config-types.js";
2
+ import { type ResolvedPaths } from "./paths.js";
3
+ export declare class ConfigSchemaTooNewError extends Error {
4
+ readonly fileVersion: number;
5
+ readonly cliVersion: number;
6
+ constructor(fileVersion: number, cliVersion: number);
7
+ }
8
+ export declare class ConfigService {
9
+ private readonly paths;
10
+ constructor(paths: ResolvedPaths);
11
+ static withPaths(paths: ResolvedPaths): ConfigService;
12
+ load(): Promise<HostConfig>;
13
+ save(next: HostConfig): Promise<void>;
14
+ update(mutator: (current: HostConfig) => HostConfig): Promise<HostConfig>;
15
+ private loadUnsafe;
16
+ private migrate;
17
+ }
18
+ export declare function createConfigService(opts?: {
19
+ configDirOverride?: string;
20
+ }): ConfigService;
21
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,UAAU,EAChB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAAgB,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAE9D,qBAAa,uBAAwB,SAAQ,KAAK;aACpB,WAAW,EAAE,MAAM;aAAkB,UAAU,EAAE,MAAM;gBAAvD,WAAW,EAAE,MAAM,EAAkB,UAAU,EAAE,MAAM;CAKpF;AAED,qBAAa,aAAa;IACZ,OAAO,CAAC,QAAQ,CAAC,KAAK;gBAAL,KAAK,EAAE,aAAa;IAEjD,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,aAAa,GAAG,aAAa;IAI/C,IAAI,IAAI,OAAO,CAAC,UAAU,CAAC;IAoB3B,IAAI,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAerC,MAAM,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,UAAU,KAAK,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;YAkBjE,UAAU;IAaxB,OAAO,CAAC,OAAO;CAQhB;AAED,wBAAgB,mBAAmB,CAAC,IAAI,GAAE;IAAE,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,aAAa,CAE5F"}
@@ -0,0 +1,98 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { CONFIG_SCHEMA_VERSION, defaultConfig, } from "../shared/config-types.js";
3
+ import { acquireFileLock, atomicWriteFile } from "./fs-lock.js";
4
+ import { resolvePaths } from "./paths.js";
5
+ export class ConfigSchemaTooNewError extends Error {
6
+ fileVersion;
7
+ cliVersion;
8
+ constructor(fileVersion, cliVersion) {
9
+ super(`config schemaVersion ${fileVersion} is newer than this CLI supports (${cliVersion}). Upgrade the CLI.`);
10
+ this.fileVersion = fileVersion;
11
+ this.cliVersion = cliVersion;
12
+ }
13
+ }
14
+ export class ConfigService {
15
+ paths;
16
+ constructor(paths) {
17
+ this.paths = paths;
18
+ }
19
+ static withPaths(paths) {
20
+ return new ConfigService(paths);
21
+ }
22
+ async load() {
23
+ let raw;
24
+ try {
25
+ raw = await readFile(this.paths.configFile, "utf8");
26
+ }
27
+ catch (err) {
28
+ if (err.code === "ENOENT") {
29
+ return defaultConfig();
30
+ }
31
+ throw err;
32
+ }
33
+ const parsed = JSON.parse(raw);
34
+ const fileVersion = parsed.schemaVersion ?? 0;
35
+ if (fileVersion > CONFIG_SCHEMA_VERSION) {
36
+ throw new ConfigSchemaTooNewError(fileVersion, CONFIG_SCHEMA_VERSION);
37
+ }
38
+ return this.migrate(parsed);
39
+ }
40
+ async save(next) {
41
+ const lock = await acquireFileLock(this.paths.lockFile);
42
+ try {
43
+ const merged = {
44
+ ...next,
45
+ schemaVersion: CONFIG_SCHEMA_VERSION,
46
+ lastWriter: "cli",
47
+ schemaUpdatedAt: new Date().toISOString(),
48
+ };
49
+ await atomicWriteFile(this.paths.configFile, JSON.stringify(merged, null, 2));
50
+ }
51
+ finally {
52
+ await lock.release();
53
+ }
54
+ }
55
+ async update(mutator) {
56
+ const lock = await acquireFileLock(this.paths.lockFile);
57
+ try {
58
+ const current = await this.loadUnsafe();
59
+ const next = mutator(current);
60
+ const merged = {
61
+ ...next,
62
+ schemaVersion: CONFIG_SCHEMA_VERSION,
63
+ lastWriter: "cli",
64
+ schemaUpdatedAt: new Date().toISOString(),
65
+ };
66
+ await atomicWriteFile(this.paths.configFile, JSON.stringify(merged, null, 2));
67
+ return merged;
68
+ }
69
+ finally {
70
+ await lock.release();
71
+ }
72
+ }
73
+ async loadUnsafe() {
74
+ try {
75
+ const raw = await readFile(this.paths.configFile, "utf8");
76
+ const parsed = JSON.parse(raw);
77
+ return this.migrate(parsed);
78
+ }
79
+ catch (err) {
80
+ if (err.code === "ENOENT") {
81
+ return defaultConfig();
82
+ }
83
+ throw err;
84
+ }
85
+ }
86
+ migrate(parsed) {
87
+ const base = defaultConfig();
88
+ return {
89
+ ...base,
90
+ ...parsed,
91
+ schemaVersion: CONFIG_SCHEMA_VERSION,
92
+ };
93
+ }
94
+ }
95
+ export function createConfigService(opts = {}) {
96
+ return ConfigService.withPaths(resolvePaths(opts));
97
+ }
98
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"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"}