@xgamesfun/solana 0.24.0 → 0.25.1

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 (99) hide show
  1. package/DISCLAIMER.md +1 -1
  2. package/NOTICE +4 -4
  3. package/README.md +100 -52
  4. package/bin/xsolana.mjs +32 -11
  5. package/examples/blind-forge.json +2 -4
  6. package/examples/coin-flip-arena.json +2 -5
  7. package/examples/duel-arena.json +1 -4
  8. package/examples/fair-presale.json +1 -3
  9. package/examples/hero-trials.json +14 -2
  10. package/examples/ideas.json +788 -788
  11. package/examples/nft-raffle.json +1 -0
  12. package/examples/partner-vault.json +19 -3
  13. package/examples/sacrifice-raffle.json +2 -10
  14. package/examples/shelter-fair.json +1 -0
  15. package/examples/stakers-draw.json +4 -7
  16. package/examples/trade-in-shop.json +2 -3
  17. package/js/approve/details.mjs +117 -48
  18. package/js/approve/ed25519.mjs +5 -1
  19. package/js/approve/live-check.mjs +83 -26
  20. package/js/approve/page.html +217 -78
  21. package/js/approve/page.js +43 -15
  22. package/js/approve/server.mjs +276 -74
  23. package/js/chain/base58.js +7 -1
  24. package/js/chain/borsh.js +15 -11
  25. package/js/chain/bytes.js +11 -8
  26. package/js/chain/core.js +21 -5
  27. package/js/chain/curve.js +1 -1
  28. package/js/chain/lookup.js +118 -36
  29. package/js/chain/mint.js +6 -2
  30. package/js/chain/pda.js +2 -2
  31. package/js/chain/programs.js +6 -6
  32. package/js/chain/rpc.js +40 -14
  33. package/js/chain/token.js +13 -2
  34. package/js/chain/token2022.js +55 -16
  35. package/js/chain/tx.js +32 -22
  36. package/js/client/accounts.js +270 -80
  37. package/js/client/compressed.js +4 -3
  38. package/js/client/grant.js +165 -40
  39. package/js/client/idl/loot.js +1 -1
  40. package/js/client/idl/loot.json +104 -16
  41. package/js/client/ix.js +2121 -457
  42. package/js/client/pda.js +20 -18
  43. package/js/client/policy.js +12 -5
  44. package/js/client/random.js +2 -2
  45. package/js/client/sizes.js +220 -65
  46. package/js/client/traits.js +14 -5
  47. package/js/connect/connect.mjs +59 -17
  48. package/js/economy/check.mjs +3884 -690
  49. package/js/economy/cost.mjs +381 -57
  50. package/js/economy/examples.mjs +176 -35
  51. package/js/economy/explain.mjs +468 -110
  52. package/js/economy/guide.mjs +282 -59
  53. package/js/economy/legal.mjs +12 -6
  54. package/js/economy/live.mjs +62 -20
  55. package/js/economy/model.mjs +320 -97
  56. package/js/economy/plan.mjs +1022 -203
  57. package/js/economy/review.mjs +760 -0
  58. package/js/economy/schema.json +134 -372
  59. package/js/economy/secrets.mjs +17 -7
  60. package/js/economy/simulate.mjs +771 -178
  61. package/js/economy/trust.mjs +15 -0
  62. package/js/economy/txsize.mjs +15 -3
  63. package/js/economy/validate.mjs +61 -24
  64. package/js/index.js +1 -0
  65. package/js/mcp/server.mjs +43 -15
  66. package/js/mcp/tools.mjs +318 -80
  67. package/js/play/index.js +1960 -461
  68. package/js/play/keys.js +35 -9
  69. package/js/results/index.js +225 -32
  70. package/js/results/server.js +230 -0
  71. package/js/results/wire.js +64 -16
  72. package/package.json +6 -4
  73. package/release.json +5 -5
  74. package/skills/xsolana-economy/SKILL.md +52 -22
  75. package/skills/xsolana-economy/references/after-launch.md +32 -21
  76. package/skills/xsolana-economy/references/apps.md +47 -36
  77. package/skills/xsolana-economy/references/sentence-to-spec.md +149 -129
  78. package/skills/xsolana-economy/references/telling-the-person.md +15 -6
  79. package/skills/xsolana-economy/references/trust-and-cheating.md +126 -0
  80. package/types/chain/core.d.ts +1 -1
  81. package/types/chain/lookup.d.ts +1 -1
  82. package/types/client/accounts.d.ts +24 -3
  83. package/types/client/grant.d.ts +2 -2
  84. package/types/client/idl/loot.d.ts +22 -0
  85. package/types/client/ix.d.ts +54 -45
  86. package/types/client/pda.d.ts +3 -1
  87. package/types/economy/cost.d.mts +1 -1
  88. package/types/economy/explain.d.mts +3 -0
  89. package/types/economy/guide.d.mts +5 -0
  90. package/types/economy/model.d.mts +48 -3
  91. package/types/economy/plan.d.mts +44 -2
  92. package/types/economy/review.d.mts +45 -0
  93. package/types/economy/trust.d.mts +8 -0
  94. package/types/index.d.ts +1 -0
  95. package/types/mcp/tools.d.mts +62 -0
  96. package/types/play/index.d.ts +14 -25
  97. package/types/results/index.d.ts +8 -7
  98. package/types/results/server.d.ts +126 -0
  99. package/types/results/wire.d.ts +1 -1
