tenjin-cli 0.1.0-alpha.1 → 0.1.0-alpha.3

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 (133) hide show
  1. package/NOTICE.md +33 -0
  2. package/README.md +167 -16
  3. package/dist/{_esm-ZH2J4QEH.js → _esm-C5CRWCYU.js} +2 -2
  4. package/dist/_esm-FEASBWRP.js +881 -0
  5. package/dist/buy-EE6SEXP6.js +1598 -0
  6. package/dist/buy-EE6SEXP6.js.map +1 -0
  7. package/dist/candidate-ERMSYYQZ.js +127 -0
  8. package/dist/candidate-ERMSYYQZ.js.map +1 -0
  9. package/dist/{ccip-UCLT5VOW.js → ccip-NQXCEK2U.js} +6 -5
  10. package/dist/ccip-XR5NE5QK.js +19 -0
  11. package/dist/chunk-2I4QTOLB.js +11 -0
  12. package/dist/chunk-2I4QTOLB.js.map +1 -0
  13. package/dist/chunk-3OV7E5G5.js +18 -0
  14. package/dist/chunk-3OV7E5G5.js.map +1 -0
  15. package/dist/chunk-4ONXEEQL.js +152 -0
  16. package/dist/chunk-4ONXEEQL.js.map +1 -0
  17. package/dist/chunk-5CLSD5YN.js +209 -0
  18. package/dist/chunk-5CLSD5YN.js.map +1 -0
  19. package/dist/chunk-662MSGZB.js +286 -0
  20. package/dist/chunk-662MSGZB.js.map +1 -0
  21. package/dist/chunk-7KUW4MJD.js +59 -0
  22. package/dist/chunk-7KUW4MJD.js.map +1 -0
  23. package/dist/{doctor-3QBYN46N.js → chunk-AWPAWHNX.js} +88 -93
  24. package/dist/chunk-AWPAWHNX.js.map +1 -0
  25. package/dist/chunk-CYOF7ROH.js +70 -0
  26. package/dist/chunk-CYOF7ROH.js.map +1 -0
  27. package/dist/chunk-DXTQ3CSI.js +171 -0
  28. package/dist/chunk-DXTQ3CSI.js.map +1 -0
  29. package/dist/{chunk-EZROUI5U.js → chunk-ESPNTPQ2.js} +80 -8
  30. package/dist/chunk-ESPNTPQ2.js.map +1 -0
  31. package/dist/chunk-FJPLRISB.js +79 -0
  32. package/dist/chunk-FJPLRISB.js.map +1 -0
  33. package/dist/chunk-GO75V3NZ.js +160 -0
  34. package/dist/chunk-GO75V3NZ.js.map +1 -0
  35. package/dist/chunk-HIVZG55D.js +204 -0
  36. package/dist/chunk-HIVZG55D.js.map +1 -0
  37. package/dist/chunk-HSDCI7OV.js +7806 -0
  38. package/dist/chunk-HSDCI7OV.js.map +1 -0
  39. package/dist/chunk-JPHG2JW3.js +96 -0
  40. package/dist/chunk-JPHG2JW3.js.map +1 -0
  41. package/dist/{chunk-ZPZFPVDN.js → chunk-MUBUQVC3.js} +1 -1
  42. package/dist/chunk-MUBUQVC3.js.map +1 -0
  43. package/dist/{chunk-T4LKNY7T.js → chunk-NCE5NSN6.js} +166 -11
  44. package/dist/chunk-NCE5NSN6.js.map +1 -0
  45. package/dist/{chunk-YG2DO46P.js → chunk-OYMYCW7J.js} +18 -3
  46. package/dist/{chunk-YG2DO46P.js.map → chunk-OYMYCW7J.js.map} +1 -1
  47. package/dist/{chunk-Q53IYV2G.js → chunk-QVX5MWJZ.js} +20 -17
  48. package/dist/{chunk-Q53IYV2G.js.map → chunk-QVX5MWJZ.js.map} +1 -1
  49. package/dist/{chunk-CUWUHTIL.js → chunk-RBJPAZFI.js} +16 -202
  50. package/dist/chunk-RBJPAZFI.js.map +1 -0
  51. package/dist/chunk-RRN3YTK7.js +6199 -0
  52. package/dist/chunk-RRN3YTK7.js.map +1 -0
  53. package/dist/chunk-RY4XKNV3.js +140 -0
  54. package/dist/chunk-RY4XKNV3.js.map +1 -0
  55. package/dist/chunk-S3IGX57D.js +14682 -0
  56. package/dist/chunk-S3IGX57D.js.map +1 -0
  57. package/dist/chunk-TLCMMYLY.js +126 -0
  58. package/dist/chunk-TLCMMYLY.js.map +1 -0
  59. package/dist/{chunk-IPOWB3G3.js → chunk-UGX7YPX2.js} +3314 -306
  60. package/dist/chunk-UGX7YPX2.js.map +1 -0
  61. package/dist/chunk-UO22YNY4.js +69 -0
  62. package/dist/chunk-UO22YNY4.js.map +1 -0
  63. package/dist/{config-CEFTL5ZL.js → chunk-XHC6FCGZ.js} +115 -18
  64. package/dist/chunk-XHC6FCGZ.js.map +1 -0
  65. package/dist/chunk-XJIW7USF.js +217 -0
  66. package/dist/chunk-XJIW7USF.js.map +1 -0
  67. package/dist/{chunk-BRJHUQSY.js → chunk-YALGASEU.js} +1548 -1452
  68. package/dist/chunk-YALGASEU.js.map +1 -0
  69. package/dist/{chunk-DXPYFVKG.js → chunk-YN5SHIXQ.js} +6 -6
  70. package/dist/chunk-YN5SHIXQ.js.map +1 -0
  71. package/dist/chunk-Z52RA3NC.js +137 -0
  72. package/dist/chunk-Z52RA3NC.js.map +1 -0
  73. package/dist/{chunk-EXBMF5X7.js → chunk-Z6MFJV5Z.js} +151 -19
  74. package/dist/chunk-Z6MFJV5Z.js.map +1 -0
  75. package/dist/chunk-ZABPQJ3M.js +83 -0
  76. package/dist/chunk-ZABPQJ3M.js.map +1 -0
  77. package/dist/{chunk-LPRVHM7P.js → chunk-ZMHYXMO6.js} +1655 -114
  78. package/dist/chunk-ZMHYXMO6.js.map +1 -0
  79. package/dist/{chunk-3IMLRUZE.js → chunk-ZXTAQYNA.js} +6 -2
  80. package/dist/{cli-WA65NP4Y.js → cli-SBXI5AMS.js} +177 -177
  81. package/dist/cli-SBXI5AMS.js.map +1 -0
  82. package/dist/config-VELDKLHY.js +21 -0
  83. package/dist/doctor-T3KWNNP2.js +20 -0
  84. package/dist/doctor-T3KWNNP2.js.map +1 -0
  85. package/dist/ethersCompat-Df4a6QIZ-3YZIAXDK.js +18 -0
  86. package/dist/ethersCompat-Df4a6QIZ-3YZIAXDK.js.map +1 -0
  87. package/dist/index.js +1 -1
  88. package/dist/inspect-LMKOXE4Y.js +96 -0
  89. package/dist/inspect-LMKOXE4Y.js.map +1 -0
  90. package/dist/install-LEX3ENQ6.js +387 -0
  91. package/dist/install-LEX3ENQ6.js.map +1 -0
  92. package/dist/lookup-ZPN2Q67N.js +129 -0
  93. package/dist/lookup-ZPN2Q67N.js.map +1 -0
  94. package/dist/{mine.wasm-GQECMSGN.js → mine.wasm-6PIT3DK6.js} +2 -2
  95. package/dist/outcome-N7TAK6WR.js +66 -0
  96. package/dist/outcome-N7TAK6WR.js.map +1 -0
  97. package/dist/publish-BKBQQAW4.js +1478 -0
  98. package/dist/publish-BKBQQAW4.js.map +1 -0
  99. package/dist/{secp256k1-BEZS642W.js → secp256k1-N3ZHU7LB.js} +5 -4
  100. package/dist/secp256k1-N3ZHU7LB.js.map +1 -0
  101. package/dist/usdc-JIAJW4SV.js +22 -0
  102. package/dist/usdc-JIAJW4SV.js.map +1 -0
  103. package/dist/viemAdapter-By13KInL-ZZE6UV4Y.js +14 -0
  104. package/dist/viemAdapter-By13KInL-ZZE6UV4Y.js.map +1 -0
  105. package/dist/{wallet-XD576HF3.js → wallet-CWEMYVIH.js} +28 -22
  106. package/dist/{wallet-XD576HF3.js.map → wallet-CWEMYVIH.js.map} +1 -1
  107. package/dist/wallet-PA54CRBL.js +30 -0
  108. package/dist/wallet-PA54CRBL.js.map +1 -0
  109. package/package.json +19 -16
  110. package/skills/tenjin/SKILL.md +199 -0
  111. package/skills/tenjin-publish/SKILL.md +111 -0
  112. package/skills/tenjin-search/SKILL.md +133 -0
  113. package/dist/chunk-BRJHUQSY.js.map +0 -1
  114. package/dist/chunk-CUWUHTIL.js.map +0 -1
  115. package/dist/chunk-DXPYFVKG.js.map +0 -1
  116. package/dist/chunk-EXBMF5X7.js.map +0 -1
  117. package/dist/chunk-EZROUI5U.js.map +0 -1
  118. package/dist/chunk-IPOWB3G3.js.map +0 -1
  119. package/dist/chunk-LPRVHM7P.js.map +0 -1
  120. package/dist/chunk-T4LKNY7T.js.map +0 -1
  121. package/dist/chunk-ZPZFPVDN.js.map +0 -1
  122. package/dist/cli-WA65NP4Y.js.map +0 -1
  123. package/dist/config-CEFTL5ZL.js.map +0 -1
  124. package/dist/doctor-3QBYN46N.js.map +0 -1
  125. package/dist/usdc-44R6XZF2.js +0 -18
  126. package/dist/wallet-ELBTBMXO.js +0 -20
  127. /package/dist/{_esm-ZH2J4QEH.js.map → _esm-C5CRWCYU.js.map} +0 -0
  128. /package/dist/{ccip-UCLT5VOW.js.map → _esm-FEASBWRP.js.map} +0 -0
  129. /package/dist/{chunk-3IMLRUZE.js.map → ccip-NQXCEK2U.js.map} +0 -0
  130. /package/dist/{secp256k1-BEZS642W.js.map → ccip-XR5NE5QK.js.map} +0 -0
  131. /package/dist/{usdc-44R6XZF2.js.map → chunk-ZXTAQYNA.js.map} +0 -0
  132. /package/dist/{wallet-ELBTBMXO.js.map → config-VELDKLHY.js.map} +0 -0
  133. /package/dist/{mine.wasm-GQECMSGN.js.map → mine.wasm-6PIT3DK6.js.map} +0 -0
