arc402-cli 0.9.19 → 0.10.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 (359) hide show
  1. package/README.md +41 -2
  2. package/dist/abis.d.ts +1 -0
  3. package/dist/abis.d.ts.map +1 -1
  4. package/dist/abis.js +45 -14
  5. package/dist/abis.js.map +1 -1
  6. package/dist/bundler.d.ts +1 -1
  7. package/dist/bundler.d.ts.map +1 -1
  8. package/dist/bundler.js +61 -27
  9. package/dist/bundler.js.map +1 -1
  10. package/dist/client.d.ts +1 -1
  11. package/dist/client.d.ts.map +1 -1
  12. package/dist/client.js +9 -5
  13. package/dist/client.js.map +1 -1
  14. package/dist/coinbase-smart-wallet.js +4 -1
  15. package/dist/coinbase-smart-wallet.js.map +1 -1
  16. package/dist/commands/accept.js +28 -25
  17. package/dist/commands/accept.js.map +1 -1
  18. package/dist/commands/agent-handshake.js +18 -15
  19. package/dist/commands/agent-handshake.js.map +1 -1
  20. package/dist/commands/agent.js +104 -98
  21. package/dist/commands/agent.js.map +1 -1
  22. package/dist/commands/agreements.js +98 -62
  23. package/dist/commands/agreements.js.map +1 -1
  24. package/dist/commands/arbitrator.js +81 -45
  25. package/dist/commands/arbitrator.js.map +1 -1
  26. package/dist/commands/arena-handshake.d.ts.map +1 -1
  27. package/dist/commands/arena-handshake.js +35 -53
  28. package/dist/commands/arena-handshake.js.map +1 -1
  29. package/dist/commands/arena.js +18 -12
  30. package/dist/commands/arena.js.map +1 -1
  31. package/dist/commands/backup.js +36 -30
  32. package/dist/commands/backup.js.map +1 -1
  33. package/dist/commands/cancel.js +18 -15
  34. package/dist/commands/cancel.js.map +1 -1
  35. package/dist/commands/channel.js +81 -45
  36. package/dist/commands/channel.js.map +1 -1
  37. package/dist/commands/coldstart.js +34 -31
  38. package/dist/commands/coldstart.js.map +1 -1
  39. package/dist/commands/compute.d.ts +14 -0
  40. package/dist/commands/compute.d.ts.map +1 -0
  41. package/dist/commands/compute.js +466 -0
  42. package/dist/commands/compute.js.map +1 -0
  43. package/dist/commands/config.js +30 -24
  44. package/dist/commands/config.js.map +1 -1
  45. package/dist/commands/contract-interaction.js +15 -12
  46. package/dist/commands/contract-interaction.js.map +1 -1
  47. package/dist/commands/daemon.d.ts.map +1 -1
  48. package/dist/commands/daemon.js +135 -98
  49. package/dist/commands/daemon.js.map +1 -1
  50. package/dist/commands/deliver.js +76 -37
  51. package/dist/commands/deliver.js.map +1 -1
  52. package/dist/commands/discover.js +27 -24
  53. package/dist/commands/discover.js.map +1 -1
  54. package/dist/commands/dispute.js +110 -104
  55. package/dist/commands/dispute.js.map +1 -1
  56. package/dist/commands/doctor.js +55 -16
  57. package/dist/commands/doctor.js.map +1 -1
  58. package/dist/commands/endpoint.js +95 -56
  59. package/dist/commands/endpoint.js.map +1 -1
  60. package/dist/commands/feed.js +18 -11
  61. package/dist/commands/feed.js.map +1 -1
  62. package/dist/commands/hire.js +40 -37
  63. package/dist/commands/hire.js.map +1 -1
  64. package/dist/commands/migrate.js +33 -30
  65. package/dist/commands/migrate.js.map +1 -1
  66. package/dist/commands/negotiate.d.ts.map +1 -1
  67. package/dist/commands/negotiate.js +36 -34
  68. package/dist/commands/negotiate.js.map +1 -1
  69. package/dist/commands/openshell.js +104 -68
  70. package/dist/commands/openshell.js.map +1 -1
  71. package/dist/commands/owner.js +20 -17
  72. package/dist/commands/owner.js.map +1 -1
  73. package/dist/commands/policy.js +43 -41
  74. package/dist/commands/policy.js.map +1 -1
  75. package/dist/commands/relay.d.ts.map +1 -1
  76. package/dist/commands/relay.js +51 -18
  77. package/dist/commands/relay.js.map +1 -1
  78. package/dist/commands/remediate.js +23 -20
  79. package/dist/commands/remediate.js.map +1 -1
  80. package/dist/commands/reputation.js +27 -25
  81. package/dist/commands/reputation.js.map +1 -1
  82. package/dist/commands/setup.js +104 -65
  83. package/dist/commands/setup.js.map +1 -1
  84. package/dist/commands/trust.js +20 -17
  85. package/dist/commands/trust.js.map +1 -1
  86. package/dist/commands/verify.js +21 -18
  87. package/dist/commands/verify.js.map +1 -1
  88. package/dist/commands/wallet.d.ts.map +1 -1
  89. package/dist/commands/wallet.js +645 -679
  90. package/dist/commands/wallet.js.map +1 -1
  91. package/dist/commands/watch.js +36 -33
  92. package/dist/commands/watch.js.map +1 -1
  93. package/dist/commands/watchtower.js +73 -37
  94. package/dist/commands/watchtower.js.map +1 -1
  95. package/dist/commands/workroom.d.ts.map +1 -1
  96. package/dist/commands/workroom.js +282 -143
  97. package/dist/commands/workroom.js.map +1 -1
  98. package/dist/config.d.ts +3 -0
  99. package/dist/config.d.ts.map +1 -1
  100. package/dist/config.js +71 -22
  101. package/dist/config.js.map +1 -1
  102. package/dist/daemon/compute-metering.d.ts +61 -0
  103. package/dist/daemon/compute-metering.d.ts.map +1 -0
  104. package/dist/daemon/compute-metering.js +299 -0
  105. package/dist/daemon/compute-metering.js.map +1 -0
  106. package/dist/daemon/compute-session.d.ts +100 -0
  107. package/dist/daemon/compute-session.d.ts.map +1 -0
  108. package/dist/daemon/compute-session.js +231 -0
  109. package/dist/daemon/compute-session.js.map +1 -0
  110. package/dist/daemon/config.d.ts +19 -1
  111. package/dist/daemon/config.d.ts.map +1 -1
  112. package/dist/daemon/config.js +90 -16
  113. package/dist/daemon/config.js.map +1 -1
  114. package/dist/daemon/credentials.d.ts +24 -0
  115. package/dist/daemon/credentials.d.ts.map +1 -0
  116. package/dist/daemon/credentials.js +80 -0
  117. package/dist/daemon/credentials.js.map +1 -0
  118. package/dist/daemon/delivery-client.d.ts +35 -0
  119. package/dist/daemon/delivery-client.d.ts.map +1 -0
  120. package/dist/daemon/delivery-client.js +231 -0
  121. package/dist/daemon/delivery-client.js.map +1 -0
  122. package/dist/daemon/file-delivery.d.ts +98 -0
  123. package/dist/daemon/file-delivery.d.ts.map +1 -0
  124. package/dist/daemon/file-delivery.js +461 -0
  125. package/dist/daemon/file-delivery.js.map +1 -0
  126. package/dist/daemon/hire-listener.d.ts +3 -3
  127. package/dist/daemon/hire-listener.d.ts.map +1 -1
  128. package/dist/daemon/hire-listener.js +47 -13
  129. package/dist/daemon/hire-listener.js.map +1 -1
  130. package/dist/daemon/index.d.ts +2 -1
  131. package/dist/daemon/index.d.ts.map +1 -1
  132. package/dist/daemon/index.js +526 -53
  133. package/dist/daemon/index.js.map +1 -1
  134. package/dist/daemon/job-lifecycle.d.ts +1 -1
  135. package/dist/daemon/job-lifecycle.d.ts.map +1 -1
  136. package/dist/daemon/job-lifecycle.js +51 -11
  137. package/dist/daemon/job-lifecycle.js.map +1 -1
  138. package/dist/daemon/notify.d.ts +1 -1
  139. package/dist/daemon/notify.d.ts.map +1 -1
  140. package/dist/daemon/notify.js +53 -19
  141. package/dist/daemon/notify.js.map +1 -1
  142. package/dist/daemon/token-metering.js +47 -8
  143. package/dist/daemon/token-metering.js.map +1 -1
  144. package/dist/daemon/userops.d.ts +2 -2
  145. package/dist/daemon/userops.d.ts.map +1 -1
  146. package/dist/daemon/userops.js +27 -23
  147. package/dist/daemon/userops.js.map +1 -1
  148. package/dist/daemon/wallet-monitor.d.ts +1 -1
  149. package/dist/daemon/wallet-monitor.d.ts.map +1 -1
  150. package/dist/daemon/wallet-monitor.js +12 -8
  151. package/dist/daemon/wallet-monitor.js.map +1 -1
  152. package/dist/daemon/worker-executor.d.ts +71 -0
  153. package/dist/daemon/worker-executor.d.ts.map +1 -0
  154. package/dist/daemon/worker-executor.js +382 -0
  155. package/dist/daemon/worker-executor.js.map +1 -0
  156. package/dist/drain-v4.js +64 -26
  157. package/dist/drain-v4.js.map +1 -1
  158. package/dist/endpoint-config.js +63 -20
  159. package/dist/endpoint-config.js.map +1 -1
  160. package/dist/endpoint-notify.d.ts.map +1 -1
  161. package/dist/endpoint-notify.js +49 -15
  162. package/dist/endpoint-notify.js.map +1 -1
  163. package/dist/index.js +50 -18
  164. package/dist/index.js.map +1 -1
  165. package/dist/openshell-runtime.d.ts.map +1 -1
  166. package/dist/openshell-runtime.js +82 -38
  167. package/dist/openshell-runtime.js.map +1 -1
  168. package/dist/program.d.ts.map +1 -1
  169. package/dist/program.js +85 -78
  170. package/dist/program.js.map +1 -1
  171. package/dist/repl.js +31 -25
  172. package/dist/repl.js.map +1 -1
  173. package/dist/signing.js +6 -3
  174. package/dist/signing.js.map +1 -1
  175. package/dist/telegram-notify.js +40 -3
  176. package/dist/telegram-notify.js.map +1 -1
  177. package/dist/tui/App.d.ts.map +1 -1
  178. package/dist/tui/App.js +56 -89
  179. package/dist/tui/App.js.map +1 -1
  180. package/dist/tui/Footer.js +7 -4
  181. package/dist/tui/Footer.js.map +1 -1
  182. package/dist/tui/Header.d.ts +1 -1
  183. package/dist/tui/Header.d.ts.map +1 -1
  184. package/dist/tui/Header.js +14 -9
  185. package/dist/tui/Header.js.map +1 -1
  186. package/dist/tui/InputLine.d.ts +2 -1
  187. package/dist/tui/InputLine.d.ts.map +1 -1
  188. package/dist/tui/InputLine.js +47 -97
  189. package/dist/tui/InputLine.js.map +1 -1
  190. package/dist/tui/Viewport.d.ts +1 -2
  191. package/dist/tui/Viewport.d.ts.map +1 -1
  192. package/dist/tui/Viewport.js +26 -6
  193. package/dist/tui/Viewport.js.map +1 -1
  194. package/dist/tui/WalletConnectPairing.js +19 -16
  195. package/dist/tui/WalletConnectPairing.js.map +1 -1
  196. package/dist/tui/components/Button.js +9 -6
  197. package/dist/tui/components/Button.js.map +1 -1
  198. package/dist/tui/components/CeremonyView.js +8 -5
  199. package/dist/tui/components/CeremonyView.js.map +1 -1
  200. package/dist/tui/components/CompletionDropdown.js +9 -6
  201. package/dist/tui/components/CompletionDropdown.js.map +1 -1
  202. package/dist/tui/components/ConfirmPrompt.js +8 -5
  203. package/dist/tui/components/ConfirmPrompt.js.map +1 -1
  204. package/dist/tui/components/CustomTextInput.js +14 -11
  205. package/dist/tui/components/CustomTextInput.js.map +1 -1
  206. package/dist/tui/components/InteractiveTable.js +12 -9
  207. package/dist/tui/components/InteractiveTable.js.map +1 -1
  208. package/dist/tui/components/StepSpinner.js +13 -10
  209. package/dist/tui/components/StepSpinner.js.map +1 -1
  210. package/dist/tui/components/Toast.js +12 -8
  211. package/dist/tui/components/Toast.js.map +1 -1
  212. package/dist/tui/index.d.ts.map +1 -1
  213. package/dist/tui/index.js +21 -28
  214. package/dist/tui/index.js.map +1 -1
  215. package/dist/tui/useChat.js +19 -13
  216. package/dist/tui/useChat.js.map +1 -1
  217. package/dist/tui/useCommand.d.ts +2 -3
  218. package/dist/tui/useCommand.d.ts.map +1 -1
  219. package/dist/tui/useCommand.js +24 -100
  220. package/dist/tui/useCommand.js.map +1 -1
  221. package/dist/tui/useNotifications.js +8 -5
  222. package/dist/tui/useNotifications.js.map +1 -1
  223. package/dist/tui/useScroll.d.ts.map +1 -1
  224. package/dist/tui/useScroll.js +12 -15
  225. package/dist/tui/useScroll.js.map +1 -1
  226. package/dist/ui/banner.d.ts +0 -12
  227. package/dist/ui/banner.d.ts.map +1 -1
  228. package/dist/ui/banner.js +19 -35
  229. package/dist/ui/banner.js.map +1 -1
  230. package/dist/ui/colors.js +19 -13
  231. package/dist/ui/colors.js.map +1 -1
  232. package/dist/ui/format.js +14 -6
  233. package/dist/ui/format.js.map +1 -1
  234. package/dist/ui/qr-render.js +11 -4
  235. package/dist/ui/qr-render.js.map +1 -1
  236. package/dist/ui/rpc-fallback.js +11 -6
  237. package/dist/ui/rpc-fallback.js.map +1 -1
  238. package/dist/ui/spinner.js +12 -6
  239. package/dist/ui/spinner.js.map +1 -1
  240. package/dist/ui/tree.js +6 -3
  241. package/dist/ui/tree.js.map +1 -1
  242. package/dist/utils/format.js +41 -27
  243. package/dist/utils/format.js.map +1 -1
  244. package/dist/utils/hash.js +42 -4
  245. package/dist/utils/hash.js.map +1 -1
  246. package/dist/utils/time.js +6 -2
  247. package/dist/utils/time.js.map +1 -1
  248. package/dist/wallet-router.d.ts +1 -1
  249. package/dist/wallet-router.d.ts.map +1 -1
  250. package/dist/wallet-router.js +19 -12
  251. package/dist/wallet-router.js.map +1 -1
  252. package/dist/walletconnect-session.d.ts +1 -1
  253. package/dist/walletconnect-session.d.ts.map +1 -1
  254. package/dist/walletconnect-session.js +11 -6
  255. package/dist/walletconnect-session.js.map +1 -1
  256. package/dist/walletconnect.d.ts +5 -6
  257. package/dist/walletconnect.d.ts.map +1 -1
  258. package/dist/walletconnect.js +35 -32
  259. package/dist/walletconnect.js.map +1 -1
  260. package/package.json +11 -10
  261. package/INK6-UX-SPEC.md +0 -446
  262. package/MIGRATION-SPEC.md +0 -108
  263. package/TUI-SPEC.md +0 -214
  264. package/scripts/authorize-machine-key.ts +0 -43
  265. package/scripts/drain-wallet.ts +0 -149
  266. package/scripts/execute-spend-only.ts +0 -81
  267. package/scripts/register-agent-userop.ts +0 -186
  268. package/src/abis.ts +0 -187
  269. package/src/bundler.ts +0 -235
  270. package/src/client.ts +0 -36
  271. package/src/coinbase-smart-wallet.ts +0 -51
  272. package/src/commands/accept.ts +0 -64
  273. package/src/commands/agent-handshake.ts +0 -72
  274. package/src/commands/agent.ts +0 -691
  275. package/src/commands/agreements.ts +0 -350
  276. package/src/commands/arbitrator.ts +0 -180
  277. package/src/commands/arena-handshake.ts +0 -274
  278. package/src/commands/arena.ts +0 -122
  279. package/src/commands/backup.ts +0 -117
  280. package/src/commands/cancel.ts +0 -35
  281. package/src/commands/channel.ts +0 -218
  282. package/src/commands/coldstart.ts +0 -165
  283. package/src/commands/config.ts +0 -68
  284. package/src/commands/contract-interaction.ts +0 -166
  285. package/src/commands/daemon.ts +0 -1054
  286. package/src/commands/deliver.ts +0 -148
  287. package/src/commands/discover.ts +0 -350
  288. package/src/commands/dispute.ts +0 -375
  289. package/src/commands/doctor.ts +0 -172
  290. package/src/commands/endpoint.ts +0 -620
  291. package/src/commands/feed.ts +0 -229
  292. package/src/commands/hire.ts +0 -245
  293. package/src/commands/migrate.ts +0 -177
  294. package/src/commands/negotiate.ts +0 -272
  295. package/src/commands/openshell.ts +0 -1055
  296. package/src/commands/owner.ts +0 -35
  297. package/src/commands/policy.ts +0 -263
  298. package/src/commands/relay.ts +0 -277
  299. package/src/commands/remediate.ts +0 -24
  300. package/src/commands/reputation.ts +0 -79
  301. package/src/commands/setup.ts +0 -343
  302. package/src/commands/trust.ts +0 -27
  303. package/src/commands/verify.ts +0 -91
  304. package/src/commands/wallet.ts +0 -3548
  305. package/src/commands/watch.ts +0 -220
  306. package/src/commands/watchtower.ts +0 -248
  307. package/src/commands/workroom.ts +0 -963
  308. package/src/config.ts +0 -220
  309. package/src/daemon/config.ts +0 -344
  310. package/src/daemon/hire-listener.ts +0 -226
  311. package/src/daemon/index.ts +0 -1089
  312. package/src/daemon/job-lifecycle.ts +0 -215
  313. package/src/daemon/notify.ts +0 -297
  314. package/src/daemon/token-metering.ts +0 -183
  315. package/src/daemon/userops.ts +0 -119
  316. package/src/daemon/wallet-monitor.ts +0 -90
  317. package/src/drain-v4.ts +0 -159
  318. package/src/endpoint-config.ts +0 -83
  319. package/src/endpoint-notify.ts +0 -134
  320. package/src/index.ts +0 -74
  321. package/src/openshell-runtime.ts +0 -281
  322. package/src/program.ts +0 -88
  323. package/src/repl.ts +0 -178
  324. package/src/signing.ts +0 -28
  325. package/src/telegram-notify.ts +0 -88
  326. package/src/tui/App.tsx +0 -263
  327. package/src/tui/Footer.tsx +0 -18
  328. package/src/tui/Header.tsx +0 -45
  329. package/src/tui/InputLine.tsx +0 -243
  330. package/src/tui/Viewport.tsx +0 -51
  331. package/src/tui/WalletConnectPairing.tsx +0 -114
  332. package/src/tui/components/Button.tsx +0 -38
  333. package/src/tui/components/CeremonyView.tsx +0 -39
  334. package/src/tui/components/CompletionDropdown.tsx +0 -56
  335. package/src/tui/components/ConfirmPrompt.tsx +0 -36
  336. package/src/tui/components/CustomTextInput.tsx +0 -132
  337. package/src/tui/components/InteractiveTable.tsx +0 -106
  338. package/src/tui/components/StepSpinner.tsx +0 -84
  339. package/src/tui/components/Toast.tsx +0 -59
  340. package/src/tui/index.tsx +0 -90
  341. package/src/tui/useChat.ts +0 -103
  342. package/src/tui/useCommand.ts +0 -238
  343. package/src/tui/useNotifications.ts +0 -28
  344. package/src/tui/useScroll.ts +0 -69
  345. package/src/ui/banner.ts +0 -78
  346. package/src/ui/colors.ts +0 -30
  347. package/src/ui/format.ts +0 -78
  348. package/src/ui/qr-render.ts +0 -92
  349. package/src/ui/rpc-fallback.ts +0 -59
  350. package/src/ui/spinner.ts +0 -56
  351. package/src/ui/tree.ts +0 -16
  352. package/src/utils/format.ts +0 -48
  353. package/src/utils/hash.ts +0 -5
  354. package/src/utils/time.ts +0 -15
  355. package/src/wallet-router.ts +0 -178
  356. package/src/walletconnect-session.ts +0 -27
  357. package/src/walletconnect.ts +0 -309
  358. package/test/time.test.js +0 -11
  359. package/tsconfig.json +0 -33