package/DISCLAIMER.md CHANGED
@@ -35,7 +35,7 @@ Read this before you use this package, its tools or the loot program. Using them
35
35
 
36
36
  ## Limitation of liability
37
37
 
38
- To the fullest extent the law allows, games.fun, XGamesFun and the contributors to this package are not liable for any
38
+ To the fullest extent the law allows, xgames.fun, XGamesFun and the contributors to this package are not liable for any
39
39
  loss or damage of any kind, direct or indirect, including lost funds, tokens, NFTs, profits or data, arising from the
40
40
  use of, or inability to use, this package, the loot program, the results server or anything built with them, even if
41
41
  told such loss was possible.
package/NOTICE CHANGED
@@ -1,10 +1,10 @@
1
1
  loot
2
- Copyright 2026 games.fun
2
+ Copyright 2026 xgames.fun
3
3
 
4
- This product includes software developed at games.fun.
4
+ This product includes software developed at xgames.fun.
5
5
 
6
- Parts of the JavaScript client and tools (js/) are adapted from the games.fun kit,
7
- MIT License, Copyright (c) 2026 games.fun.
6
+ Parts of the JavaScript client and tools (js/) are adapted from the xgames.fun kit,
7
+ MIT License, Copyright (c) 2026 xgames.fun.
8
8
 
9
9
  The tests run upstream Solana programs (SPL Token, Token-2022, Associated Token, Memo,
10
10
  Metaplex Core, Token Metadata, Bubblegum, Account Compression, Noop, MagicBlock VRF) as
package/README.md CHANGED
@@ -6,19 +6,65 @@ package `@xgamesfun/solana`:
6
6
  - a JavaScript client with no Solana SDK (`@xgamesfun/solana/client`), a player module for apps (`/play`) and a results
7
7
  client (`/results`);
8
8
  - the economy spec and its checker, quick simulation, cost and plain-words explainer;
9
- - the `xsolana` CLI and an MCP server with ten `xsolana_*` tools;
9
+ - the `xsolana` CLI and an MCP server with eleven `xsolana_*` tools;
10
10
  - the `xsolana-economy` skill, and one plugin that carries the tools and the skill to Claude Code and Codex;
11
11
  - a local approval page where a project's owner approves going live in their own wallet.
12
12
 
13
13
  An economy is a JSON spec, not a new smart contract. Every project shares the one program, and none writes its own.
14
14
 
15
- > **Status:** loot 0.24.0, program ID `9cwqM1TXytPnFZsLfmUyv2dg4uW6Ch9C6UJVPns7NFQ`, **devnet only**. The program is
16
- > not independently audited, and nothing runs on mainnet until it is. See [SECURITY.md](SECURITY.md).
15
+ > **Status:** these tools are for loot 0.25.0, program ID `9cwqM1TXytPnFZsLfmUyv2dg4uW6Ch9C6UJVPns7NFQ`, **devnet
16
+ > only** (deployed 2026-11-08, slot 519,994,814). The program is not independently audited, and nothing runs
17
+ > on mainnet until it is. See [SECURITY.md](SECURITY.md).
17
18
 
18
19
  > **Disclaimer:** provided as is, with no warranty and no guarantee that the program or the tools are safe. Use them
19
20
  > at your own risk; you are responsible for every transaction you approve and for making sure what you build is legal
20
21
  > where it runs. Nothing here is legal or financial advice. Read [DISCLAIMER.md](DISCLAIMER.md) before you use it.
21
22
 