@@ -0,0 +1,69 @@
1
+ import { createRequire as __tenjinCreateRequire } from 'node:module'; const require = __tenjinCreateRequire(import.meta.url);
2
+
3
+ // src/lib/policy.ts
4
+ function normCreator(value) {
5
+ return value.trim().toLowerCase();
6
+ }
7
+ function evaluateSpendPolicy(policy, req) {
8
+ if (req.maxPriceAtomic !== void 0 && req.amountAtomic > req.maxPriceAtomic) {
9
+ return {
10
+ decision: "deny",
11
+ reason: "price_cap_exceeded",
12
+ message: `Price ${req.amountAtomic} exceeds the --max-price cap ${req.maxPriceAtomic}.`
13
+ };
14
+ }
15
+ if (policy.allowlistCreators.length > 0) {
16
+ const allowed = policy.allowlistCreators.map(normCreator);
17
+ if (!allowed.includes(normCreator(req.creator))) {
18
+ return {
19
+ decision: "deny",
20
+ reason: "not_allowlisted",
21
+ message: `Creator "${req.creator}" is not in allowlistCreators.`
22
+ };
23
+ }
24
+ }
25
+ if (policy.sessionBudgetAtomic > 0n) {
26
+ const projected = req.sessionSpentAtomic + req.amountAtomic;
27
+ if (projected > policy.sessionBudgetAtomic) {
28
+ return {
29
+ decision: "deny",
30
+ reason: "session_budget_exceeded",
31
+ message: `This spend would bring the session total to ${projected}, over sessionBudget ${policy.sessionBudgetAtomic}.`
32
+ };
33
+ }
34
+ }
35
+ if (req.amountAtomic > policy.maxAutoSpendAtomic) {
36
+ return {
37
+ decision: "confirm",
38
+ reason: "above_auto_spend",
39
+ message: `Price ${req.amountAtomic} is above maxAutoSpend ${policy.maxAutoSpendAtomic}; confirmation required.`
40
+ };
41
+ }
42
+ if (policy.confirm.mode === "always") {
43
+ return {
44
+ decision: "confirm",
45
+ reason: "confirm_always",
46
+ message: 'confirm policy is "always"; confirmation required.'
47
+ };
48
+ }
49
+ if (req.amountAtomic > policy.confirm.thresholdAtomic) {
50
+ return {
51
+ decision: "confirm",
52
+ reason: "above_confirm_threshold",
53
+ message: `Price ${req.amountAtomic} is above the confirm threshold ${policy.confirm.thresholdAtomic}; confirmation required.`
54
+ };
55
+ }
56
+ return { decision: "allow", reason: "within_policy", message: "within spend policy" };
57
+ }
58
+ function parseConfirmPolicy(stored) {
59
+ if (stored === "always") return { mode: "always" };
60
+ const m = /^above:(\d+)$/.exec(stored);
61
+ if (m && m[1] !== void 0) return { mode: "above", thresholdAtomic: BigInt(m[1]) };
62
+ return { mode: "always" };
63
+ }
64
+
65
+ export {
66
+ evaluateSpendPolicy,
67
+ parseConfirmPolicy
68
+ };
69
+ //# sourceMappingURL=chunk-UO22YNY4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/policy.ts"],"sourcesContent":["/**\n * Spend-policy evaluation, pure and provider-agnostic. The wallet provider layer\n * (lib/wallet/spend.ts) owns the ledger and calls this; a future hosted provider\n * (Privy, B5) reuses the same decision rules, so the knobs live in exactly one\n * place. Nothing here does IO, the caller supplies the already-spent total and\n * decides how to satisfy a `confirm` decision (a `--yes`, a TTY prompt, or a\n * non-interactive refusal).\n */\n\n/** How a `confirm` gate is configured (parsed from the stored config string). */\nexport type ConfirmPolicy = { mode: 'always' } | { mode: 'above'; thresholdAtomic: bigint };\n\nexport interface SpendPolicy {\n /** Amounts at or below this auto-approve WITHOUT a prompt (still subject to the\n * confirm gate below). Default 0 → nothing auto-approves. */\n maxAutoSpendAtomic: bigint;\n /** Rolling local ceiling on cumulative session spend. 0 = disabled (no ceiling). */\n sessionBudgetAtomic: bigint;\n /** When a human confirmation is requested. */\n confirm: ConfirmPolicy;\n /** Creators (handle or 0x-address, lowercased) auto-payment is restricted to.\n * Empty = no restriction. A non-empty list is a hard gate: a non-member is\n * denied even with `--yes`. */\n allowlistCreators: string[];\n}\n\nexport interface SpendRequest {\n amountAtomic: bigint;\n /** Creator identity from the 402 preview / candidate, handle or 0x address. */\n creator: string;\n /** The caller's `--max-price` cap, if given. A hard ceiling, never bypassable. */\n maxPriceAtomic?: bigint;\n /** Cumulative spend already recorded in this rolling session window. */\n sessionSpentAtomic: bigint;\n}\n\n/**\n * `allow`: within policy, proceed silently. `confirm`: an approval is required ,\n * the caller satisfies it with `--yes`, an interactive prompt, or refuses. `deny`:\n * a hard gate blocked it (price cap, allowlist, session budget); NOT satisfiable\n * by `--yes` or a prompt.\n */\nexport type SpendDecision = 'allow' | 'confirm' | 'deny';\n\nexport type PolicyReason =\n | 'within_policy'\n | 'price_cap_exceeded'\n | 'not_allowlisted'\n | 'session_budget_exceeded'\n | 'above_auto_spend'\n | 'confirm_always'\n | 'above_confirm_threshold';\n\nexport interface PolicyEvaluation {\n decision: SpendDecision;\n reason: PolicyReason;\n message: string;\n}\n\n/** Normalize a creator identity for allowlist comparison (case-insensitive; a\n * word-handle and a 0x address are both single tokens). */\nfunction normCreator(value: string): string {\n return value.trim().toLowerCase();\n}\n\n/**\n * Evaluate one spend against the policy. Hard gates run first (price cap →\n * allowlist → session budget); only if all pass is the confirm gate consulted. A\n * spend at or below `maxAutoSpend` that the confirm policy would not prompt for is\n * the only `allow`; everything else within the hard gates is `confirm`.\n */\nexport function evaluateSpendPolicy(policy: SpendPolicy, req: SpendRequest): PolicyEvaluation {\n if (req.maxPriceAtomic !== undefined && req.amountAtomic > req.maxPriceAtomic) {\n return {\n decision: 'deny',\n reason: 'price_cap_exceeded',\n message: `Price ${req.amountAtomic} exceeds the --max-price cap ${req.maxPriceAtomic}.`,\n };\n }\n\n if (policy.allowlistCreators.length > 0) {\n const allowed = policy.allowlistCreators.map(normCreator);\n if (!allowed.includes(normCreator(req.creator))) {\n return {\n decision: 'deny',\n reason: 'not_allowlisted',\n message: `Creator \"${req.creator}\" is not in allowlistCreators.`,\n };\n }\n }\n\n if (policy.sessionBudgetAtomic > 0n) {\n const projected = req.sessionSpentAtomic + req.amountAtomic;\n if (projected > policy.sessionBudgetAtomic) {\n return {\n decision: 'deny',\n reason: 'session_budget_exceeded',\n message: `This spend would bring the session total to ${projected}, over sessionBudget ${policy.sessionBudgetAtomic}.`,\n };\n }\n }\n\n if (req.amountAtomic > policy.maxAutoSpendAtomic) {\n return {\n decision: 'confirm',\n reason: 'above_auto_spend',\n message: `Price ${req.amountAtomic} is above maxAutoSpend ${policy.maxAutoSpendAtomic}; confirmation required.`,\n };\n }\n\n if (policy.confirm.mode === 'always') {\n return {\n decision: 'confirm',\n reason: 'confirm_always',\n message: 'confirm policy is \"always\"; confirmation required.',\n };\n }\n\n if (req.amountAtomic > policy.confirm.thresholdAtomic) {\n return {\n decision: 'confirm',\n reason: 'above_confirm_threshold',\n message: `Price ${req.amountAtomic} is above the confirm threshold ${policy.confirm.thresholdAtomic}; confirmation required.`,\n };\n }\n\n return { decision: 'allow', reason: 'within_policy', message: 'within spend policy' };\n}\n\n/** Parse the stored `confirm` config value (\"always\" | \"above:<atomic>\"). */\nexport function parseConfirmPolicy(stored: string): ConfirmPolicy {\n if (stored === 'always') return { mode: 'always' };\n const m = /^above:(\\d+)$/.exec(stored);\n if (m && m[1] !== undefined) return { mode: 'above', thresholdAtomic: BigInt(m[1]) };\n // The config schema already constrains this; a malformed value here is a bug,\n // so fail closed to the safest interpretation rather than throwing mid-buy.\n return { mode: 'always' };\n}\n"],"mappings":";;;AA6DA,SAAS,YAAY,OAAuB;AAC1C,SAAO,MAAM,KAAK,EAAE,YAAY;AAClC;AAQO,SAAS,oBAAoB,QAAqB,KAAqC;AAC5F,MAAI,IAAI,mBAAmB,UAAa,IAAI,eAAe,IAAI,gBAAgB;AAC7E,WAAO;AAAA,MACL,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,SAAS,SAAS,IAAI,YAAY,gCAAgC,IAAI,cAAc;AAAA,IACtF;AAAA,EACF;AAEA,MAAI,OAAO,kBAAkB,SAAS,GAAG;AACvC,UAAM,UAAU,OAAO,kBAAkB,IAAI,WAAW;AACxD,QAAI,CAAC,QAAQ,SAAS,YAAY,IAAI,OAAO,CAAC,GAAG;AAC/C,aAAO;AAAA,QACL,UAAU;AAAA,QACV,QAAQ;AAAA,QACR,SAAS,YAAY,IAAI,OAAO;AAAA,MAClC;AAAA,IACF;AAAA,EACF;AAEA,MAAI,OAAO,sBAAsB,IAAI;AACnC,UAAM,YAAY,IAAI,qBAAqB,IAAI;AAC/C,QAAI,YAAY,OAAO,qBAAqB;AAC1C,aAAO;AAAA,QACL,UAAU;AAAA,QACV,QAAQ;AAAA,QACR,SAAS,+CAA+C,SAAS,wBAAwB,OAAO,mBAAmB;AAAA,MACrH;AAAA,IACF;AAAA,EACF;AAEA,MAAI,IAAI,eAAe,OAAO,oBAAoB;AAChD,WAAO;AAAA,MACL,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,SAAS,SAAS,IAAI,YAAY,0BAA0B,OAAO,kBAAkB;AAAA,IACvF;AAAA,EACF;AAEA,MAAI,OAAO,QAAQ,SAAS,UAAU;AACpC,WAAO;AAAA,MACL,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,SAAS;AAAA,IACX;AAAA,EACF;AAEA,MAAI,IAAI,eAAe,OAAO,QAAQ,iBAAiB;AACrD,WAAO;AAAA,MACL,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,SAAS,SAAS,IAAI,YAAY,mCAAmC,OAAO,QAAQ,eAAe;AAAA,IACrG;AAAA,EACF;AAEA,SAAO,EAAE,UAAU,SAAS,QAAQ,iBAAiB,SAAS,sBAAsB;AACtF;AAGO,SAAS,mBAAmB,QAA+B;AAChE,MAAI,WAAW,SAAU,QAAO,EAAE,MAAM,SAAS;AACjD,QAAM,IAAI,gBAAgB,KAAK,MAAM;AACrC,MAAI,KAAK,EAAE,CAAC,MAAM,OAAW,QAAO,EAAE,MAAM,SAAS,iBAAiB,OAAO,EAAE,CAAC,CAAC,EAAE;AAGnF,SAAO,EAAE,MAAM,SAAS;AAC1B;","names":[]}
@@ -1,30 +1,48 @@
1
1
  import { createRequire as __tenjinCreateRequire } from 'node:module'; const require = __tenjinCreateRequire(import.meta.url);
