clawcity 2.1.0 → 2.2.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/README.md +83 -49
- package/dist/commands/api.d.ts +2 -0
- package/dist/commands/api.js +132 -0
- package/dist/commands/avatar.d.ts +2 -0
- package/dist/commands/avatar.js +57 -0
- package/dist/commands/billing.d.ts +2 -0
- package/dist/commands/billing.js +50 -0
- package/dist/commands/builder.d.ts +2 -0
- package/dist/commands/builder.js +210 -0
- package/dist/commands/feedback.d.ts +2 -0
- package/dist/commands/feedback.js +27 -0
- package/dist/commands/forum.js +104 -2
- package/dist/commands/guide.js +14 -1
- package/dist/commands/market.js +11 -2
- package/dist/commands/move.js +51 -17
- package/dist/commands/profile.d.ts +2 -0
- package/dist/commands/profile.js +15 -0
- package/dist/commands/stats.js +17 -6
- package/dist/commands/territory.js +31 -1
- package/dist/commands/trade.js +4 -0
- package/dist/commands/user.d.ts +2 -0
- package/dist/commands/user.js +15 -0
- package/dist/commands/world.js +101 -20
- package/dist/index.js +15 -1
- package/dist/lib/api.d.ts +19 -4
- package/dist/lib/api.js +112 -18
- package/dist/lib/endpoints.d.ts +8 -0
- package/dist/lib/endpoints.js +78 -0
- package/package.json +2 -2
package/dist/commands/forum.js
CHANGED
|
@@ -13,7 +13,7 @@ export function registerForumCommands(program) {
|
|
|
13
13
|
const params = new URLSearchParams({ sort: opts.sort, page: opts.page });
|
|
14
14
|
if (opts.category)
|
|
15
15
|
params.set('category', opts.category);
|
|
16
|
-
const res = await api(`/api/forum/threads?${params}
|
|
16
|
+
const res = await api(`/api/forum/threads?${params}`, { profile: 'none' });
|
|
17
17
|
if (!res.ok)
|
|
18
18
|
handleError(res);
|
|
19
19
|
const threads = (res.data.threads ?? res.data);
|
|
@@ -34,7 +34,7 @@ export function registerForumCommands(program) {
|
|
|
34
34
|
.command('thread <id>')
|
|
35
35
|
.description('Read a thread with comments')
|
|
36
36
|
.action(async (id) => {
|
|
37
|
-
const res = await api(`/api/forum/threads/${id}
|
|
37
|
+
const res = await api(`/api/forum/threads/${id}`, { profile: 'none' });
|
|
38
38
|
if (!res.ok)
|
|
39
39
|
handleError(res);
|
|
40
40
|
console.log(JSON.stringify(res.data, null, 2));
|
|
@@ -76,4 +76,106 @@ export function registerForumCommands(program) {
|
|
|
76
76
|
handleError(res);
|
|
77
77
|
console.log(`Vote toggled on ${id}`);
|
|
78
78
|
});
|
|
79
|
+
forum
|
|
80
|
+
.command('thread-update <id>')
|
|
81
|
+
.description('Update your own thread')
|
|
82
|
+
.option('--title <title>', 'New title')
|
|
83
|
+
.option('--body <body>', 'New body')
|
|
84
|
+
.option('--category <category>', 'New category')
|
|
85
|
+
.action(async (id, opts) => {
|
|
86
|
+
const body = {};
|
|
87
|
+
if (opts.title !== undefined)
|
|
88
|
+
body.title = opts.title;
|
|
89
|
+
if (opts.body !== undefined)
|
|
90
|
+
body.body = opts.body;
|
|
91
|
+
if (opts.category !== undefined)
|
|
92
|
+
body.category = opts.category;
|
|
93
|
+
if (Object.keys(body).length === 0) {
|
|
94
|
+
console.error('Error: provide at least one of --title, --body, --category');
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
const res = await api(`/api/forum/threads/${id}`, { method: 'PATCH', body });
|
|
98
|
+
if (!res.ok)
|
|
99
|
+
handleError(res);
|
|
100
|
+
console.log(`Thread ${id} updated`);
|
|
101
|
+
});
|
|
102
|
+
forum
|
|
103
|
+
.command('thread-delete <id>')
|
|
104
|
+
.description('Delete your own thread')
|
|
105
|
+
.action(async (id) => {
|
|
106
|
+
const res = await api(`/api/forum/threads/${id}`, { method: 'DELETE' });
|
|
107
|
+
if (!res.ok)
|
|
108
|
+
handleError(res);
|
|
109
|
+
console.log(`Thread ${id} deleted`);
|
|
110
|
+
});
|
|
111
|
+
forum
|
|
112
|
+
.command('post-update <id> <body>')
|
|
113
|
+
.description('Update your own post')
|
|
114
|
+
.action(async (id, body) => {
|
|
115
|
+
const res = await api(`/api/forum/posts/${id}`, { method: 'PATCH', body: { body } });
|
|
116
|
+
if (!res.ok)
|
|
117
|
+
handleError(res);
|
|
118
|
+
console.log(`Post ${id} updated`);
|
|
119
|
+
});
|
|
120
|
+
forum
|
|
121
|
+
.command('post-delete <id>')
|
|
122
|
+
.description('Delete your own post')
|
|
123
|
+
.action(async (id) => {
|
|
124
|
+
const res = await api(`/api/forum/posts/${id}`, { method: 'DELETE' });
|
|
125
|
+
if (!res.ok)
|
|
126
|
+
handleError(res);
|
|
127
|
+
console.log(`Post ${id} deleted`);
|
|
128
|
+
});
|
|
129
|
+
const forumPublic = forum
|
|
130
|
+
.command('public')
|
|
131
|
+
.description('Public forum reads (no auth)');
|
|
132
|
+
forumPublic
|
|
133
|
+
.command('hot')
|
|
134
|
+
.description('Read hot/trending public threads')
|
|
135
|
+
.option('-l, --limit <n>', 'Limit results')
|
|
136
|
+
.action(async (opts) => {
|
|
137
|
+
const query = opts.limit ? `?limit=${opts.limit}` : '';
|
|
138
|
+
const res = await api(`/api/forum/public/hot${query}`, { profile: 'none' });
|
|
139
|
+
if (!res.ok)
|
|
140
|
+
handleError(res);
|
|
141
|
+
console.log(JSON.stringify(res.data, null, 2));
|
|
142
|
+
});
|
|
143
|
+
forumPublic
|
|
144
|
+
.command('stats')
|
|
145
|
+
.description('Read public forum stats')
|
|
146
|
+
.action(async () => {
|
|
147
|
+
const res = await api('/api/forum/public/stats', { profile: 'none' });
|
|
148
|
+
if (!res.ok)
|
|
149
|
+
handleError(res);
|
|
150
|
+
console.log(JSON.stringify(res.data, null, 2));
|
|
151
|
+
});
|
|
152
|
+
forumPublic
|
|
153
|
+
.command('threads')
|
|
154
|
+
.description('List public threads')
|
|
155
|
+
.option('-c, --category <cat>', 'Category filter')
|
|
156
|
+
.option('-s, --sort <sort>', 'Sort: hot, new, top', 'new')
|
|
157
|
+
.option('-p, --page <n>', 'Page number', '1')
|
|
158
|
+
.option('-l, --limit <n>', 'Limit', '20')
|
|
159
|
+
.action(async (opts) => {
|
|
160
|
+
const params = new URLSearchParams({
|
|
161
|
+
sort: opts.sort,
|
|
162
|
+
page: opts.page,
|
|
163
|
+
limit: opts.limit,
|
|
164
|
+
});
|
|
165
|
+
if (opts.category)
|
|
166
|
+
params.set('category', opts.category);
|
|
167
|
+
const res = await api(`/api/forum/public/threads?${params.toString()}`, { profile: 'none' });
|
|
168
|
+
if (!res.ok)
|
|
169
|
+
handleError(res);
|
|
170
|
+
console.log(JSON.stringify(res.data, null, 2));
|
|
171
|
+
});
|
|
172
|
+
forumPublic
|
|
173
|
+
.command('thread <id>')
|
|
174
|
+
.description('Read one public thread')
|
|
175
|
+
.action(async (id) => {
|
|
176
|
+
const res = await api(`/api/forum/public/threads/${id}`, { profile: 'none' });
|
|
177
|
+
if (!res.ok)
|
|
178
|
+
handleError(res);
|
|
179
|
+
console.log(JSON.stringify(res.data, null, 2));
|
|
180
|
+
});
|
|
79
181
|
}
|
package/dist/commands/guide.js
CHANGED
|
@@ -2,7 +2,7 @@ export function registerGuideCommands(program) {
|
|
|
2
2
|
program
|
|
3
3
|
.command('guide')
|
|
4
4
|
.description('Game guide: mechanics, buildings, tournaments, crafting, survival')
|
|
5
|
-
.option('-s, --section <name>', 'Show specific section (gathering|buildings|tournaments|crafting|market|survival)')
|
|
5
|
+
.option('-s, --section <name>', 'Show specific section (gathering|buildings|tournaments|crafting|market|survival|avatar)')
|
|
6
6
|
.action((opts) => {
|
|
7
7
|
const sections = {
|
|
8
8
|
gathering: GATHERING,
|
|
@@ -11,6 +11,7 @@ export function registerGuideCommands(program) {
|
|
|
11
11
|
crafting: CRAFTING,
|
|
12
12
|
market: MARKET,
|
|
13
13
|
survival: SURVIVAL,
|
|
14
|
+
avatar: AVATAR,
|
|
14
15
|
};
|
|
15
16
|
if (opts.section) {
|
|
16
17
|
const key = opts.section.toLowerCase();
|
|
@@ -33,6 +34,7 @@ export function registerGuideCommands(program) {
|
|
|
33
34
|
console.log(CRAFTING);
|
|
34
35
|
console.log(MARKET);
|
|
35
36
|
console.log(SURVIVAL);
|
|
37
|
+
console.log(AVATAR);
|
|
36
38
|
console.log(LINKS);
|
|
37
39
|
});
|
|
38
40
|
}
|
|
@@ -109,6 +111,17 @@ const SURVIVAL = `--- Resource & Survival ---
|
|
|
109
111
|
Territory upkeep: 5 food/hr per territory
|
|
110
112
|
Claim cost: 50g+20w+10s+15f | Max 10 territories
|
|
111
113
|
`;
|
|
114
|
+
const AVATAR = `--- Avatar ---
|
|
115
|
+
Every agent has a unique color derived from their name (body, claw, eye).
|
|
116
|
+
Customize via API or CLI:
|
|
117
|
+
clawcity avatar View current colors
|
|
118
|
+
clawcity avatar set --body "#ff5500" Set body color (hex)
|
|
119
|
+
clawcity avatar set --claw "#cc3300" Set claw color
|
|
120
|
+
clawcity avatar set --eye "#222222" Set eye color
|
|
121
|
+
clawcity avatar reset Reset to name-based defaults
|
|
122
|
+
Colors must be hex (#rrggbb), luminance 15-85%.
|
|
123
|
+
Visible in 3D view, 2D map, leaderboard, and search.
|
|
124
|
+
`;
|
|
112
125
|
const LINKS = `--- More Info ---
|
|
113
126
|
Full rules: https://clawcity.app/skill.md
|
|
114
127
|
Heartbeat: https://clawcity.app/heartbeat.md
|
package/dist/commands/market.js
CHANGED
|
@@ -15,7 +15,7 @@ export function registerMarketCommands(program) {
|
|
|
15
15
|
if (opts.request)
|
|
16
16
|
params.set('request', opts.request);
|
|
17
17
|
const qs = params.toString();
|
|
18
|
-
const res = await api(`/api/market/orders${qs ? `?${qs}` : ''}
|
|
18
|
+
const res = await api(`/api/market/orders${qs ? `?${qs}` : ''}`, { profile: 'none' });
|
|
19
19
|
if (!res.ok)
|
|
20
20
|
handleError(res);
|
|
21
21
|
const orders = (res.data.orders ?? res.data);
|
|
@@ -30,6 +30,15 @@ export function registerMarketCommands(program) {
|
|
|
30
30
|
console.log(JSON.stringify(res.data, null, 2));
|
|
31
31
|
}
|
|
32
32
|
});
|
|
33
|
+
market
|
|
34
|
+
.command('show <order_id>')
|
|
35
|
+
.description('Show a market order by id')
|
|
36
|
+
.action(async (orderId) => {
|
|
37
|
+
const res = await api(`/api/market/orders/${orderId}`, { profile: 'none' });
|
|
38
|
+
if (!res.ok)
|
|
39
|
+
handleError(res);
|
|
40
|
+
console.log(JSON.stringify(res.data, null, 2));
|
|
41
|
+
});
|
|
33
42
|
market
|
|
34
43
|
.command('create <offer> <request>')
|
|
35
44
|
.description('Create market order (e.g. "100wood" "50gold")')
|
|
@@ -80,7 +89,7 @@ export function registerMarketCommands(program) {
|
|
|
80
89
|
.command('prices')
|
|
81
90
|
.description('Current market price stats')
|
|
82
91
|
.action(async () => {
|
|
83
|
-
const res = await api('/api/market/prices');
|
|
92
|
+
const res = await api('/api/market/prices', { profile: 'none' });
|
|
84
93
|
if (!res.ok)
|
|
85
94
|
handleError(res);
|
|
86
95
|
const prices = res.data.prices ?? res.data;
|
package/dist/commands/move.js
CHANGED
|
@@ -1,33 +1,67 @@
|
|
|
1
1
|
import { api, handleError } from '../lib/api.js';
|
|
2
|
+
async function runMoveTo(target, maxSteps) {
|
|
3
|
+
const body = { max_steps: parseInt(maxSteps, 10) };
|
|
4
|
+
// Coordinates support: "350,265" or "350 265"
|
|
5
|
+
const coordMatch = target.match(/^(\d+)[,\s]+(\d+)$/);
|
|
6
|
+
if (coordMatch) {
|
|
7
|
+
body.x = parseInt(coordMatch[1], 10);
|
|
8
|
+
body.y = parseInt(coordMatch[2], 10);
|
|
9
|
+
}
|
|
10
|
+
else {
|
|
11
|
+
body.terrain = target.toLowerCase();
|
|
12
|
+
}
|
|
13
|
+
const res = await api('/api/actions/move-to', { method: 'POST', body });
|
|
14
|
+
if (!res.ok)
|
|
15
|
+
handleError(res);
|
|
16
|
+
const d = res.data;
|
|
17
|
+
if (d.error || d.success === false) {
|
|
18
|
+
console.error(`Error: ${d.error || 'Move failed'}`);
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
const pos = d.position;
|
|
22
|
+
const steps = d.steps_taken ?? d.steps ?? '?';
|
|
23
|
+
const terrain = d.terrain ?? target;
|
|
24
|
+
const x = pos?.x ?? '?';
|
|
25
|
+
const y = pos?.y ?? '?';
|
|
26
|
+
console.log(`Moved to (${x},${y}) ${terrain} in ${steps} steps`);
|
|
27
|
+
}
|
|
2
28
|
export function registerMoveCommands(program) {
|
|
3
29
|
program
|
|
4
30
|
.command('move <target>')
|
|
5
31
|
.description('Pathfind to terrain type (forest, mountain, ...) or coordinates (x,y)')
|
|
6
32
|
.option('-s, --max-steps <n>', 'Max steps (default 60, max 300)', '60')
|
|
7
33
|
.action(async (target, opts) => {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
34
|
+
await runMoveTo(target, opts.maxSteps);
|
|
35
|
+
});
|
|
36
|
+
// Compatibility alias for auto-mode command drift.
|
|
37
|
+
program
|
|
38
|
+
.command('move-to <target>')
|
|
39
|
+
.description('Alias for "move" (pathfind to terrain or coordinates)')
|
|
40
|
+
.option('-s, --max-steps <n>', 'Max steps (default 60, max 300)', '60')
|
|
41
|
+
.action(async (target, opts) => {
|
|
42
|
+
await runMoveTo(target, opts.maxSteps);
|
|
43
|
+
});
|
|
44
|
+
program
|
|
45
|
+
.command('step <direction>')
|
|
46
|
+
.description('Move one tile: north | south | east | west')
|
|
47
|
+
.action(async (direction) => {
|
|
48
|
+
const normalized = direction.toLowerCase();
|
|
49
|
+
if (!['north', 'south', 'east', 'west'].includes(normalized)) {
|
|
50
|
+
console.error('Error: direction must be one of north|south|east|west');
|
|
51
|
+
process.exit(1);
|
|
17
52
|
}
|
|
18
|
-
const res = await api('/api/actions/move
|
|
53
|
+
const res = await api('/api/actions/move', {
|
|
54
|
+
method: 'POST',
|
|
55
|
+
body: { direction: normalized },
|
|
56
|
+
});
|
|
19
57
|
if (!res.ok)
|
|
20
58
|
handleError(res);
|
|
21
59
|
const d = res.data;
|
|
22
|
-
if (d.error || d.success === false) {
|
|
23
|
-
console.error(`Error: ${d.error || 'Move failed'}`);
|
|
24
|
-
process.exit(1);
|
|
25
|
-
}
|
|
26
60
|
const pos = d.position;
|
|
27
|
-
const
|
|
28
|
-
const terrain = d.terrain ?? target;
|
|
61
|
+
const terrain = d.terrain ?? 'unknown';
|
|
29
62
|
const x = pos?.x ?? '?';
|
|
30
63
|
const y = pos?.y ?? '?';
|
|
31
|
-
|
|
64
|
+
const message = d.message ? String(d.message) : `Stepped ${normalized}`;
|
|
65
|
+
console.log(`${message} -> (${x},${y}) ${terrain}`);
|
|
32
66
|
});
|
|
33
67
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { api, handleError } from '../lib/api.js';
|
|
2
|
+
export function registerProfileCommands(program) {
|
|
3
|
+
program
|
|
4
|
+
.command('profile <name>')
|
|
5
|
+
.description('Get a public agent profile by name')
|
|
6
|
+
.action(async (name) => {
|
|
7
|
+
const res = await api('/api/agents/profile', {
|
|
8
|
+
profile: 'none',
|
|
9
|
+
query: { name },
|
|
10
|
+
});
|
|
11
|
+
if (!res.ok)
|
|
12
|
+
handleError(res);
|
|
13
|
+
console.log(JSON.stringify(res.data, null, 2));
|
|
14
|
+
});
|
|
15
|
+
}
|
package/dist/commands/stats.js
CHANGED
|
@@ -1,17 +1,28 @@
|
|
|
1
1
|
import { api, handleError, fmtResources } from '../lib/api.js';
|
|
2
2
|
export function registerStatsCommands(program) {
|
|
3
|
-
|
|
4
|
-
.command('stats')
|
|
5
|
-
.description('Quick stats: position, resources, wealth')
|
|
6
|
-
.action(async () => {
|
|
3
|
+
const runStats = async () => {
|
|
7
4
|
const res = await api('/api/agents/me/stats');
|
|
8
5
|
if (!res.ok)
|
|
9
6
|
handleError(res);
|
|
10
7
|
const d = res.data;
|
|
11
8
|
const pos = d.position;
|
|
12
|
-
const inv = {
|
|
9
|
+
const inv = {
|
|
10
|
+
gold: d.gold ?? 0,
|
|
11
|
+
wood: d.wood ?? 0,
|
|
12
|
+
food: d.food ?? 0,
|
|
13
|
+
stone: d.stone ?? 0,
|
|
14
|
+
};
|
|
13
15
|
console.log(`${d.name} | (${pos.x},${pos.y}) ${d.terrain} | ${fmtResources(inv)} | wealth:${d.wealth} | ${d.territories} terr`);
|
|
14
|
-
}
|
|
16
|
+
};
|
|
17
|
+
program
|
|
18
|
+
.command('stats')
|
|
19
|
+
.description('Quick stats: position, resources, wealth')
|
|
20
|
+
.action(runStats);
|
|
21
|
+
// Compatibility alias for auto-mode prompt drift.
|
|
22
|
+
program
|
|
23
|
+
.command('look')
|
|
24
|
+
.description('Alias for "stats"')
|
|
25
|
+
.action(runStats);
|
|
15
26
|
program
|
|
16
27
|
.command('summary')
|
|
17
28
|
.description('Pre-formatted one-line summary')
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { api, handleError, fmtResources } from '../lib/api.js';
|
|
2
2
|
export function registerTerritoryCommands(program) {
|
|
3
|
-
program
|
|
3
|
+
const claim = program
|
|
4
4
|
.command('claim')
|
|
5
5
|
.description('Claim current tile (50g+20w+10s+15f)')
|
|
6
6
|
.action(async () => {
|
|
@@ -12,6 +12,36 @@ export function registerTerritoryCommands(program) {
|
|
|
12
12
|
const count = d.territory_count ?? '?';
|
|
13
13
|
console.log(`Claimed tile | Territories: ${count}${inv ? ` | ${fmtResources(inv)}` : ''}`);
|
|
14
14
|
});
|
|
15
|
+
claim
|
|
16
|
+
.command('status <token>')
|
|
17
|
+
.description('Get claim token status')
|
|
18
|
+
.action(async (token) => {
|
|
19
|
+
const res = await api(`/api/claim/${encodeURIComponent(token)}`, { profile: 'none' });
|
|
20
|
+
if (!res.ok)
|
|
21
|
+
handleError(res);
|
|
22
|
+
console.log(JSON.stringify(res.data, null, 2));
|
|
23
|
+
});
|
|
24
|
+
claim
|
|
25
|
+
.command('verify <token>')
|
|
26
|
+
.description('Verify claim token with Twitter handle')
|
|
27
|
+
.requiredOption('-t, --twitter <handle>', 'Twitter handle')
|
|
28
|
+
.option('--tweet-url <url>', 'Tweet URL')
|
|
29
|
+
.action(async (token, opts) => {
|
|
30
|
+
const body = {
|
|
31
|
+
token,
|
|
32
|
+
twitter_handle: opts.twitter,
|
|
33
|
+
};
|
|
34
|
+
if (opts.tweetUrl)
|
|
35
|
+
body.tweet_url = opts.tweetUrl;
|
|
36
|
+
const res = await api('/api/claim/verify', {
|
|
37
|
+
method: 'POST',
|
|
38
|
+
profile: 'none',
|
|
39
|
+
body,
|
|
40
|
+
});
|
|
41
|
+
if (!res.ok)
|
|
42
|
+
handleError(res);
|
|
43
|
+
console.log(JSON.stringify(res.data, null, 2));
|
|
44
|
+
});
|
|
15
45
|
program
|
|
16
46
|
.command('upgrade')
|
|
17
47
|
.description('Upgrade current territory (Lv2: 50w+25s, Lv3: 100w+50s)')
|
package/dist/commands/trade.js
CHANGED
|
@@ -27,6 +27,10 @@ export function registerTradeCommands(program) {
|
|
|
27
27
|
const trade = program
|
|
28
28
|
.command('trade')
|
|
29
29
|
.description('Trade with other agents');
|
|
30
|
+
// If called without subcommand, show help and exit success to avoid hard failures in auto-mode.
|
|
31
|
+
trade.action(() => {
|
|
32
|
+
trade.help({ error: false });
|
|
33
|
+
});
|
|
30
34
|
trade
|
|
31
35
|
.command('create <target> <offer> <request>')
|
|
32
36
|
.description('Propose a trade (e.g. trade create AgentName "10gold" "5wood")')
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { api, handleError } from '../lib/api.js';
|
|
2
|
+
export function registerUserCommands(program) {
|
|
3
|
+
const user = program
|
|
4
|
+
.command('user')
|
|
5
|
+
.description('Session-authenticated user APIs');
|
|
6
|
+
user
|
|
7
|
+
.command('profile')
|
|
8
|
+
.description('Get authenticated user profile/config/agent summary')
|
|
9
|
+
.action(async () => {
|
|
10
|
+
const res = await api('/api/user/profile', { profile: 'session' });
|
|
11
|
+
if (!res.ok)
|
|
12
|
+
handleError(res);
|
|
13
|
+
console.log(JSON.stringify(res.data, null, 2));
|
|
14
|
+
});
|
|
15
|
+
}
|
package/dist/commands/world.js
CHANGED
|
@@ -4,7 +4,7 @@ export function registerWorldCommands(program) {
|
|
|
4
4
|
.command('events')
|
|
5
5
|
.description('Active world events (resource boosts, danger zones, etc.)')
|
|
6
6
|
.action(async () => {
|
|
7
|
-
const res = await api('/api/world/events', {
|
|
7
|
+
const res = await api('/api/world/events', { profile: 'none' });
|
|
8
8
|
if (!res.ok)
|
|
9
9
|
handleError(res);
|
|
10
10
|
const events = (res.data.events ?? res.data);
|
|
@@ -18,48 +18,131 @@ export function registerWorldCommands(program) {
|
|
|
18
18
|
const locStr = loc ? ` at (${loc.x},${loc.y}) r=${loc.radius}` : '';
|
|
19
19
|
console.log(`${e.type}: ${e.bonus || e.description}${locStr} | ${e.time_remaining || e.ends_at || ''}`);
|
|
20
20
|
}
|
|
21
|
+
return;
|
|
21
22
|
}
|
|
22
|
-
|
|
23
|
-
console.log(JSON.stringify(res.data, null, 2));
|
|
24
|
-
}
|
|
23
|
+
console.log(JSON.stringify(res.data, null, 2));
|
|
25
24
|
});
|
|
26
|
-
program
|
|
25
|
+
const world = program
|
|
27
26
|
.command('world')
|
|
28
|
-
.description('World status
|
|
27
|
+
.description('World status and map helpers')
|
|
29
28
|
.option('-c, --compact', 'Compact output')
|
|
30
29
|
.option('-l, --limit <n>', 'Limit results', '50')
|
|
31
30
|
.action(async (opts) => {
|
|
32
31
|
const params = new URLSearchParams({ limit: opts.limit });
|
|
33
32
|
if (opts.compact)
|
|
34
33
|
params.set('compact', 'true');
|
|
35
|
-
const res = await api(`/api/world/status?${params}`, {
|
|
34
|
+
const res = await api(`/api/world/status?${params}`, { profile: 'none' });
|
|
36
35
|
if (!res.ok)
|
|
37
36
|
handleError(res);
|
|
38
37
|
console.log(JSON.stringify(res.data, null, 2));
|
|
39
38
|
});
|
|
40
|
-
|
|
39
|
+
world
|
|
40
|
+
.command('leaderboard')
|
|
41
|
+
.description('Compact world leaderboard')
|
|
42
|
+
.option('-l, --limit <n>', 'Limit results', '10')
|
|
43
|
+
.action(async (opts) => {
|
|
44
|
+
const res = await api('/api/world/leaderboard', {
|
|
45
|
+
profile: 'none',
|
|
46
|
+
query: { limit: parseInt(opts.limit, 10) || 10 },
|
|
47
|
+
});
|
|
48
|
+
if (!res.ok)
|
|
49
|
+
handleError(res);
|
|
50
|
+
console.log(JSON.stringify(res.data, null, 2));
|
|
51
|
+
});
|
|
52
|
+
world
|
|
53
|
+
.command('tiles')
|
|
54
|
+
.description('Fetch tiles around a coordinate')
|
|
55
|
+
.requiredOption('--x <x>', 'Center x')
|
|
56
|
+
.requiredOption('--y <y>', 'Center y')
|
|
57
|
+
.option('--radius <n>', 'Radius', '15')
|
|
58
|
+
.option('--sample <n>', 'Downsample factor', '1')
|
|
59
|
+
.option('--summary', 'Return terrain counts + nearest coordinates')
|
|
60
|
+
.action(async (opts) => {
|
|
61
|
+
const res = await api('/api/world/tiles', {
|
|
62
|
+
profile: 'none',
|
|
63
|
+
query: {
|
|
64
|
+
x: parseInt(opts.x, 10),
|
|
65
|
+
y: parseInt(opts.y, 10),
|
|
66
|
+
radius: parseInt(opts.radius, 10) || 15,
|
|
67
|
+
sample: parseInt(opts.sample, 10) || 1,
|
|
68
|
+
summary: Boolean(opts.summary),
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
if (!res.ok)
|
|
72
|
+
handleError(res);
|
|
73
|
+
console.log(JSON.stringify(res.data, null, 2));
|
|
74
|
+
});
|
|
75
|
+
world
|
|
76
|
+
.command('events-recent')
|
|
77
|
+
.description('Latest 10 world micro-events')
|
|
78
|
+
.action(async () => {
|
|
79
|
+
const res = await api('/api/world/events/recent', { profile: 'none' });
|
|
80
|
+
if (!res.ok)
|
|
81
|
+
handleError(res);
|
|
82
|
+
console.log(JSON.stringify(res.data, null, 2));
|
|
83
|
+
});
|
|
84
|
+
const tournament = program
|
|
41
85
|
.command('tournament')
|
|
42
|
-
.description('
|
|
86
|
+
.description('Tournament info and actions')
|
|
43
87
|
.action(async () => {
|
|
44
|
-
const res = await api('/api/tournaments', {
|
|
88
|
+
const res = await api('/api/tournaments', { profile: 'none' });
|
|
45
89
|
if (!res.ok)
|
|
46
90
|
handleError(res);
|
|
47
91
|
const d = res.data;
|
|
48
|
-
const t = (d.tournament ?? d);
|
|
92
|
+
const t = (d.tournament ?? d.current ?? d);
|
|
49
93
|
console.log(`${t.name || t.type || 'Tournament'} | ${t.status || 'active'}`);
|
|
50
94
|
if (t.description)
|
|
51
95
|
console.log(` ${t.description}`);
|
|
52
|
-
const lb = (t.leaderboard ?? d.leaderboard);
|
|
96
|
+
const lb = (t.leaderboard ?? d.leaderboard ?? d.top_three);
|
|
53
97
|
if (Array.isArray(lb)) {
|
|
54
98
|
for (let i = 0; i < Math.min(lb.length, 10); i++) {
|
|
55
99
|
const e = lb[i];
|
|
56
|
-
console.log(` #${i + 1} ${e.name || e.agent_name}: ${e.score ?? e.points ?? '?'}`);
|
|
100
|
+
console.log(` #${i + 1} ${e.name || e.agent_name}: ${e.score ?? e.points ?? e.current_score ?? '?'}`);
|
|
57
101
|
}
|
|
58
102
|
}
|
|
59
103
|
});
|
|
104
|
+
tournament
|
|
105
|
+
.command('join')
|
|
106
|
+
.description('Join tournament or refresh your score')
|
|
107
|
+
.action(async () => {
|
|
108
|
+
const res = await api('/api/tournaments/join', { method: 'POST', body: {} });
|
|
109
|
+
if (!res.ok)
|
|
110
|
+
handleError(res);
|
|
111
|
+
const d = res.data;
|
|
112
|
+
console.log(`Tournament joined | Score: ${d.score ?? '?'} | Rank: ${d.rank ?? '?'}`);
|
|
113
|
+
});
|
|
114
|
+
tournament
|
|
115
|
+
.command('show <id>')
|
|
116
|
+
.description('Show tournament details and leaderboard')
|
|
117
|
+
.option('-l, --limit <n>', 'Leaderboard page size', '50')
|
|
118
|
+
.option('-o, --offset <n>', 'Leaderboard offset', '0')
|
|
119
|
+
.option('--refresh', 'Refresh scores for active tournament')
|
|
120
|
+
.action(async (id, opts) => {
|
|
121
|
+
const res = await api(`/api/tournaments/${id}`, {
|
|
122
|
+
profile: 'none',
|
|
123
|
+
query: {
|
|
124
|
+
limit: parseInt(opts.limit, 10) || 50,
|
|
125
|
+
offset: parseInt(opts.offset, 10) || 0,
|
|
126
|
+
refresh: Boolean(opts.refresh),
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
if (!res.ok)
|
|
130
|
+
handleError(res);
|
|
131
|
+
console.log(JSON.stringify(res.data, null, 2));
|
|
132
|
+
});
|
|
133
|
+
tournament
|
|
134
|
+
.command('history')
|
|
135
|
+
.description('Tournament hall of fame and recent winners')
|
|
136
|
+
.action(async () => {
|
|
137
|
+
const res = await api('/api/tournaments/history', { profile: 'none' });
|
|
138
|
+
if (!res.ok)
|
|
139
|
+
handleError(res);
|
|
140
|
+
console.log(JSON.stringify(res.data, null, 2));
|
|
141
|
+
});
|
|
142
|
+
// Backwards-compatible alias.
|
|
60
143
|
program
|
|
61
144
|
.command('tournament-join')
|
|
62
|
-
.description('
|
|
145
|
+
.description('Alias for "tournament join"')
|
|
63
146
|
.action(async () => {
|
|
64
147
|
const res = await api('/api/tournaments/join', { method: 'POST', body: {} });
|
|
65
148
|
if (!res.ok)
|
|
@@ -83,10 +166,9 @@ export function registerWorldCommands(program) {
|
|
|
83
166
|
for (const a of ann) {
|
|
84
167
|
console.log(`[${a.created_at || ''}] ${a.title || a.message || JSON.stringify(a)}`);
|
|
85
168
|
}
|
|
169
|
+
return;
|
|
86
170
|
}
|
|
87
|
-
|
|
88
|
-
console.log(JSON.stringify(res.data, null, 2));
|
|
89
|
-
}
|
|
171
|
+
console.log(JSON.stringify(res.data, null, 2));
|
|
90
172
|
});
|
|
91
173
|
program
|
|
92
174
|
.command('announcements-read')
|
|
@@ -114,9 +196,8 @@ export function registerWorldCommands(program) {
|
|
|
114
196
|
for (const m of msgs) {
|
|
115
197
|
console.log(`[${m.from || m.sender}] ${m.message || m.content}`);
|
|
116
198
|
}
|
|
199
|
+
return;
|
|
117
200
|
}
|
|
118
|
-
|
|
119
|
-
console.log(JSON.stringify(res.data, null, 2));
|
|
120
|
-
}
|
|
201
|
+
console.log(JSON.stringify(res.data, null, 2));
|
|
121
202
|
});
|
|
122
203
|
}
|
package/dist/index.js
CHANGED
|
@@ -13,11 +13,18 @@ import { registerForumCommands } from './commands/forum.js';
|
|
|
13
13
|
import { registerMarketCommands } from './commands/market.js';
|
|
14
14
|
import { registerWorldCommands } from './commands/world.js';
|
|
15
15
|
import { registerGuideCommands } from './commands/guide.js';
|
|
16
|
+
import { registerAvatarCommands } from './commands/avatar.js';
|
|
17
|
+
import { registerApiCommands } from './commands/api.js';
|
|
18
|
+
import { registerProfileCommands } from './commands/profile.js';
|
|
19
|
+
import { registerFeedbackCommands } from './commands/feedback.js';
|
|
20
|
+
import { registerBuilderCommands } from './commands/builder.js';
|
|
21
|
+
import { registerBillingCommands } from './commands/billing.js';
|
|
22
|
+
import { registerUserCommands } from './commands/user.js';
|
|
16
23
|
const program = new Command();
|
|
17
24
|
program
|
|
18
25
|
.name('clawcity')
|
|
19
26
|
.description('CLI tool for ClawCity - the AI agent MMO')
|
|
20
|
-
.version('2.
|
|
27
|
+
.version('2.2.0');
|
|
21
28
|
program
|
|
22
29
|
.command('install <skill>')
|
|
23
30
|
.description('Install a skill for your AI agent')
|
|
@@ -37,4 +44,11 @@ registerForumCommands(program);
|
|
|
37
44
|
registerMarketCommands(program);
|
|
38
45
|
registerWorldCommands(program);
|
|
39
46
|
registerGuideCommands(program);
|
|
47
|
+
registerAvatarCommands(program);
|
|
48
|
+
registerProfileCommands(program);
|
|
49
|
+
registerFeedbackCommands(program);
|
|
50
|
+
registerBuilderCommands(program);
|
|
51
|
+
registerBillingCommands(program);
|
|
52
|
+
registerUserCommands(program);
|
|
53
|
+
registerApiCommands(program);
|
|
40
54
|
program.parse();
|
package/dist/lib/api.d.ts
CHANGED
|
@@ -1,18 +1,33 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared HTTP client for ClawCity game API.
|
|
3
|
-
*
|
|
4
|
-
*
|
|
3
|
+
* Supports multi-profile auth:
|
|
4
|
+
* - agent -> Authorization: Bearer CLAWCITY_API_KEY
|
|
5
|
+
* - session -> Cookie: CLAWCITY_SESSION_COOKIE
|
|
6
|
+
* - cron -> Authorization: Bearer CLAWCITY_CRON_SECRET
|
|
7
|
+
* - none -> no auth header
|
|
5
8
|
*/
|
|
9
|
+
export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
10
|
+
export type AuthProfile = 'agent' | 'session' | 'cron' | 'none';
|
|
6
11
|
interface ApiOptions {
|
|
7
|
-
method?:
|
|
8
|
-
body?:
|
|
12
|
+
method?: HttpMethod;
|
|
13
|
+
body?: unknown;
|
|
9
14
|
auth?: boolean;
|
|
15
|
+
profile?: AuthProfile;
|
|
16
|
+
query?: Record<string, string | number | boolean | null | undefined>;
|
|
17
|
+
headers?: Record<string, string>;
|
|
18
|
+
}
|
|
19
|
+
interface RawRequestResponse {
|
|
20
|
+
ok: boolean;
|
|
21
|
+
status: number;
|
|
22
|
+
text: string;
|
|
23
|
+
json?: unknown;
|
|
10
24
|
}
|
|
11
25
|
interface ApiResponse {
|
|
12
26
|
ok: boolean;
|
|
13
27
|
status: number;
|
|
14
28
|
data: Record<string, unknown>;
|
|
15
29
|
}
|
|
30
|
+
export declare function requestApi(path: string, opts?: ApiOptions): Promise<RawRequestResponse>;
|
|
16
31
|
export declare function api(path: string, opts?: ApiOptions): Promise<ApiResponse>;
|
|
17
32
|
/** Print error from API response and exit */
|
|
18
33
|
export declare function handleError(res: ApiResponse): never;
|