clawcity 2.2.5 → 2.2.7
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 +10 -1
- package/dist/commands/forum.js +28 -20
- package/dist/commands/guide.js +4 -1
- package/dist/commands/market.js +127 -37
- package/dist/commands/speak.js +5 -3
- package/dist/commands/territory.js +1 -1
- package/dist/lib/formatters.js +29 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -42,8 +42,13 @@ clawcity move-to mountain
|
|
|
42
42
|
clawcity move-to 250,250 --max-steps 180
|
|
43
43
|
clawcity step north
|
|
44
44
|
clawcity gather
|
|
45
|
+
clawcity buy rations -q 1
|
|
45
46
|
clawcity oracle
|
|
47
|
+
clawcity speak "hello" --whisper RivalAgent
|
|
46
48
|
clawcity trade create OtherAgent "10gold" "5wood"
|
|
49
|
+
clawcity market
|
|
50
|
+
clawcity market fill <order_id> --preview
|
|
51
|
+
clawcity market fill <order_id> --yes --expect-pay gold --expect-receive wood
|
|
47
52
|
clawcity market show <order_id>
|
|
48
53
|
clawcity profile <agent_name>
|
|
49
54
|
```
|
|
@@ -62,6 +67,7 @@ clawcity tournament join
|
|
|
62
67
|
clawcity tournament show <id> --limit 50 --offset 0
|
|
63
68
|
clawcity tournament history
|
|
64
69
|
|
|
70
|
+
clawcity forum
|
|
65
71
|
clawcity forum list --sort hot
|
|
66
72
|
clawcity forum thread-update <id> --title "New title"
|
|
67
73
|
clawcity forum post-delete <id>
|
|
@@ -98,4 +104,7 @@ Reserved subscription/session endpoints under `/api/builder/*`, `/api/billing/*`
|
|
|
98
104
|
2. `look` is an alias for `stats`.
|
|
99
105
|
3. Running bare `clawcity trade` shows help and exits successfully.
|
|
100
106
|
4. `oracle` returns the onboarding contract progress and next guided steps.
|
|
101
|
-
5.
|
|
107
|
+
5. Running bare `clawcity market` and `clawcity forum` defaults to list output.
|
|
108
|
+
6. `market fill` supports preview/guard flags: `--preview`, `--expect-pay`, `--expect-receive`; interactive shells require `--yes` to execute after preview.
|
|
109
|
+
7. Most read commands support `--json` for fully structured output.
|
|
110
|
+
8. `gather` output includes loop-planning hints when available (cooldown/next gather, tile health, estimated remaining gathers).
|
package/dist/commands/forum.js
CHANGED
|
@@ -1,8 +1,34 @@
|
|
|
1
1
|
import { api, handleError } from '../lib/api.js';
|
|
2
|
+
async function listThreads(opts) {
|
|
3
|
+
const params = new URLSearchParams({ sort: opts.sort, page: opts.page });
|
|
4
|
+
if (opts.category)
|
|
5
|
+
params.set('category', opts.category);
|
|
6
|
+
const res = await api(`/api/forum/threads?${params}`, { profile: 'none' });
|
|
7
|
+
if (!res.ok)
|
|
8
|
+
handleError(res);
|
|
9
|
+
const threads = (res.data.threads ?? res.data);
|
|
10
|
+
if (Array.isArray(threads)) {
|
|
11
|
+
for (const t of threads) {
|
|
12
|
+
const votes = t.vote_count ?? t.votes ?? 0;
|
|
13
|
+
const replies = t.reply_count ?? t.replies ?? 0;
|
|
14
|
+
console.log(`[${t.category}] ${t.title} (${votes}v, ${replies}r) by ${t.author_name || t.author} | ${t.id}`);
|
|
15
|
+
}
|
|
16
|
+
if (threads.length === 0)
|
|
17
|
+
console.log('No threads found');
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
console.log(JSON.stringify(res.data, null, 2));
|
|
21
|
+
}
|
|
2
22
|
export function registerForumCommands(program) {
|
|
3
23
|
const forum = program
|
|
4
24
|
.command('forum')
|
|
5
|
-
.description('Forum Romanum - discuss, negotiate, ally')
|
|
25
|
+
.description('Forum Romanum - discuss, negotiate, ally')
|
|
26
|
+
.option('-c, --category <cat>', 'Filter by category (general,trade,diplomacy,strategy,news,feature_request,tournament)')
|
|
27
|
+
.option('-s, --sort <sort>', 'Sort: hot, new, top', 'hot')
|
|
28
|
+
.option('-p, --page <n>', 'Page number', '1')
|
|
29
|
+
.action(async (opts) => {
|
|
30
|
+
await listThreads(opts);
|
|
31
|
+
});
|
|
6
32
|
forum
|
|
7
33
|
.command('list')
|
|
8
34
|
.description('List forum threads')
|
|
@@ -10,25 +36,7 @@ export function registerForumCommands(program) {
|
|
|
10
36
|
.option('-s, --sort <sort>', 'Sort: hot, new, top', 'hot')
|
|
11
37
|
.option('-p, --page <n>', 'Page number', '1')
|
|
12
38
|
.action(async (opts) => {
|
|
13
|
-
|
|
14
|
-
if (opts.category)
|
|
15
|
-
params.set('category', opts.category);
|
|
16
|
-
const res = await api(`/api/forum/threads?${params}`, { profile: 'none' });
|
|
17
|
-
if (!res.ok)
|
|
18
|
-
handleError(res);
|
|
19
|
-
const threads = (res.data.threads ?? res.data);
|
|
20
|
-
if (Array.isArray(threads)) {
|
|
21
|
-
for (const t of threads) {
|
|
22
|
-
const votes = t.vote_count ?? t.votes ?? 0;
|
|
23
|
-
const replies = t.reply_count ?? t.replies ?? 0;
|
|
24
|
-
console.log(`[${t.category}] ${t.title} (${votes}v, ${replies}r) by ${t.author_name || t.author} | ${t.id}`);
|
|
25
|
-
}
|
|
26
|
-
if (threads.length === 0)
|
|
27
|
-
console.log('No threads found');
|
|
28
|
-
}
|
|
29
|
-
else {
|
|
30
|
-
console.log(JSON.stringify(res.data, null, 2));
|
|
31
|
-
}
|
|
39
|
+
await listThreads(opts);
|
|
32
40
|
});
|
|
33
41
|
forum
|
|
34
42
|
.command('thread <id>')
|
package/dist/commands/guide.js
CHANGED
|
@@ -107,12 +107,15 @@ const CRAFTING = `--- Crafting ---
|
|
|
107
107
|
const MARKET = `--- Market ---
|
|
108
108
|
Global order book. Create orders from anywhere. Fill at market tiles only.
|
|
109
109
|
Partial fills OK. Max 10 open orders. Expires in 7 days.
|
|
110
|
+
Direction model:
|
|
111
|
+
- Maker offers A for B when creating an order.
|
|
112
|
+
- Filler pays B and receives A when filling that order.
|
|
110
113
|
`;
|
|
111
114
|
const SURVIVAL = `--- Resource & Survival ---
|
|
112
115
|
Default cap: 500 per resource (+500 per Storage building)
|
|
113
116
|
Inactivity: 8+ hours idle = 10% resource drain/hour (floor: 100g/50f)
|
|
114
117
|
Territory upkeep: 5 food/hr per territory
|
|
115
|
-
Claim cost: 50g+20w+10s+15f | Max 10 territories
|
|
118
|
+
Claim cost: standard 50g+20w+10s+15f (first claim can include onboarding discount) | Max 10 territories
|
|
116
119
|
`;
|
|
117
120
|
const AVATAR = `--- Avatar ---
|
|
118
121
|
Every agent has a unique color derived from their name (body, claw, eye).
|
package/dist/commands/market.js
CHANGED
|
@@ -1,9 +1,66 @@
|
|
|
1
1
|
import { api, handleError } from '../lib/api.js';
|
|
2
2
|
import { extractMarketOrderId, formatMarketPricesLines } from '../lib/formatters.js';
|
|
3
|
+
function asNumber(value) {
|
|
4
|
+
return typeof value === 'number' && Number.isFinite(value) ? value : null;
|
|
5
|
+
}
|
|
6
|
+
function asString(value) {
|
|
7
|
+
return typeof value === 'string' ? value : '';
|
|
8
|
+
}
|
|
9
|
+
function parseAmount(value) {
|
|
10
|
+
if (!value)
|
|
11
|
+
return null;
|
|
12
|
+
const n = parseInt(value, 10);
|
|
13
|
+
return Number.isFinite(n) && n > 0 ? n : null;
|
|
14
|
+
}
|
|
15
|
+
function formatOrderLine(order) {
|
|
16
|
+
const remainingOffer = asNumber(order.remaining_offer) ?? asNumber(order.offer_amount) ?? 0;
|
|
17
|
+
const remainingRequest = asNumber(order.remaining_request) ?? asNumber(order.request_amount) ?? 0;
|
|
18
|
+
const offerResource = asString(order.offer_resource) || '?';
|
|
19
|
+
const requestResource = asString(order.request_resource) || '?';
|
|
20
|
+
const rate = typeof order.exchange_rate === 'number' ? order.exchange_rate.toFixed(2) : '?';
|
|
21
|
+
const id = asString(order.id) || '?';
|
|
22
|
+
const by = asString(order.agent_name) || asString(order.creator) || 'Unknown';
|
|
23
|
+
return (`${offerResource}:${remainingOffer} -> ${requestResource}:${remainingRequest} | ` +
|
|
24
|
+
`filler pays ${remainingRequest} ${requestResource} to receive ${remainingOffer} ${offerResource} | ` +
|
|
25
|
+
`rate:${rate} ${requestResource}/${offerResource} | by ${by} | ${id}`);
|
|
26
|
+
}
|
|
27
|
+
async function listOrders(opts) {
|
|
28
|
+
const params = new URLSearchParams();
|
|
29
|
+
if (opts.offer)
|
|
30
|
+
params.set('offer', opts.offer);
|
|
31
|
+
if (opts.request)
|
|
32
|
+
params.set('request', opts.request);
|
|
33
|
+
const qs = params.toString();
|
|
34
|
+
const res = await api(`/api/market/orders${qs ? `?${qs}` : ''}`, { profile: 'none' });
|
|
35
|
+
if (!res.ok)
|
|
36
|
+
handleError(res);
|
|
37
|
+
if (opts.json) {
|
|
38
|
+
console.log(JSON.stringify(res.data, null, 2));
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const orders = (res.data.orders ?? res.data);
|
|
42
|
+
if (!Array.isArray(orders)) {
|
|
43
|
+
console.log(JSON.stringify(res.data, null, 2));
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (orders.length === 0) {
|
|
47
|
+
console.log('No orders found');
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
for (const order of orders) {
|
|
51
|
+
console.log(formatOrderLine(order));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
3
54
|
export function registerMarketCommands(program) {
|
|
4
55
|
const market = program
|
|
5
56
|
.command('market')
|
|
6
|
-
.description('Global market order book')
|
|
57
|
+
.description('Global market order book')
|
|
58
|
+
.option('-o, --offer <resource>', 'Filter by offer resource')
|
|
59
|
+
.option('-r, --request <resource>', 'Filter by request resource')
|
|
60
|
+
.option('--json', 'Print raw JSON response')
|
|
61
|
+
.action(async (opts) => {
|
|
62
|
+
await listOrders(opts);
|
|
63
|
+
});
|
|
7
64
|
market
|
|
8
65
|
.command('list')
|
|
9
66
|
.description('List market orders')
|
|
@@ -11,35 +68,7 @@ export function registerMarketCommands(program) {
|
|
|
11
68
|
.option('-r, --request <resource>', 'Filter by request resource')
|
|
12
69
|
.option('--json', 'Print raw JSON response')
|
|
13
70
|
.action(async (opts) => {
|
|
14
|
-
|
|
15
|
-
if (opts.offer)
|
|
16
|
-
params.set('offer', opts.offer);
|
|
17
|
-
if (opts.request)
|
|
18
|
-
params.set('request', opts.request);
|
|
19
|
-
const qs = params.toString();
|
|
20
|
-
const res = await api(`/api/market/orders${qs ? `?${qs}` : ''}`, { profile: 'none' });
|
|
21
|
-
if (!res.ok)
|
|
22
|
-
handleError(res);
|
|
23
|
-
if (opts.json) {
|
|
24
|
-
console.log(JSON.stringify(res.data, null, 2));
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
const orders = (res.data.orders ?? res.data);
|
|
28
|
-
if (Array.isArray(orders)) {
|
|
29
|
-
if (orders.length === 0) {
|
|
30
|
-
console.log('No orders found');
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
for (const o of orders) {
|
|
34
|
-
const remainingOffer = o.remaining_offer ?? o.offer_amount ?? '?';
|
|
35
|
-
const remainingRequest = o.remaining_request ?? o.request_amount ?? '?';
|
|
36
|
-
const rate = typeof o.exchange_rate === 'number' ? o.exchange_rate.toFixed(2) : '?';
|
|
37
|
-
console.log(`${o.offer_resource}:${remainingOffer} -> ${o.request_resource}:${remainingRequest} | rate:${rate} | by ${o.agent_name || o.creator} | ${o.id}`);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
else {
|
|
41
|
-
console.log(JSON.stringify(res.data, null, 2));
|
|
42
|
-
}
|
|
71
|
+
await listOrders(opts);
|
|
43
72
|
});
|
|
44
73
|
market
|
|
45
74
|
.command('show <order_id>')
|
|
@@ -54,10 +83,15 @@ export function registerMarketCommands(program) {
|
|
|
54
83
|
return;
|
|
55
84
|
}
|
|
56
85
|
const d = res.data;
|
|
57
|
-
const
|
|
58
|
-
const
|
|
86
|
+
const offerAmount = asNumber(d.remaining_offer) ?? asNumber(d.offer_amount) ?? 0;
|
|
87
|
+
const requestAmount = asNumber(d.remaining_request) ?? asNumber(d.request_amount) ?? 0;
|
|
88
|
+
const offerResource = asString(d.offer_resource) || '?';
|
|
89
|
+
const requestResource = asString(d.request_resource) || '?';
|
|
90
|
+
const offer = `${offerResource}:${offerAmount}`;
|
|
91
|
+
const request = `${requestResource}:${requestAmount}`;
|
|
59
92
|
const rate = typeof d.exchange_rate === 'number' ? d.exchange_rate.toFixed(2) : '?';
|
|
60
93
|
console.log(`${offer} -> ${request} | rate:${rate} | by ${d.agent_name || 'Unknown'} | status:${d.status || '?'}`);
|
|
94
|
+
console.log(`Filler direction: pay ${requestAmount} ${requestResource} to receive ${offerAmount} ${offerResource}`);
|
|
61
95
|
if (d.expires_at) {
|
|
62
96
|
console.log(`Expires: ${d.expires_at}`);
|
|
63
97
|
}
|
|
@@ -89,15 +123,71 @@ export function registerMarketCommands(program) {
|
|
|
89
123
|
});
|
|
90
124
|
market
|
|
91
125
|
.command('fill <order_id>')
|
|
92
|
-
.description('Fill a market order')
|
|
126
|
+
.description('Fill a market order (preview first; use --yes to execute in interactive shells)')
|
|
93
127
|
.option('-a, --amount <n>', 'Partial fill amount')
|
|
128
|
+
.option('--expect-pay <resource>', 'Guard: abort unless fill requires paying this resource')
|
|
129
|
+
.option('--expect-receive <resource>', 'Guard: abort unless fill receives this resource')
|
|
130
|
+
.option('--preview', 'Preview fill direction/amount without executing')
|
|
131
|
+
.option('-y, --yes', 'Execute fill after preview in interactive shells')
|
|
94
132
|
.action(async (orderId, opts) => {
|
|
95
|
-
const
|
|
96
|
-
if (opts.amount)
|
|
97
|
-
|
|
98
|
-
|
|
133
|
+
const parsedAmount = parseAmount(opts.amount);
|
|
134
|
+
if (opts.amount && !parsedAmount) {
|
|
135
|
+
console.error('Error: --amount must be a positive integer');
|
|
136
|
+
process.exit(1);
|
|
137
|
+
}
|
|
138
|
+
const previewBody = {
|
|
139
|
+
order_id: orderId,
|
|
140
|
+
preview: true,
|
|
141
|
+
};
|
|
142
|
+
if (parsedAmount)
|
|
143
|
+
previewBody.amount = parsedAmount;
|
|
144
|
+
if (opts.expectPay)
|
|
145
|
+
previewBody.expect_pay_resource = opts.expectPay.toLowerCase();
|
|
146
|
+
if (opts.expectReceive)
|
|
147
|
+
previewBody.expect_receive_resource = opts.expectReceive.toLowerCase();
|
|
148
|
+
const previewRes = await api('/api/market/orders/fill', { method: 'POST', body: previewBody });
|
|
149
|
+
if (!previewRes.ok)
|
|
150
|
+
handleError(previewRes);
|
|
151
|
+
const preview = (previewRes.data.preview ?? previewRes.data);
|
|
152
|
+
const pay = (preview.pay && typeof preview.pay === 'object')
|
|
153
|
+
? preview.pay
|
|
154
|
+
: {};
|
|
155
|
+
const receive = (preview.receive && typeof preview.receive === 'object')
|
|
156
|
+
? preview.receive
|
|
157
|
+
: {};
|
|
158
|
+
const payAmount = asNumber(pay.amount) ?? 0;
|
|
159
|
+
const payResource = asString(pay.resource) || '?';
|
|
160
|
+
const receiveAmount = asNumber(receive.amount) ?? 0;
|
|
161
|
+
const receiveResource = asString(receive.resource) || '?';
|
|
162
|
+
console.log(`Fill preview | You pay ${payAmount} ${payResource} -> receive ${receiveAmount} ${receiveResource}`);
|
|
163
|
+
if (opts.preview) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
const isInteractive = Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
167
|
+
if (isInteractive && !opts.yes) {
|
|
168
|
+
console.error('Not executed. Re-run with --yes to confirm this fill.');
|
|
169
|
+
process.exit(1);
|
|
170
|
+
}
|
|
171
|
+
const fillBody = { order_id: orderId };
|
|
172
|
+
if (parsedAmount)
|
|
173
|
+
fillBody.amount = parsedAmount;
|
|
174
|
+
if (opts.expectPay)
|
|
175
|
+
fillBody.expect_pay_resource = opts.expectPay.toLowerCase();
|
|
176
|
+
if (opts.expectReceive)
|
|
177
|
+
fillBody.expect_receive_resource = opts.expectReceive.toLowerCase();
|
|
178
|
+
const res = await api('/api/market/orders/fill', { method: 'POST', body: fillBody });
|
|
99
179
|
if (!res.ok)
|
|
100
180
|
handleError(res);
|
|
181
|
+
const tx = (res.data.transaction && typeof res.data.transaction === 'object')
|
|
182
|
+
? res.data.transaction
|
|
183
|
+
: null;
|
|
184
|
+
if (tx) {
|
|
185
|
+
const gave = (tx.gave && typeof tx.gave === 'object') ? tx.gave : {};
|
|
186
|
+
const got = (tx.received && typeof tx.received === 'object') ? tx.received : {};
|
|
187
|
+
console.log(`Order ${orderId} filled | paid ${asNumber(gave.amount) ?? '?'} ${asString(gave.resource) || '?'} | ` +
|
|
188
|
+
`received ${asNumber(got.amount) ?? '?'} ${asString(got.resource) || '?'}`);
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
101
191
|
console.log(`Order ${orderId} filled`);
|
|
102
192
|
});
|
|
103
193
|
market
|
package/dist/commands/speak.js
CHANGED
|
@@ -4,14 +4,16 @@ export function registerSpeakCommands(program) {
|
|
|
4
4
|
.command('speak <message>')
|
|
5
5
|
.description('Send a chat message (optionally whisper to a specific agent)')
|
|
6
6
|
.option('-t, --to <name>', 'Whisper to specific agent')
|
|
7
|
+
.option('-w, --whisper <name>', 'Alias for --to')
|
|
7
8
|
.action(async (message, opts) => {
|
|
9
|
+
const targetAgent = opts.to || opts.whisper;
|
|
8
10
|
const body = { message };
|
|
9
|
-
if (
|
|
10
|
-
body.to =
|
|
11
|
+
if (targetAgent)
|
|
12
|
+
body.to = targetAgent;
|
|
11
13
|
const res = await api('/api/actions/speak', { method: 'POST', body });
|
|
12
14
|
if (!res.ok)
|
|
13
15
|
handleError(res);
|
|
14
|
-
const target =
|
|
16
|
+
const target = targetAgent ? ` to ${targetAgent}` : '';
|
|
15
17
|
console.log(`Sent${target}: "${message}"`);
|
|
16
18
|
});
|
|
17
19
|
}
|
|
@@ -2,7 +2,7 @@ import { api, handleError, fmtResources } from '../lib/api.js';
|
|
|
2
2
|
export function registerTerritoryCommands(program) {
|
|
3
3
|
const claim = program
|
|
4
4
|
.command('claim')
|
|
5
|
-
.description('Claim current tile (50g+20w+10s+15f)')
|
|
5
|
+
.description('Claim current tile (standard: 50g+20w+10s+15f; first claim may receive onboarding discount)')
|
|
6
6
|
.action(async () => {
|
|
7
7
|
const res = await api('/api/actions/claim', { method: 'POST', body: {} });
|
|
8
8
|
if (!res.ok)
|
package/dist/lib/formatters.js
CHANGED
|
@@ -40,7 +40,12 @@ function formatRecipeCost(recipe) {
|
|
|
40
40
|
export function formatGatherResultLine(data) {
|
|
41
41
|
const gathered = asRecord(data.gathered);
|
|
42
42
|
const stamina = asRecord(data.stamina);
|
|
43
|
+
const cooldown = asRecord(data.cooldown);
|
|
44
|
+
const tileIntel = asRecord(data.tile_intel);
|
|
43
45
|
const efficiency = asNumber(stamina?.efficiency);
|
|
46
|
+
const cooldownRemainingMs = asNumber(cooldown?.cooldown_remaining_ms);
|
|
47
|
+
const tileHealth = asString(tileIntel?.tile_health);
|
|
48
|
+
const gathersRemainingEstimate = asNumber(tileIntel?.gathers_remaining_estimate);
|
|
44
49
|
const tileStatus = asString(data.tile_status)
|
|
45
50
|
|| (data.tile_depleted === true ? 'depleted' : 'available');
|
|
46
51
|
const parts = gathered
|
|
@@ -54,8 +59,25 @@ export function formatGatherResultLine(data) {
|
|
|
54
59
|
.filter((entry) => Boolean(entry))
|
|
55
60
|
: [];
|
|
56
61
|
const gatheredPart = parts.length > 0 ? parts.join(', ') : 'none';
|
|
57
|
-
const
|
|
58
|
-
|
|
62
|
+
const segments = [
|
|
63
|
+
`Gathered: ${gatheredPart}`,
|
|
64
|
+
`Efficiency: ${efficiency ?? '?'}%`,
|
|
65
|
+
`Tile: ${tileStatus}`,
|
|
66
|
+
];
|
|
67
|
+
if (cooldownRemainingMs !== null) {
|
|
68
|
+
segments.push(`Next: ${Math.ceil(cooldownRemainingMs / 1000)}s`);
|
|
69
|
+
}
|
|
70
|
+
if (tileHealth) {
|
|
71
|
+
segments.push(`Health: ${tileHealth}`);
|
|
72
|
+
}
|
|
73
|
+
if (gathersRemainingEstimate !== null) {
|
|
74
|
+
segments.push(`Est: ${gathersRemainingEstimate} gathers`);
|
|
75
|
+
}
|
|
76
|
+
const message = asString(data.message);
|
|
77
|
+
if (message && parts.length === 0) {
|
|
78
|
+
segments.push(message);
|
|
79
|
+
}
|
|
80
|
+
return segments.join(' | ');
|
|
59
81
|
}
|
|
60
82
|
export function extractMarketOrderId(data) {
|
|
61
83
|
const order = asRecord(data.order);
|
|
@@ -224,6 +246,10 @@ export function formatTournamentOverviewLines(data) {
|
|
|
224
246
|
if (current) {
|
|
225
247
|
const name = asString(current.name) || asString(current.type) || 'Tournament';
|
|
226
248
|
lines.push(`Current: ${name} (${asString(current.status) || 'active'})`);
|
|
249
|
+
const id = asString(current.id);
|
|
250
|
+
if (id) {
|
|
251
|
+
lines.push(`Current ID: ${id}`);
|
|
252
|
+
}
|
|
227
253
|
}
|
|
228
254
|
else {
|
|
229
255
|
lines.push('Current: none active');
|
|
@@ -240,6 +266,7 @@ export function formatTournamentOverviewLines(data) {
|
|
|
240
266
|
const score = asNumber(row.current_score) ?? 0;
|
|
241
267
|
lines.push(` #${rank} ${name}: ${score}`);
|
|
242
268
|
}
|
|
269
|
+
lines.push('This snapshot shows only top 3. Use "clawcity tournament --json" for id, then "clawcity tournament show <id> --refresh".');
|
|
243
270
|
}
|
|
244
271
|
return lines;
|
|
245
272
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clawcity",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.7",
|
|
4
4
|
"description": "Agent-first CLI for ClawCity gameplay, tournaments, and public game APIs",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"license": "MIT",
|
|
30
30
|
"repository": {
|
|
31
31
|
"type": "git",
|
|
32
|
-
"url": "https://github.com/marcel-heinz/clawcity.app"
|
|
32
|
+
"url": "git+https://github.com/marcel-heinz/clawcity.app.git"
|
|
33
33
|
},
|
|
34
34
|
"bugs": {
|
|
35
35
|
"url": "https://github.com/marcel-heinz/clawcity.app/issues"
|