@xgamesfun/solana 0.0.0-stage → 0.24.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.
- package/DISCLAIMER.md +41 -0
- package/LICENSE +202 -0
- package/NOTICE +13 -0
- package/README.md +172 -2
- package/bin/xsolana.mjs +189 -0
- package/examples/artwork-auction.json +51 -0
- package/examples/blind-forge.json +128 -0
- package/examples/coin-flip-arena.json +103 -0
- package/examples/duel-arena.json +137 -0
- package/examples/elements-set.json +274 -0
- package/examples/event-badges.json +67 -0
- package/examples/expedition-guild.json +154 -0
- package/examples/fair-presale.json +48 -0
- package/examples/falling-drop.json +90 -0
- package/examples/guild-missions.json +137 -0
- package/examples/halving-seasons.json +107 -0
- package/examples/hero-trials.json +93 -0
- package/examples/ideas.json +789 -0
- package/examples/level-ladder.json +65 -0
- package/examples/merge-2048.json +128 -0
- package/examples/nft-raffle.json +33 -0
- package/examples/paper-hands-farm.json +44 -0
- package/examples/partner-vault.json +112 -0
- package/examples/sacrifice-raffle.json +118 -0
- package/examples/scorched-treasury.json +84 -0
- package/examples/shelter-fair.json +164 -0
- package/examples/spark-pity.json +153 -0
- package/examples/stakers-draw.json +118 -0
- package/examples/star-fleet.json +150 -0
- package/examples/starforce.json +116 -0
- package/examples/stud-farm.json +134 -0
- package/examples/team-vesting.json +70 -0
- package/examples/trade-in-shop.json +168 -0
- package/js/approve/details.mjs +263 -0
- package/js/approve/ed25519.mjs +36 -0
- package/js/approve/live-check.mjs +144 -0
- package/js/approve/page.html +86 -0
- package/js/approve/page.js +203 -0
- package/js/approve/server.mjs +726 -0
- package/js/chain/base58.js +73 -0
- package/js/chain/borsh.js +270 -0
- package/js/chain/bytes.js +141 -0
- package/js/chain/core.js +181 -0
- package/js/chain/curve.js +52 -0
- package/js/chain/lookup.js +279 -0
- package/js/chain/mint.js +96 -0
- package/js/chain/pda.js +66 -0
- package/js/chain/programs.js +102 -0
- package/js/chain/rpc.js +219 -0
- package/js/chain/sha256.js +68 -0
- package/js/chain/token.js +85 -0
- package/js/chain/token2022.js +247 -0
- package/js/chain/tx.js +224 -0
- package/js/client/accounts.js +679 -0
- package/js/client/compressed.js +46 -0
- package/js/client/grant.js +299 -0
- package/js/client/idl/loot.js +2 -0
- package/js/client/idl/loot.json +17206 -0
- package/js/client/index.js +10 -0
- package/js/client/ix.js +2887 -0
- package/js/client/pda.js +114 -0
- package/js/client/policy.js +69 -0
- package/js/client/random.js +70 -0
- package/js/client/sizes.js +297 -0
- package/js/client/traits.js +44 -0
- package/js/connect/connect.mjs +182 -0
- package/js/economy/check.mjs +2236 -0
- package/js/economy/cost.mjs +185 -0
- package/js/economy/examples.mjs +114 -0
- package/js/economy/explain.mjs +239 -0
- package/js/economy/guide.mjs +232 -0
- package/js/economy/legal.mjs +15 -0
- package/js/economy/live.mjs +130 -0
- package/js/economy/model.mjs +698 -0
- package/js/economy/plan.mjs +1155 -0
- package/js/economy/schema.json +3071 -0
- package/js/economy/secrets.mjs +60 -0
- package/js/economy/simulate.mjs +1019 -0
- package/js/economy/txsize.mjs +45 -0
- package/js/economy/validate.mjs +85 -0
- package/js/index.js +10 -0
- package/js/mcp/server.mjs +113 -0
- package/js/mcp/tools.mjs +485 -0
- package/js/play/index.js +2855 -0
- package/js/play/keys.js +167 -0
- package/js/results/index.js +184 -0
- package/js/results/wire.js +90 -0
- package/package.json +100 -4
- package/release.json +8 -0
- package/skills/xsolana-economy/SKILL.md +109 -0
- package/skills/xsolana-economy/references/after-launch.md +124 -0
- package/skills/xsolana-economy/references/apps.md +193 -0
- package/skills/xsolana-economy/references/sentence-to-spec.md +180 -0
- package/skills/xsolana-economy/references/telling-the-person.md +134 -0
- package/types/chain/base58.d.ts +10 -0
- package/types/chain/borsh.d.ts +23 -0
- package/types/chain/bytes.d.ts +45 -0
- package/types/chain/core.d.ts +52 -0
- package/types/chain/curve.d.ts +1 -0
- package/types/chain/lookup.d.ts +194 -0
- package/types/chain/mint.d.ts +25 -0
- package/types/chain/pda.d.ts +25 -0
- package/types/chain/programs.d.ts +65 -0
- package/types/chain/rpc.d.ts +68 -0
- package/types/chain/sha256.d.ts +1 -0
- package/types/chain/token.d.ts +141 -0
- package/types/chain/token2022.d.ts +53 -0
- package/types/chain/tx.d.ts +60 -0
- package/types/client/accounts.d.ts +318 -0
- package/types/client/compressed.d.ts +29 -0
- package/types/client/grant.d.ts +170 -0
- package/types/client/idl/loot.d.ts +4498 -0
- package/types/client/index.d.ts +9 -0
- package/types/client/ix.d.ts +5315 -0
- package/types/client/pda.d.ts +95 -0
- package/types/client/policy.d.ts +48 -0
- package/types/client/random.d.ts +26 -0
- package/types/client/sizes.d.ts +101 -0
- package/types/client/traits.d.ts +12 -0
- package/types/economy/check.d.mts +100 -0
- package/types/economy/cost.d.mts +69 -0
- package/types/economy/examples.d.mts +27 -0
- package/types/economy/explain.d.mts +19 -0
- package/types/economy/guide.d.mts +140 -0
- package/types/economy/legal.d.mts +12 -0
- package/types/economy/live.d.mts +124 -0
- package/types/economy/model.d.mts +431 -0
- package/types/economy/plan.d.mts +1014 -0
- package/types/economy/secrets.d.mts +4 -0
- package/types/economy/simulate.d.mts +164 -0
- package/types/economy/txsize.d.mts +17 -0
- package/types/economy/validate.d.mts +3 -0
- package/types/index.d.ts +9 -0
- package/types/mcp/tools.d.mts +635 -0
- package/types/play/index.d.ts +880 -0
- package/types/play/keys.d.ts +51 -0
- package/types/results/index.d.ts +155 -0
- package/types/results/wire.d.ts +122 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
// `xsolana connect`: adds the xsolana MCP server and the xsolana-economy skill to the coding agents on this machine (Claude
|
|
2
|
+
// Code, Codex), through each agent's own commands. It never edits an agent's config file and never reads a
|
|
3
|
+
// credential. With `--local`, the server runs from this checkout (before the package is published); otherwise from npm.
|
|
4
|
+
// `--scope user` (the default) adds them for every project of this user; `--scope project`, for the project folder
|
|
5
|
+
// it runs in only.
|
|
6
|
+
import { exec, execFile } from 'node:child_process';
|
|
7
|
+
import { cp, mkdir, readFile, rm, stat } from 'node:fs/promises';
|
|
8
|
+
import os from 'node:os';
|
|
9
|
+
import path from 'node:path';
|
|
10
|
+
import { fileURLToPath } from 'node:url';
|
|
11
|
+
|
|
12
|
+
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
|
|
13
|
+
const NAME = 'xsolana';
|
|
14
|
+
const SKILL = 'xsolana-economy';
|
|
15
|
+
|
|
16
|
+
/** The scopes `xsolana connect` knows: every project of this user, or the one project folder it runs in. */
|
|
17
|
+
export const SCOPES = ['user', 'project'];
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The agents xsolana connect to, as data: a new agent is a row. `scopes`: where the agent can register an MCP server
|
|
21
|
+
* from its command line. `skills(scope, cwd)`: the folder its skills are read from.
|
|
22
|
+
*/
|
|
23
|
+
export const AGENTS = {
|
|
24
|
+
claude: {
|
|
25
|
+
name: 'Claude Code',
|
|
26
|
+
bin: 'claude',
|
|
27
|
+
scopes: ['user', 'project'],
|
|
28
|
+
add: (command, args, scope) => ['mcp', 'add', '--transport', 'stdio', '--scope', scope, NAME, '--', command, ...args],
|
|
29
|
+
remove: (scope) => ['mcp', 'remove', '--scope', scope, NAME],
|
|
30
|
+
get: ['mcp', 'get', NAME],
|
|
31
|
+
skills: (scope, cwd) => (scope === 'project' ? path.join(cwd, '.claude', 'skills') : path.join(os.homedir(), '.claude', 'skills')),
|
|
32
|
+
plugin: 'Or install the plugin: /plugin marketplace add XGamesFun/solana-kit, then /plugin install xsolana@xgamesfun.',
|
|
33
|
+
next: 'Start a new Claude Code session (or /mcp) to load the xsolana tools.',
|
|
34
|
+
},
|
|
35
|
+
codex: {
|
|
36
|
+
name: 'Codex',
|
|
37
|
+
bin: 'codex',
|
|
38
|
+
scopes: ['user'],
|
|
39
|
+
add: (command, args) => ['mcp', 'add', NAME, '--', command, ...args],
|
|
40
|
+
remove: () => ['mcp', 'remove', NAME],
|
|
41
|
+
get: ['mcp', 'get', NAME],
|
|
42
|
+
skills: (scope, cwd) => (scope === 'project' ? path.join(cwd, '.agents', 'skills') : path.join(os.homedir(), '.agents', 'skills')),
|
|
43
|
+
plugin: 'Or install the plugin: codex plugin marketplace add XGamesFun/solana-kit, then codex plugin add xsolana@xgamesfun.',
|
|
44
|
+
next: 'Start a new Codex session so it picks up the xsolana tools.',
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/** One word for cmd.exe: as it is when it is plain, else in double quotes (a quote inside doubled). */
|
|
49
|
+
const winWord = (a) => (/^[\w@+=:,./\\-]+$/.test(a) ? a : `"${String(a).replace(/"/g, '""')}"`);
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Runs an agent's command and answers { code, out }. On Windows the agents are installed as .cmd shims, which only a
|
|
53
|
+
* shell can start: there the command goes to cmd.exe as one line, each word quoted as it needs.
|
|
54
|
+
*/
|
|
55
|
+
export function runAgent(bin, args, { platform = process.platform, execFileImpl = execFile, execImpl = exec } = {}) {
|
|
56
|
+
return new Promise((resolve) => {
|
|
57
|
+
const done = (error, stdout, stderr) => resolve({ code: error ? (typeof error.code === 'number' ? error.code : 1) : 0, out: `${stdout ?? ''}${stderr ?? ''}`.trim() });
|
|
58
|
+
if (platform === 'win32') execImpl([bin, ...args].map(winWord).join(' '), { timeout: 60_000, windowsHide: true }, done);
|
|
59
|
+
else execFileImpl(bin, args, { timeout: 60_000 }, done);
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* The command that starts the server: this checkout's (`local`), or the published package's. On Windows, npx is a
|
|
65
|
+
* .cmd shim that an agent can only start through cmd.exe.
|
|
66
|
+
*/
|
|
67
|
+
export async function serverCommand({ local = false, platform = process.platform } = {}) {
|
|
68
|
+
if (local) return { command: process.execPath, args: [path.join(ROOT, 'bin', 'xsolana.mjs'), 'mcp'] };
|
|
69
|
+
const { version } = JSON.parse(await readFile(path.join(ROOT, 'package.json'), 'utf8'));
|
|
70
|
+
const npx = ['-y', `--package=@xgamesfun/solana@${version}`, 'xsolana', 'mcp'];
|
|
71
|
+
return platform === 'win32' ? { command: 'cmd', args: ['/c', 'npx', ...npx] } : { command: 'npx', args: npx };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* What is in a skill folder: 'none' (nothing there), 'ours' (xsolana's own skill: its SKILL.md names xsolana-economy in its
|
|
76
|
+
* frontmatter, so it may be replaced or removed), or 'other' (anything else, which xsolana never touches).
|
|
77
|
+
*/
|
|
78
|
+
export async function skillFolder(dir) {
|
|
79
|
+
try {
|
|
80
|
+
await stat(dir);
|
|
81
|
+
} catch {
|
|
82
|
+
return 'none';
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
const text = await readFile(path.join(dir, 'SKILL.md'), 'utf8');
|
|
86
|
+
const front = /^---\r?\n([\s\S]*?)\r?\n---/.exec(text)?.[1] ?? '';
|
|
87
|
+
return /^name:\s*["']?xsolana-economy["']?\s*$/m.test(front) ? 'ours' : 'other';
|
|
88
|
+
} catch {
|
|
89
|
+
return 'other';
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** Connects (or with `remove`, disconnects) each agent found. Returns an exit code. */
|
|
94
|
+
export async function connect({ agent, local = false, remove = false, dryRun = false, scope = 'user', cwd = process.cwd(), log = (...a) => console.log(...a), run = runAgent } = {}) {
|
|
95
|
+
if (!SCOPES.includes(scope)) {
|
|
96
|
+
log(`No scope called “${scope}” (${SCOPES.join(', ')}).`);
|
|
97
|
+
return 1;
|
|
98
|
+
}
|
|
99
|
+
if (agent && !AGENTS[agent]) {
|
|
100
|
+
log(`No agent called “${agent}” (${Object.keys(AGENTS).join(', ')}).`);
|
|
101
|
+
return 1;
|
|
102
|
+
}
|
|
103
|
+
const ids = agent ? [agent] : Object.keys(AGENTS);
|
|
104
|
+
const { command, args } = await serverCommand({ local });
|
|
105
|
+
let failed = 0;
|
|
106
|
+
let found = 0;
|
|
107
|
+
for (const id of ids) {
|
|
108
|
+
const a = AGENTS[id];
|
|
109
|
+
const version = await run(a.bin, ['--version']);
|
|
110
|
+
if (version.code !== 0) {
|
|
111
|
+
if (agent) log(`${a.name}: not found on this machine.`);
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
found++;
|
|
115
|
+
if (!a.scopes.includes(scope)) {
|
|
116
|
+
log(`${a.name}: adds MCP servers only for the whole user (--scope ${a.scopes.join(' or ')}), so it was left as it is. Run \`xsolana connect --agent ${id}\` for that.`);
|
|
117
|
+
if (agent) failed++;
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
// Registered already (at some scope): taken out at this scope first. Before an add that may fail (it is at the
|
|
121
|
+
// other scope); for --remove it is the whole point, so whether it worked is told.
|
|
122
|
+
const steps = [];
|
|
123
|
+
const had = await run(a.bin, a.get);
|
|
124
|
+
if (had.code === 0) steps.push({ args: a.remove(scope), optional: true, removal: true });
|
|
125
|
+
if (!remove) steps.push({ args: a.add(command, args, scope) });
|
|
126
|
+
let ok = true;
|
|
127
|
+
let removed = false;
|
|
128
|
+
for (const { args: s, optional, removal } of steps) {
|
|
129
|
+
if (dryRun) {
|
|
130
|
+
log(`${a.bin} ${s.join(' ')}`);
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
const r = await run(a.bin, s);
|
|
134
|
+
if (removal && r.code === 0) removed = true;
|
|
135
|
+
if (r.code !== 0 && !optional) {
|
|
136
|
+
log(`${a.name}: ${a.bin} ${s.slice(0, 3).join(' ')} failed: ${r.out.split('\n').at(-1)}`);
|
|
137
|
+
failed++;
|
|
138
|
+
ok = false;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// The skill: copied into the agent's skills folder for this scope. A folder of that name that is not xsolana's own
|
|
143
|
+
// skill is never replaced or removed.
|
|
144
|
+
const skills = a.skills(scope, cwd);
|
|
145
|
+
const skillDir = path.join(skills, SKILL);
|
|
146
|
+
const there = await skillFolder(skillDir);
|
|
147
|
+
let skillSaid;
|
|
148
|
+
if (there === 'other') {
|
|
149
|
+
log(`${a.name}: ${skillDir} is there already and is not xsolana's ${SKILL} skill, so it was left as it is${remove ? '' : ' and the skill was not copied'}. Move it away, then run \`xsolana connect\` again.`);
|
|
150
|
+
failed++;
|
|
151
|
+
ok = false;
|
|
152
|
+
} else if (remove) {
|
|
153
|
+
if (dryRun) log(there === 'ours' ? `remove ${skillDir}` : `(no skill at ${skillDir} to remove)`);
|
|
154
|
+
else if (there === 'ours') await rm(skillDir, { recursive: true, force: true });
|
|
155
|
+
skillSaid = there === 'ours' ? `; the ${SKILL} skill removed from ${skillDir}` : '';
|
|
156
|
+
} else {
|
|
157
|
+
if (dryRun) log(`${there === 'ours' ? 'replace the xsolana skill at' : 'copy skills/xsolana-economy to'} ${skillDir}`);
|
|
158
|
+
else {
|
|
159
|
+
await mkdir(skills, { recursive: true });
|
|
160
|
+
if (there === 'ours') await rm(skillDir, { recursive: true, force: true });
|
|
161
|
+
await cp(path.join(ROOT, 'skills', SKILL), skillDir, { recursive: true });
|
|
162
|
+
}
|
|
163
|
+
skillSaid = ` and the ${SKILL} skill copied to ${skillDir}`;
|
|
164
|
+
}
|
|
165
|
+
if (dryRun) continue;
|
|
166
|
+
if (remove) {
|
|
167
|
+
// Registered, but not at this scope: it is still there, and the person asked for it gone.
|
|
168
|
+
const stays = had.code === 0 && !removed;
|
|
169
|
+
if (stays) failed++;
|
|
170
|
+
const server = removed ? 'xsolana removed' : stays ? `xsolana’s server was not found at the ${scope} scope, so it was left where it is (\`${a.bin} mcp get ${NAME}\` shows where)` : 'xsolana’s server was not registered';
|
|
171
|
+
log(`${a.name}: ${server}${skillSaid ?? ''}.`);
|
|
172
|
+
} else if (ok) {
|
|
173
|
+
log(`${a.name}: xsolana tools added (${local ? 'from this checkout' : 'from npm'}, ${scope === 'project' ? `for ${cwd} only` : 'for every project'})${skillSaid}. ${a.next}`);
|
|
174
|
+
log(` ${a.plugin}`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
if (!found) {
|
|
178
|
+
log('No coding agent found (Claude Code: npm install -g @anthropic-ai/claude-code; Codex: npm install -g @openai/codex).');
|
|
179
|
+
return 1;
|
|
180
|
+
}
|
|
181
|
+
return failed ? 1 : 0;
|
|
182
|
+
}
|