@jinn-network/client 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 (278) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +162 -0
  3. package/deployments/deployment-phase1a-l2-baseSepolia-fast.json +32 -0
  4. package/deployments/deployment-phase1a-token-baseSepolia-fast.json +27 -0
  5. package/deployments/deployment-phase1b-mech-baseSepolia-fast.json +26 -0
  6. package/deployments/deployment-stolas-l2-baseSepolia-fast.json +35 -0
  7. package/dist/adapters/adapter.d.ts +11 -0
  8. package/dist/adapters/adapter.js +2 -0
  9. package/dist/adapters/adapter.js.map +1 -0
  10. package/dist/adapters/local/adapter.d.ts +20 -0
  11. package/dist/adapters/local/adapter.js +146 -0
  12. package/dist/adapters/local/adapter.js.map +1 -0
  13. package/dist/adapters/mech/adapter.d.ts +29 -0
  14. package/dist/adapters/mech/adapter.js +332 -0
  15. package/dist/adapters/mech/adapter.js.map +1 -0
  16. package/dist/adapters/mech/claim-policy.d.ts +40 -0
  17. package/dist/adapters/mech/claim-policy.js +104 -0
  18. package/dist/adapters/mech/claim-policy.js.map +1 -0
  19. package/dist/adapters/mech/contracts.d.ts +44 -0
  20. package/dist/adapters/mech/contracts.js +323 -0
  21. package/dist/adapters/mech/contracts.js.map +1 -0
  22. package/dist/adapters/mech/ipfs.d.ts +43 -0
  23. package/dist/adapters/mech/ipfs.js +142 -0
  24. package/dist/adapters/mech/ipfs.js.map +1 -0
  25. package/dist/adapters/mech/safe.d.ts +15 -0
  26. package/dist/adapters/mech/safe.js +113 -0
  27. package/dist/adapters/mech/safe.js.map +1 -0
  28. package/dist/adapters/mech/types.d.ts +561 -0
  29. package/dist/adapters/mech/types.js +340 -0
  30. package/dist/adapters/mech/types.js.map +1 -0
  31. package/dist/api/balance-build.d.ts +22 -0
  32. package/dist/api/balance-build.js +37 -0
  33. package/dist/api/balance-build.js.map +1 -0
  34. package/dist/api/fleet-build.d.ts +62 -0
  35. package/dist/api/fleet-build.js +91 -0
  36. package/dist/api/fleet-build.js.map +1 -0
  37. package/dist/api/gather-status.d.ts +20 -0
  38. package/dist/api/gather-status.js +137 -0
  39. package/dist/api/gather-status.js.map +1 -0
  40. package/dist/api/history-build.d.ts +32 -0
  41. package/dist/api/history-build.js +48 -0
  42. package/dist/api/history-build.js.map +1 -0
  43. package/dist/api/peers.d.ts +27 -0
  44. package/dist/api/peers.js +94 -0
  45. package/dist/api/peers.js.map +1 -0
  46. package/dist/api/rewards-build.d.ts +20 -0
  47. package/dist/api/rewards-build.js +42 -0
  48. package/dist/api/rewards-build.js.map +1 -0
  49. package/dist/api/server.d.ts +34 -0
  50. package/dist/api/server.js +130 -0
  51. package/dist/api/server.js.map +1 -0
  52. package/dist/api/status-build.d.ts +92 -0
  53. package/dist/api/status-build.js +175 -0
  54. package/dist/api/status-build.js.map +1 -0
  55. package/dist/api/status-rollup-build.d.ts +36 -0
  56. package/dist/api/status-rollup-build.js +69 -0
  57. package/dist/api/status-rollup-build.js.map +1 -0
  58. package/dist/auth/erc8128.d.ts +43 -0
  59. package/dist/auth/erc8128.js +88 -0
  60. package/dist/auth/erc8128.js.map +1 -0
  61. package/dist/bin/jinn.d.ts +11 -0
  62. package/dist/bin/jinn.js +20 -0
  63. package/dist/bin/jinn.js.map +1 -0
  64. package/dist/build-meta.json +3 -0
  65. package/dist/chain-read-errors.d.ts +9 -0
  66. package/dist/chain-read-errors.js +43 -0
  67. package/dist/chain-read-errors.js.map +1 -0
  68. package/dist/cli/action.d.ts +26 -0
  69. package/dist/cli/action.js +56 -0
  70. package/dist/cli/action.js.map +1 -0
  71. package/dist/cli/command.d.ts +62 -0
  72. package/dist/cli/command.js +29 -0
  73. package/dist/cli/command.js.map +1 -0
  74. package/dist/cli/commands/balance.d.ts +3 -0
  75. package/dist/cli/commands/balance.js +46 -0
  76. package/dist/cli/commands/balance.js.map +1 -0
  77. package/dist/cli/commands/bootstrap.d.ts +3 -0
  78. package/dist/cli/commands/bootstrap.js +165 -0
  79. package/dist/cli/commands/bootstrap.js.map +1 -0
  80. package/dist/cli/commands/claim-rewards.d.ts +3 -0
  81. package/dist/cli/commands/claim-rewards.js +121 -0
  82. package/dist/cli/commands/claim-rewards.js.map +1 -0
  83. package/dist/cli/commands/doctor.d.ts +3 -0
  84. package/dist/cli/commands/doctor.js +151 -0
  85. package/dist/cli/commands/doctor.js.map +1 -0
  86. package/dist/cli/commands/fleet-scale.d.ts +3 -0
  87. package/dist/cli/commands/fleet-scale.js +449 -0
  88. package/dist/cli/commands/fleet-scale.js.map +1 -0
  89. package/dist/cli/commands/fleet.d.ts +3 -0
  90. package/dist/cli/commands/fleet.js +45 -0
  91. package/dist/cli/commands/fleet.js.map +1 -0
  92. package/dist/cli/commands/fund-requirements.d.ts +3 -0
  93. package/dist/cli/commands/fund-requirements.js +139 -0
  94. package/dist/cli/commands/fund-requirements.js.map +1 -0
  95. package/dist/cli/commands/history.d.ts +3 -0
  96. package/dist/cli/commands/history.js +61 -0
  97. package/dist/cli/commands/history.js.map +1 -0
  98. package/dist/cli/commands/init.d.ts +3 -0
  99. package/dist/cli/commands/init.js +91 -0
  100. package/dist/cli/commands/init.js.map +1 -0
  101. package/dist/cli/commands/keys-backup.d.ts +3 -0
  102. package/dist/cli/commands/keys-backup.js +107 -0
  103. package/dist/cli/commands/keys-backup.js.map +1 -0
  104. package/dist/cli/commands/logs.d.ts +3 -0
  105. package/dist/cli/commands/logs.js +69 -0
  106. package/dist/cli/commands/logs.js.map +1 -0
  107. package/dist/cli/commands/rewards.d.ts +3 -0
  108. package/dist/cli/commands/rewards.js +54 -0
  109. package/dist/cli/commands/rewards.js.map +1 -0
  110. package/dist/cli/commands/run.d.ts +3 -0
  111. package/dist/cli/commands/run.js +96 -0
  112. package/dist/cli/commands/run.js.map +1 -0
  113. package/dist/cli/commands/status.d.ts +3 -0
  114. package/dist/cli/commands/status.js +54 -0
  115. package/dist/cli/commands/status.js.map +1 -0
  116. package/dist/cli/commands/stop.d.ts +3 -0
  117. package/dist/cli/commands/stop.js +82 -0
  118. package/dist/cli/commands/stop.js.map +1 -0
  119. package/dist/cli/commands/submit-intent.d.ts +3 -0
  120. package/dist/cli/commands/submit-intent.js +169 -0
  121. package/dist/cli/commands/submit-intent.js.map +1 -0
  122. package/dist/cli/commands/version.d.ts +3 -0
  123. package/dist/cli/commands/version.js +114 -0
  124. package/dist/cli/commands/version.js.map +1 -0
  125. package/dist/cli/commands/withdraw.d.ts +3 -0
  126. package/dist/cli/commands/withdraw.js +181 -0
  127. package/dist/cli/commands/withdraw.js.map +1 -0
  128. package/dist/cli/deployment-digest.d.ts +10 -0
  129. package/dist/cli/deployment-digest.js +25 -0
  130. package/dist/cli/deployment-digest.js.map +1 -0
  131. package/dist/cli/execution-context.d.ts +50 -0
  132. package/dist/cli/execution-context.js +154 -0
  133. package/dist/cli/execution-context.js.map +1 -0
  134. package/dist/cli/help.d.ts +3 -0
  135. package/dist/cli/help.js +37 -0
  136. package/dist/cli/help.js.map +1 -0
  137. package/dist/cli/index.d.ts +17 -0
  138. package/dist/cli/index.js +132 -0
  139. package/dist/cli/index.js.map +1 -0
  140. package/dist/cli/introspection-context.d.ts +10 -0
  141. package/dist/cli/introspection-context.js +60 -0
  142. package/dist/cli/introspection-context.js.map +1 -0
  143. package/dist/cli/output.d.ts +36 -0
  144. package/dist/cli/output.js +35 -0
  145. package/dist/cli/output.js.map +1 -0
  146. package/dist/cli/password.d.ts +12 -0
  147. package/dist/cli/password.js +51 -0
  148. package/dist/cli/password.js.map +1 -0
  149. package/dist/config.d.ts +174 -0
  150. package/dist/config.js +252 -0
  151. package/dist/config.js.map +1 -0
  152. package/dist/daemon/creator.d.ts +24 -0
  153. package/dist/daemon/creator.js +80 -0
  154. package/dist/daemon/creator.js.map +1 -0
  155. package/dist/daemon/daemon.d.ts +60 -0
  156. package/dist/daemon/daemon.js +158 -0
  157. package/dist/daemon/daemon.js.map +1 -0
  158. package/dist/daemon/delivery-watcher.d.ts +10 -0
  159. package/dist/daemon/delivery-watcher.js +37 -0
  160. package/dist/daemon/delivery-watcher.js.map +1 -0
  161. package/dist/daemon/restorer.d.ts +19 -0
  162. package/dist/daemon/restorer.js +82 -0
  163. package/dist/daemon/restorer.js.map +1 -0
  164. package/dist/daemon/reward-claim-loop.d.ts +38 -0
  165. package/dist/daemon/reward-claim-loop.js +48 -0
  166. package/dist/daemon/reward-claim-loop.js.map +1 -0
  167. package/dist/discovery/registry.d.ts +43 -0
  168. package/dist/discovery/registry.js +104 -0
  169. package/dist/discovery/registry.js.map +1 -0
  170. package/dist/discovery/subgraph.d.ts +37 -0
  171. package/dist/discovery/subgraph.js +87 -0
  172. package/dist/discovery/subgraph.js.map +1 -0
  173. package/dist/earning/bootstrap.d.ts +79 -0
  174. package/dist/earning/bootstrap.js +989 -0
  175. package/dist/earning/bootstrap.js.map +1 -0
  176. package/dist/earning/contracts.d.ts +431 -0
  177. package/dist/earning/contracts.js +518 -0
  178. package/dist/earning/contracts.js.map +1 -0
  179. package/dist/earning/evidence-simhash.d.ts +59 -0
  180. package/dist/earning/evidence-simhash.js +87 -0
  181. package/dist/earning/evidence-simhash.js.map +1 -0
  182. package/dist/earning/fleet-display-index.d.ts +8 -0
  183. package/dist/earning/fleet-display-index.js +12 -0
  184. package/dist/earning/fleet-display-index.js.map +1 -0
  185. package/dist/earning/fleet-retire.d.ts +28 -0
  186. package/dist/earning/fleet-retire.js +75 -0
  187. package/dist/earning/fleet-retire.js.map +1 -0
  188. package/dist/earning/jinn-rewards.d.ts +62 -0
  189. package/dist/earning/jinn-rewards.js +81 -0
  190. package/dist/earning/jinn-rewards.js.map +1 -0
  191. package/dist/earning/next-service-index.d.ts +4 -0
  192. package/dist/earning/next-service-index.js +7 -0
  193. package/dist/earning/next-service-index.js.map +1 -0
  194. package/dist/earning/orphan-sweep.d.ts +33 -0
  195. package/dist/earning/orphan-sweep.js +157 -0
  196. package/dist/earning/orphan-sweep.js.map +1 -0
  197. package/dist/earning/reconcile.d.ts +37 -0
  198. package/dist/earning/reconcile.js +216 -0
  199. package/dist/earning/reconcile.js.map +1 -0
  200. package/dist/earning/safe-adapter.d.ts +70 -0
  201. package/dist/earning/safe-adapter.js +228 -0
  202. package/dist/earning/safe-adapter.js.map +1 -0
  203. package/dist/earning/stolas-claim.d.ts +47 -0
  204. package/dist/earning/stolas-claim.js +115 -0
  205. package/dist/earning/stolas-claim.js.map +1 -0
  206. package/dist/earning/store.d.ts +36 -0
  207. package/dist/earning/store.js +156 -0
  208. package/dist/earning/store.js.map +1 -0
  209. package/dist/earning/types.d.ts +123 -0
  210. package/dist/earning/types.js +64 -0
  211. package/dist/earning/types.js.map +1 -0
  212. package/dist/earning/viem-clients.d.ts +9 -0
  213. package/dist/earning/viem-clients.js +22 -0
  214. package/dist/earning/viem-clients.js.map +1 -0
  215. package/dist/earning/wallet.d.ts +20 -0
  216. package/dist/earning/wallet.js +103 -0
  217. package/dist/earning/wallet.js.map +1 -0
  218. package/dist/errors/envelope.d.ts +41 -0
  219. package/dist/errors/envelope.js +48 -0
  220. package/dist/errors/envelope.js.map +1 -0
  221. package/dist/index.d.ts +14 -0
  222. package/dist/index.js +17 -0
  223. package/dist/index.js.map +1 -0
  224. package/dist/main.d.ts +32 -0
  225. package/dist/main.js +281 -0
  226. package/dist/main.js.map +1 -0
  227. package/dist/mcp/server.d.ts +14 -0
  228. package/dist/mcp/server.js +205 -0
  229. package/dist/mcp/server.js.map +1 -0
  230. package/dist/operator-errors.d.ts +16 -0
  231. package/dist/operator-errors.js +88 -0
  232. package/dist/operator-errors.js.map +1 -0
  233. package/dist/preflight/claude-binary.d.ts +19 -0
  234. package/dist/preflight/claude-binary.js +44 -0
  235. package/dist/preflight/claude-binary.js.map +1 -0
  236. package/dist/preflight/claude-invocation-envelope.d.ts +11 -0
  237. package/dist/preflight/claude-invocation-envelope.js +67 -0
  238. package/dist/preflight/claude-invocation-envelope.js.map +1 -0
  239. package/dist/runner/claude.d.ts +15 -0
  240. package/dist/runner/claude.js +193 -0
  241. package/dist/runner/claude.js.map +1 -0
  242. package/dist/runner/runner.d.ts +11 -0
  243. package/dist/runner/runner.js +2 -0
  244. package/dist/runner/runner.js.map +1 -0
  245. package/dist/runner/simple.d.ts +8 -0
  246. package/dist/runner/simple.js +11 -0
  247. package/dist/runner/simple.js.map +1 -0
  248. package/dist/store/store.d.ts +74 -0
  249. package/dist/store/store.js +168 -0
  250. package/dist/store/store.js.map +1 -0
  251. package/dist/tx-retry.d.ts +55 -0
  252. package/dist/tx-retry.js +214 -0
  253. package/dist/tx-retry.js.map +1 -0
  254. package/dist/types/desired-state.d.ts +41 -0
  255. package/dist/types/desired-state.js +16 -0
  256. package/dist/types/desired-state.js.map +1 -0
  257. package/dist/types/errors.d.ts +8 -0
  258. package/dist/types/errors.js +17 -0
  259. package/dist/types/errors.js.map +1 -0
  260. package/dist/types/index.d.ts +2 -0
  261. package/dist/types/index.js +3 -0
  262. package/dist/types/index.js.map +1 -0
  263. package/dist/withdraw/args.d.ts +29 -0
  264. package/dist/withdraw/args.js +198 -0
  265. package/dist/withdraw/args.js.map +1 -0
  266. package/dist/withdraw/run-withdraw-plan.d.ts +21 -0
  267. package/dist/withdraw/run-withdraw-plan.js +257 -0
  268. package/dist/withdraw/run-withdraw-plan.js.map +1 -0
  269. package/dist/x402/acquire.d.ts +6 -0
  270. package/dist/x402/acquire.js +32 -0
  271. package/dist/x402/acquire.js.map +1 -0
  272. package/dist/x402/facilitator.d.ts +11 -0
  273. package/dist/x402/facilitator.js +52 -0
  274. package/dist/x402/facilitator.js.map +1 -0
  275. package/dist/x402/handler.d.ts +15 -0
  276. package/dist/x402/handler.js +40 -0
  277. package/dist/x402/handler.js.map +1 -0
  278. package/package.json +72 -0
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Shared gather for introspection verbs (local SQLite + fleet + RPC).
3
+ *
4
+ * When the HTTP API is reachable, merges a healthier `rpc` snapshot from GET /v1/status
5
+ * into the local gather (short timeout; failures are ignored).
6
+ */
7
+ import type { GatheredStatusRaw } from '../api/status-build.js';
8
+ export declare function gatherIntrospectionRaw(opts?: {
9
+ argv?: string[];
10
+ }): Promise<GatheredStatusRaw>;
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Shared gather for introspection verbs (local SQLite + fleet + RPC).
3
+ *
4
+ * When the HTTP API is reachable, merges a healthier `rpc` snapshot from GET /v1/status
5
+ * into the local gather (short timeout; failures are ignored).
6
+ */
7
+ import { gatherGatheredStatusRaw } from '../api/gather-status.js';
8
+ import { loadConfig, getConfigPathFromArgs } from '../config.js';
9
+ import { Store } from '../store/store.js';
10
+ async function tryMergeStatusFromHttp(config, local) {
11
+ const url = `http://127.0.0.1:${config.apiPort}/v1/status`;
12
+ const ac = new AbortController();
13
+ const t = setTimeout(() => ac.abort(), 500);
14
+ try {
15
+ const res = await fetch(url, { signal: ac.signal });
16
+ if (!res.ok)
17
+ return local;
18
+ const remote = (await res.json());
19
+ if (remote.rpc?.ok && !local.rpc.ok) {
20
+ return {
21
+ ...local,
22
+ rpc: {
23
+ ok: remote.rpc.ok,
24
+ chainId: remote.rpc.chainId,
25
+ blockNumber: remote.rpc.blockNumber,
26
+ ...(remote.rpc.error ? { error: remote.rpc.error } : {}),
27
+ },
28
+ };
29
+ }
30
+ }
31
+ catch {
32
+ /* ignore — local gather is authoritative */
33
+ }
34
+ finally {
35
+ clearTimeout(t);
36
+ }
37
+ return local;
38
+ }
39
+ export async function gatherIntrospectionRaw(opts) {
40
+ const fromVerbFlags = getConfigPathFromArgs(opts?.argv ?? []);
41
+ const fromProcess = typeof process !== 'undefined' ? getConfigPathFromArgs(process.argv.slice(2)) : undefined;
42
+ const configPath = fromVerbFlags ?? fromProcess;
43
+ const config = loadConfig(configPath);
44
+ const store = new Store(config.dbPath);
45
+ const status = {
46
+ earningDir: config.earningDir,
47
+ rpcUrl: config.rpcUrl,
48
+ network: config.network,
49
+ pollIntervalMs: config.pollIntervalMs,
50
+ masterEthDailyEstimateWei: config.masterEthDailyEstimateWei,
51
+ rewardClaimIntervalMs: config.rewardClaimIntervalMs,
52
+ testnetL2DeploymentPath: config.testnetL2DeploymentPath,
53
+ testnetL2TokenDeploymentPath: config.testnetL2TokenDeploymentPath,
54
+ testnetMechDeploymentPath: config.testnetMechDeploymentPath,
55
+ testnetStolasDeploymentPath: config.testnetStolasDeploymentPath,
56
+ };
57
+ const local = await gatherGatheredStatusRaw(store, status);
58
+ return tryMergeStatusFromHttp(config, local);
59
+ }
60
+ //# sourceMappingURL=introspection-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"introspection-context.js","sourceRoot":"","sources":["../../src/cli/introspection-context.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,uBAAuB,EAA2B,MAAM,yBAAyB,CAAC;AAC3F,OAAO,EAAE,UAAU,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAE1C,KAAK,UAAU,sBAAsB,CACnC,MAAqC,EACrC,KAAwB;IAExB,MAAM,GAAG,GAAG,oBAAoB,MAAM,CAAC,OAAO,YAAY,CAAC;IAC3D,MAAM,EAAE,GAAG,IAAI,eAAe,EAAE,CAAC;IACjC,MAAM,CAAC,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE,GAAG,CAAC,CAAC;IAC5C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC;QACpD,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,OAAO,KAAK,CAAC;QAC1B,MAAM,MAAM,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAqB,CAAC;QACtD,IAAI,MAAM,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACpC,OAAO;gBACL,GAAG,KAAK;gBACR,GAAG,EAAE;oBACH,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE;oBACjB,OAAO,EAAE,MAAM,CAAC,GAAG,CAAC,OAAO;oBAC3B,WAAW,EAAE,MAAM,CAAC,GAAG,CAAC,WAAW;oBACnC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBACzD;aACF,CAAC;QACJ,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,4CAA4C;IAC9C,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,IAE5C;IACC,MAAM,aAAa,GAAG,qBAAqB,CAAC,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;IAC9D,MAAM,WAAW,GACf,OAAO,OAAO,KAAK,WAAW,CAAC,CAAC,CAAC,qBAAqB,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC5F,MAAM,UAAU,GAAG,aAAa,IAAI,WAAW,CAAC;IAChD,MAAM,MAAM,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC;IACtC,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACvC,MAAM,MAAM,GAAuB;QACjC,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,cAAc,EAAE,MAAM,CAAC,cAAc;QACrC,yBAAyB,EAAE,MAAM,CAAC,yBAAyB;QAC3D,qBAAqB,EAAE,MAAM,CAAC,qBAAqB;QACnD,uBAAuB,EAAE,MAAM,CAAC,uBAAuB;QACvD,4BAA4B,EAAE,MAAM,CAAC,4BAA4B;QACjE,yBAAyB,EAAE,MAAM,CAAC,yBAAyB;QAC3D,2BAA2B,EAAE,MAAM,CAAC,2BAA2B;KAChE,CAAC;IACF,MAAM,KAAK,GAAG,MAAM,uBAAuB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAC3D,OAAO,sBAAsB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AAC/C,CAAC"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * CLI output helpers.
3
+ *
4
+ * Operational verbs emit JSON unless `--human` is set (TTY does not change
5
+ * the default). `stdoutIsTty` is kept for callers/tests; `isJsonMode` only
6
+ * keys off `human`.
7
+ *
8
+ * Spec note: `spec/2026-04-14-client-surface.md` §7.2 still describes a
9
+ * TTY-based default; implementation and packaged README follow this module.
10
+ * - NO_COLOR strips ANSI in human mode.
11
+ */
12
+ export interface JsonModeInput {
13
+ json: boolean;
14
+ human: boolean;
15
+ stdoutIsTty: boolean;
16
+ }
17
+ export declare function isJsonMode(input: JsonModeInput): boolean;
18
+ export declare function formatJson(value: unknown): string;
19
+ export interface HumanModeOpts {
20
+ noColor: boolean;
21
+ }
22
+ export declare function formatHuman(text: string, opts: HumanModeOpts): string;
23
+ /**
24
+ * Decide the effective output mode for a verb and write the value.
25
+ * Production callers pass `process.stdout`; tests inject a writer.
26
+ */
27
+ export interface EmitOpts {
28
+ json: boolean;
29
+ human?: boolean;
30
+ writer?: {
31
+ write: (s: string) => boolean;
32
+ };
33
+ stdoutIsTty?: boolean;
34
+ noColor?: boolean;
35
+ }
36
+ export declare function emitResult(value: unknown, humanRender: (v: unknown) => string, opts: EmitOpts): void;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * CLI output helpers.
3
+ *
4
+ * Operational verbs emit JSON unless `--human` is set (TTY does not change
5
+ * the default). `stdoutIsTty` is kept for callers/tests; `isJsonMode` only
6
+ * keys off `human`.
7
+ *
8
+ * Spec note: `spec/2026-04-14-client-surface.md` §7.2 still describes a
9
+ * TTY-based default; implementation and packaged README follow this module.
10
+ * - NO_COLOR strips ANSI in human mode.
11
+ */
12
+ export function isJsonMode(input) {
13
+ return !input.human;
14
+ }
15
+ export function formatJson(value) {
16
+ return JSON.stringify(value) + '\n';
17
+ }
18
+ const ANSI_PATTERN = /\u001b\[[0-9;]*m/g;
19
+ export function formatHuman(text, opts) {
20
+ if (opts.noColor)
21
+ return text.replace(ANSI_PATTERN, '');
22
+ return text;
23
+ }
24
+ export function emitResult(value, humanRender, opts) {
25
+ const writer = opts.writer ?? process.stdout;
26
+ const stdoutIsTty = opts.stdoutIsTty ?? Boolean(process.stdout.isTTY);
27
+ const noColor = opts.noColor ?? Boolean(process.env['NO_COLOR']);
28
+ if (isJsonMode({ json: opts.json, human: Boolean(opts.human), stdoutIsTty })) {
29
+ writer.write(formatJson(value));
30
+ }
31
+ else {
32
+ writer.write(formatHuman(humanRender(value), { noColor }) + '\n');
33
+ }
34
+ }
35
+ //# sourceMappingURL=output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/cli/output.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAQH,MAAM,UAAU,UAAU,CAAC,KAAoB;IAC7C,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAc;IACvC,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;AACtC,CAAC;AAED,MAAM,YAAY,GAAG,mBAAmB,CAAC;AAMzC,MAAM,UAAU,WAAW,CAAC,IAAY,EAAE,IAAmB;IAC3D,IAAI,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IACxD,OAAO,IAAI,CAAC;AACd,CAAC;AAcD,MAAM,UAAU,UAAU,CAAC,KAAc,EAAE,WAAmC,EAAE,IAAc;IAC5F,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC;IAC7C,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACtE,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC;IACjE,IAAI,UAAU,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC;QAC7E,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;IAClC,CAAC;SAAM,CAAC;QACN,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;IACpE,CAAC;AACH,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * CLI password resolution: JINN_PASSWORD env or --password-fd N (reads once, trims).
3
+ */
4
+ export declare function parsePasswordFdFromArgv(argv: string[]): number | undefined;
5
+ export declare function readPasswordFromFd(fd: number): string;
6
+ export declare function resolveCliPassword(argv?: string[], env?: NodeJS.ProcessEnv): {
7
+ ok: true;
8
+ password: string;
9
+ } | {
10
+ ok: false;
11
+ message: string;
12
+ };
@@ -0,0 +1,51 @@
1
+ /**
2
+ * CLI password resolution: JINN_PASSWORD env or --password-fd N (reads once, trims).
3
+ */
4
+ import { readFileSync } from 'node:fs';
5
+ export function parsePasswordFdFromArgv(argv) {
6
+ const idx = argv.indexOf('--password-fd');
7
+ if (idx === -1)
8
+ return undefined;
9
+ const raw = argv[idx + 1];
10
+ const n = raw !== undefined ? parseInt(raw, 10) : NaN;
11
+ if (!Number.isFinite(n) || n < 0)
12
+ return undefined;
13
+ return n;
14
+ }
15
+ export function readPasswordFromFd(fd) {
16
+ const buf = readFileSync(fd, { encoding: 'utf8' });
17
+ return buf.replace(/\r?\n$/, '').trim();
18
+ }
19
+ function mergeArgv(argv) {
20
+ const fromVerb = argv ?? [];
21
+ const fromProcess = typeof process !== 'undefined' ? process.argv.slice(2) : [];
22
+ return [...fromVerb, ...fromProcess];
23
+ }
24
+ export function resolveCliPassword(argv, env = process.env) {
25
+ const merged = mergeArgv(argv);
26
+ const fd = parsePasswordFdFromArgv(merged);
27
+ if (fd !== undefined) {
28
+ try {
29
+ const password = readPasswordFromFd(fd);
30
+ if (!password) {
31
+ return { ok: false, message: 'Password from --password-fd is empty.' };
32
+ }
33
+ return { ok: true, password };
34
+ }
35
+ catch (e) {
36
+ return {
37
+ ok: false,
38
+ message: e instanceof Error ? e.message : String(e),
39
+ };
40
+ }
41
+ }
42
+ const p = env['JINN_PASSWORD'];
43
+ if (!p) {
44
+ return {
45
+ ok: false,
46
+ message: 'Set JINN_PASSWORD or pass --password-fd N with a readable file descriptor.',
47
+ };
48
+ }
49
+ return { ok: true, password: p };
50
+ }
51
+ //# sourceMappingURL=password.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"password.js","sourceRoot":"","sources":["../../src/cli/password.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,MAAM,UAAU,uBAAuB,CAAC,IAAc;IACpD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IAC1C,IAAI,GAAG,KAAK,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC;IACjC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;IAC1B,MAAM,CAAC,GAAG,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IACtD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IACnD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,EAAU;IAC3C,MAAM,GAAG,GAAG,YAAY,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IACnD,OAAO,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;AAC1C,CAAC;AAED,SAAS,SAAS,CAAC,IAAe;IAChC,MAAM,QAAQ,GAAG,IAAI,IAAI,EAAE,CAAC;IAC5B,MAAM,WAAW,GAAG,OAAO,OAAO,KAAK,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAChF,OAAO,CAAC,GAAG,QAAQ,EAAE,GAAG,WAAW,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,IAAe,EACf,MAAyB,OAAO,CAAC,GAAG;IAEpC,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAC/B,MAAM,EAAE,GAAG,uBAAuB,CAAC,MAAM,CAAC,CAAC;IAC3C,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;QACrB,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,kBAAkB,CAAC,EAAE,CAAC,CAAC;YACxC,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,uCAAuC,EAAE,CAAC;YACzE,CAAC;YACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;QAChC,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,OAAO,EAAE,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;aACpD,CAAC;QACJ,CAAC;IACH,CAAC;IACD,MAAM,CAAC,GAAG,GAAG,CAAC,eAAe,CAAC,CAAC;IAC/B,IAAI,CAAC,CAAC,EAAE,CAAC;QACP,OAAO;YACL,EAAE,EAAE,KAAK;YACT,OAAO,EAAE,4EAA4E;SACtF,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;AACnC,CAAC"}
@@ -0,0 +1,174 @@
1
+ /**
2
+ * Config loader for jinn-client.
3
+ *
4
+ * Resolution order (highest priority wins):
5
+ * 1. Environment variables (JINN_*, BASE_RPC_URL, BASE_SEPOLIA_RPC_URL)
6
+ * 2. Config file (--config flag or ~/.jinn-client/config.json)
7
+ * 3. Built-in defaults
8
+ *
9
+ * JINN_PASSWORD is always env-only — never written to config files.
10
+ *
11
+ * Operator UX: JINN_DEBUG=1 enables full stack traces. JINN_MASTER_ETH_DAILY_WEI
12
+ * (wei, integer string) tunes master wallet low-ETH runway warnings.
13
+ * Router claims: JINN_ROUTER_CLAIM_DELIVERY_VERSION=v1|v2 overrides chain default
14
+ * (mainnet V1, testnet V2) for JinnRouter claimDelivery encoding.
15
+ */
16
+ import { z } from 'zod';
17
+ export declare const JinnConfigSchema: z.ZodObject<{
18
+ /**
19
+ * Network to connect to.
20
+ * 'testnet' → Base Sepolia (default during Phase 1b; fast epochs, free funds).
21
+ * 'mainnet' → Base mainnet (flipped on at Phase 2 launch).
22
+ * Operators should not normally need to set this — the default tracks whatever
23
+ * phase the protocol is in.
24
+ */
25
+ network: z.ZodDefault<z.ZodEnum<["mainnet", "testnet"]>>;
26
+ /**
27
+ * Base RPC endpoint.
28
+ * Defaults to https://mainnet.base.org for 'mainnet' and
29
+ * https://sepolia.base.org for 'testnet'. Set explicitly to override.
30
+ */
31
+ rpcUrl: z.ZodOptional<z.ZodString>;
32
+ /** Earning state directory */
33
+ earningDir: z.ZodDefault<z.ZodString>;
34
+ /** SQLite database path */
35
+ dbPath: z.ZodDefault<z.ZodString>;
36
+ /** Chain poll interval in ms */
37
+ pollIntervalMs: z.ZodDefault<z.ZodNumber>;
38
+ /**
39
+ * How often the daemon attempts stOLAS ExternalStakingDistributor.claim for each staked
40
+ * fleet service (ms). Default 600000 (10 min) — well under typical checkpoint liveness windows
41
+ * on Base while limiting RPC/gas churn. Set to 0 to disable auto-claim.
42
+ * Env: JINN_REWARD_CLAIM_INTERVAL_MS
43
+ */
44
+ rewardClaimIntervalMs: z.ZodDefault<z.ZodNumber>;
45
+ /** HTTP API port */
46
+ apiPort: z.ZodDefault<z.ZodNumber>;
47
+ /** Path to claude CLI binary */
48
+ claudePath: z.ZodDefault<z.ZodString>;
49
+ /** Model for restoration/evaluation agent */
50
+ claudeModel: z.ZodDefault<z.ZodString>;
51
+ /** Comma-separated or array of peer URLs */
52
+ peers: z.ZodDefault<z.ZodUnion<[z.ZodEffects<z.ZodString, string[], string>, z.ZodArray<z.ZodString, "many">]>>;
53
+ /** The Graph subgraph URL for artifact discovery */
54
+ subgraphUrl: z.ZodOptional<z.ZodString>;
55
+ /** This node's public HTTP endpoint (for 8004 registration) */
56
+ nodeEndpoint: z.ZodOptional<z.ZodString>;
57
+ /** Desired states to create and restore */
58
+ desiredStates: z.ZodDefault<z.ZodArray<z.ZodObject<{
59
+ id: z.ZodString;
60
+ description: z.ZodString;
61
+ context: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
62
+ }, "strip", z.ZodTypeAny, {
63
+ id: string;
64
+ description: string;
65
+ context?: Record<string, unknown> | undefined;
66
+ }, {
67
+ id: string;
68
+ description: string;
69
+ context?: Record<string, unknown> | undefined;
70
+ }>, "many">>;
71
+ /** IPFS upload endpoint */
72
+ ipfsRegistryUrl: z.ZodDefault<z.ZodString>;
73
+ /** IPFS read endpoint */
74
+ ipfsGatewayUrl: z.ZodDefault<z.ZodString>;
75
+ /** Optional Base Sepolia Phase 1a staking deployment artifact path */
76
+ testnetL2DeploymentPath: z.ZodOptional<z.ZodString>;
77
+ /** Optional Base Sepolia Phase 1a token deployment artifact path */
78
+ testnetL2TokenDeploymentPath: z.ZodOptional<z.ZodString>;
79
+ /** Optional Base Sepolia mech marketplace deployment artifact path */
80
+ testnetMechDeploymentPath: z.ZodOptional<z.ZodString>;
81
+ /** Optional Base Sepolia stOLAS deployment artifact path */
82
+ testnetStolasDeploymentPath: z.ZodOptional<z.ZodString>;
83
+ /** Staking mode: 'standard' uses stOLAS (no OLAS needed), 'self-bond' uses operator-provided OLAS. */
84
+ stakingMode: z.ZodDefault<z.ZodEnum<["standard", "self-bond"]>>;
85
+ /** Number of services to bootstrap and run. */
86
+ targetServices: z.ZodDefault<z.ZodNumber>;
87
+ /**
88
+ * When true, log full error objects and stack traces from bootstrap / main.
89
+ * Env: JINN_DEBUG=1|true|yes
90
+ */
91
+ debug: z.ZodDefault<z.ZodBoolean>;
92
+ /**
93
+ * Estimated master wallet gas usage per day (wei string), for low-ETH runway warnings.
94
+ * Default is applied in bootstrap when unset. Env: JINN_MASTER_ETH_DAILY_WEI
95
+ */
96
+ masterEthDailyEstimateWei: z.ZodOptional<z.ZodString>;
97
+ }, "strip", z.ZodTypeAny, {
98
+ network: "testnet" | "mainnet";
99
+ earningDir: string;
100
+ dbPath: string;
101
+ pollIntervalMs: number;
102
+ rewardClaimIntervalMs: number;
103
+ apiPort: number;
104
+ claudePath: string;
105
+ claudeModel: string;
106
+ peers: string[];
107
+ desiredStates: {
108
+ id: string;
109
+ description: string;
110
+ context?: Record<string, unknown> | undefined;
111
+ }[];
112
+ ipfsRegistryUrl: string;
113
+ ipfsGatewayUrl: string;
114
+ stakingMode: "standard" | "self-bond";
115
+ targetServices: number;
116
+ debug: boolean;
117
+ rpcUrl?: string | undefined;
118
+ subgraphUrl?: string | undefined;
119
+ nodeEndpoint?: string | undefined;
120
+ testnetL2DeploymentPath?: string | undefined;
121
+ testnetL2TokenDeploymentPath?: string | undefined;
122
+ testnetMechDeploymentPath?: string | undefined;
123
+ testnetStolasDeploymentPath?: string | undefined;
124
+ masterEthDailyEstimateWei?: string | undefined;
125
+ }, {
126
+ network?: "testnet" | "mainnet" | undefined;
127
+ rpcUrl?: string | undefined;
128
+ earningDir?: string | undefined;
129
+ dbPath?: string | undefined;
130
+ pollIntervalMs?: number | undefined;
131
+ rewardClaimIntervalMs?: number | undefined;
132
+ apiPort?: number | undefined;
133
+ claudePath?: string | undefined;
134
+ claudeModel?: string | undefined;
135
+ peers?: string | string[] | undefined;
136
+ subgraphUrl?: string | undefined;
137
+ nodeEndpoint?: string | undefined;
138
+ desiredStates?: {
139
+ id: string;
140
+ description: string;
141
+ context?: Record<string, unknown> | undefined;
142
+ }[] | undefined;
143
+ ipfsRegistryUrl?: string | undefined;
144
+ ipfsGatewayUrl?: string | undefined;
145
+ testnetL2DeploymentPath?: string | undefined;
146
+ testnetL2TokenDeploymentPath?: string | undefined;
147
+ testnetMechDeploymentPath?: string | undefined;
148
+ testnetStolasDeploymentPath?: string | undefined;
149
+ stakingMode?: "standard" | "self-bond" | undefined;
150
+ targetServices?: number | undefined;
151
+ debug?: boolean | undefined;
152
+ masterEthDailyEstimateWei?: string | undefined;
153
+ }>;
154
+ /** JinnConfig with rpcUrl guaranteed to be resolved (never undefined). */
155
+ export type JinnConfig = Omit<z.infer<typeof JinnConfigSchema>, 'rpcUrl'> & {
156
+ rpcUrl: string;
157
+ };
158
+ export type ConfigLoadErrorCode = 'config_file_not_found' | 'config_json_invalid' | 'desired_states_file_not_found' | 'desired_states_json_invalid' | 'config_invalid';
159
+ export declare class ConfigLoadError extends Error {
160
+ readonly code: ConfigLoadErrorCode;
161
+ readonly details?: Record<string, unknown>;
162
+ constructor(code: ConfigLoadErrorCode, message: string, details?: Record<string, unknown>);
163
+ }
164
+ /**
165
+ * Load config with resolution: env > config file > defaults.
166
+ *
167
+ * @param configPath — explicit config file path (e.g. from --config flag).
168
+ * Falls back to ~/.jinn-client/config.json if it exists.
169
+ */
170
+ export declare function loadConfig(configPath?: string): JinnConfig;
171
+ /**
172
+ * Get the config file path from --config CLI arg, if provided.
173
+ */
174
+ export declare function getConfigPathFromArgs(argv?: string[]): string | undefined;
package/dist/config.js ADDED
@@ -0,0 +1,252 @@
1
+ /**
2
+ * Config loader for jinn-client.
3
+ *
4
+ * Resolution order (highest priority wins):
5
+ * 1. Environment variables (JINN_*, BASE_RPC_URL, BASE_SEPOLIA_RPC_URL)
6
+ * 2. Config file (--config flag or ~/.jinn-client/config.json)
7
+ * 3. Built-in defaults
8
+ *
9
+ * JINN_PASSWORD is always env-only — never written to config files.
10
+ *
11
+ * Operator UX: JINN_DEBUG=1 enables full stack traces. JINN_MASTER_ETH_DAILY_WEI
12
+ * (wei, integer string) tunes master wallet low-ETH runway warnings.
13
+ * Router claims: JINN_ROUTER_CLAIM_DELIVERY_VERSION=v1|v2 overrides chain default
14
+ * (mainnet V1, testnet V2) for JinnRouter claimDelivery encoding.
15
+ */
16
+ import { existsSync, readFileSync } from 'node:fs';
17
+ import { homedir } from 'node:os';
18
+ import { join } from 'node:path';
19
+ import { z } from 'zod';
20
+ // ── Schema ──────────────────────────────────────────────────────────────────
21
+ const DesiredStateSchema = z.object({
22
+ id: z.string(),
23
+ description: z.string().min(1),
24
+ context: z.record(z.unknown()).optional(),
25
+ });
26
+ export const JinnConfigSchema = z.object({
27
+ /**
28
+ * Network to connect to.
29
+ * 'testnet' → Base Sepolia (default during Phase 1b; fast epochs, free funds).
30
+ * 'mainnet' → Base mainnet (flipped on at Phase 2 launch).
31
+ * Operators should not normally need to set this — the default tracks whatever
32
+ * phase the protocol is in.
33
+ */
34
+ network: z.enum(['mainnet', 'testnet']).default('testnet'),
35
+ /**
36
+ * Base RPC endpoint.
37
+ * Defaults to https://mainnet.base.org for 'mainnet' and
38
+ * https://sepolia.base.org for 'testnet'. Set explicitly to override.
39
+ */
40
+ rpcUrl: z.string().optional(),
41
+ /** Earning state directory */
42
+ earningDir: z.string().default(join(homedir(), '.jinn-client', 'earning')),
43
+ /** SQLite database path */
44
+ dbPath: z.string().default(join(homedir(), '.jinn-client', 'jinn.db')),
45
+ /** Chain poll interval in ms */
46
+ pollIntervalMs: z.number().int().positive().default(5000),
47
+ /**
48
+ * How often the daemon attempts stOLAS ExternalStakingDistributor.claim for each staked
49
+ * fleet service (ms). Default 600000 (10 min) — well under typical checkpoint liveness windows
50
+ * on Base while limiting RPC/gas churn. Set to 0 to disable auto-claim.
51
+ * Env: JINN_REWARD_CLAIM_INTERVAL_MS
52
+ */
53
+ rewardClaimIntervalMs: z.number().int().min(0).default(600_000),
54
+ /** HTTP API port */
55
+ apiPort: z.number().int().positive().default(7331),
56
+ /** Path to claude CLI binary */
57
+ claudePath: z.string().default('claude'),
58
+ /** Model for restoration/evaluation agent */
59
+ claudeModel: z.string().default('claude-haiku-4-5-20251001'),
60
+ /** Comma-separated or array of peer URLs */
61
+ peers: z.union([
62
+ z.string().transform(s => s.split(',').filter(Boolean)),
63
+ z.array(z.string()),
64
+ ]).default([]),
65
+ /** The Graph subgraph URL for artifact discovery */
66
+ subgraphUrl: z.string().optional(),
67
+ /** This node's public HTTP endpoint (for 8004 registration) */
68
+ nodeEndpoint: z.string().optional(),
69
+ /** Desired states to create and restore */
70
+ desiredStates: z.array(DesiredStateSchema).default([
71
+ {
72
+ id: 'health-check',
73
+ description: 'The service is running and participating in the Jinn protocol loop.',
74
+ },
75
+ ]),
76
+ /** IPFS upload endpoint */
77
+ ipfsRegistryUrl: z.string().default('https://registry.autonolas.tech'),
78
+ /** IPFS read endpoint */
79
+ ipfsGatewayUrl: z.string().default('https://gateway.autonolas.tech'),
80
+ /** Optional Base Sepolia Phase 1a staking deployment artifact path */
81
+ testnetL2DeploymentPath: z.string().optional(),
82
+ /** Optional Base Sepolia Phase 1a token deployment artifact path */
83
+ testnetL2TokenDeploymentPath: z.string().optional(),
84
+ /** Optional Base Sepolia mech marketplace deployment artifact path */
85
+ testnetMechDeploymentPath: z.string().optional(),
86
+ /** Optional Base Sepolia stOLAS deployment artifact path */
87
+ testnetStolasDeploymentPath: z.string().optional(),
88
+ /** Staking mode: 'standard' uses stOLAS (no OLAS needed), 'self-bond' uses operator-provided OLAS. */
89
+ stakingMode: z.enum(['standard', 'self-bond']).default('standard'),
90
+ /** Number of services to bootstrap and run. */
91
+ targetServices: z.number().int().positive().default(1),
92
+ /**
93
+ * When true, log full error objects and stack traces from bootstrap / main.
94
+ * Env: JINN_DEBUG=1|true|yes
95
+ */
96
+ debug: z.boolean().default(false),
97
+ /**
98
+ * Estimated master wallet gas usage per day (wei string), for low-ETH runway warnings.
99
+ * Default is applied in bootstrap when unset. Env: JINN_MASTER_ETH_DAILY_WEI
100
+ */
101
+ masterEthDailyEstimateWei: z
102
+ .string()
103
+ .regex(/^\d+$/, 'must be a non-negative integer string')
104
+ .optional(),
105
+ });
106
+ // ── Defaults ────────────────────────────────────────────────────────────────
107
+ const DEFAULT_DIR = join(homedir(), '.jinn-client');
108
+ const DEFAULT_CONFIG_PATH = join(DEFAULT_DIR, 'config.json');
109
+ export class ConfigLoadError extends Error {
110
+ code;
111
+ details;
112
+ constructor(code, message, details) {
113
+ super(message);
114
+ this.name = 'ConfigLoadError';
115
+ this.code = code;
116
+ this.details = details;
117
+ }
118
+ }
119
+ // ── Loader ──────────────────────────────────────────────────────────────────
120
+ /**
121
+ * Load config with resolution: env > config file > defaults.
122
+ *
123
+ * @param configPath — explicit config file path (e.g. from --config flag).
124
+ * Falls back to ~/.jinn-client/config.json if it exists.
125
+ */
126
+ export function loadConfig(configPath) {
127
+ // 1. Load config file (if any)
128
+ const filePath = configPath ?? DEFAULT_CONFIG_PATH;
129
+ let fileValues = {};
130
+ if (existsSync(filePath)) {
131
+ const raw = readFileSync(filePath, 'utf-8');
132
+ try {
133
+ fileValues = JSON.parse(raw);
134
+ }
135
+ catch (error) {
136
+ throw new ConfigLoadError('config_json_invalid', `Invalid JSON in config file: ${filePath}`, {
137
+ path: filePath,
138
+ cause: error instanceof Error ? error.message : String(error),
139
+ });
140
+ }
141
+ console.error(`[config] Loaded ${filePath}`);
142
+ }
143
+ else if (configPath) {
144
+ throw new ConfigLoadError('config_file_not_found', `Config file not found: ${configPath}`, {
145
+ path: configPath,
146
+ });
147
+ }
148
+ // 2. Apply env var overrides
149
+ const env = process.env;
150
+ const merged = { ...fileValues };
151
+ if (env['JINN_NETWORK'])
152
+ merged.network = env['JINN_NETWORK'];
153
+ if (env['JINN_EARNING_DIR'])
154
+ merged.earningDir = env['JINN_EARNING_DIR'];
155
+ if (env['JINN_DB_PATH'])
156
+ merged.dbPath = env['JINN_DB_PATH'];
157
+ if (env['JINN_POLL_INTERVAL_MS'])
158
+ merged.pollIntervalMs = parseInt(env['JINN_POLL_INTERVAL_MS'], 10);
159
+ if (env['JINN_REWARD_CLAIM_INTERVAL_MS'] !== undefined) {
160
+ merged.rewardClaimIntervalMs = parseInt(env['JINN_REWARD_CLAIM_INTERVAL_MS'], 10);
161
+ }
162
+ if (env['JINN_API_PORT'])
163
+ merged.apiPort = parseInt(env['JINN_API_PORT'], 10);
164
+ if (env['JINN_CLAUDE_PATH'])
165
+ merged.claudePath = env['JINN_CLAUDE_PATH'];
166
+ if (env['JINN_CLAUDE_MODEL'])
167
+ merged.claudeModel = env['JINN_CLAUDE_MODEL'];
168
+ if (env['JINN_PEERS'])
169
+ merged.peers = env['JINN_PEERS'];
170
+ if (env['JINN_SUBGRAPH_URL'])
171
+ merged.subgraphUrl = env['JINN_SUBGRAPH_URL'];
172
+ if (env['JINN_NODE_ENDPOINT'])
173
+ merged.nodeEndpoint = env['JINN_NODE_ENDPOINT'];
174
+ if (env['JINN_IPFS_REGISTRY_URL'])
175
+ merged.ipfsRegistryUrl = env['JINN_IPFS_REGISTRY_URL'];
176
+ if (env['JINN_IPFS_GATEWAY_URL'])
177
+ merged.ipfsGatewayUrl = env['JINN_IPFS_GATEWAY_URL'];
178
+ if (env['JINN_TESTNET_L2_DEPLOYMENT'])
179
+ merged.testnetL2DeploymentPath = env['JINN_TESTNET_L2_DEPLOYMENT'];
180
+ if (env['JINN_TESTNET_TOKEN_DEPLOYMENT'])
181
+ merged.testnetL2TokenDeploymentPath = env['JINN_TESTNET_TOKEN_DEPLOYMENT'];
182
+ if (env['JINN_TESTNET_MECH_DEPLOYMENT'])
183
+ merged.testnetMechDeploymentPath = env['JINN_TESTNET_MECH_DEPLOYMENT'];
184
+ if (env['JINN_STAKING_MODE'])
185
+ merged.stakingMode = env['JINN_STAKING_MODE'];
186
+ if (env['JINN_TARGET_SERVICES'])
187
+ merged.targetServices = parseInt(env['JINN_TARGET_SERVICES'], 10);
188
+ if (env['JINN_DEBUG'] !== undefined) {
189
+ const v = env['JINN_DEBUG'].trim().toLowerCase();
190
+ merged.debug = v === '1' || v === 'true' || v === 'yes';
191
+ }
192
+ if (env['JINN_MASTER_ETH_DAILY_WEI']) {
193
+ merged.masterEthDailyEstimateWei = env['JINN_MASTER_ETH_DAILY_WEI'].trim();
194
+ }
195
+ const resolvedNetwork = merged.network === 'testnet' ? 'testnet' : 'mainnet';
196
+ // Keep the legacy BASE_RPC_URL override for Base mainnet only. Testnet must
197
+ // not silently inherit a mainnet RPC from client/.env during bootstrap.
198
+ if (env['JINN_RPC_URL']) {
199
+ merged.rpcUrl = env['JINN_RPC_URL'];
200
+ }
201
+ else if (resolvedNetwork === 'testnet') {
202
+ if (env['BASE_SEPOLIA_RPC_URL']) {
203
+ merged.rpcUrl = env['BASE_SEPOLIA_RPC_URL'];
204
+ }
205
+ }
206
+ else if (env['BASE_RPC_URL']) {
207
+ merged.rpcUrl = env['BASE_RPC_URL'];
208
+ }
209
+ // desiredStates from env points to a JSON file
210
+ if (env['JINN_DESIRED_STATES']) {
211
+ const statesPath = env['JINN_DESIRED_STATES'];
212
+ if (!existsSync(statesPath)) {
213
+ throw new ConfigLoadError('desired_states_file_not_found', `JINN_DESIRED_STATES file not found: ${statesPath}`, { path: statesPath });
214
+ }
215
+ try {
216
+ merged.desiredStates = JSON.parse(readFileSync(statesPath, 'utf-8'));
217
+ }
218
+ catch (error) {
219
+ throw new ConfigLoadError('desired_states_json_invalid', `Invalid JSON in JINN_DESIRED_STATES file: ${statesPath}`, {
220
+ path: statesPath,
221
+ cause: error instanceof Error ? error.message : String(error),
222
+ });
223
+ }
224
+ }
225
+ // 3. Validate
226
+ const result = JinnConfigSchema.safeParse(merged);
227
+ if (!result.success) {
228
+ throw new ConfigLoadError('config_invalid', 'Invalid config.', {
229
+ issues: result.error.issues.map((issue) => ({
230
+ path: issue.path.join('.'),
231
+ message: issue.message,
232
+ })),
233
+ });
234
+ }
235
+ // 4. Resolve rpcUrl default based on network (if not explicitly set)
236
+ const parsed = result.data;
237
+ const defaultRpcUrl = parsed.network === 'testnet'
238
+ ? 'https://sepolia.base.org'
239
+ : 'https://mainnet.base.org';
240
+ return {
241
+ ...parsed,
242
+ rpcUrl: parsed.rpcUrl ?? defaultRpcUrl,
243
+ };
244
+ }
245
+ /**
246
+ * Get the config file path from --config CLI arg, if provided.
247
+ */
248
+ export function getConfigPathFromArgs(argv = process.argv) {
249
+ const idx = argv.indexOf('--config');
250
+ return idx >= 0 && argv[idx + 1] ? argv[idx + 1] : undefined;
251
+ }
252
+ //# sourceMappingURL=config.js.map