2
2
  import {
3
- LockTimeoutError,
4
- withFileLock
5
- } from "./chunk-YBMMV4Y4.js";
3
+ loadProjectConfig
4
+ } from "./chunk-GO75V3NZ.js";
6
5
  import {
7
6
  CONFIG_KEYS,
7
+ PUBLISH_CONFIG_KEYS,
8
+ PublishModeSchema,
8
9
  RawConfigSchema,
9
10
  loadRawConfig,
10
11
  parseUsdToAtomic,
11
12
  resolveSettings,
12
13
  toMoney
13
- } from "./chunk-EZROUI5U.js";
14
+ } from "./chunk-ESPNTPQ2.js";
15
+ import {
16
+ LockTimeoutError,
17
+ withFileLock
18
+ } from "./chunk-YBMMV4Y4.js";
14
19
  import {
15
20
  writeFileAtomic
16
- } from "./chunk-ZPZFPVDN.js";
21
+ } from "./chunk-MUBUQVC3.js";
17
22
  import {
18
23
  CliError,
19
24
  configPath
20
- } from "./chunk-YG2DO46P.js";
21
- import "./chunk-3IMLRUZE.js";
25
+ } from "./chunk-OYMYCW7J.js";
22
26
 
23
27
  // src/commands/config.ts
24
28
  import { mkdir } from "fs/promises";
25
29
  import { styleText } from "util";
26
30
  var CONFIRM_ABOVE = "above:";