23
+ ## Before you use it
24
+
25
+ - **Devnet only, and not independently audited.** Nothing here is for real money yet. Use a devnet wallet.
26
+ - **The program can be upgraded, and an upgrade can mean starting again.** Its upgrade authority can replace the
27
+ program's code, which is power over every economy on it (on mainnet that key is to be a multisig). No version so far
28
+ has carried accounts over from the one before: an economy made on 0.23 was made again for 0.24. Pin the package
29
+ version (each one names the program build it is for in `release.json`) and expect to set an economy up again after an
30
+ upgrade.
31
+ - **Players trust the project.** Its owner and authority are trusted keys with no caps: the authority mints, moves the
32
+ project's pool funds, decides contests and writes its NFTs. The program protects players from each other, from the
33
+ platform and from mistakes, not from the project they chose to play. Money held for a record (an order, a bid, a
34
+ farm's stakes, a contest's or lottery's pot) leaves only by that record's rules.
35
+ - **Players also trust the token and the collection.** A mint's issuer (a freeze authority, a pause, a transfer hook, a
36
+ permanent delegate) or a collection's controller can stop or move what loot holds. USDC has a freeze authority.
37
+ - **The chain can't see a game.** Results a game reports (a win, a score, a clear) are vouched for by a key the project
38
+ trusts, a results server or deciders. Checking that a player really did it is the project's job, on its own server:
39
+ a server that decides the result, replays it, or only bounds what the page reports leaves a cheater very different
40
+ amounts. A grant says which in `trust`, and `xsolana review` says what a cheater gets on every route
41
+ ([trust and cheating](skills/xsolana-economy/references/trust-and-cheating.md)).
42
+ - **The hosted results server is optional.** `https://play.xgames.fun/xsolana` (`@xgamesfun/solana/results`'s
43
+ default) signs vouchers for games without a server of their own. It can only pay what a grant allows, and only for a
44
+ grant whose owner named its key in `vouchers`. It sends nothing on chain, and it is offered as is: it can be down, and
45
+ it is behind for a while after each program upgrade. A game with its own server signs its own vouchers
46
+ (`signVoucher`), which is the better choice once it has one.
47
+ - **Nothing runs by itself.** Someone sends every step: settles (the player, the project's keys, or a key the player
48
+ named), lottery draws, auction ends, refunds (anyone), contest results (the authority or its deciders) and schedule
49
+ runs (the project's keys). A run nobody sends on time is missed, except a sealed schedule's fixed amount. Apps built
50
+ with `@xgamesfun/solana/play` send the steps a player needs. Don't count on a hosted keeper.
51
+ - **The rules are strict.** A prize is a fixed amount: a jackpot that grows is a lottery's pot. A lottery says where its
52
+ places are paid from: a pot that carries over (gifts and what earlier rounds left count), or each round's own ticket
53
+ money, which nothing from outside can change. A prize never shifts to a later round. A draw uses the odds
54
+ as written. When an outcome runs out, a box either stops selling (`stopSales`, the default) or keeps selling and
55
+ draws among what's left (`drawLeft`, which lets a player empty a common outcome to make a rare one likelier).
56
+ - **Chance comes from an oracle.** MagicBlock's VRF answers every random roll and draw. If it stops answering, rolls wait. An
57
+ order still unanswered after 7 days can be refunded. Once a roll has waited 10 minutes, a buyer who sees a late
58
+ answer coming can take a refund instead.
59
+ - **Fees and rent.** The platform sets two flat fees: by default 0.002 SOL a player action and 0.00001 SOL a project
60
+ action. Each is capped at 0.01 SOL, and a raise waits 7 days. Accounts cost rent: going live, and each settle that
61
+ opens or mints something. `xsolana cost` gives the totals. The platform can suspend purchases, but it never stops
62
+ payouts, refunds or unstakes (the one exception is a recipe that charges).
63
+ - **Some things aren't built,** and some limits are kept by design. Read
64
+ [Known limits](docs/program.md#known-limits) before promising players something unusual.
65
+ - **The law is yours to check.** The checker's legal flags (chance at money, resellable random items, revenue
66
+ sharing) are reminders, not advice. A spec with no flag isn't therefore legal.
67
+
22
68
  ## What an economy can be made of
23
69
 
24
70
  - payments and splits, in tokens or with an NFT
@@ -59,13 +105,13 @@ codex plugin add xsolana@xgamesfun
59
105
  ```
60
106
 
61
107
  **Any agent with MCP** (Cursor, opencode, Cline…): run the server with
62
- `npx -y --package=@xgamesfun/solana@0.24.0 xsolana mcp`. Or let `npx -y @xgamesfun/solana@0.24.0 connect` register it, with
108
+ `npx -y --package=@xgamesfun/solana@0.25.1 xsolana mcp`. Or let `npx -y @xgamesfun/solana@0.25.1 connect` register it, with
63
109
  the skill, for Claude Code and Codex.
64
110
 
65
- Then ask for an economy, for example *"a fishing game where each cast costs 0.02 SOL, with a rare golden fish and a
66
- monthly draw"*.
111
+ Then ask for an economy, for example _"a fishing game where each cast costs 0.02 SOL, with a rare golden fish and a
112
+ monthly draw"_.
67
113
 
68
- Going live is always yours: `npx -y @xgamesfun/solana@0.24.0 approve` opens a page on your computer where you connect a
114
+ Going live is always yours: `npx -y @xgamesfun/solana@0.25.1 approve` opens a page on your computer where you connect a
69
115
  devnet wallet and approve each transaction. The agent never signs and never asks for a key.
70
116
 
71
117
  ## Use it from a terminal
@@ -73,12 +119,13 @@ devnet wallet and approve each transaction. The agent never signs and never asks
73
119
  Every tool runs from the CLI too, on a spec file (`xsolana.json` by default):
74
120
 
75
121
  ```bash
76
- npx -y @xgamesfun/solana@0.24.0 examples shop with loot boxes # the nearest worked examples
77
- npx -y @xgamesfun/solana@0.24.0 check xsolana.json # refusals and warnings
78
- npx -y @xgamesfun/solana@0.24.0 simulate xsolana.json # where the money goes, day by day
79
- npx -y @xgamesfun/solana@0.24.0 cost xsolana.json # what going live and each action cost
80
- npx -y @xgamesfun/solana@0.24.0 explain xsolana.json # the economy in plain words
81
- npx -y @xgamesfun/solana@0.24.0 approve xsolana.json # go live, approved in your own wallet
122
+ npx -y @xgamesfun/solana@0.25.1 examples shop with loot boxes # the nearest worked examples
123
+ npx -y @xgamesfun/solana@0.25.1 check xsolana.json # refusals and warnings
124
+ npx -y @xgamesfun/solana@0.25.1 simulate xsolana.json # where the money goes, day by day
125
+ npx -y @xgamesfun/solana@0.25.1 cost xsolana.json # what going live and each action cost
126
+ npx -y @xgamesfun/solana@0.25.1 explain xsolana.json # the economy in plain words
127
+ npx -y @xgamesfun/solana@0.25.1 review xsolana.json # what a cheater gets on each route (exits 1 on a high finding)
128
+ npx -y @xgamesfun/solana@0.25.1 approve xsolana.json # go live, approved in your own wallet
82
129
  ```
83
130
 
84
131
  `xsolana help` lists every command. Every command names the exact version, so `npx` runs that release and never whatever
@@ -95,45 +142,46 @@ import * as loot from '@xgamesfun/solana/client';
95
142
  const ix = loot.openBoxIx({ player, project, box, nonce }); // one builder per instruction, no Solana SDK
96
143
  ```
97
144
 
98
- | Import | What |
99
- | --- | --- |
100
- | `@xgamesfun/solana` | the economy tools: `check`, `simulate`, `plan`, `cost`, `explainEconomy`, `model` |
101
- | `@xgamesfun/solana/client` | every PDA, one builder per instruction, account and receipt decoders, grant vouchers |
102
- | `@xgamesfun/solana/play` | `solanaApp`: what a player does with a live economy, from a browser app |
103
- | `@xgamesfun/solana/results` | results and vouchers a game's server signs |
104
- | `@xgamesfun/solana/chain/*` | browser-safe Solana primitives: base58, Borsh, transactions, PDAs, tokens, Core |
105
- | `@xgamesfun/solana/idl.json` | the program's IDL, the authority for account and argument layouts |
106
- | `@xgamesfun/solana/release.json` | the program build, IDL and client this release is pinned to |
145
+ | Import | What |
146
+ | -------------------------------- | ------------------------------------------------------------------------------------------- |
147
+ | `@xgamesfun/solana` | the economy tools: `check`, `simulate`, `plan`, `cost`, `explainEconomy`, `review`, `model` |
148
+ | `@xgamesfun/solana/client` | every PDA, one builder per instruction, account and receipt decoders, grant vouchers |
149
+ | `@xgamesfun/solana/play` | `solanaApp`: what a player does with a live economy, from a browser app |
150
+ | `@xgamesfun/solana/results` | results and vouchers a game's server signs |
151
+ | `@xgamesfun/solana/chain/*` | browser-safe Solana primitives: base58, Borsh, transactions, PDAs, tokens, Core |
152
+ | `@xgamesfun/solana/idl.json` | the program's IDL, the authority for account and argument layouts |
153
+ | `@xgamesfun/solana/release.json` | the program build, IDL and client this release is pinned to |
107
154
 
108
155
  The client, chain and play modules run in browsers and Node 22 or later, with no bundler required. The package
109
156
  ships TypeScript declarations for every entry point.
110
157
 
111
158
  ## Documentation
112
159
 
113
- | | |
114
- | --- | --- |
115
- | [`docs/program.md`](docs/program.md) | the program: who signs, accounts, every instruction, fees, limits, receipts, costs |
116
- | [`docs/nfts.md`](docs/nfts.md) | NFTs and tokens, with and without the project's authority |
117
- | [`docs/harnesses.md`](docs/harnesses.md) | how the plugin reaches Claude Code and Codex, and the release checklist |
118
- | [`skills/xsolana-economy`](skills/xsolana-economy/SKILL.md) | the skill an agent follows |
119
- | [`examples/`](examples) | whole economies that check and go live in the tests; `ideas.json`, 112 real economies rated |
120
- | [`evals/`](evals/README.md) | fresh-session evals of agents building on loot |
121
- | [`CHANGELOG.md`](CHANGELOG.md), [`SECURITY.md`](SECURITY.md) | versions, the trust model, reporting a vulnerability |
160
+ | | |
161
+ | ---------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
162
+ | [`docs/program.md`](docs/program.md) | the program: who signs, accounts, every instruction, fees, limits, receipts, costs |
163
+ | [`docs/nfts.md`](docs/nfts.md) | NFTs and tokens, with and without the project's authority |
164
+ | [`docs/harnesses.md`](docs/harnesses.md) | how the plugin reaches Claude Code and Codex, and the release checklist |
165
+ | [`skills/xsolana-economy`](skills/xsolana-economy/SKILL.md) | the skill an agent follows |
166
+ | [`trust-and-cheating.md`](skills/xsolana-economy/references/trust-and-cheating.md) | what a server decides, replays or bounds; who gets paid; an exploit checklist |
167
+ | [`examples/`](examples) | whole economies that check and go live in the tests; `ideas.json`, 112 real economies rated |
168
+ | [`evals/`](evals/README.md) | fresh-session evals of agents building on loot |
169
+ | [`CHANGELOG.md`](CHANGELOG.md), [`SECURITY.md`](SECURITY.md) | versions, the trust model, reporting a vulnerability |
122
170
 
123
171
  ## Layout
124
172
 
125
- | Path | What |
126
- | --- | --- |
127
- | `js/chain/` | browser-safe Solana primitives, no SDK |
128
- | `js/client/` | the client; `idl/` is the program's IDL |
129
- | `js/economy/` | the economy spec (version 2, `schema.json`), checker, simulation, setup plan, cost, explainer, guide |
130
- | `js/play/`, `js/results/` | a player's side of a live economy; results a server vouches for |
131
- | `js/approve/`, `js/mcp/`, `js/connect/` | the approval page, the MCP server and its tools, `xsolana connect` |
132
- | `js/sim/`, `js/test/` | LiteSVM running the real program; the tests and their pinned fixtures |
133
- | `bin/xsolana.mjs` | the CLI |
134
- | `skills/`, `plugin/` | the skill (copied to `plugin/skills`, `.claude/skills`, `.agents/skills`) and the plugin |
135
- | `scripts/` | fixtures, skill sync, IDL sync, release manifest, a devnet end-to-end run |
136
- | `release.json` | the program binary, IDL and client hashes this version is pinned to |
173
+ | Path | What |
174
+ | --------------------------------------- | ---------------------------------------------------------------------------------------------------- |
175
+ | `js/chain/` | browser-safe Solana primitives, no SDK |
176
+ | `js/client/` | the client; `idl/` is the program's IDL |
177
+ | `js/economy/` | the economy spec (version 2, `schema.json`), checker, simulation, setup plan, cost, explainer, guide |
178
+ | `js/play/`, `js/results/` | a player's side of a live economy; results a server vouches for |
179
+ | `js/approve/`, `js/mcp/`, `js/connect/` | the approval page, the MCP server and its tools, `xsolana connect` |
180
+ | `js/sim/`, `js/test/` | LiteSVM running the real program; the tests and their pinned fixtures |
181
+ | `bin/xsolana.mjs` | the CLI |
182
+ | `skills/`, `plugin/` | the skill (copied to `plugin/skills`, `.claude/skills`, `.agents/skills`) and the plugin |
183
+ | `scripts/` | fixtures, skill sync, IDL sync, release manifest, a devnet end-to-end run |
184
+ | `release.json` | the program binary, IDL and client hashes this version is pinned to |
137
185
 
138
186
  ## Development
139
187
 
@@ -143,20 +191,20 @@ Node 22 or later.
143
191
  npm ci
144
192
  npm run fixtures # downloads the loot program from devnet and the programs it calls from mainnet, each checked by hash
145
193
  npm test # every instruction the client builds, and every example's whole setup, against the real program in LiteSVM
146
- npm run lint # ESLint
194
+ npm run lint # ESLint and Prettier (npm run format fixes the formatting)
147
195
  npm run check # fixtures, skill copies and release.json in step, lint, then the tests
148
196
  ```
149
197
 
150
198
  Nothing in the tests deploys or spends SOL.
151
199
 
152
- | Variable | What it does |
153
- | --- | --- |
154
- | `XSOLANA_RPC_URL` | a devnet RPC of your own for `xsolana approve` and `xsolana status` (a mainnet URL is refused) |
155
- | `XSOLANA_NO_OPEN` | `xsolana approve` prints its link without opening a browser |
156
- | `XSOLANA_DEBUG` | the CLI prints a failure's whole stack, not one line |
157
- | `XSOLANA_PROGRAM_DIR` | the tests run that program build's `target/deploy/loot.so`, and check the IDL against it | To try the tools in your own agent from a clone,
158
- `node bin/xsolana.mjs connect --local` registers this checkout's MCP server and the skill with Claude Code and Codex
159
- (`--remove` takes them out again).
200
+ | Variable | What it does |
201
+ | -------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
202
+ | `XSOLANA_RPC_URL` | a devnet RPC of your own for `xsolana approve` and `xsolana status` (a mainnet URL is refused) |
203
+ | `XSOLANA_NO_OPEN` | `xsolana approve` prints its link without opening a browser |
204
+ | `XSOLANA_DEBUG` | the CLI prints a failure's whole stack, not one line |
205
+ | `XSOLANA_PROGRAM_DIR` | the tests run that program build's `target/deploy/loot.so`, and check the IDL against it | To try the tools in your own agent from a clone, |
206
+ | `node bin/xsolana.mjs connect --local` registers this checkout's MCP server and the skill with Claude Code and Codex |
207
+ | (`--remove` takes them out again). |
160
208
 
161
209
  After editing `skills/`, run `npm run sync-skills`. Changes to tool texts, the skill or the plugin are best measured
162
210
  with the evals before and after ([`evals/README.md`](evals/README.md)). [`AGENTS.md`](AGENTS.md) has the rules for
package/bin/xsolana.mjs CHANGED
@@ -5,7 +5,7 @@
5
5
  // xsolana mcp serve the tools over stdio (what a plugin's MCP config runs)
6
6
  // xsolana guide [part] [--json] what an economy can be made of, and what loot cannot do
7
7
  // xsolana examples [words…] [--json] the nearest worked examples and rated economies
8
- // xsolana check|simulate|cost|explain|publish|status [file] [--json] one tool on a spec file (default xsolana.json)
8
+ // xsolana check|simulate|cost|explain|review|publish|status [file] [--json] one tool on a spec file (default xsolana.json)
9
9
  // xsolana approve [file] [--port n] [--no-open] open the local page where the owner approves going live in their wallet
10
10
  // xsolana connect [--agent claude|codex] [--scope user|project] [--local] [--remove] [--dry-run] register the MCP server and the skill
11
11
  // xsolana tool --list | xsolana tool <name> '<json>' [--args-file f] [--json] any tool by name
@@ -25,6 +25,7 @@ const USAGE = `xsolana: the tools for loot, one shared Solana program for game a
25
25
  xsolana simulate [file] the quick simulation
26
26
  xsolana cost [file] what going live and each action cost
27
27
  xsolana explain [file] the economy in plain words
28
+ xsolana review [file] what a cheater gets on each route, and what to fix before going live
28
29
  xsolana publish [file] what going live does, and how to approve it
29
30
  xsolana approve [file] approve going live in your own wallet (a local page; --port n, --no-open)
30
31
  xsolana status [file] a live economy on chain
@@ -33,7 +34,8 @@ const USAGE = `xsolana: the tools for loot, one shared Solana program for game a
33
34
  xsolana tool --list every tool; xsolana tool <name> '<json>' runs one (--args-file f)
34
35
  xsolana version this package's xsolana version and program
35
36
 
36
- A tool's command (guide, examples, check … status, tool) takes --json for its whole answer as JSON.`;
37
+ A tool's command (guide, examples, check … status, tool) takes --json for its whole answer as JSON.
38
+ review exits 1 when it finds something high.`;
37
39
 
38
40
  /** A failure the person caused (a bad flag, a missing file): said in one line, without a stack. */
39
41
  class UsageError extends Error {}
@@ -50,6 +52,7 @@ const FLAGS = {
50
52
  simulate: TOOL_FLAGS,
51
53
  cost: TOOL_FLAGS,
52
54
  explain: TOOL_FLAGS,
55
+ review: TOOL_FLAGS,
53
56
  publish: TOOL_FLAGS,
54
57
  status: TOOL_FLAGS,
55
58
  approve: ['--port', '--no-open'],
@@ -74,7 +77,8 @@ function parseArgs(rest) {
74
77
  flags.add(name);
75
78
  if (eq > 0) values.set(name, a.slice(eq + 1));
76
79
  else if (VALUED.has(name)) {
77
- if (i + 1 >= rest.length || rest[i + 1].startsWith('--')) throw new UsageError(`${name} needs a value (${name} <value> or ${name}=<value>).`);
80
+ if (i + 1 >= rest.length || rest[i + 1].startsWith('--'))
81
+ throw new UsageError(`${name} needs a value (${name} <value> or ${name}=<value>).`);
78
82
  values.set(name, rest[++i]);
79
83
  }
80
84
  }
@@ -85,7 +89,8 @@ function parseArgs(rest) {
85
89
  function portOf(value) {
86
90
  if (value === undefined) return undefined;
87
91
  const n = Number(value);
88
- if (!/^\d+$/.test(String(value)) || n < 1 || n > 65535) throw new UsageError(`--port must be a whole number from 1 to 65535, not ${JSON.stringify(value)}.`);
92
+ if (!/^\d+$/.test(String(value)) || n < 1 || n > 65535)
93
+ throw new UsageError(`--port must be a whole number from 1 to 65535, not ${JSON.stringify(value)}.`);
89
94
  return n;
90
95
  }
91
96
 
@@ -93,15 +98,20 @@ async function main(argv) {
93
98
  const [command, ...rest] = argv;
94
99
  const { flags, values, positional } = parseArgs(rest);
95
100
  const takes = Object.hasOwn(FLAGS, command) ? FLAGS[command] : null;
96
- const unknown = takes && [...flags].find((f) => !takes.includes(f));
97
- if (unknown) throw new UsageError(`“${command}” takes no ${unknown} flag (${takes.length ? `only ${takes.join(', ')}` : 'it takes none'}).`);
101
+ const unknown = takes && [...flags].find(f => !takes.includes(f));
102
+ if (unknown)
103
+ throw new UsageError(
104
+ `“${command}” takes no ${unknown} flag (${takes.length ? `only ${takes.join(', ')}` : 'it takes none'}).`,
105
+ );
98
106
 
99
107
  async function tool(name, input) {
100
108
  const { runTool } = await import('../js/mcp/server.mjs');
101
109
  const r = await runTool(name, input, { cwd: process.cwd() });
102
110
  const failed = Boolean(r.isError || r.ok === false);
111
+ // A review is a report whatever it finds: printed on stdout, its exit code saying whether a finding is high.
112
+ const report = name === 'xsolana_review' && !r.isError && !r.refusals;
103
113
  if (flags.has('--json')) console.log(JSON.stringify(r, (_, v) => (typeof v === 'bigint' ? v.toString() : v), 2));
104
- else (failed ? console.error : console.log)(r.text ?? JSON.stringify(r, null, 2));
114
+ else (failed && !report ? console.error : console.log)(r.text ?? JSON.stringify(r, null, 2));
105
115
  if (failed) process.exitCode = 1;
106
116
  }
107
117
 
@@ -123,6 +133,7 @@ async function main(argv) {
123
133
  case 'simulate':
124
134
  case 'cost':
125
135
  case 'explain':
136
+ case 'review':
126
137
  case 'publish':
127
138
  case 'status':
128
139
  await tool(`xsolana_${command}`, fileInput());
@@ -135,7 +146,13 @@ async function main(argv) {
135
146
  }
136
147
  case 'connect': {
137
148
  const { connect } = await import('../js/connect/connect.mjs');
138
- process.exitCode = await connect({ agent: values.get('--agent'), local: flags.has('--local'), remove: flags.has('--remove'), dryRun: flags.has('--dry-run'), scope: values.get('--scope') });
149
+ process.exitCode = await connect({
150
+ agent: values.get('--agent'),
151
+ local: flags.has('--local'),
152
+ remove: flags.has('--remove'),
153
+ dryRun: flags.has('--dry-run'),
154
+ scope: values.get('--scope'),
155
+ });
139
156
  break;
140
157
  }
141
158
  case 'tool': {
@@ -145,12 +162,15 @@ async function main(argv) {
145
162
  break;
146
163
  }
147
164
  const from = values.get('--args-file');
148
- const raw = from ? await readFile(from, 'utf8') : positional[1] ?? '{}';
165
+ const raw = from ? await readFile(from, 'utf8') : (positional[1] ?? '{}');
149
166
  let input;
150
167
  try {
151
168
  input = JSON.parse(raw);
152
169
  } catch (e) {
153
- throw new UsageError(`The arguments ${from ? `in ${from} ` : ''}are not JSON (${e.message}). Give them as one word, as in: xsolana tool xsolana_check '{"file":"xsolana.json"}'.`, { cause: e });
170
+ throw new UsageError(
171
+ `The arguments ${from ? `in ${from} ` : ''}are not JSON (${e.message}). Give them as one word, as in: xsolana tool xsolana_check '{"file":"xsolana.json"}'.`,
172
+ { cause: e },
173
+ );
154
174
  }
155
175
  await tool(positional[0], input);
156
176
  break;
@@ -176,7 +196,8 @@ async function main(argv) {
176
196
  /** One line for a failure: what went wrong, without a stack (a missing file names the file). */
177
197
  function oneLine(e) {
178
198
  if (e?.code === 'ENOENT' && e.path) return `${e.path} does not exist.`;
179
- if (e?.code === 'EADDRINUSE') return `Port ${e.port} is in use: pick another with --port, or leave it out for any free one.`;
199
+ if (e?.code === 'EADDRINUSE')
200
+ return `Port ${e.port} is in use: pick another with --port, or leave it out for any free one.`;
180
201
  return String(e?.message ?? e);
181
202
  }
182
203
 
@@ -109,12 +109,10 @@
109
109
  {
110
110
  "key": "buyers-draw",
111
111
  "name": "Buyers' draw",
112
+ "pot": 0,
112
113
  "price": 1,
113
114
  "cutPercent": 5,
114
- "places": [
115
- 70,
116
- 30
117
- ],
115
+ "places": [70, 30],
118
116
  "every": "7d"
119
117
  }
120
118
  ],
@@ -65,12 +65,9 @@
65
65
  {
66
66
  "key": "weekly",
67
67
  "name": "Weekly draw",
68
+ "pot": 0,
68
69
  "price": 0.01,
69
- "places": [
70
- 50,
71
- 30,
72
- 20
73
- ],
70
+ "places": [50, 30, 20],
74
71
  "every": "7d",
75
72
  "firstDraw": "publish+7d"
76
73
  }
@@ -59,10 +59,7 @@
59
59
  "name": "Duel",
60
60
  "currency": "usdc",
61
61
  "sides": 2,
62
- "sideNames": [
63
- "Red",
64
- "Blue"
65
- ],
62
+ "sideNames": ["Red", "Blue"],
66
63
  "entriesClose": "10m",
67
64
  "resultDue": "1h",
68
65
  "every": "1h",
@@ -24,9 +24,7 @@
24
24
  "name": "The raise",
25
25
  "currency": "sol",
26
26
  "sides": 1,
27
- "sideNames": [
28
- "Back it"
29
- ],
27
+ "sideNames": ["Back it"],
30
28
  "entriesClose": "7d",
31
29
  "resultDue": "8d",
32
30
  "minPot": 50,
@@ -26,7 +26,13 @@
26
26
  { "gives": "nothing", "chance": 25, "shifts": [{ "attribute": "level", "by": -1 }] },
27
27
  { "gives": "nothing", "chance": 5, "then": "burn" }
28
28
  ],
29
- "odds": [{ "outcome": 0, "when": { "item": "hero", "attribute": "level", "atLeast": 0 }, "add": { "perPointPercent": 10, "upTo": 10 } }]
29
+ "odds": [
30
+ {
31
+ "outcome": 0,
32
+ "when": { "item": "hero", "attribute": "level", "atLeast": 0 },
33
+ "add": { "perPointPercent": 10, "upTo": 10 }
34
+ }
35
+ ]
30
36
  },
31
37
  {
32
38
  "key": "expedition-result",
@@ -39,7 +45,13 @@
39
45
  { "gives": "nothing", "chance": 30, "shifts": [{ "attribute": "affection", "by": -2 }] },
40
46
  { "gives": "nothing", "chance": 10, "then": "treasury" }
41
47
  ],
42
- "odds": [{ "outcome": 0, "when": { "item": "hero", "attribute": "level", "atLeast": 0 }, "add": { "perPointPercent": 20, "upTo": 10 } }]
48
+ "odds": [
49
+ {
50
+ "outcome": 0,
51
+ "when": { "item": "hero", "attribute": "level", "atLeast": 0 },
52
+ "add": { "perPointPercent": 20, "upTo": 10 }
53
+ }
54
+ ]
43
55
  },
44
56
  {
45
57
  "key": "forge",