@@ -0,0 +1,299 @@
1
+ "use strict";
2
+ /**
3
+ * ComputeMetering — GPU utilization tracking for ARC-402 compute sessions.
4
+ *
5
+ * - Polls nvidia-smi every N seconds (configurable; default 30)
6
+ * - Falls back to mock metrics when nvidia-smi is not available (testing)
7
+ * - Aggregates into 15-minute UsageReports signed with the provider key
8
+ * - Persists raw metrics to ~/.arc402/compute/<sessionId>/metrics.jsonl
9
+ * - Persists signed reports to ~/.arc402/compute/<sessionId>/reports/
10
+ */
11
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ var desc = Object.getOwnPropertyDescriptor(m, k);
14
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
15
+ desc = { enumerable: true, get: function() { return m[k]; } };
16
+ }
17
+ Object.defineProperty(o, k2, desc);
18
+ }) : (function(o, m, k, k2) {
19
+ if (k2 === undefined) k2 = k;
20
+ o[k2] = m[k];
21
+ }));
22
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
23
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
24
+ }) : function(o, v) {
25
+ o["default"] = v;
26
+ });
27
+ var __importStar = (this && this.__importStar) || (function () {
28
+ var ownKeys = function(o) {
29
+ ownKeys = Object.getOwnPropertyNames || function (o) {
30
+ var ar = [];
31
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
32
+ return ar;
33
+ };
34
+ return ownKeys(o);
35
+ };
36
+ return function (mod) {
37
+ if (mod && mod.__esModule) return mod;
38
+ var result = {};
39
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
40
+ __setModuleDefault(result, mod);
41
+ return result;
42
+ };
43
+ })();
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ exports.ComputeMetering = void 0;
46
+ const fs = __importStar(require("fs"));
47
+ const path = __importStar(require("path"));
48
+ const child_process_1 = require("child_process");
49
+ const ethers_1 = require("ethers");
50
+ const config_1 = require("./config");
51
+ // ─── Constants ────────────────────────────────────────────────────────────────
52
+ const COMPUTE_DATA_DIR = path.join(config_1.DAEMON_DIR, "compute");
53
+ const GPU_ACTIVE_THRESHOLD = 5; // utilization % above which we count compute-minutes
54
+ // ─── nvidia-smi poll ──────────────────────────────────────────────────────────
55
+ function pollNvidiaSmi() {
56
+ try {
57
+ const output = (0, child_process_1.execSync)("nvidia-smi --query-gpu=utilization.gpu,memory.used,temperature.gpu --format=csv,noheader,nounits", { timeout: 5000, stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
58
+ const parts = output.split(",").map(s => s.trim());
59
+ if (parts.length < 3)
60
+ return null;
61
+ const utilization = parseFloat(parts[0]);
62
+ const memoryMB = parseFloat(parts[1]);
63
+ const temperatureC = parseFloat(parts[2]);
64
+ if (isNaN(utilization) || isNaN(memoryMB) || isNaN(temperatureC))
65
+ return null;
66
+ return { utilization, memoryMB, temperatureC };
67
+ }
68
+ catch {
69
+ return null;
70
+ }
71
+ }
72
+ function mockMetrics() {
73
+ // Deterministic-ish mock that oscillates for test realism
74
+ const t = Date.now() / 1000;
75
+ return {
76
+ utilization: Math.round(50 + 30 * Math.sin(t / 60)),
77
+ memoryMB: Math.round(4000 + 1000 * Math.cos(t / 90)),
78
+ temperatureC: Math.round(65 + 10 * Math.sin(t / 120)),
79
+ };
80
+ }
81
+ // ─── Report signing ───────────────────────────────────────────────────────────
82
+ /**
83
+ * Produce the same digest that ComputeAgreement.sol verifies.
84
+ * CA-IND-1: includes chainId and contractAddress to prevent cross-chain/cross-contract replay.
85
+ * structHash = keccak256(abi.encode(chainId, contractAddress, sessionId, periodStart,
86
+ * periodEnd, computeMinutes, avgUtilization, metricsHash))
87
+ * digest = EIP-191 personal_sign(structHash)
88
+ */
89
+ function buildReportDigest(chainId, contractAddress, sessionId, periodStart, periodEnd, computeMinutes, avgUtilization, metricsHash) {
90
+ const encoded = ethers_1.ethers.AbiCoder.defaultAbiCoder().encode(["uint256", "address", "bytes32", "uint256", "uint256", "uint256", "uint256", "bytes32"], [
91
+ BigInt(chainId),
92
+ contractAddress,
93
+ sessionId,
94
+ BigInt(periodStart),
95
+ BigInt(periodEnd),
96
+ BigInt(computeMinutes),
97
+ BigInt(avgUtilization),
98
+ metricsHash,
99
+ ]);
100
+ const structHash = ethers_1.ethers.keccak256(encoded);
101
+ // EIP-191 prefix — matches "\x19Ethereum Signed Message:\n32" + structHash
102
+ return ethers_1.ethers.hashMessage(ethers_1.ethers.getBytes(structHash));
103
+ }
104
+ async function signReport(wallet, chainId, contractAddress, sessionId, periodStart, periodEnd, computeMinutes, avgUtilization, metricsHash) {
105
+ const encoded = ethers_1.ethers.AbiCoder.defaultAbiCoder().encode(["uint256", "address", "bytes32", "uint256", "uint256", "uint256", "uint256", "bytes32"], [
106
+ BigInt(chainId),
107
+ contractAddress,
108
+ sessionId,
109
+ BigInt(periodStart),
110
+ BigInt(periodEnd),
111
+ BigInt(computeMinutes),
112
+ BigInt(avgUtilization),
113
+ metricsHash,
114
+ ]);
115
+ const structHash = ethers_1.ethers.keccak256(encoded);
116
+ return wallet.signMessage(ethers_1.ethers.getBytes(structHash));
117
+ }
118
+ // ─── Main class ───────────────────────────────────────────────────────────────
119
+ const SUBMIT_USAGE_REPORT_ABI = [
120
+ "function submitUsageReport(bytes32 sessionId, uint256 periodStart, uint256 periodEnd, uint256 computeMinutes, uint256 avgUtilization, bytes providerSignature, bytes32 metricsHash) external",
121
+ ];
122
+ class ComputeMetering {
123
+ constructor(providerPrivateKey, chainId, contractAddress, meteringIntervalSeconds = 30, reportIntervalMinutes = 15, onchainProvider) {
124
+ this.sessions = new Map();
125
+ this.wallet = new ethers_1.ethers.Wallet(providerPrivateKey);
126
+ this.chainId = chainId;
127
+ this.contractAddress = contractAddress;
128
+ this.meteringIntervalMs = meteringIntervalSeconds * 1000;
129
+ this.reportIntervalMs = reportIntervalMinutes * 60 * 1000;
130
+ this.onchainProvider = onchainProvider;
131
+ }
132
+ /**
133
+ * Start metering a new session.
134
+ * Polls nvidia-smi on the metering interval and aggregates 15-min reports.
135
+ */
136
+ startMetering(sessionId) {
137
+ if (this.sessions.has(sessionId))
138
+ return;
139
+ const sessionDir = path.join(COMPUTE_DATA_DIR, sessionId);
140
+ const reportsDir = path.join(sessionDir, "reports");
141
+ fs.mkdirSync(reportsDir, { recursive: true, mode: 0o700 });
142
+ const state = {
143
+ sessionId,
144
+ startTime: Date.now(),
145
+ lastReportTime: Date.now(),
146
+ rawMetrics: [],
147
+ allReports: [],
148
+ metricsFilePath: path.join(sessionDir, "metrics.jsonl"),
149
+ reportsDir,
150
+ intervalHandle: null,
151
+ reportIntervalHandle: null,
152
+ };
153
+ // Metering poll
154
+ state.intervalHandle = setInterval(() => {
155
+ this._collectMetric(state);
156
+ }, this.meteringIntervalMs);
157
+ // Report generation
158
+ state.reportIntervalHandle = setInterval(() => {
159
+ void this._generateReport(state);
160
+ }, this.reportIntervalMs);
161
+ this.sessions.set(sessionId, state);
162
+ }
163
+ /**
164
+ * Stop metering and return the final usage report.
165
+ * Generates a final report covering remaining metrics since last report.
166
+ */
167
+ async stopMetering(sessionId) {
168
+ const state = this.sessions.get(sessionId);
169
+ if (!state)
170
+ return null;
171
+ clearInterval(state.intervalHandle);
172
+ clearInterval(state.reportIntervalHandle);
173
+ // Final report from remaining buffered metrics
174
+ const finalReport = await this._generateReport(state);
175
+ this.sessions.delete(sessionId);
176
+ return finalReport;
177
+ }
178
+ /**
179
+ * Return the latest metrics snapshot for a running session.
180
+ */
181
+ getCurrentMetrics(sessionId) {
182
+ const state = this.sessions.get(sessionId);
183
+ if (!state || state.rawMetrics.length === 0)
184
+ return null;
185
+ return state.rawMetrics[state.rawMetrics.length - 1];
186
+ }
187
+ /**
188
+ * Return all usage reports generated for a session.
189
+ */
190
+ getUsageReports(sessionId) {
191
+ const state = this.sessions.get(sessionId);
192
+ if (!state) {
193
+ // Try to load persisted reports from disk
194
+ return this._loadReportsFromDisk(sessionId);
195
+ }
196
+ return [...state.allReports];
197
+ }
198
+ // ─── Private ────────────────────────────────────────────────────────────────
199
+ _collectMetric(state) {
200
+ const gpu = pollNvidiaSmi() ?? mockMetrics();
201
+ const now = Date.now();
202
+ const wallMs = now - state.startTime;
203
+ const wallMins = wallMs / 60000;
204
+ // Compute-minutes: count wall-clock intervals where utilization exceeded threshold
205
+ const active = gpu.utilization > GPU_ACTIVE_THRESHOLD;
206
+ const addComputeMins = active ? this.meteringIntervalMs / 60000 : 0;
207
+ // Accumulate into the current period buffer
208
+ const prevComputeMins = state.rawMetrics.length > 0
209
+ ? state.rawMetrics[state.rawMetrics.length - 1].computeMinutes
210
+ : 0;
211
+ const metric = {
212
+ sessionId: state.sessionId,
213
+ gpuUtilizationPercent: gpu.utilization,
214
+ gpuMemoryUsedMB: gpu.memoryMB,
215
+ gpuTemperatureC: gpu.temperatureC,
216
+ activeMinutes: wallMins,
217
+ computeMinutes: prevComputeMins + addComputeMins,
218
+ timestamp: now,
219
+ };
220
+ state.rawMetrics.push(metric);
221
+ // Persist to JSONL
222
+ try {
223
+ fs.appendFileSync(state.metricsFilePath, JSON.stringify(metric) + "\n", { mode: 0o600 });
224
+ }
225
+ catch { /* non-fatal — disk full etc */ }
226
+ }
227
+ async _generateReport(state) {
228
+ if (state.rawMetrics.length === 0)
229
+ return null;
230
+ const periodStart = state.lastReportTime;
231
+ const periodEnd = Date.now();
232
+ // Metrics accumulated in this period
233
+ const periodMetrics = state.rawMetrics.filter(m => m.timestamp >= periodStart);
234
+ if (periodMetrics.length === 0)
235
+ return null;
236
+ const computeMinutes = periodMetrics.reduce((acc, m) => {
237
+ // Each poll interval contributes proportionally
238
+ const active = m.gpuUtilizationPercent > GPU_ACTIVE_THRESHOLD;
239
+ return acc + (active ? this.meteringIntervalMs / 60000 : 0);
240
+ }, 0);
241
+ const avgUtilization = Math.round(periodMetrics.reduce((acc, m) => acc + m.gpuUtilizationPercent, 0) / periodMetrics.length);
242
+ // Hash raw metrics for dispute evidence
243
+ const metricsJson = JSON.stringify(periodMetrics);
244
+ const metricsHash = ethers_1.ethers.keccak256(ethers_1.ethers.toUtf8Bytes(metricsJson));
245
+ const roundedMinutes = Math.round(computeMinutes);
246
+ const sig = await signReport(this.wallet, this.chainId, this.contractAddress, state.sessionId, Math.floor(periodStart / 1000), Math.floor(periodEnd / 1000), roundedMinutes, avgUtilization, metricsHash);
247
+ const report = {
248
+ sessionId: state.sessionId,
249
+ periodStart: Math.floor(periodStart / 1000),
250
+ periodEnd: Math.floor(periodEnd / 1000),
251
+ computeMinutes: roundedMinutes,
252
+ avgUtilization,
253
+ providerSignature: sig,
254
+ metricsHash,
255
+ };
256
+ state.allReports.push(report);
257
+ state.lastReportTime = periodEnd;
258
+ // Clear the processed period's metrics from the buffer
259
+ state.rawMetrics = state.rawMetrics.filter(m => m.timestamp >= periodEnd);
260
+ // Persist report to disk
261
+ const reportFile = path.join(state.reportsDir, `report_${report.periodStart}.json`);
262
+ try {
263
+ fs.writeFileSync(reportFile, JSON.stringify(report, null, 2), { mode: 0o600 });
264
+ }
265
+ catch { /* non-fatal */ }
266
+ // Submit on-chain if provider is configured
267
+ if (this.onchainProvider && this.contractAddress) {
268
+ void this._submitOnChain(report).catch(() => { });
269
+ }
270
+ return report;
271
+ }
272
+ async _submitOnChain(report) {
273
+ if (!this.onchainProvider)
274
+ return;
275
+ const signer = this.wallet.connect(this.onchainProvider);
276
+ const contract = new ethers_1.ethers.Contract(this.contractAddress, SUBMIT_USAGE_REPORT_ABI, signer);
277
+ const tx = await contract.submitUsageReport(report.sessionId, BigInt(report.periodStart), BigInt(report.periodEnd), BigInt(report.computeMinutes), BigInt(report.avgUtilization), report.providerSignature, report.metricsHash);
278
+ await tx.wait();
279
+ }
280
+ _loadReportsFromDisk(sessionId) {
281
+ const reportsDir = path.join(COMPUTE_DATA_DIR, sessionId, "reports");
282
+ if (!fs.existsSync(reportsDir))
283
+ return [];
284
+ try {
285
+ const files = fs.readdirSync(reportsDir)
286
+ .filter(f => f.endsWith(".json"))
287
+ .sort();
288
+ return files.map(f => {
289
+ const raw = fs.readFileSync(path.join(reportsDir, f), "utf-8");
290
+ return JSON.parse(raw);
291
+ });
292
+ }
293
+ catch {
294
+ return [];
295
+ }
296
+ }
297
+ }
298
+ exports.ComputeMetering = ComputeMetering;
299
+ //# sourceMappingURL=compute-metering.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compute-metering.js","sourceRoot":"","sources":["../../src/daemon/compute-metering.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEH,uCAAyB;AACzB,2CAA6B;AAE7B,iDAAyC;AACzC,mCAAgC;AAChC,qCAAsC;AAoCtC,iFAAiF;AAEjF,MAAM,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAAC,mBAAU,EAAE,SAAS,CAAC,CAAC;AAC1D,MAAM,oBAAoB,GAAG,CAAC,CAAC,CAAE,qDAAqD;AAEtF,iFAAiF;AAEjF,SAAS,aAAa;IACpB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAA,wBAAQ,EACrB,kGAAkG,EAClG,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CACvD,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC;QAEpB,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QACnD,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QAElC,MAAM,WAAW,GAAI,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1C,MAAM,QAAQ,GAAO,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1C,MAAM,YAAY,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAE1C,IAAI,KAAK,CAAC,WAAW,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,YAAY,CAAC;YAAE,OAAO,IAAI,CAAC;QAE9E,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;IACjD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,WAAW;IAClB,0DAA0D;IAC1D,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;IAC5B,OAAO;QACL,WAAW,EAAG,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;QACpD,QAAQ,EAAM,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;QACxD,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;KACtD,CAAC;AACJ,CAAC;AAED,iFAAiF;AAEjF;;;;;;GAMG;AACH,SAAS,iBAAiB,CACxB,OAAe,EACf,eAAuB,EACvB,SAAiB,EACjB,WAAmB,EACnB,SAAiB,EACjB,cAAsB,EACtB,cAAsB,EACtB,WAAmB;IAEnB,MAAM,OAAO,GAAG,eAAM,CAAC,QAAQ,CAAC,eAAe,EAAE,CAAC,MAAM,CACtD,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,EACxF;QACE,MAAM,CAAC,OAAO,CAAC;QACf,eAAe;QACf,SAAS;QACT,MAAM,CAAC,WAAW,CAAC;QACnB,MAAM,CAAC,SAAS,CAAC;QACjB,MAAM,CAAC,cAAc,CAAC;QACtB,MAAM,CAAC,cAAc,CAAC;QACtB,WAAW;KACZ,CACF,CAAC;IACF,MAAM,UAAU,GAAG,eAAM,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IAC7C,2EAA2E;IAC3E,OAAO,eAAM,CAAC,WAAW,CAAC,eAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC;AACzD,CAAC;AAED,KAAK,UAAU,UAAU,CACvB,MAAqB,EACrB,OAAe,EACf,eAAuB,EACvB,SAAiB,EACjB,WAAmB,EACnB,SAAiB,EACjB,cAAsB,EACtB,cAAsB,EACtB,WAAmB;IAEnB,MAAM,OAAO,GAAG,eAAM,CAAC,QAAQ,CAAC,eAAe,EAAE,CAAC,MAAM,CACtD,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,EACxF;QACE,MAAM,CAAC,OAAO,CAAC;QACf,eAAe;QACf,SAAS;QACT,MAAM,CAAC,WAAW,CAAC;QACnB,MAAM,CAAC,SAAS,CAAC;QACjB,MAAM,CAAC,cAAc,CAAC;QACtB,MAAM,CAAC,cAAc,CAAC;QACtB,WAAW;KACZ,CACF,CAAC;IACF,MAAM,UAAU,GAAG,eAAM,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IAC7C,OAAO,MAAM,CAAC,WAAW,CAAC,eAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC;AACzD,CAAC;AAED,iFAAiF;AAEjF,MAAM,uBAAuB,GAAG;IAC9B,8LAA8L;CAC/L,CAAC;AAEF,MAAa,eAAe;IAS1B,YACE,kBAA0B,EAC1B,OAAe,EACf,eAAuB,EACvB,uBAAuB,GAAG,EAAE,EAC5B,qBAAqB,GAAK,EAAE,EAC5B,eAAwC;QAdlC,aAAQ,GAAsC,IAAI,GAAG,EAAE,CAAC;QAgB9D,IAAI,CAAC,MAAM,GAAgB,IAAI,eAAM,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC;QACjE,IAAI,CAAC,OAAO,GAAe,OAAO,CAAC;QACnC,IAAI,CAAC,eAAe,GAAO,eAAe,CAAC;QAC3C,IAAI,CAAC,kBAAkB,GAAI,uBAAuB,GAAG,IAAI,CAAC;QAC1D,IAAI,CAAC,gBAAgB,GAAM,qBAAqB,GAAG,EAAE,GAAG,IAAI,CAAC;QAC7D,IAAI,CAAC,eAAe,GAAO,eAAe,CAAC;IAC7C,CAAC;IAED;;;OAGG;IACH,aAAa,CAAC,SAAiB;QAC7B,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC;YAAE,OAAO;QAEzC,MAAM,UAAU,GAAI,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,SAAS,CAAC,CAAC;QAC3D,MAAM,UAAU,GAAI,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;QACrD,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAE3D,MAAM,KAAK,GAAyB;YAClC,SAAS;YACT,SAAS,EAAS,IAAI,CAAC,GAAG,EAAE;YAC5B,cAAc,EAAI,IAAI,CAAC,GAAG,EAAE;YAC5B,UAAU,EAAQ,EAAE;YACpB,UAAU,EAAQ,EAAE;YACpB,eAAe,EAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,eAAe,CAAC;YACxD,UAAU;YACV,cAAc,EAAQ,IAAiD;YACvE,oBAAoB,EAAE,IAAiD;SACxE,CAAC;QAEF,gBAAgB;QAChB,KAAK,CAAC,cAAc,GAAG,WAAW,CAAC,GAAG,EAAE;YACtC,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;QAC7B,CAAC,EAAE,IAAI,CAAC,kBAAkB,CAAC,CAAC;QAE5B,oBAAoB;QACpB,KAAK,CAAC,oBAAoB,GAAG,WAAW,CAAC,GAAG,EAAE;YAC5C,KAAK,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QACnC,CAAC,EAAE,IAAI,CAAC,gBAAgB,CAAC,CAAC;QAE1B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IACtC,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,YAAY,CAAC,SAAiB;QAClC,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC3C,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QAExB,aAAa,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;QACpC,aAAa,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC;QAE1C,+CAA+C;QAC/C,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QAEtD,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAChC,OAAO,WAAW,CAAC;IACrB,CAAC;IAED;;OAEG;IACH,iBAAiB,CAAC,SAAiB;QACjC,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC3C,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QACzD,OAAO,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACvD,CAAC;IAED;;OAEG;IACH,eAAe,CAAC,SAAiB;QAC/B,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC3C,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,0CAA0C;YAC1C,OAAO,IAAI,CAAC,oBAAoB,CAAC,SAAS,CAAC,CAAC;QAC9C,CAAC;QACD,OAAO,CAAC,GAAG,KAAK,CAAC,UAAU,CAAC,CAAC;IAC/B,CAAC;IAED,+EAA+E;IAEvE,cAAc,CAAC,KAA2B;QAChD,MAAM,GAAG,GAAG,aAAa,EAAE,IAAI,WAAW,EAAE,CAAC;QAE7C,MAAM,GAAG,GAAQ,IAAI,CAAC,GAAG,EAAE,CAAC;QAC5B,MAAM,MAAM,GAAK,GAAG,GAAG,KAAK,CAAC,SAAS,CAAC;QACvC,MAAM,QAAQ,GAAG,MAAM,GAAG,KAAM,CAAC;QAEjC,mFAAmF;QACnF,MAAM,MAAM,GAAG,GAAG,CAAC,WAAW,GAAG,oBAAoB,CAAC;QACtD,MAAM,cAAc,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,kBAAkB,GAAG,KAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAErE,4CAA4C;QAC5C,MAAM,eAAe,GAAG,KAAK,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC;YACjD,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,cAAc;YAC9D,CAAC,CAAC,CAAC,CAAC;QAEN,MAAM,MAAM,GAAmB;YAC7B,SAAS,EAAa,KAAK,CAAC,SAAS;YACrC,qBAAqB,EAAE,GAAG,CAAC,WAAW;YACtC,eAAe,EAAQ,GAAG,CAAC,QAAQ;YACnC,eAAe,EAAQ,GAAG,CAAC,YAAY;YACvC,aAAa,EAAU,QAAQ;YAC/B,cAAc,EAAS,eAAe,GAAG,cAAc;YACvD,SAAS,EAAc,GAAG;SAC3B,CAAC;QAEF,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAE9B,mBAAmB;QACnB,IAAI,CAAC;YACH,EAAE,CAAC,cAAc,CACf,KAAK,CAAC,eAAe,EACrB,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,IAAI,EAC7B,EAAE,IAAI,EAAE,KAAK,EAAE,CAChB,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC,CAAC,+BAA+B,CAAC,CAAC;IAC7C,CAAC;IAEO,KAAK,CAAC,eAAe,CAAC,KAA2B;QACvD,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAE/C,MAAM,WAAW,GAAG,KAAK,CAAC,cAAc,CAAC;QACzC,MAAM,SAAS,GAAK,IAAI,CAAC,GAAG,EAAE,CAAC;QAE/B,qCAAqC;QACrC,MAAM,aAAa,GAAG,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,IAAI,WAAW,CAAC,CAAC;QAC/E,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAE5C,MAAM,cAAc,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE;YACrD,gDAAgD;YAChD,MAAM,MAAM,GAAG,CAAC,CAAC,qBAAqB,GAAG,oBAAoB,CAAC;YAC9D,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,kBAAkB,GAAG,KAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/D,CAAC,EAAE,CAAC,CAAC,CAAC;QAEN,MAAM,cAAc,GAAG,IAAI,CAAC,KAAK,CAC/B,aAAa,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,qBAAqB,EAAE,CAAC,CAAC,GAAG,aAAa,CAAC,MAAM,CAC1F,CAAC;QAEF,wCAAwC;QACxC,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;QAClD,MAAM,WAAW,GAAG,eAAM,CAAC,SAAS,CAAC,eAAM,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,CAAC;QAEtE,MAAM,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;QAElD,MAAM,GAAG,GAAG,MAAM,UAAU,CAC1B,IAAI,CAAC,MAAM,EACX,IAAI,CAAC,OAAO,EACZ,IAAI,CAAC,eAAe,EACpB,KAAK,CAAC,SAAS,EACf,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC,EAC9B,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,EAC5B,cAAc,EACd,cAAc,EACd,WAAW,CACZ,CAAC;QAEF,MAAM,MAAM,GAAgB;YAC1B,SAAS,EAAU,KAAK,CAAC,SAAS;YAClC,WAAW,EAAQ,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC;YACjD,SAAS,EAAU,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC;YAC/C,cAAc,EAAK,cAAc;YACjC,cAAc;YACd,iBAAiB,EAAE,GAAG;YACtB,WAAW;SACZ,CAAC;QAEF,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC9B,KAAK,CAAC,cAAc,GAAG,SAAS,CAAC;QACjC,uDAAuD;QACvD,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,IAAI,SAAS,CAAC,CAAC;QAE1E,yBAAyB;QACzB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAC1B,KAAK,CAAC,UAAU,EAChB,UAAU,MAAM,CAAC,WAAW,OAAO,CACpC,CAAC;QACF,IAAI,CAAC;YACH,EAAE,CAAC,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACjF,CAAC;QAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC;QAE3B,4CAA4C;QAC5C,IAAI,IAAI,CAAC,eAAe,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;YACjD,KAAK,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAmB,CAAC,CAAC,CAAC;QACpE,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAEO,KAAK,CAAC,cAAc,CAAC,MAAmB;QAC9C,IAAI,CAAC,IAAI,CAAC,eAAe;YAAE,OAAO;QAClC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QACzD,MAAM,QAAQ,GAAG,IAAI,eAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,eAAe,EAAE,uBAAuB,EAAE,MAAM,CAAC,CAAC;QAC5F,MAAM,EAAE,GAAG,MAAM,QAAQ,CAAC,iBAAiB,CACzC,MAAM,CAAC,SAAS,EAChB,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,EAC1B,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,EACxB,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,EAC7B,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,EAC7B,MAAM,CAAC,iBAAiB,EACxB,MAAM,CAAC,WAAW,CACnB,CAAC;QACF,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC;IAClB,CAAC;IAEO,oBAAoB,CAAC,SAAiB;QAC5C,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;QACrE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC;YAAE,OAAO,EAAE,CAAC;QAC1C,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,EAAE,CAAC,WAAW,CAAC,UAAU,CAAC;iBACrC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;iBAChC,IAAI,EAAE,CAAC;YACV,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;gBACnB,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;gBAC/D,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAgB,CAAC;YACxC,CAAC,CAAC,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;CACF;AAjPD,0CAiPC"}
@@ -0,0 +1,100 @@
1
+ /**
2
+ * ComputeSessionManager — session lifecycle management for ARC-402 compute rental.
3
+ *
4
+ * Owns the in-memory + persisted state for all compute sessions handled by
5
+ * this provider node. Coordinates with ComputeMetering for GPU tracking.
6
+ */
7
+ import { ComputeMetering, UsageReport } from "./compute-metering";
8
+ export type ComputeSessionStatus = "proposed" | "accepted" | "active" | "completed" | "disputed";
9
+ export interface ComputeProposal {
10
+ sessionId: string;
11
+ clientAddress: string;
12
+ providerAddress: string;
13
+ ratePerHourWei: string;
14
+ maxHours: number;
15
+ gpuSpecHash: string;
16
+ workloadDescription: string;
17
+ depositAmount: string;
18
+ proposedAt: number;
19
+ }
20
+ export interface ComputeSessionState {
21
+ proposal: ComputeProposal;
22
+ status: ComputeSessionStatus;
23
+ startedAt: number | null;
24
+ endedAt: number | null;
25
+ accessEndpoint: string | null;
26
+ consumedMinutes: number;
27
+ usageReports: UsageReport[];
28
+ updatedAt: number;
29
+ }
30
+ export interface SettlementResult {
31
+ sessionId: string;
32
+ consumedMinutes: number;
33
+ costWei: bigint;
34
+ depositWei: bigint;
35
+ refundWei: bigint;
36
+ reports: UsageReport[];
37
+ }
38
+ export declare class ComputeSessionManager {
39
+ sessions: Map<string, ComputeSessionState>;
40
+ private metering;
41
+ constructor(metering?: ComputeMetering);
42
+ /**
43
+ * Record an incoming compute proposal (from a client).
44
+ * Validates it doesn't conflict with capacity limits.
45
+ */
46
+ handleProposal(proposal: ComputeProposal): {
47
+ ok: boolean;
48
+ error?: string;
49
+ };
50
+ /**
51
+ * Provider accepts the proposal. On-chain call should follow.
52
+ */
53
+ acceptSession(sessionId: string): {
54
+ ok: boolean;
55
+ error?: string;
56
+ };
57
+ /**
58
+ * Provider marks the session as active. Starts GPU metering.
59
+ * @param accessEndpoint Optional SSH / API endpoint to surface to client.
60
+ */
61
+ startSession(sessionId: string, accessEndpoint?: string): {
62
+ ok: boolean;
63
+ error?: string;
64
+ };
65
+ /**
66
+ * Either party ends the session. Stops metering, calculates settlement.
67
+ */
68
+ endSession(sessionId: string): Promise<{
69
+ ok: boolean;
70
+ error?: string;
71
+ result?: SettlementResult;
72
+ }>;
73
+ /**
74
+ * Client disputes the session — freezes it pending arbitration.
75
+ */
76
+ disputeSession(sessionId: string): {
77
+ ok: boolean;
78
+ error?: string;
79
+ };
80
+ /**
81
+ * Append a usage report (from daemon's periodic reporting loop).
82
+ */
83
+ appendUsageReport(sessionId: string, report: UsageReport): {
84
+ ok: boolean;
85
+ error?: string;
86
+ };
87
+ /**
88
+ * Get a single session by ID.
89
+ */
90
+ getSession(sessionId: string): ComputeSessionState | null;
91
+ /**
92
+ * List all sessions.
93
+ */
94
+ listSessions(): ComputeSessionState[];
95
+ /**
96
+ * Count sessions in a given status.
97
+ */
98
+ countByStatus(status: ComputeSessionStatus): number;
99
+ }
100
+ //# sourceMappingURL=compute-session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compute-session.d.ts","sourceRoot":"","sources":["../../src/daemon/compute-session.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAIlE,MAAM,MAAM,oBAAoB,GAC5B,UAAU,GACV,UAAU,GACV,QAAQ,GACR,WAAW,GACX,UAAU,CAAC;AAEf,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAY,MAAM,CAAC;IAC5B,aAAa,EAAQ,MAAM,CAAC;IAC5B,eAAe,EAAM,MAAM,CAAC;IAC5B,cAAc,EAAO,MAAM,CAAC;IAC5B,QAAQ,EAAa,MAAM,CAAC;IAC5B,WAAW,EAAU,MAAM,CAAC;IAC5B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,aAAa,EAAQ,MAAM,CAAC;IAC5B,UAAU,EAAW,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAS,eAAe,CAAC;IACjC,MAAM,EAAW,oBAAoB,CAAC;IACtC,SAAS,EAAQ,MAAM,GAAG,IAAI,CAAC;IAC/B,OAAO,EAAU,MAAM,GAAG,IAAI,CAAC;IAC/B,cAAc,EAAG,MAAM,GAAG,IAAI,CAAC;IAC/B,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAK,WAAW,EAAE,CAAC;IAC/B,SAAS,EAAQ,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAQ,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAU,MAAM,CAAC;IACxB,UAAU,EAAO,MAAM,CAAC;IACxB,SAAS,EAAQ,MAAM,CAAC;IACxB,OAAO,EAAU,WAAW,EAAE,CAAC;CAChC;AA8BD,qBAAa,qBAAqB;IACzB,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;IAClD,OAAO,CAAC,QAAQ,CAAyB;gBAE7B,QAAQ,CAAC,EAAE,eAAe;IAKtC;;;OAGG;IACH,cAAc,CAAC,QAAQ,EAAE,eAAe,GAAG;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;IAqB1E;;OAEG;IACH,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;IAWjE;;;OAGG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;IAoBzF;;OAEG;IACG,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,gBAAgB,CAAA;KAAE,CAAC;IA8CxG;;OAEG;IACH,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;IAWlE;;OAEG;IACH,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;IAY1F;;OAEG;IACH,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,mBAAmB,GAAG,IAAI;IAIzD;;OAEG;IACH,YAAY,IAAI,mBAAmB,EAAE;IAIrC;;OAEG;IACH,aAAa,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM;CAOpD"}
@@ -0,0 +1,231 @@
1
+ "use strict";
2
+ /**
3
+ * ComputeSessionManager — session lifecycle management for ARC-402 compute rental.
4
+ *
5
+ * Owns the in-memory + persisted state for all compute sessions handled by
6
+ * this provider node. Coordinates with ComputeMetering for GPU tracking.
7
+ */
8
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ var desc = Object.getOwnPropertyDescriptor(m, k);
11
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12
+ desc = { enumerable: true, get: function() { return m[k]; } };
13
+ }
14
+ Object.defineProperty(o, k2, desc);
15
+ }) : (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ o[k2] = m[k];
18
+ }));
19
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
20
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
21
+ }) : function(o, v) {
22
+ o["default"] = v;
23
+ });
24
+ var __importStar = (this && this.__importStar) || (function () {
25
+ var ownKeys = function(o) {
26
+ ownKeys = Object.getOwnPropertyNames || function (o) {
27
+ var ar = [];
28
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
+ return ar;
30
+ };
31
+ return ownKeys(o);
32
+ };
33
+ return function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
40
+ })();
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.ComputeSessionManager = void 0;
43
+ const fs = __importStar(require("fs"));
44
+ const path = __importStar(require("path"));
45
+ const config_1 = require("./config");
46
+ // ─── Persistence ──────────────────────────────────────────────────────────────
47
+ const SESSIONS_DIR = path.join(config_1.DAEMON_DIR, "compute");
48
+ function sessionsFile() {
49
+ return path.join(SESSIONS_DIR, "sessions.json");
50
+ }
51
+ function persistSessions(sessions) {
52
+ fs.mkdirSync(SESSIONS_DIR, { recursive: true, mode: 0o700 });
53
+ const obj = Object.fromEntries(sessions.entries());
54
+ fs.writeFileSync(sessionsFile(), JSON.stringify(obj, null, 2), { mode: 0o600 });
55
+ }
56
+ function loadSessions() {
57
+ const file = sessionsFile();
58
+ if (!fs.existsSync(file))
59
+ return new Map();
60
+ try {
61
+ const raw = fs.readFileSync(file, "utf-8");
62
+ const obj = JSON.parse(raw);
63
+ return new Map(Object.entries(obj));
64
+ }
65
+ catch {
66
+ return new Map();
67
+ }
68
+ }
69
+ // ─── Manager class ────────────────────────────────────────────────────────────
70
+ class ComputeSessionManager {
71
+ constructor(metering) {
72
+ this.sessions = loadSessions();
73
+ this.metering = metering ?? null;
74
+ }
75
+ /**
76
+ * Record an incoming compute proposal (from a client).
77
+ * Validates it doesn't conflict with capacity limits.
78
+ */
79
+ handleProposal(proposal) {
80
+ if (this.sessions.has(proposal.sessionId)) {
81
+ return { ok: false, error: "session_already_exists" };
82
+ }
83
+ const state = {
84
+ proposal,
85
+ status: "proposed",
86
+ startedAt: null,
87
+ endedAt: null,
88
+ accessEndpoint: null,
89
+ consumedMinutes: 0,
90
+ usageReports: [],
91
+ updatedAt: Math.floor(Date.now() / 1000),
92
+ };
93
+ this.sessions.set(proposal.sessionId, state);
94
+ persistSessions(this.sessions);
95
+ return { ok: true };
96
+ }
97
+ /**
98
+ * Provider accepts the proposal. On-chain call should follow.
99
+ */
100
+ acceptSession(sessionId) {
101
+ const s = this.sessions.get(sessionId);
102
+ if (!s)
103
+ return { ok: false, error: "session_not_found" };
104
+ if (s.status !== "proposed")
105
+ return { ok: false, error: `wrong_status:${s.status}` };
106
+ s.status = "accepted";
107
+ s.updatedAt = Math.floor(Date.now() / 1000);
108
+ persistSessions(this.sessions);
109
+ return { ok: true };
110
+ }
111
+ /**
112
+ * Provider marks the session as active. Starts GPU metering.
113
+ * @param accessEndpoint Optional SSH / API endpoint to surface to client.
114
+ */
115
+ startSession(sessionId, accessEndpoint) {
116
+ const s = this.sessions.get(sessionId);
117
+ if (!s)
118
+ return { ok: false, error: "session_not_found" };
119
+ if (s.status !== "accepted")
120
+ return { ok: false, error: `wrong_status:${s.status}` };
121
+ const now = Math.floor(Date.now() / 1000);
122
+ s.status = "active";
123
+ s.startedAt = now;
124
+ s.accessEndpoint = accessEndpoint ?? null;
125
+ s.updatedAt = now;
126
+ persistSessions(this.sessions);
127
+ if (this.metering) {
128
+ this.metering.startMetering(sessionId);
129
+ }
130
+ return { ok: true };
131
+ }
132
+ /**
133
+ * Either party ends the session. Stops metering, calculates settlement.
134
+ */
135
+ async endSession(sessionId) {
136
+ const s = this.sessions.get(sessionId);
137
+ if (!s)
138
+ return { ok: false, error: "session_not_found" };
139
+ if (s.status !== "active")
140
+ return { ok: false, error: `wrong_status:${s.status}` };
141
+ // Stop metering — generates final usage report
142
+ if (this.metering) {
143
+ const finalReport = await this.metering.stopMetering(sessionId);
144
+ if (finalReport) {
145
+ s.usageReports.push(finalReport);
146
+ s.consumedMinutes += finalReport.computeMinutes;
147
+ }
148
+ // Absorb any other reports generated during the session
149
+ const allReports = this.metering.getUsageReports(sessionId);
150
+ for (const r of allReports) {
151
+ if (!s.usageReports.find(x => x.periodStart === r.periodStart)) {
152
+ s.usageReports.push(r);
153
+ }
154
+ }
155
+ }
156
+ const now = Math.floor(Date.now() / 1000);
157
+ s.status = "completed";
158
+ s.endedAt = now;
159
+ s.updatedAt = now;
160
+ persistSessions(this.sessions);
161
+ // Settlement math: (consumedMinutes * ratePerHour) / 60
162
+ const deposit = BigInt(s.proposal.depositAmount);
163
+ const rate = BigInt(s.proposal.ratePerHourWei);
164
+ const costWei = BigInt(s.consumedMinutes) * rate / 60n;
165
+ const clamped = costWei > deposit ? deposit : costWei;
166
+ const refundWei = deposit - clamped;
167
+ const result = {
168
+ sessionId,
169
+ consumedMinutes: s.consumedMinutes,
170
+ costWei: clamped,
171
+ depositWei: deposit,
172
+ refundWei,
173
+ reports: s.usageReports,
174
+ };
175
+ return { ok: true, result };
176
+ }
177
+ /**
178
+ * Client disputes the session — freezes it pending arbitration.
179
+ */
180
+ disputeSession(sessionId) {
181
+ const s = this.sessions.get(sessionId);
182
+ if (!s)
183
+ return { ok: false, error: "session_not_found" };
184
+ if (s.status !== "active")
185
+ return { ok: false, error: `wrong_status:${s.status}` };
186
+ s.status = "disputed";
187
+ s.updatedAt = Math.floor(Date.now() / 1000);
188
+ persistSessions(this.sessions);
189
+ return { ok: true };
190
+ }
191
+ /**
192
+ * Append a usage report (from daemon's periodic reporting loop).
193
+ */
194
+ appendUsageReport(sessionId, report) {
195
+ const s = this.sessions.get(sessionId);
196
+ if (!s)
197
+ return { ok: false, error: "session_not_found" };
198
+ if (s.status !== "active")
199
+ return { ok: false, error: `wrong_status:${s.status}` };
200
+ s.usageReports.push(report);
201
+ s.consumedMinutes += report.computeMinutes;
202
+ s.updatedAt = Math.floor(Date.now() / 1000);
203
+ persistSessions(this.sessions);
204
+ return { ok: true };
205
+ }
206
+ /**
207
+ * Get a single session by ID.
208
+ */
209
+ getSession(sessionId) {
210
+ return this.sessions.get(sessionId) ?? null;
211
+ }
212
+ /**
213
+ * List all sessions.
214
+ */
215
+ listSessions() {
216
+ return Array.from(this.sessions.values());
217
+ }
218
+ /**
219
+ * Count sessions in a given status.
220
+ */
221
+ countByStatus(status) {
222
+ let n = 0;
223
+ for (const s of this.sessions.values()) {
224
+ if (s.status === status)
225
+ n++;
226
+ }
227
+ return n;
228
+ }
229
+ }
230
+ exports.ComputeSessionManager = ComputeSessionManager;
231
+ //# sourceMappingURL=compute-session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compute-session.js","sourceRoot":"","sources":["../../src/daemon/compute-session.ts"],"names":[],"mappings":"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"}