27
- var KEY_WIDTH = Math.max(...CONFIG_KEYS.map((key) => key.length));
31
+ var KEY_WIDTH = Math.max(...[...CONFIG_KEYS, ...PUBLISH_CONFIG_KEYS].map((key) => key.length));
32
+ var KEY_DESCRIPTIONS = {
33
+ maxAutoSpend: "auto-approve a read up to this amount",
34
+ sessionBudget: "cap on total auto-spend per session",
35
+ confirm: "when to ask before paying",
36
+ allowlistCreators: "only auto-pay these creators (empty = any)",
37
+ baseUrl: "Tenjin API base URL",
38
+ rpcUrl: "Base RPC endpoint for balance reads",
39
+ evalCohort: "opt in to the lookup evaluation cohort",
40
+ "publish.mode": "review=always ask, auto=ask on findings, full-auto=only hard blocks stop it",
41
+ "publish.defaultPrice": "price used when none is given"
42
+ };
43
+ function isPublishKey(key) {
44
+ return PUBLISH_CONFIG_KEYS.includes(key);
45
+ }
28
46
  async function runConfigList(ctx) {
29
47
  const settings = await resolveFromContext(ctx);
30
48
  const data = {};
@@ -32,38 +50,90 @@ async function runConfigList(ctx) {
32
50
  for (const key of CONFIG_KEYS) {
33
51
  const entry = renderSetting(key, settings[key].value, settings[key].source);
34
52
  data[key] = entry;
35
- humanLines.push(formatLine(key, entry));
53
+ humanLines.push(describedLine(key, entry));
54
+ }
55
+ for (const key of PUBLISH_CONFIG_KEYS) {
56
+ const entry = renderPublishSetting(key, settings);
57
+ data[key] = entry;
58
+ humanLines.push(describedLine(key, entry, downgradeNote(key, settings)));
36
59
  }
37
60
  return { data, humanLines };
38
61
  }
39
62
  async function runConfigGet({ key }, ctx) {
63
+ if (isPublishKey(key)) {
64
+ const settings2 = await resolveFromContext(ctx);
65
+ const entry2 = renderPublishSetting(key, settings2);
66
+ return {
67
+ data: { key, ...entry2 },
68
+ humanLines: [withNote(formatLine(key, entry2), downgradeNote(key, settings2))]
69
+ };
70
+ }
40
71
  const configKey = assertKey(key);
41
72
  const settings = await resolveFromContext(ctx);
42
73
  const entry = renderSetting(configKey, settings[configKey].value, settings[configKey].source);
43
74
  return { data: { key: configKey, ...entry }, humanLines: [formatLine(configKey, entry)] };
44
75
  }
45
76
  async function runConfigSet({ key, value }, ctx) {
77
+ if (isPublishKey(key)) return setPublishKey(key, value, ctx);
46
78
  const configKey = assertKey(key);
47
79
  const stored = parseValue(configKey, value);
48
- await persist(ctx.dataDir, configKey, stored);
80
+ await persist(ctx.dataDir, (existing) => ({ ...existing, [configKey]: stored }));
49
81
  const entry = renderSetting(configKey, stored, "file");
50
82
  return { data: { key: configKey, ...entry }, humanLines: [formatLine(configKey, entry)] };
51
83
  }
84
+ async function setPublishKey(key, value, ctx) {
85
+ const entry = key === "publish.mode" ? { value: parsePublishMode(value), source: "file" } : { value: toMoney(parseUsdToAtomic(value)), source: "file" };
86
+ const subkey = key === "publish.mode" ? "mode" : "defaultPrice";
87
+ const stored = key === "publish.mode" ? entry.value : entry.value.atomic;
88
+ await persist(ctx.dataDir, (existing) => ({
89
+ ...existing,
90
+ publish: { ...existing.publish, [subkey]: stored }
91
+ }));
92
+ return { data: { key, ...entry }, humanLines: [formatLine(key, entry)] };
93
+ }
94
+ function parsePublishMode(value) {
95
+ const parsed = PublishModeSchema.safeParse(value);
96
+ if (parsed.success) return parsed.data;
97
+ throw new CliError("USAGE", `Invalid publish mode: ${JSON.stringify(value)}`, {
98
+ fix: 'Use "review", "auto", or "full-auto".'
99
+ });
100
+ }
101
+ async function persistPublishMode(dir, mode) {
102
+ await persist(dir, (existing) => ({
103
+ ...existing,
104
+ publish: { ...existing.publish, mode }
105
+ }));
106
+ }
52
107
  async function resolveFromContext(ctx) {
53
108
  const config = await loadRawConfig(ctx.dataDir);
54
- return resolveSettings({ config, flags: { baseUrl: ctx.flags.baseUrl }, env: process.env });
109
+ const project = await loadProjectConfig(process.cwd());
110
+ return resolveSettings({
111
+ config,
112
+ flags: { baseUrl: ctx.flags.baseUrl },
113
+ env: process.env,
114
+ project: project?.layer
115
+ });
55
116
  }
56
117
  function assertKey(key) {
57
118
  if (CONFIG_KEYS.includes(key)) return key;
58
119
  throw new CliError("USAGE", `Unknown config key: ${JSON.stringify(key)}`, {
59
- fix: `Valid keys: ${CONFIG_KEYS.join(", ")}.`
120
+ fix: `Valid keys: ${[...CONFIG_KEYS, ...PUBLISH_CONFIG_KEYS].join(", ")}.`
60
121
  });
61
122
  }
62
123
  function renderSetting(key, stored, source) {
63
124
  return { ...renderValue(key, stored), source };
64
125
  }
126
+ function renderPublishSetting(key, settings) {
127
+ if (key === "publish.mode") {
128
+ return { value: settings.publishMode.value, source: settings.publishMode.source };
129
+ }
130
+ return {
131
+ value: toMoney(settings.publishDefaultPrice.value),
132
+ source: settings.publishDefaultPrice.source
133
+ };
134
+ }
65
135
  function renderValue(key, stored) {
66
- if (Array.isArray(stored)) return { value: stored };
136
+ if (Array.isArray(stored) || typeof stored === "boolean") return { value: stored };
67
137
  if (key === "maxAutoSpend" || key === "sessionBudget") return { value: toMoney(stored) };
68
138
  if (key === "confirm" && stored.startsWith(CONFIRM_ABOVE)) {
69
139
  return { value: stored, threshold: toMoney(stored.slice(CONFIRM_ABOVE.length)) };
@@ -83,8 +153,17 @@ function parseValue(key, value) {
83
153
  case "baseUrl":
84
154
  case "rpcUrl":
85
155
  return parseHttpUrl(value);
156
+ case "evalCohort":
157
+ return parseBoolean(value);
86
158
  }
87
159
  }
160
+ function parseBoolean(value) {
161
+ if (value === "true") return true;
162
+ if (value === "false") return false;
163
+ throw new CliError("USAGE", `Invalid boolean value: ${JSON.stringify(value)}`, {
164
+ fix: 'Use "true" or "false".'
165
+ });
166
+ }
88
167
  function parseConfirm(value) {
89
168
  if (value === "always") return "always";
90
169
  if (value.startsWith(CONFIRM_ABOVE)) {
@@ -121,13 +200,13 @@ function parseHttpUrl(value) {
121
200
  }
122
201
  return value;
123
202
  }
124
- async function persist(dir, key, stored) {
203
+ async function persist(dir, merge) {
125
204
  await mkdir(dir, { recursive: true, mode: 448 });
126
205
  const lockPath = `${configPath(dir)}.lock`;
127
206
  try {
128
207
  await withFileLock(lockPath, async () => {
129
208
  const existing = await loadRawConfig(dir);
130
- const merged = { ...existing, [key]: stored };
209
+ const merged = merge(existing);
131
210
  const validated = RawConfigSchema.parse(merged);
132
211
  await writeFileAtomic(configPath(dir), `${JSON.stringify(validated, null, 2)}
133
212
  `, {
@@ -149,16 +228,34 @@ function formatLine(key, entry) {
149
228
  const label = key.padEnd(KEY_WIDTH);
150
229
  return ` ${label} ${displayValue(entry)} ${styleText("dim", `(${entry.source})`)}`;
151
230
  }
231
+ function describedLine(key, entry, note) {
232
+ const description = KEY_DESCRIPTIONS[key];
233
+ let line = formatLine(key, entry);
234
+ if (description !== void 0) line += ` ${styleText("dim", `- ${description}`)}`;
235
+ return withNote(line, note);
236
+ }
237
+ function withNote(line, note) {
238
+ return note !== void 0 ? `${line} ${styleText("dim", `(${note})`)}` : line;
239
+ }
240
+ function downgradeNote(key, settings) {
241
+ if (key !== "publish.mode" || settings.publishMode.downgradedWarning === void 0) {
242
+ return void 0;
243
+ }
244
+ return "downgraded from full-auto: committed .tenjin.json (gitignore it to opt in)";
245
+ }
152
246
  function displayValue(entry) {
153
247
  const { value } = entry;
154
248
  if (Array.isArray(value)) return value.length > 0 ? value.join(", ") : "(empty)";
249
+ if (typeof value === "boolean") return value ? "true" : "false";
155
250
  if (typeof value === "object") return `${value.usd} USD`;
156
251
  if (entry.threshold !== void 0) return `above ${entry.threshold.usd} USD`;
157
252
  return value;
158
253
  }
254
+
159
255
  export {
160
- runConfigGet,
161
256
  runConfigList,
162
- runConfigSet
257
+ runConfigGet,
258
+ runConfigSet,
259
+ persistPublishMode
163
260
  };
164
- //# sourceMappingURL=config-CEFTL5ZL.js.map
261
+ //# sourceMappingURL=chunk-XHC6FCGZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/config.ts"],"sourcesContent":["import { mkdir } from 'node:fs/promises';\nimport { styleText } from 'node:util';\nimport { CliError } from '../lib/errors';\nimport {\n CONFIG_KEYS,\n PUBLISH_CONFIG_KEYS,\n PublishModeSchema,\n RawConfigSchema,\n loadRawConfig,\n resolveSettings,\n} from '../lib/config';\nimport type {\n EffectiveSettings,\n PartialConfig,\n Provenance,\n PublishConfigKey,\n PublishMode,\n ScalarConfigKey,\n} from '../lib/config';\nimport { loadProjectConfig } from '../lib/settings';\nimport { configPath } from '../lib/paths';\nimport { writeFileAtomic } from '../lib/atomic-json';\nimport { withFileLock, LockTimeoutError } from '../lib/lock';\nimport { parseUsdToAtomic, toMoney } from '../lib/money';\nimport type { Money } from '../schemas';\nimport type { CommandContext, CommandResult } from '../context';\n\n/**\n * How one config key is presented in `data`. `value` is the machine form: dual\n * Money for the spend keys, the stored string for `confirm`/URLs, the string[]\n * for the allowlist. `threshold` rides along only for `confirm: above:<atomic>`\n * so an agent reads the dollar amount without re-parsing the string.\n */\ninterface RenderedValue {\n value: Money | string | string[] | boolean;\n threshold?: Money;\n}\ninterface RenderedSetting extends RenderedValue {\n source: Provenance;\n}\n\nconst CONFIRM_ABOVE = 'above:';\nconst KEY_WIDTH = Math.max(...[...CONFIG_KEYS, ...PUBLISH_CONFIG_KEYS].map((key) => key.length));\n\n/**\n * A one-line human description per key, appended (dim) to the bare `config`\n * listing only. Machine `data` is unchanged; these are humanLines decoration.\n */\nconst KEY_DESCRIPTIONS: Record<string, string> = {\n maxAutoSpend: 'auto-approve a read up to this amount',\n sessionBudget: 'cap on total auto-spend per session',\n confirm: 'when to ask before paying',\n allowlistCreators: 'only auto-pay these creators (empty = any)',\n baseUrl: 'Tenjin API base URL',\n rpcUrl: 'Base RPC endpoint for balance reads',\n evalCohort: 'opt in to the lookup evaluation cohort',\n 'publish.mode': 'review=always ask, auto=ask on findings, full-auto=only hard blocks stop it',\n 'publish.defaultPrice': 'price used when none is given',\n};\n\nfunction isPublishKey(key: string): key is PublishConfigKey {\n return (PUBLISH_CONFIG_KEYS as readonly string[]).includes(key);\n}\n\n/**\n * Show every effective key with its value and provenance. `data` is keyed by\n * config key; provenance comes from resolveSettings over the *raw* file (not the\n * defaults-merged config), so a key the user never set reads `default`, not\n * `file`.\n */\nexport async function runConfigList(ctx: CommandContext): Promise<CommandResult> {\n const settings = await resolveFromContext(ctx);\n const data: Record<string, RenderedSetting> = {};\n const humanLines: string[] = [];\n for (const key of CONFIG_KEYS) {\n const entry = renderSetting(key, settings[key].value, settings[key].source);\n data[key] = entry;\n humanLines.push(describedLine(key, entry));\n }\n for (const key of PUBLISH_CONFIG_KEYS) {\n const entry = renderPublishSetting(key, settings);\n data[key] = entry;\n humanLines.push(describedLine(key, entry, downgradeNote(key, settings)));\n }\n return { data, humanLines };\n}\n\n/** Same per-key shape as list, for one key. Unknown key is a USAGE failure. */\nexport async function runConfigGet(\n { key }: { key: string },\n ctx: CommandContext,\n): Promise<CommandResult> {\n if (isPublishKey(key)) {\n const settings = await resolveFromContext(ctx);\n const entry = renderPublishSetting(key, settings);\n return {\n data: { key, ...entry },\n humanLines: [withNote(formatLine(key, entry), downgradeNote(key, settings))],\n };\n }\n const configKey = assertKey(key);\n const settings = await resolveFromContext(ctx);\n const entry = renderSetting(configKey, settings[configKey].value, settings[configKey].source);\n return { data: { key: configKey, ...entry }, humanLines: [formatLine(configKey, entry)] };\n}\n\n/**\n * Parse the value for this key, then persist it merged into the existing raw\n * file — never materializing defaults for keys the user did not set, so\n * provenance stays truthful. The written key now reads `file`.\n */\nexport async function runConfigSet(\n { key, value }: { key: string; value: string },\n ctx: CommandContext,\n): Promise<CommandResult> {\n if (isPublishKey(key)) return setPublishKey(key, value, ctx);\n const configKey = assertKey(key);\n const stored = parseValue(configKey, value);\n await persist(ctx.dataDir, (existing) => ({ ...existing, [configKey]: stored }));\n const entry = renderSetting(configKey, stored, 'file');\n return { data: { key: configKey, ...entry }, humanLines: [formatLine(configKey, entry)] };\n}\n\n/**\n * `config set publish.mode|publish.defaultPrice`. mode validates to the enum;\n * defaultPrice parses decimal USD at the edge into atomic (matching the spend\n * keys). The subkey is merged into the nested publish block, so a sibling subkey\n * (or an unknown one a newer CLI wrote) is preserved.\n */\nasync function setPublishKey(\n key: PublishConfigKey,\n value: string,\n ctx: CommandContext,\n): Promise<CommandResult> {\n const entry: RenderedSetting =\n key === 'publish.mode'\n ? { value: parsePublishMode(value), source: 'file' }\n : { value: toMoney(parseUsdToAtomic(value)), source: 'file' };\n const subkey = key === 'publish.mode' ? 'mode' : 'defaultPrice';\n const stored = key === 'publish.mode' ? (entry.value as string) : (entry.value as Money).atomic;\n await persist(ctx.dataDir, (existing) => ({\n ...existing,\n publish: { ...existing.publish, [subkey]: stored },\n }));\n return { data: { key, ...entry }, humanLines: [formatLine(key, entry)] };\n}\n\nfunction parsePublishMode(value: string): string {\n const parsed = PublishModeSchema.safeParse(value);\n if (parsed.success) return parsed.data;\n throw new CliError('USAGE', `Invalid publish mode: ${JSON.stringify(value)}`, {\n fix: 'Use \"review\", \"auto\", or \"full-auto\".',\n });\n}\n\n/**\n * Persist just `publish.mode` into the global config through the same locked\n * merge-write every `config set` uses (never a raw overwrite), so a sibling\n * subkey or an unknown block a newer CLI wrote is preserved. Used by `install`'s\n * setup prompt; the mode is a validated PublishMode.\n */\nexport async function persistPublishMode(dir: string, mode: PublishMode): Promise<void> {\n await persist(dir, (existing) => ({\n ...existing,\n publish: { ...existing.publish, mode },\n }));\n}\n\nasync function resolveFromContext(ctx: CommandContext): Promise<EffectiveSettings> {\n const config = await loadRawConfig(ctx.dataDir);\n // Feed the per-project `.tenjin.json` layer so the publish keys read out what a\n // real `publish` would resolve (project/env included), not a global-only guess.\n const project = await loadProjectConfig(process.cwd());\n return resolveSettings({\n config,\n flags: { baseUrl: ctx.flags.baseUrl },\n env: process.env,\n project: project?.layer,\n });\n}\n\nfunction assertKey(key: string): ScalarConfigKey {\n if ((CONFIG_KEYS as string[]).includes(key)) return key as ScalarConfigKey;\n throw new CliError('USAGE', `Unknown config key: ${JSON.stringify(key)}`, {\n fix: `Valid keys: ${[...CONFIG_KEYS, ...PUBLISH_CONFIG_KEYS].join(', ')}.`,\n });\n}\n\nfunction renderSetting(\n key: ScalarConfigKey,\n stored: string | string[] | boolean,\n source: Provenance,\n): RenderedSetting {\n return { ...renderValue(key, stored), source };\n}\n\n/**\n * The list/get shape for a publish key, read from the resolved effective\n * settings, which now include the per-project `.tenjin.json` layer (see\n * resolveFromContext) so the source reflects what a publish would actually use.\n */\nfunction renderPublishSetting(key: PublishConfigKey, settings: EffectiveSettings): RenderedSetting {\n if (key === 'publish.mode') {\n return { value: settings.publishMode.value, source: settings.publishMode.source };\n }\n return {\n value: toMoney(settings.publishDefaultPrice.value),\n source: settings.publishDefaultPrice.source,\n };\n}\n\nfunction renderValue(key: ScalarConfigKey, stored: string | string[] | boolean): RenderedValue {\n if (Array.isArray(stored) || typeof stored === 'boolean') return { value: stored };\n if (key === 'maxAutoSpend' || key === 'sessionBudget') return { value: toMoney(stored) };\n if (key === 'confirm' && stored.startsWith(CONFIRM_ABOVE)) {\n return { value: stored, threshold: toMoney(stored.slice(CONFIRM_ABOVE.length)) };\n }\n return { value: stored };\n}\n\n/** Per-key edge parsing. Returns the persisted form; throws USAGE on bad input. */\nfunction parseValue(key: ScalarConfigKey, value: string): string | string[] | boolean {\n switch (key) {\n case 'maxAutoSpend':\n case 'sessionBudget':\n return parseUsdToAtomic(value); // throws USAGE on a bad amount\n case 'confirm':\n return parseConfirm(value);\n case 'allowlistCreators':\n return parseAllowlist(value);\n case 'baseUrl':\n case 'rpcUrl':\n return parseHttpUrl(value);\n case 'evalCohort':\n return parseBoolean(value);\n }\n}\n\nfunction parseBoolean(value: string): boolean {\n if (value === 'true') return true;\n if (value === 'false') return false;\n throw new CliError('USAGE', `Invalid boolean value: ${JSON.stringify(value)}`, {\n fix: 'Use \"true\" or \"false\".',\n });\n}\n\nfunction parseConfirm(value: string): string {\n if (value === 'always') return 'always';\n if (value.startsWith(CONFIRM_ABOVE)) {\n return `${CONFIRM_ABOVE}${parseUsdToAtomic(value.slice(CONFIRM_ABOVE.length))}`;\n }\n throw new CliError('USAGE', `Invalid confirm value: ${JSON.stringify(value)}`, {\n fix: 'Use \"always\" or \"above:<usd>\", e.g. above:0.25.',\n });\n}\n\nfunction parseAllowlist(value: string): string[] {\n // \"\" clears to []; comma-split, trim, drop empties. Reject an entry with\n // internal whitespace — a creator handle/address is a single token.\n const entries = value\n .split(',')\n .map((entry) => entry.trim())\n .filter((entry) => entry.length > 0);\n for (const entry of entries) {\n if (/\\s/.test(entry)) {\n throw new CliError('USAGE', `Invalid creator entry: ${JSON.stringify(entry)}`, {\n fix: 'Creator entries cannot contain spaces; separate multiple with commas.',\n });\n }\n }\n return entries;\n}\n\nfunction parseHttpUrl(value: string): string {\n let url: URL;\n try {\n url = new URL(value);\n } catch {\n throw new CliError('USAGE', `Invalid URL: ${JSON.stringify(value)}`, {\n fix: 'Pass an absolute http(s) URL like https://tenjin.blog.',\n });\n }\n if (url.protocol !== 'http:' && url.protocol !== 'https:') {\n throw new CliError('USAGE', `URL must be http or https: ${JSON.stringify(value)}`, {\n fix: 'Pass an absolute http(s) URL like https://tenjin.blog.',\n });\n }\n return value;\n}\n\n/**\n * Apply `merge` to the raw file and write it back atomically. Uses the partial\n * schema and writeFileAtomic (not writeConfig, which would materialize every\n * default into the file and corrupt provenance). loadRawConfig surfaces a\n * corrupt existing file as CONFIG_INVALID, which propagates.\n *\n * The whole read-merge-write runs under a cross-process file lock: without it two\n * concurrent `config set` on different keys race on the read, and the last writer\n * drops the other's update (worst case, a zeroed maxAutoSpend resurrected). The\n * data dir is ensured first so the lock's mkdir has a parent on a fresh install.\n */\nasync function persist(\n dir: string,\n merge: (existing: PartialConfig) => PartialConfig,\n): Promise<void> {\n await mkdir(dir, { recursive: true, mode: 0o700 });\n const lockPath = `${configPath(dir)}.lock`;\n try {\n await withFileLock(lockPath, async () => {\n const existing = await loadRawConfig(dir);\n const merged = merge(existing);\n const validated = RawConfigSchema.parse(merged);\n await writeFileAtomic(configPath(dir), `${JSON.stringify(validated, null, 2)}\\n`, {\n mode: 0o644,\n dirMode: 0o700,\n });\n });\n } catch (err) {\n // A lock timeout is not the user's malformed input; surface it as INTERNAL with\n // the one manual step (there is no auto-steal), keeping the JSON error contract.\n if (err instanceof LockTimeoutError) {\n throw new CliError('INTERNAL', err.message, {\n fix: `If no other tenjin process is running, remove ${lockPath} and retry.`,\n cause: err,\n });\n }\n throw err;\n }\n}\n\nfunction formatLine(key: string, entry: RenderedSetting): string {\n const label = key.padEnd(KEY_WIDTH);\n return ` ${label} ${displayValue(entry)} ${styleText('dim', `(${entry.source})`)}`;\n}\n\n/** The list variant: the value line, a dim description, and an optional dim note. */\nfunction describedLine(key: string, entry: RenderedSetting, note?: string): string {\n const description = KEY_DESCRIPTIONS[key];\n let line = formatLine(key, entry);\n if (description !== undefined) line += ` ${styleText('dim', `- ${description}`)}`;\n return withNote(line, note);\n}\n\n/** Append a dim parenthetical note (e.g. the full-auto downgrade) when present. */\nfunction withNote(line: string, note?: string): string {\n return note !== undefined ? `${line} ${styleText('dim', `(${note})`)}` : line;\n}\n\n/**\n * The `publish.mode` line gains a downgrade note when the effective mode came from\n * a committed `.tenjin.json` asking for `full-auto` (the loosening gate demoted it\n * to `auto`). Human-only; the machine `data` shape is unchanged.\n */\nfunction downgradeNote(key: PublishConfigKey, settings: EffectiveSettings): string | undefined {\n if (key !== 'publish.mode' || settings.publishMode.downgradedWarning === undefined) {\n return undefined;\n }\n return 'downgraded from full-auto: committed .tenjin.json (gitignore it to opt in)';\n}\n\nfunction displayValue(entry: RenderedSetting): string {\n const { value } = entry;\n if (Array.isArray(value)) return value.length > 0 ? value.join(', ') : '(empty)';\n if (typeof value === 'boolean') return value ? 'true' : 'false'; // evalCohort\n if (typeof value === 'object') return `${value.usd} USD`; // Money (spend keys)\n if (entry.threshold !== undefined) return `above ${entry.threshold.usd} USD`; // confirm\n return value; // 'always', baseUrl, rpcUrl\n}\n"],"mappings":"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","names":["settings","entry"]}
@@ -0,0 +1,217 @@
1
+ import { createRequire as __tenjinCreateRequire } from 'node:module'; const require = __tenjinCreateRequire(import.meta.url);
2
+ import {
3
+ createPublicClient,
4
+ defineBlock,
5
+ defineChain,
6
+ defineTransaction,
7
+ defineTransactionReceipt,
8
+ formatTransaction,
9
+ http
10
+ } from "./chunk-UGX7YPX2.js";
11
+ import {
12
+ serializeTransaction,
13
+ toRlp
14
+ } from "./chunk-NCE5NSN6.js";
15
+ import {
16
+ erc20Abi
17
+ } from "./chunk-ZMHYXMO6.js";
18
+ import {
19
+ InvalidAddressError,
20
+ concatHex,
21
+ hexToBigInt,
22
+ hexToNumber,
23
+ isAddress,
24
+ toHex
25
+ } from "./chunk-YALGASEU.js";
26
+
27
+ // node_modules/.pnpm/viem@2.55.2_typescript@6.0.3_zod@4.4.3/node_modules/viem/_esm/op-stack/contracts.js
28
+ var contracts = {
29
+ gasPriceOracle: { address: "0x420000000000000000000000000000000000000F" },
30
+ l1Block: { address: "0x4200000000000000000000000000000000000015" },
31
+ l2CrossDomainMessenger: {
32
+ address: "0x4200000000000000000000000000000000000007"
33
+ },
34
+ l2Erc721Bridge: { address: "0x4200000000000000000000000000000000000014" },
35
+ l2StandardBridge: { address: "0x4200000000000000000000000000000000000010" },
36
+ l2ToL1MessagePasser: {
37
+ address: "0x4200000000000000000000000000000000000016"
38
+ }
39
+ };
40
+
41
+ // node_modules/.pnpm/viem@2.55.2_typescript@6.0.3_zod@4.4.3/node_modules/viem/_esm/op-stack/formatters.js
42
+ var formatters = {
43
+ block: /* @__PURE__ */ defineBlock({
44
+ format(args) {
45
+ const transactions = args.transactions?.map((transaction) => {
46
+ if (typeof transaction === "string")
47
+ return transaction;
48
+ const formatted = formatTransaction(transaction);
49
+ if (formatted.typeHex === "0x7e") {
50
+ formatted.isSystemTx = transaction.isSystemTx;
51
+ formatted.mint = transaction.mint ? hexToBigInt(transaction.mint) : void 0;
52
+ formatted.sourceHash = transaction.sourceHash;
53
+ formatted.type = "deposit";
54
+ }
55
+ return formatted;
56
+ });
57
+ return {
58
+ transactions,
59
+ stateRoot: args.stateRoot
60
+ };
61
+ }
62
+ }),
63
+ transaction: /* @__PURE__ */ defineTransaction({
64
+ format(args) {
65
+ const transaction = {};
66
+ if (args.type === "0x7e") {
67
+ transaction.isSystemTx = args.isSystemTx;
68
+ transaction.mint = args.mint ? hexToBigInt(args.mint) : void 0;
69
+ transaction.sourceHash = args.sourceHash;
70
+ transaction.type = "deposit";
71
+ }
72
+ return transaction;
73
+ }
74
+ }),
75
+ transactionReceipt: /* @__PURE__ */ defineTransactionReceipt({
76
+ format(args) {
77
+ return {
78
+ ...args.depositNonce ? { depositNonce: hexToBigInt(args.depositNonce) } : {},
79
+ ...args.depositReceiptVersion ? { depositReceiptVersion: hexToNumber(args.depositReceiptVersion) } : {},
80
+ l1GasPrice: args.l1GasPrice ? hexToBigInt(args.l1GasPrice) : null,
81
+ l1GasUsed: args.l1GasUsed ? hexToBigInt(args.l1GasUsed) : null,
82
+ l1Fee: args.l1Fee ? hexToBigInt(args.l1Fee) : null,
83
+ l1FeeScalar: args.l1FeeScalar ? Number(args.l1FeeScalar) : null
84
+ };
85
+ }
86
+ })
87
+ };
88
+
89
+ // node_modules/.pnpm/viem@2.55.2_typescript@6.0.3_zod@4.4.3/node_modules/viem/_esm/op-stack/serializers.js
90
+ function serializeTransaction2(transaction, signature) {
91
+ if (isDeposit(transaction))
92
+ return serializeTransactionDeposit(transaction);
93
+ return serializeTransaction(transaction, signature);
94
+ }
95
+ var serializers = {
96
+ transaction: serializeTransaction2
97
+ };
98
+ function serializeTransactionDeposit(transaction) {
99
+ assertTransactionDeposit(transaction);
100
+ const { sourceHash, data, from, gas, isSystemTx, mint, to, value } = transaction;
101
+ const serializedTransaction = [
102
+ sourceHash,
103
+ from,
104
+ to ?? "0x",
105
+ mint ? toHex(mint) : "0x",
106
+ value ? toHex(value) : "0x",
107
+ gas ? toHex(gas) : "0x",
108
+ isSystemTx ? "0x1" : "0x",
109
+ data ?? "0x"
110
+ ];
111
+ return concatHex([
112
+ "0x7e",
113
+ toRlp(serializedTransaction)
114
+ ]);
115
+ }
116
+ function isDeposit(transaction) {
117
+ if (transaction.type === "deposit")
118
+ return true;
119
+ if (typeof transaction.sourceHash !== "undefined")
120
+ return true;
121
+ return false;
122
+ }
123
+ function assertTransactionDeposit(transaction) {
124
+ const { from, to } = transaction;
125
+ if (from && !isAddress(from))
126
+ throw new InvalidAddressError({ address: from });
127
+ if (to && !isAddress(to))
128
+ throw new InvalidAddressError({ address: to });
129
+ }
130
+
131
+ // node_modules/.pnpm/viem@2.55.2_typescript@6.0.3_zod@4.4.3/node_modules/viem/_esm/op-stack/chainConfig.js
132
+ var chainConfig = {
133
+ blockTime: 2e3,
134
+ contracts,
135
+ formatters,
136
+ serializers
137
+ };
138
+
139
+ // node_modules/.pnpm/viem@2.55.2_typescript@6.0.3_zod@4.4.3/node_modules/viem/_esm/chains/definitions/base.js
140
+ var sourceId = 1;
141
+ var base = /* @__PURE__ */ defineChain({
142
+ ...chainConfig,
143
+ id: 8453,
144
+ name: "Base",
145
+ nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
146
+ rpcUrls: {
147
+ default: {
148
+ http: ["https://mainnet.base.org"]
149
+ }
150
+ },
151
+ blockExplorers: {
152
+ default: {
153
+ name: "Basescan",
154
+ url: "https://basescan.org",
155
+ apiUrl: "https://api.basescan.org/api"
156
+ }
157
+ },
158
+ contracts: {
159
+ ...chainConfig.contracts,
160
+ disputeGameFactory: {
161
+ [sourceId]: {
162
+ address: "0x43edB88C4B80fDD2AdFF2412A7BebF9dF42cB40e"
163
+ }
164
+ },
165
+ l2OutputOracle: {
166
+ [sourceId]: {
167
+ address: "0x56315b90c40730925ec5485cf004d835058518A0"
168
+ }
169
+ },
170
+ multicall3: {
171
+ address: "0xca11bde05977b3631167028862be2a173976ca11",
172
+ blockCreated: 5022
173
+ },
174
+ portal: {
175
+ [sourceId]: {
176
+ address: "0x49048044D57e1C92A77f79988d21Fa8fAF74E97e",
177
+ blockCreated: 17482143
178
+ }
179
+ },
180
+ l1StandardBridge: {
181
+ [sourceId]: {
182
+ address: "0x3154Cf16ccdb4C6d922629664174b904d80F2C35",
183
+ blockCreated: 17482143
184
+ }
185
+ }
186
+ },
187
+ sourceId
188
+ });
189
+ var basePreconf = /* @__PURE__ */ defineChain({
190
+ ...base,
191
+ experimental_preconfirmationTime: 200,
192
+ rpcUrls: {
193
+ default: {
194
+ http: ["https://mainnet-preconf.base.org"]
195
+ }
196
+ }
197
+ });
198
+
199
+ // src/lib/usdc.ts
200
+ var USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
201
+ var USDC_DECIMALS = 6;
202
+ async function getUsdcBalance(address, rpcUrl) {
203
+ const client = createPublicClient({ chain: base, transport: http(rpcUrl) });
204
+ return client.readContract({
205
+ address: USDC_ADDRESS,
206
+ abi: erc20Abi,
207
+ functionName: "balanceOf",
208
+ args: [address]
209
+ });
210
+ }
211
+
212
+ export {
213
+ USDC_ADDRESS,
214
+ USDC_DECIMALS,
215
+ getUsdcBalance
216
+ };
217
+ //# sourceMappingURL=chunk-XJIW7USF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../node_modules/.pnpm/viem@2.55.2_typescript@6.0.3_zod@4.4.3/node_modules/viem/op-stack/contracts.ts","../node_modules/.pnpm/viem@2.55.2_typescript@6.0.3_zod@4.4.3/node_modules/viem/op-stack/formatters.ts","../node_modules/.pnpm/viem@2.55.2_typescript@6.0.3_zod@4.4.3/node_modules/viem/op-stack/serializers.ts","../node_modules/.pnpm/viem@2.55.2_typescript@6.0.3_zod@4.4.3/node_modules/viem/op-stack/chainConfig.ts","../node_modules/.pnpm/viem@2.55.2_typescript@6.0.3_zod@4.4.3/node_modules/viem/chains/definitions/base.ts","../src/lib/usdc.ts"],"sourcesContent":["import type { Chain } from '../types/chain.js'\n\n/**\n * Predeploy contracts for OP Stack.\n * @see https://github.com/ethereum-optimism/optimism/blob/develop/specs/predeploys.md\n */\nexport const contracts = {\n gasPriceOracle: { address: '0x420000000000000000000000000000000000000F' },\n l1Block: { address: '0x4200000000000000000000000000000000000015' },\n l2CrossDomainMessenger: {\n address: '0x4200000000000000000000000000000000000007',\n },\n l2Erc721Bridge: { address: '0x4200000000000000000000000000000000000014' },\n l2StandardBridge: { address: '0x4200000000000000000000000000000000000010' },\n l2ToL1MessagePasser: {\n address: '0x4200000000000000000000000000000000000016',\n },\n} as const satisfies Chain['contracts']\n","import type { ChainFormatters } from '../types/chain.js'\nimport type { RpcTransaction } from '../types/rpc.js'\nimport { hexToBigInt, hexToNumber } from '../utils/encoding/fromHex.js'\nimport { defineBlock } from '../utils/formatters/block.js'\nimport {\n defineTransaction,\n formatTransaction,\n} from '../utils/formatters/transaction.js'\nimport { defineTransactionReceipt } from '../utils/formatters/transactionReceipt.js'\nimport type { OpStackBlock, OpStackRpcBlock } from './types/block.js'\nimport type {\n OpStackRpcTransaction,\n OpStackRpcTransactionReceipt,\n OpStackTransaction,\n OpStackTransactionReceipt,\n} from './types/transaction.js'\n\nexport const formatters = {\n block: /*#__PURE__*/ defineBlock({\n format(args: OpStackRpcBlock): OpStackBlock {\n const transactions = args.transactions?.map((transaction) => {\n if (typeof transaction === 'string') return transaction\n const formatted = formatTransaction(\n transaction as RpcTransaction,\n ) as OpStackTransaction\n if (formatted.typeHex === '0x7e') {\n formatted.isSystemTx = transaction.isSystemTx\n formatted.mint = transaction.mint\n ? hexToBigInt(transaction.mint)\n : undefined\n formatted.sourceHash = transaction.sourceHash\n formatted.type = 'deposit'\n }\n return formatted\n })\n return {\n transactions,\n stateRoot: args.stateRoot,\n } as OpStackBlock\n },\n }),\n transaction: /*#__PURE__*/ defineTransaction({\n format(args: OpStackRpcTransaction): OpStackTransaction {\n const transaction = {} as OpStackTransaction\n if (args.type === '0x7e') {\n transaction.isSystemTx = args.isSystemTx\n transaction.mint = args.mint ? hexToBigInt(args.mint) : undefined\n transaction.sourceHash = args.sourceHash\n transaction.type = 'deposit'\n }\n return transaction\n },\n }),\n transactionReceipt: /*#__PURE__*/ defineTransactionReceipt({\n format(args: OpStackRpcTransactionReceipt): OpStackTransactionReceipt {\n return {\n ...(args.depositNonce\n ? { depositNonce: hexToBigInt(args.depositNonce) }\n : {}),\n ...(args.depositReceiptVersion\n ? { depositReceiptVersion: hexToNumber(args.depositReceiptVersion) }\n : {}),\n l1GasPrice: args.l1GasPrice ? hexToBigInt(args.l1GasPrice) : null,\n l1GasUsed: args.l1GasUsed ? hexToBigInt(args.l1GasUsed) : null,\n l1Fee: args.l1Fee ? hexToBigInt(args.l1Fee) : null,\n l1FeeScalar: args.l1FeeScalar ? Number(args.l1FeeScalar) : null,\n } as OpStackTransactionReceipt\n },\n }),\n} as const satisfies ChainFormatters\n","import { InvalidAddressError } from '../errors/address.js'\nimport type { ErrorType } from '../errors/utils.js'\nimport type { ChainSerializers } from '../types/chain.js'\nimport type { Hex, Signature } from '../types/misc.js'\nimport type { TransactionSerializable } from '../types/transaction.js'\nimport type { RequiredBy } from '../types/utils.js'\nimport { isAddress } from '../utils/address/isAddress.js'\nimport { concatHex } from '../utils/data/concat.js'\nimport { toHex } from '../utils/encoding/toHex.js'\nimport { toRlp } from '../utils/encoding/toRlp.js'\nimport {\n type SerializeTransactionErrorType as SerializeTransactionErrorType_,\n serializeTransaction as serializeTransaction_,\n} from '../utils/transaction/serializeTransaction.js'\nimport type {\n OpStackTransactionSerializable,\n TransactionSerializableDeposit,\n TransactionSerializedDeposit,\n} from './types/transaction.js'\n\nexport type SerializeTransactionReturnType = ReturnType<\n typeof serializeTransaction\n>\n\nexport type SerializeTransactionErrorType =\n | SerializeTransactionErrorType_\n | ErrorType\n\nexport function serializeTransaction(\n transaction: OpStackTransactionSerializable,\n signature?: Signature,\n) {\n if (isDeposit(transaction)) return serializeTransactionDeposit(transaction)\n return serializeTransaction_(\n transaction as TransactionSerializable,\n signature,\n )\n}\n\nexport const serializers = {\n transaction: serializeTransaction,\n} as const satisfies ChainSerializers\n\n//////////////////////////////////////////////////////////////////////////////\n// Serializers\n\nexport type SerializeTransactionDepositReturnType = TransactionSerializedDeposit\n\nfunction serializeTransactionDeposit(\n transaction: TransactionSerializableDeposit,\n): SerializeTransactionDepositReturnType {\n assertTransactionDeposit(transaction)\n\n const { sourceHash, data, from, gas, isSystemTx, mint, to, value } =\n transaction\n\n const serializedTransaction: Hex[] = [\n sourceHash,\n from,\n to ?? '0x',\n mint ? toHex(mint) : '0x',\n value ? toHex(value) : '0x',\n gas ? toHex(gas) : '0x',\n isSystemTx ? '0x1' : '0x',\n data ?? '0x',\n ]\n\n return concatHex([\n '0x7e',\n toRlp(serializedTransaction),\n ]) as SerializeTransactionDepositReturnType\n}\n\nfunction isDeposit(\n transaction: OpStackTransactionSerializable,\n): transaction is RequiredBy<TransactionSerializableDeposit, 'type'> {\n if (transaction.type === 'deposit') return true\n if (typeof transaction.sourceHash !== 'undefined') return true\n return false\n}\n\nexport function assertTransactionDeposit(\n transaction: TransactionSerializableDeposit,\n) {\n const { from, to } = transaction\n if (from && !isAddress(from)) throw new InvalidAddressError({ address: from })\n if (to && !isAddress(to)) throw new InvalidAddressError({ address: to })\n}\n","import { contracts } from './contracts.js'\nimport { formatters } from './formatters.js'\nimport { serializers } from './serializers.js'\n\nexport const chainConfig = {\n blockTime: 2_000,\n contracts,\n formatters,\n serializers,\n} as const\n","import { chainConfig } from '../../op-stack/chainConfig.js'\nimport { defineChain } from '../../utils/chain/defineChain.js'\n\nconst sourceId = 1 // mainnet\n\nexport const base = /*#__PURE__*/ defineChain({\n ...chainConfig,\n id: 8453,\n name: 'Base',\n nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 },\n rpcUrls: {\n default: {\n http: ['https://mainnet.base.org'],\n },\n },\n blockExplorers: {\n default: {\n name: 'Basescan',\n url: 'https://basescan.org',\n apiUrl: 'https://api.basescan.org/api',\n },\n },\n contracts: {\n ...chainConfig.contracts,\n disputeGameFactory: {\n [sourceId]: {\n address: '0x43edB88C4B80fDD2AdFF2412A7BebF9dF42cB40e',\n },\n },\n l2OutputOracle: {\n [sourceId]: {\n address: '0x56315b90c40730925ec5485cf004d835058518A0',\n },\n },\n multicall3: {\n address: '0xca11bde05977b3631167028862be2a173976ca11',\n blockCreated: 5022,\n },\n portal: {\n [sourceId]: {\n address: '0x49048044D57e1C92A77f79988d21Fa8fAF74E97e',\n blockCreated: 17482143,\n },\n },\n l1StandardBridge: {\n [sourceId]: {\n address: '0x3154Cf16ccdb4C6d922629664174b904d80F2C35',\n blockCreated: 17482143,\n },\n },\n },\n sourceId,\n})\n\nexport const basePreconf = /*#__PURE__*/ defineChain({\n ...base,\n experimental_preconfirmationTime: 200,\n rpcUrls: {\n default: {\n http: ['https://mainnet-preconf.base.org'],\n },\n },\n})\n","import { createPublicClient, erc20Abi, http, type Address } from 'viem';\nimport { base } from 'viem/chains';\n\n// Values mirror the app's lib/chain.ts Base mainnet entry (chain 8453).\nexport const USDC_ADDRESS: Address = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913';\nexport const USDC_DECIMALS = 6;\n\nexport async function getUsdcBalance(address: Address, rpcUrl: string): Promise<bigint> {\n const client = createPublicClient({ chain: base, transport: http(rpcUrl) });\n return client.readContract({\n address: USDC_ADDRESS,\n abi: erc20Abi,\n functionName: 'balanceOf',\n args: [address],\n });\n}\n"],"mappings":"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","names":["serializeTransaction"]}