plugin-syndicate 0.1.0 → 0.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 +24 -2
- package/dist/index.d.ts +2 -1
- package/dist/index.js +71 -13
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
The elizaOS adapter for **The Syndicate** — a deterministic, turn-based
|
|
4
4
|
crime-city strategy game where the loot is **real trading cards priced by a
|
|
5
|
-
live on-chain TCG oracle**.
|
|
6
|
-
leaderboard.
|
|
5
|
+
live on-chain TCG oracle**. Each syndicate runs its own city; humans and
|
|
6
|
+
agents compete on one shared leaderboard.
|
|
7
7
|
|
|
8
8
|
The game itself is agent-agnostic: **any** agent can play it over the public
|
|
9
9
|
HTTP API (rules: [SKILL.md](https://play.the-undesirables.com/SKILL.md)) or
|
|
@@ -57,12 +57,34 @@ per day. Self verbs (`heal`, `pray`, `lay_low`, `retain`, `injunction`,
|
|
|
57
57
|
Set `SYNDICATE_SESSION_ID` in your character settings to resume a specific
|
|
58
58
|
session (games expire after 7 idle days server-side).
|
|
59
59
|
|
|
60
|
+
## Three real-world feeds, one game
|
|
61
|
+
|
|
62
|
+
- **Card prices** — loot is real cards at live oracle prices; your stash
|
|
63
|
+
re-prices daily. Hold the risers, fence the dippers.
|
|
64
|
+
- **Chicago weather** — the REAL O'Hare observation shapes each day (rain
|
|
65
|
+
favors laying low, heatwaves pay extortion premiums) and the Weather Book
|
|
66
|
+
takes tickets on tomorrow's sky.
|
|
67
|
+
- **MLB stat lines** — the Sports Book sets player props from our
|
|
68
|
+
on-chain-committed daily panel and settles them on the player's next real
|
|
69
|
+
game, with a public Merkle proof cited on every settled ticket.
|
|
70
|
+
|
|
71
|
+
All bets are **in-game capital only** — pretend money, real data. It is a
|
|
72
|
+
practice range for pricing real-world uncertainty with zero real-world
|
|
73
|
+
downside.
|
|
74
|
+
|
|
60
75
|
## The one trap worth knowing
|
|
61
76
|
|
|
62
77
|
`beatable: "solo"` assumes your **strongest** member leads the attack — the
|
|
63
78
|
state names them in `power.bestSoloAgentId`. Sending a weaker member into a
|
|
64
79
|
"beatable" fight loses. Crew death is permanent.
|
|
65
80
|
|
|
81
|
+
## Context provider
|
|
82
|
+
|
|
83
|
+
`syndicate-game-state` narrates the current game (day, capital, heat,
|
|
84
|
+
territory, stash) into the agent's context on every message — from the cache
|
|
85
|
+
written by the actions, with **zero** extra API calls. Your character always
|
|
86
|
+
knows where the game stands without polling.
|
|
87
|
+
|
|
66
88
|
## Related
|
|
67
89
|
|
|
68
90
|
- [`plugin-undesirables`](https://github.com/sailorpepe/plugin-undesirables) —
|
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,8 @@ import { Plugin } from '@elizaos/core';
|
|
|
5
5
|
* ====================================
|
|
6
6
|
* Lets any elizaOS agent run a crime family in The Syndicate: a deterministic,
|
|
7
7
|
* turn-based 80×80 city where the loot is REAL trading cards priced by a live
|
|
8
|
-
* on-chain TCG oracle.
|
|
8
|
+
* on-chain TCG oracle. Each syndicate runs its OWN city; humans and agents
|
|
9
|
+
* compete on one shared leaderboard.
|
|
9
10
|
*
|
|
10
11
|
* The game is server-authoritative — this plugin submits order INTENTS to the
|
|
11
12
|
* public API and narrates what the engine resolved. There is no client-side
|
package/dist/index.js
CHANGED
|
@@ -2,29 +2,58 @@
|
|
|
2
2
|
var GAME_API = "https://play.the-undesirables.com/api/game";
|
|
3
3
|
var SCORES_API = "https://play.the-undesirables.com/api/scores";
|
|
4
4
|
var SKILL_URL = "https://play.the-undesirables.com/SKILL.md";
|
|
5
|
-
var PLUGIN_VERSION = "0.
|
|
5
|
+
var PLUGIN_VERSION = "0.2.0";
|
|
6
|
+
var FETCH_TIMEOUT_MS = 15e3;
|
|
6
7
|
var sessions = /* @__PURE__ */ new Map();
|
|
8
|
+
var lastViews = /* @__PURE__ */ new Map();
|
|
7
9
|
function sessionFor(runtime) {
|
|
8
10
|
const configured = runtime.getSetting?.("SYNDICATE_SESSION_ID");
|
|
9
11
|
if (configured && typeof configured === "string") return configured;
|
|
10
12
|
return sessions.get(String(runtime.agentId));
|
|
11
13
|
}
|
|
14
|
+
var GameError = class extends Error {
|
|
15
|
+
constructor(message, expired = false) {
|
|
16
|
+
super(message);
|
|
17
|
+
this.expired = expired;
|
|
18
|
+
}
|
|
19
|
+
expired;
|
|
20
|
+
};
|
|
21
|
+
function toGameError(status, serverMsg) {
|
|
22
|
+
if (status === 404) return new GameError("Session unknown or expired (games expire after 7 idle days).", true);
|
|
23
|
+
if (status === 429) return new GameError("The city is rate-limited (30 calls/min/IP). Wait a minute, then try again.");
|
|
24
|
+
if (status === 409) return new GameError(serverMsg || "Game over \u2014 start a new syndicate with SYNDICATE_NEW.");
|
|
25
|
+
return new GameError(serverMsg || `HTTP ${status}`);
|
|
26
|
+
}
|
|
12
27
|
async function api(body) {
|
|
13
28
|
const res = await fetch(GAME_API, {
|
|
14
29
|
method: "POST",
|
|
15
30
|
headers: { "content-type": "application/json" },
|
|
16
|
-
body: JSON.stringify(body)
|
|
31
|
+
body: JSON.stringify(body),
|
|
32
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
|
|
17
33
|
});
|
|
18
|
-
const data = await res.json();
|
|
19
|
-
if (!res.ok) throw
|
|
34
|
+
const data = await res.json().catch(() => ({}));
|
|
35
|
+
if (!res.ok) throw toGameError(res.status, String(data.error || ""));
|
|
20
36
|
return data;
|
|
21
37
|
}
|
|
22
38
|
async function apiView(sessionId) {
|
|
23
|
-
const res = await fetch(`${GAME_API}?id=${encodeURIComponent(sessionId)}
|
|
24
|
-
|
|
25
|
-
|
|
39
|
+
const res = await fetch(`${GAME_API}?id=${encodeURIComponent(sessionId)}`, {
|
|
40
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
|
|
41
|
+
});
|
|
42
|
+
const data = await res.json().catch(() => ({}));
|
|
43
|
+
if (!res.ok) throw toGameError(res.status, String(data.error || ""));
|
|
26
44
|
return data;
|
|
27
45
|
}
|
|
46
|
+
function handleGameError(runtime, e) {
|
|
47
|
+
if (e instanceof GameError && e.expired) {
|
|
48
|
+
sessions.delete(String(runtime.agentId));
|
|
49
|
+
lastViews.delete(String(runtime.agentId));
|
|
50
|
+
return `${e.message} Start fresh with SYNDICATE_NEW.`;
|
|
51
|
+
}
|
|
52
|
+
if (e instanceof Error && e.name === "TimeoutError") {
|
|
53
|
+
return "The game server did not answer within 15s \u2014 it may be waking up. Try again shortly.";
|
|
54
|
+
}
|
|
55
|
+
return e instanceof Error ? e.message : String(e);
|
|
56
|
+
}
|
|
28
57
|
function summarizeView(v) {
|
|
29
58
|
const events = Array.isArray(v.events) ? v.events.slice(0, 12) : [];
|
|
30
59
|
const crew = Array.isArray(v.crew) ? v.crew : [];
|
|
@@ -33,8 +62,16 @@ function summarizeView(v) {
|
|
|
33
62
|
const stash = v.stash || {};
|
|
34
63
|
const targets = Array.isArray(v.targets) ? v.targets : [];
|
|
35
64
|
const beatable = targets.filter((t) => t.beatable !== "no").slice(0, 8);
|
|
65
|
+
const weather = v.weather;
|
|
66
|
+
const contract = v.contract;
|
|
67
|
+
const wBet = v.weatherBet;
|
|
68
|
+
const sBet = v.sportsBet;
|
|
36
69
|
const lines = [
|
|
37
70
|
`Day ${v.day} \u2014 capital $${v.capital}, heat ${v.heat}, wanted ${v.wantedLevel}`,
|
|
71
|
+
...weather ? [`Chicago weather (REAL, shifts today's odds): ${weather.condition}, ${weather.tempF}\xB0F \u2014 ${weather.kind}`] : [],
|
|
72
|
+
...contract ? [`Commission contract: ${contract.desc}`] : [],
|
|
73
|
+
...wBet ? [`Open weather ticket: $${wBet.stake} on ${wBet.on}`] : [],
|
|
74
|
+
...sBet ? [`Open sports ticket: $${sBet.stake} on ${sBet.playerName} (${sBet.prop})`] : [],
|
|
38
75
|
`Territory: ${territory.ownedTiles}/${territory.tilesToWin} tiles toward the Kingpin win`,
|
|
39
76
|
`Stash: ${stash.cards} card(s), fence value $${stash.fenceValue}`,
|
|
40
77
|
`Crew: ${crew.map((c) => `${c.name} (hp ${c.hp}${c.unavailable ? `, ${c.unavailable}` : ""})`).join(" \xB7 ")}`,
|
|
@@ -43,8 +80,12 @@ function summarizeView(v) {
|
|
|
43
80
|
];
|
|
44
81
|
if (events.length) lines.push("", "What happened:", ...events.map((e) => ` ${e}`));
|
|
45
82
|
if (v.gameOver) lines.push("", "GAME OVER \u2014 start a new syndicate with SYNDICATE_NEW.");
|
|
83
|
+
if (v.sessionId) lines.push("", `(session ${v.sessionId} \u2014 set SYNDICATE_SESSION_ID to resume it after a restart)`);
|
|
46
84
|
return lines.join("\n");
|
|
47
85
|
}
|
|
86
|
+
function remember(runtime, view) {
|
|
87
|
+
lastViews.set(String(runtime.agentId), view);
|
|
88
|
+
}
|
|
48
89
|
var newGameAction = {
|
|
49
90
|
name: "SYNDICATE_NEW",
|
|
50
91
|
description: "Start a new game of The Syndicate. Creates a fresh crime family in a deterministic 80\xD780 city. One session per agent; the old session is abandoned.",
|
|
@@ -69,13 +110,14 @@ var newGameAction = {
|
|
|
69
110
|
try {
|
|
70
111
|
const view = await api({ action: "new", name: name.slice(0, 32), model: `elizaos/${runtime.character?.name || "agent"}` });
|
|
71
112
|
sessions.set(String(runtime.agentId), String(view.sessionId));
|
|
113
|
+
remember(runtime, view);
|
|
72
114
|
const text = `New syndicate founded. Read the rules once: ${SKILL_URL}
|
|
73
115
|
|
|
74
116
|
${summarizeView(view)}`;
|
|
75
117
|
if (callback) await callback({ text });
|
|
76
118
|
return { success: true, text, data: { sessionId: String(view.sessionId), view } };
|
|
77
119
|
} catch (e) {
|
|
78
|
-
const text = `Could not start a game: ${
|
|
120
|
+
const text = `Could not start a game: ${handleGameError(runtime, e)}`;
|
|
79
121
|
if (callback) await callback({ text });
|
|
80
122
|
return { success: false, text };
|
|
81
123
|
}
|
|
@@ -102,11 +144,12 @@ var stateAction = {
|
|
|
102
144
|
}
|
|
103
145
|
try {
|
|
104
146
|
const view = await apiView(sessionId);
|
|
147
|
+
remember(runtime, view);
|
|
105
148
|
const text = summarizeView(view);
|
|
106
149
|
if (callback) await callback({ text });
|
|
107
150
|
return { success: true, text, data: { view } };
|
|
108
151
|
} catch (e) {
|
|
109
|
-
const text = `Could not read the game: ${
|
|
152
|
+
const text = `Could not read the game: ${handleGameError(runtime, e)}`;
|
|
110
153
|
if (callback) await callback({ text });
|
|
111
154
|
return { success: false, text };
|
|
112
155
|
}
|
|
@@ -114,7 +157,7 @@ var stateAction = {
|
|
|
114
157
|
};
|
|
115
158
|
var moveAction = {
|
|
116
159
|
name: "SYNDICATE_MOVE",
|
|
117
|
-
description: "Submit one day of orders to The Syndicate and get back what the engine resolved. Orders are [{agentId, targetId, actionType, squad?}] \u2014 one per crew member. Self verbs (heal, pray, lay_low, retain, injunction, cook_books, audit, launder) may omit targetId. Check SYNDICATE_STATE first: 'beatable: solo' assumes your STRONGEST member leads.",
|
|
160
|
+
description: "Submit one day of orders to The Syndicate and get back what the engine resolved. Orders are [{agentId, targetId, actionType, squad?}] \u2014 one per crew member. Self verbs (heal, pray, lay_low, retain, injunction, cook_books, audit, launder, weather_bet, sports_bet) may omit targetId. Betting (in-game capital only): {actionType:'weather_bet', on:'rain', stake:500} on tomorrow's REAL Chicago weather; {actionType:'sports_bet', playerId, prop:'hr', stake:500} on a real MLB player's next game \u2014 pick playerId from sportsBook.featured. Check SYNDICATE_STATE first: 'beatable: solo' assumes your STRONGEST member leads.",
|
|
118
161
|
similes: ["SYNDICATE_ORDERS", "PLAY_TURN", "RUN_THE_DAY"],
|
|
119
162
|
parameters: [
|
|
120
163
|
{
|
|
@@ -150,11 +193,12 @@ var moveAction = {
|
|
|
150
193
|
}
|
|
151
194
|
try {
|
|
152
195
|
const view = await api({ action: "orders", sessionId, orders });
|
|
196
|
+
remember(runtime, view);
|
|
153
197
|
const text = summarizeView(view);
|
|
154
198
|
if (callback) await callback({ text });
|
|
155
199
|
return { success: true, text, data: { view } };
|
|
156
200
|
} catch (e) {
|
|
157
|
-
const text = `The engine rejected the orders: ${
|
|
201
|
+
const text = `The engine rejected the orders: ${handleGameError(runtime, e)}`;
|
|
158
202
|
if (callback) await callback({ text });
|
|
159
203
|
return { success: false, text };
|
|
160
204
|
}
|
|
@@ -174,7 +218,7 @@ var leaderboardAction = {
|
|
|
174
218
|
validate: async () => true,
|
|
175
219
|
handler: async (_runtime, _message, _state, _options, callback) => {
|
|
176
220
|
try {
|
|
177
|
-
const res = await fetch(SCORES_API);
|
|
221
|
+
const res = await fetch(SCORES_API, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS) });
|
|
178
222
|
const data = await res.json();
|
|
179
223
|
const rows = (data.scores || []).slice(0, 10);
|
|
180
224
|
const text = rows.length ? rows.map(
|
|
@@ -189,11 +233,25 @@ var leaderboardAction = {
|
|
|
189
233
|
}
|
|
190
234
|
}
|
|
191
235
|
};
|
|
236
|
+
var syndicateProvider = {
|
|
237
|
+
name: "syndicate-game-state",
|
|
238
|
+
description: "Current state of the agent's Syndicate game (cached from the last action; no network calls)",
|
|
239
|
+
get: async (runtime, _message, _state) => {
|
|
240
|
+
const view = lastViews.get(String(runtime.agentId));
|
|
241
|
+
if (!view || !sessionFor(runtime)) return { text: "" };
|
|
242
|
+
const territory = view.territory || {};
|
|
243
|
+
const stash = view.stash || {};
|
|
244
|
+
return {
|
|
245
|
+
text: `[The Syndicate \u2014 day ${view.day}: capital $${view.capital}, heat ${view.heat}, ${territory.ownedTiles}/${territory.tilesToWin} tiles, stash $${stash.fenceValue}. Use SYNDICATE_STATE for detail, SYNDICATE_MOVE to play the day.]`,
|
|
246
|
+
data: { view }
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
};
|
|
192
250
|
var syndicatePlugin = {
|
|
193
251
|
name: "plugin-syndicate",
|
|
194
252
|
description: `The Syndicate v${PLUGIN_VERSION} \u2014 agent-playable crime-city strategy with oracle-priced loot. Rules: ${SKILL_URL}`,
|
|
195
253
|
actions: [newGameAction, stateAction, moveAction, leaderboardAction],
|
|
196
|
-
providers: [],
|
|
254
|
+
providers: [syndicateProvider],
|
|
197
255
|
evaluators: []
|
|
198
256
|
};
|
|
199
257
|
var index_default = syndicatePlugin;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * The Syndicate — ElizaOS Plugin v0.1\n * ====================================\n * Lets any elizaOS agent run a crime family in The Syndicate: a deterministic,\n * turn-based 80×80 city where the loot is REAL trading cards priced by a live\n * on-chain TCG oracle. Humans and agents share one world and one leaderboard.\n *\n * The game is server-authoritative — this plugin submits order INTENTS to the\n * public API and narrates what the engine resolved. There is no client-side\n * simulation and nothing to cheat.\n *\n * SYNDICATE_NEW start a game (one session per agent, kept in memory)\n * SYNDICATE_STATE read the current day without spending it\n * SYNDICATE_MOVE submit a day of orders and get the resolved events\n * SYNDICATE_LEADERBOARD the shared human+agent board\n *\n * Rules for models: https://play.the-undesirables.com/SKILL.md\n *\n * @see https://play.the-undesirables.com\n * @see https://github.com/sailorpepe/plugin-syndicate\n */\n\nimport type {\n Plugin,\n Action,\n IAgentRuntime,\n Memory,\n State,\n HandlerCallback,\n ActionExample,\n ActionResult,\n} from \"@elizaos/core\";\n\nconst GAME_API = \"https://play.the-undesirables.com/api/game\";\nconst SCORES_API = \"https://play.the-undesirables.com/api/scores\";\nconst SKILL_URL = \"https://play.the-undesirables.com/SKILL.md\";\nconst PLUGIN_VERSION = \"0.1.0\";\n\n// ============================================================\n// Session bookkeeping — one live game per agent, in-process.\n// The server holds all state; losing this map only means the\n// agent starts a fresh syndicate (sessions expire in 7 idle\n// days server-side anyway).\n// ============================================================\n\nconst sessions = new Map<string, string>(); // agentId -> sessionId\n\nfunction sessionFor(runtime: IAgentRuntime): string | undefined {\n const configured = runtime.getSetting?.(\"SYNDICATE_SESSION_ID\");\n if (configured && typeof configured === \"string\") return configured;\n return sessions.get(String(runtime.agentId));\n}\n\nasync function api(body: Record<string, unknown>): Promise<Record<string, unknown>> {\n const res = await fetch(GAME_API, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n const data = (await res.json()) as Record<string, unknown>;\n if (!res.ok) throw new Error(String((data as { error?: string }).error || `HTTP ${res.status}`));\n return data;\n}\n\nasync function apiView(sessionId: string): Promise<Record<string, unknown>> {\n const res = await fetch(`${GAME_API}?id=${encodeURIComponent(sessionId)}`);\n const data = (await res.json()) as Record<string, unknown>;\n if (!res.ok) throw new Error(String((data as { error?: string }).error || `HTTP ${res.status}`));\n return data;\n}\n\n// Compact narration so the model sees the day without drowning in JSON.\nfunction summarizeView(v: Record<string, unknown>): string {\n const events = Array.isArray(v.events) ? (v.events as string[]).slice(0, 12) : [];\n const crew = Array.isArray(v.crew) ? (v.crew as Record<string, unknown>[]) : [];\n const power = (v.power || {}) as Record<string, unknown>;\n const territory = (v.territory || {}) as Record<string, unknown>;\n const stash = (v.stash || {}) as Record<string, unknown>;\n const targets = Array.isArray(v.targets) ? (v.targets as Record<string, unknown>[]) : [];\n const beatable = targets.filter((t) => t.beatable !== \"no\").slice(0, 8);\n const lines = [\n `Day ${v.day} — capital $${v.capital}, heat ${v.heat}, wanted ${v.wantedLevel}`,\n `Territory: ${territory.ownedTiles}/${territory.tilesToWin} tiles toward the Kingpin win`,\n `Stash: ${stash.cards} card(s), fence value $${stash.fenceValue}`,\n `Crew: ${crew.map((c) => `${c.name} (hp ${c.hp}${(c as { unavailable?: string }).unavailable ? `, ${(c as { unavailable?: string }).unavailable}` : \"\"})`).join(\" · \")}`,\n `Power: best solo ${power.bestSolo} (${power.bestSoloAgentName}), full squad ${power.fullSquad}`,\n beatable.length\n ? `Beatable now: ${beatable.map((t) => `#${t.tileId} ${t.type} vault $${t.vault} (${t.beatable})`).join(\", \")}`\n : `Nothing is beatable right now — hire muscle or squad up.`,\n ];\n if (events.length) lines.push(\"\", \"What happened:\", ...events.map((e) => ` ${e}`));\n if (v.gameOver) lines.push(\"\", \"GAME OVER — start a new syndicate with SYNDICATE_NEW.\");\n return lines.join(\"\\n\");\n}\n\n// ============================================================\n// Actions\n// ============================================================\n\nconst newGameAction: Action = {\n name: \"SYNDICATE_NEW\",\n description:\n \"Start a new game of The Syndicate. Creates a fresh crime family in a deterministic 80×80 city. One session per agent; the old session is abandoned.\",\n similes: [\"START_SYNDICATE\", \"NEW_CRIME_FAMILY\", \"PLAY_SYNDICATE\"],\n parameters: [\n {\n name: \"syndicate_name\",\n description: \"Name for your crime family (max 32 chars)\",\n required: false,\n schema: { type: \"string\" },\n },\n ],\n examples: [\n [\n { name: \"{{user1}}\", content: { text: \"Start a syndicate called The Night Owls\" } } as ActionExample,\n { name: \"{{agentName}}\", content: { text: \"Founding The Night Owls...\", action: \"SYNDICATE_NEW\" } } as ActionExample,\n ],\n ],\n validate: async () => true,\n handler: async (\n runtime: IAgentRuntime,\n message: Memory,\n _state?: State,\n options?: Record<string, unknown>,\n callback?: HandlerCallback\n ): Promise<ActionResult | undefined> => {\n const name =\n (options?.syndicate_name as string) ||\n message.content.text?.match(/called\\s+(.{2,32}?)(?:\\.|$)/i)?.[1] ||\n `${runtime.character?.name || \"Agent\"} Syndicate`;\n try {\n const view = await api({ action: \"new\", name: name.slice(0, 32), model: `elizaos/${runtime.character?.name || \"agent\"}` });\n sessions.set(String(runtime.agentId), String(view.sessionId));\n const text = `New syndicate founded. Read the rules once: ${SKILL_URL}\\n\\n${summarizeView(view)}`;\n if (callback) await callback({ text });\n return { success: true, text, data: { sessionId: String(view.sessionId), view } };\n } catch (e) {\n const text = `Could not start a game: ${e instanceof Error ? e.message : String(e)}`;\n if (callback) await callback({ text });\n return { success: false, text };\n }\n },\n};\n\nconst stateAction: Action = {\n name: \"SYNDICATE_STATE\",\n description:\n \"Read the current state of your Syndicate game WITHOUT spending a day: crew, capital, heat, stash value, beatable targets, and progress toward the Kingpin win.\",\n similes: [\"SYNDICATE_STATUS\", \"CHECK_SYNDICATE\", \"GAME_STATE\"],\n parameters: [],\n examples: [\n [\n { name: \"{{user1}}\", content: { text: \"How is the syndicate doing?\" } } as ActionExample,\n { name: \"{{agentName}}\", content: { text: \"Checking the city...\", action: \"SYNDICATE_STATE\" } } as ActionExample,\n ],\n ],\n validate: async (runtime: IAgentRuntime) => sessionFor(runtime) !== undefined,\n handler: async (\n runtime: IAgentRuntime,\n _message: Memory,\n _state?: State,\n _options?: Record<string, unknown>,\n callback?: HandlerCallback\n ): Promise<ActionResult | undefined> => {\n const sessionId = sessionFor(runtime);\n if (!sessionId) {\n const text = \"No game running — use SYNDICATE_NEW to found a syndicate.\";\n if (callback) await callback({ text });\n return { success: false, text };\n }\n try {\n const view = await apiView(sessionId);\n const text = summarizeView(view);\n if (callback) await callback({ text });\n return { success: true, text, data: { view } };\n } catch (e) {\n const text = `Could not read the game: ${e instanceof Error ? e.message : String(e)}`;\n if (callback) await callback({ text });\n return { success: false, text };\n }\n },\n};\n\nconst moveAction: Action = {\n name: \"SYNDICATE_MOVE\",\n description:\n \"Submit one day of orders to The Syndicate and get back what the engine resolved. Orders are [{agentId, targetId, actionType, squad?}] — one per crew member. Self verbs (heal, pray, lay_low, retain, injunction, cook_books, audit, launder) may omit targetId. Check SYNDICATE_STATE first: 'beatable: solo' assumes your STRONGEST member leads.\",\n similes: [\"SYNDICATE_ORDERS\", \"PLAY_TURN\", \"RUN_THE_DAY\"],\n parameters: [\n {\n name: \"orders\",\n description:\n 'JSON array of orders, e.g. [{\"agentId\":123,\"targetId\":612,\"actionType\":\"raid\",\"squad\":[124,156]}]. An empty array passes the day (the world still moves).',\n required: true,\n schema: { type: \"string\" },\n },\n ],\n examples: [\n [\n { name: \"{{user1}}\", content: { text: \"Send Rogue to raid the accountant at tile 612\" } } as ActionExample,\n { name: \"{{agentName}}\", content: { text: \"Running the day...\", action: \"SYNDICATE_MOVE\" } } as ActionExample,\n ],\n ],\n validate: async (runtime: IAgentRuntime) => sessionFor(runtime) !== undefined,\n handler: async (\n runtime: IAgentRuntime,\n message: Memory,\n _state?: State,\n options?: Record<string, unknown>,\n callback?: HandlerCallback\n ): Promise<ActionResult | undefined> => {\n const sessionId = sessionFor(runtime);\n if (!sessionId) {\n const text = \"No game running — use SYNDICATE_NEW to found a syndicate.\";\n if (callback) await callback({ text });\n return { success: false, text };\n }\n let orders: unknown = [];\n const raw = (options?.orders as string) || message.content.text?.match(/\\[[\\s\\S]*\\]/)?.[0] || \"[]\";\n try {\n orders = typeof raw === \"string\" ? JSON.parse(raw) : raw;\n if (!Array.isArray(orders)) throw new Error(\"orders must be a JSON array\");\n } catch (e) {\n const text = `Could not parse orders (${e instanceof Error ? e.message : String(e)}). Expected: [{\"agentId\":ID,\"targetId\":TILE,\"actionType\":\"VERB\"}]`;\n if (callback) await callback({ text });\n return { success: false, text };\n }\n try {\n const view = await api({ action: \"orders\", sessionId, orders });\n const text = summarizeView(view);\n if (callback) await callback({ text });\n return { success: true, text, data: { view } };\n } catch (e) {\n const text = `The engine rejected the orders: ${e instanceof Error ? e.message : String(e)}`;\n if (callback) await callback({ text });\n return { success: false, text };\n }\n },\n};\n\nconst leaderboardAction: Action = {\n name: \"SYNDICATE_LEADERBOARD\",\n description:\n \"Read The Syndicate's shared leaderboard — humans and agents on one board, scored by capital, with agent entries flagged by model.\",\n similes: [\"SYNDICATE_SCORES\", \"TOP_SYNDICATES\", \"CRIME_LEADERBOARD\"],\n parameters: [],\n examples: [\n [\n { name: \"{{user1}}\", content: { text: \"Who runs the city?\" } } as ActionExample,\n { name: \"{{agentName}}\", content: { text: \"Pulling the board...\", action: \"SYNDICATE_LEADERBOARD\" } } as ActionExample,\n ],\n ],\n validate: async () => true,\n handler: async (\n _runtime: IAgentRuntime,\n _message: Memory,\n _state?: State,\n _options?: Record<string, unknown>,\n callback?: HandlerCallback\n ): Promise<ActionResult | undefined> => {\n try {\n const res = await fetch(SCORES_API);\n const data = (await res.json()) as { scores?: { syndicate: string; headline: string; day: number; value: number; agent?: boolean; model?: string }[] };\n const rows = (data.scores || []).slice(0, 10);\n const text = rows.length\n ? rows\n .map(\n (s, i) =>\n `${i + 1}. ${s.syndicate} — $${s.value.toLocaleString()} (day ${s.day}) ${s.agent ? `[agent: ${s.model || \"unknown\"}]` : \"[human]\"} — ${s.headline}`\n )\n .join(\"\\n\")\n : \"The board is empty. The city is up for grabs.\";\n if (callback) await callback({ text });\n return { success: true, text, data: { scores: rows } };\n } catch (e) {\n const text = `Could not reach the leaderboard: ${e instanceof Error ? e.message : String(e)}`;\n if (callback) await callback({ text });\n return { success: false, text };\n }\n },\n};\n\n// ============================================================\n// Plugin\n// ============================================================\n\nexport const syndicatePlugin: Plugin = {\n name: \"plugin-syndicate\",\n description: `The Syndicate v${PLUGIN_VERSION} — agent-playable crime-city strategy with oracle-priced loot. Rules: ${SKILL_URL}`,\n actions: [newGameAction, stateAction, moveAction, leaderboardAction],\n providers: [],\n evaluators: [],\n};\n\nexport default syndicatePlugin;\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * The Syndicate — ElizaOS Plugin v0.1\n * ====================================\n * Lets any elizaOS agent run a crime family in The Syndicate: a deterministic,\n * turn-based 80×80 city where the loot is REAL trading cards priced by a live\n * on-chain TCG oracle. Each syndicate runs its OWN city; humans and agents\n * compete on one shared leaderboard.\n *\n * The game is server-authoritative — this plugin submits order INTENTS to the\n * public API and narrates what the engine resolved. There is no client-side\n * simulation and nothing to cheat.\n *\n * SYNDICATE_NEW start a game (one session per agent, kept in memory)\n * SYNDICATE_STATE read the current day without spending it\n * SYNDICATE_MOVE submit a day of orders and get the resolved events\n * SYNDICATE_LEADERBOARD the shared human+agent board\n *\n * Rules for models: https://play.the-undesirables.com/SKILL.md\n *\n * @see https://play.the-undesirables.com\n * @see https://github.com/sailorpepe/plugin-syndicate\n */\n\nimport type {\n Plugin,\n Action,\n Provider,\n ProviderResult,\n IAgentRuntime,\n Memory,\n State,\n HandlerCallback,\n ActionExample,\n ActionResult,\n} from \"@elizaos/core\";\n\nconst GAME_API = \"https://play.the-undesirables.com/api/game\";\nconst SCORES_API = \"https://play.the-undesirables.com/api/scores\";\nconst SKILL_URL = \"https://play.the-undesirables.com/SKILL.md\";\nconst PLUGIN_VERSION = \"0.2.0\";\nconst FETCH_TIMEOUT_MS = 15_000;\n\n// ============================================================\n// Session bookkeeping — one live game per agent, in-process.\n// The server holds all state; losing this map only means the\n// agent starts a fresh syndicate (sessions expire in 7 idle\n// days server-side anyway). The last view is cached so the\n// context provider can narrate game state with ZERO extra\n// API calls.\n// ============================================================\n\nconst sessions = new Map<string, string>(); // agentId -> sessionId\nconst lastViews = new Map<string, Record<string, unknown>>(); // agentId -> last view\n\nfunction sessionFor(runtime: IAgentRuntime): string | undefined {\n const configured = runtime.getSetting?.(\"SYNDICATE_SESSION_ID\");\n if (configured && typeof configured === \"string\") return configured;\n return sessions.get(String(runtime.agentId));\n}\n\n/** Marks errors the agent can act on (start a new game, wait out the limit). */\nclass GameError extends Error {\n constructor(message: string, readonly expired = false) { super(message); }\n}\n\nfunction toGameError(status: number, serverMsg: string): GameError {\n if (status === 404) return new GameError(\"Session unknown or expired (games expire after 7 idle days).\", true);\n if (status === 429) return new GameError(\"The city is rate-limited (30 calls/min/IP). Wait a minute, then try again.\");\n if (status === 409) return new GameError(serverMsg || \"Game over — start a new syndicate with SYNDICATE_NEW.\");\n return new GameError(serverMsg || `HTTP ${status}`);\n}\n\nasync function api(body: Record<string, unknown>): Promise<Record<string, unknown>> {\n const res = await fetch(GAME_API, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify(body),\n signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),\n });\n const data = (await res.json().catch(() => ({}))) as Record<string, unknown>;\n if (!res.ok) throw toGameError(res.status, String((data as { error?: string }).error || \"\"));\n return data;\n}\n\nasync function apiView(sessionId: string): Promise<Record<string, unknown>> {\n const res = await fetch(`${GAME_API}?id=${encodeURIComponent(sessionId)}`, {\n signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),\n });\n const data = (await res.json().catch(() => ({}))) as Record<string, unknown>;\n if (!res.ok) throw toGameError(res.status, String((data as { error?: string }).error || \"\"));\n return data;\n}\n\n/** On session expiry, forget it so validate() steers the agent to SYNDICATE_NEW. */\nfunction handleGameError(runtime: IAgentRuntime, e: unknown): string {\n if (e instanceof GameError && e.expired) {\n sessions.delete(String(runtime.agentId));\n lastViews.delete(String(runtime.agentId));\n return `${e.message} Start fresh with SYNDICATE_NEW.`;\n }\n if (e instanceof Error && e.name === \"TimeoutError\") {\n return \"The game server did not answer within 15s — it may be waking up. Try again shortly.\";\n }\n return e instanceof Error ? e.message : String(e);\n}\n\n// Compact narration so the model sees the day without drowning in JSON.\nfunction summarizeView(v: Record<string, unknown>): string {\n const events = Array.isArray(v.events) ? (v.events as string[]).slice(0, 12) : [];\n const crew = Array.isArray(v.crew) ? (v.crew as Record<string, unknown>[]) : [];\n const power = (v.power || {}) as Record<string, unknown>;\n const territory = (v.territory || {}) as Record<string, unknown>;\n const stash = (v.stash || {}) as Record<string, unknown>;\n const targets = Array.isArray(v.targets) ? (v.targets as Record<string, unknown>[]) : [];\n const beatable = targets.filter((t) => t.beatable !== \"no\").slice(0, 8);\n const weather = v.weather as Record<string, unknown> | undefined;\n const contract = v.contract as Record<string, unknown> | undefined;\n const wBet = v.weatherBet as Record<string, unknown> | undefined;\n const sBet = v.sportsBet as Record<string, unknown> | undefined;\n const lines = [\n `Day ${v.day} — capital $${v.capital}, heat ${v.heat}, wanted ${v.wantedLevel}`,\n ...(weather ? [`Chicago weather (REAL, shifts today's odds): ${weather.condition}, ${weather.tempF}°F — ${weather.kind}`] : []),\n ...(contract ? [`Commission contract: ${(contract as { desc?: string }).desc}`] : []),\n ...(wBet ? [`Open weather ticket: $${wBet.stake} on ${wBet.on}`] : []),\n ...(sBet ? [`Open sports ticket: $${sBet.stake} on ${sBet.playerName} (${sBet.prop})`] : []),\n `Territory: ${territory.ownedTiles}/${territory.tilesToWin} tiles toward the Kingpin win`,\n `Stash: ${stash.cards} card(s), fence value $${stash.fenceValue}`,\n `Crew: ${crew.map((c) => `${c.name} (hp ${c.hp}${(c as { unavailable?: string }).unavailable ? `, ${(c as { unavailable?: string }).unavailable}` : \"\"})`).join(\" · \")}`,\n `Power: best solo ${power.bestSolo} (${power.bestSoloAgentName}), full squad ${power.fullSquad}`,\n beatable.length\n ? `Beatable now: ${beatable.map((t) => `#${t.tileId} ${t.type} vault $${t.vault} (${t.beatable})`).join(\", \")}`\n : `Nothing is beatable right now — hire muscle or squad up.`,\n ];\n if (events.length) lines.push(\"\", \"What happened:\", ...events.map((e) => ` ${e}`));\n if (v.gameOver) lines.push(\"\", \"GAME OVER — start a new syndicate with SYNDICATE_NEW.\");\n if (v.sessionId) lines.push(\"\", `(session ${v.sessionId} — set SYNDICATE_SESSION_ID to resume it after a restart)`);\n return lines.join(\"\\n\");\n}\n\nfunction remember(runtime: IAgentRuntime, view: Record<string, unknown>): void {\n lastViews.set(String(runtime.agentId), view);\n}\n\n// ============================================================\n// Actions\n// ============================================================\n\nconst newGameAction: Action = {\n name: \"SYNDICATE_NEW\",\n description:\n \"Start a new game of The Syndicate. Creates a fresh crime family in a deterministic 80×80 city. One session per agent; the old session is abandoned.\",\n similes: [\"START_SYNDICATE\", \"NEW_CRIME_FAMILY\", \"PLAY_SYNDICATE\"],\n parameters: [\n {\n name: \"syndicate_name\",\n description: \"Name for your crime family (max 32 chars)\",\n required: false,\n schema: { type: \"string\" },\n },\n ],\n examples: [\n [\n { name: \"{{user1}}\", content: { text: \"Start a syndicate called The Night Owls\" } } as ActionExample,\n { name: \"{{agentName}}\", content: { text: \"Founding The Night Owls...\", action: \"SYNDICATE_NEW\" } } as ActionExample,\n ],\n ],\n validate: async () => true,\n handler: async (\n runtime: IAgentRuntime,\n message: Memory,\n _state?: State,\n options?: Record<string, unknown>,\n callback?: HandlerCallback\n ): Promise<ActionResult | undefined> => {\n const name =\n (options?.syndicate_name as string) ||\n message.content.text?.match(/called\\s+(.{2,32}?)(?:\\.|$)/i)?.[1] ||\n `${runtime.character?.name || \"Agent\"} Syndicate`;\n try {\n const view = await api({ action: \"new\", name: name.slice(0, 32), model: `elizaos/${runtime.character?.name || \"agent\"}` });\n sessions.set(String(runtime.agentId), String(view.sessionId));\n remember(runtime, view);\n const text = `New syndicate founded. Read the rules once: ${SKILL_URL}\\n\\n${summarizeView(view)}`;\n if (callback) await callback({ text });\n return { success: true, text, data: { sessionId: String(view.sessionId), view } };\n } catch (e) {\n const text = `Could not start a game: ${handleGameError(runtime, e)}`;\n if (callback) await callback({ text });\n return { success: false, text };\n }\n },\n};\n\nconst stateAction: Action = {\n name: \"SYNDICATE_STATE\",\n description:\n \"Read the current state of your Syndicate game WITHOUT spending a day: crew, capital, heat, stash value, beatable targets, and progress toward the Kingpin win.\",\n similes: [\"SYNDICATE_STATUS\", \"CHECK_SYNDICATE\", \"GAME_STATE\"],\n parameters: [],\n examples: [\n [\n { name: \"{{user1}}\", content: { text: \"How is the syndicate doing?\" } } as ActionExample,\n { name: \"{{agentName}}\", content: { text: \"Checking the city...\", action: \"SYNDICATE_STATE\" } } as ActionExample,\n ],\n ],\n validate: async (runtime: IAgentRuntime) => sessionFor(runtime) !== undefined,\n handler: async (\n runtime: IAgentRuntime,\n _message: Memory,\n _state?: State,\n _options?: Record<string, unknown>,\n callback?: HandlerCallback\n ): Promise<ActionResult | undefined> => {\n const sessionId = sessionFor(runtime);\n if (!sessionId) {\n const text = \"No game running — use SYNDICATE_NEW to found a syndicate.\";\n if (callback) await callback({ text });\n return { success: false, text };\n }\n try {\n const view = await apiView(sessionId);\n remember(runtime, view);\n const text = summarizeView(view);\n if (callback) await callback({ text });\n return { success: true, text, data: { view } };\n } catch (e) {\n const text = `Could not read the game: ${handleGameError(runtime, e)}`;\n if (callback) await callback({ text });\n return { success: false, text };\n }\n },\n};\n\nconst moveAction: Action = {\n name: \"SYNDICATE_MOVE\",\n description:\n \"Submit one day of orders to The Syndicate and get back what the engine resolved. Orders are [{agentId, targetId, actionType, squad?}] — one per crew member. Self verbs (heal, pray, lay_low, retain, injunction, cook_books, audit, launder, weather_bet, sports_bet) may omit targetId. Betting (in-game capital only): {actionType:'weather_bet', on:'rain', stake:500} on tomorrow's REAL Chicago weather; {actionType:'sports_bet', playerId, prop:'hr', stake:500} on a real MLB player's next game — pick playerId from sportsBook.featured. Check SYNDICATE_STATE first: 'beatable: solo' assumes your STRONGEST member leads.\",\n similes: [\"SYNDICATE_ORDERS\", \"PLAY_TURN\", \"RUN_THE_DAY\"],\n parameters: [\n {\n name: \"orders\",\n description:\n 'JSON array of orders, e.g. [{\"agentId\":123,\"targetId\":612,\"actionType\":\"raid\",\"squad\":[124,156]}]. An empty array passes the day (the world still moves).',\n required: true,\n schema: { type: \"string\" },\n },\n ],\n examples: [\n [\n { name: \"{{user1}}\", content: { text: \"Send Rogue to raid the accountant at tile 612\" } } as ActionExample,\n { name: \"{{agentName}}\", content: { text: \"Running the day...\", action: \"SYNDICATE_MOVE\" } } as ActionExample,\n ],\n ],\n validate: async (runtime: IAgentRuntime) => sessionFor(runtime) !== undefined,\n handler: async (\n runtime: IAgentRuntime,\n message: Memory,\n _state?: State,\n options?: Record<string, unknown>,\n callback?: HandlerCallback\n ): Promise<ActionResult | undefined> => {\n const sessionId = sessionFor(runtime);\n if (!sessionId) {\n const text = \"No game running — use SYNDICATE_NEW to found a syndicate.\";\n if (callback) await callback({ text });\n return { success: false, text };\n }\n let orders: unknown = [];\n const raw = (options?.orders as string) || message.content.text?.match(/\\[[\\s\\S]*\\]/)?.[0] || \"[]\";\n try {\n orders = typeof raw === \"string\" ? JSON.parse(raw) : raw;\n if (!Array.isArray(orders)) throw new Error(\"orders must be a JSON array\");\n } catch (e) {\n const text = `Could not parse orders (${e instanceof Error ? e.message : String(e)}). Expected: [{\"agentId\":ID,\"targetId\":TILE,\"actionType\":\"VERB\"}]`;\n if (callback) await callback({ text });\n return { success: false, text };\n }\n try {\n const view = await api({ action: \"orders\", sessionId, orders });\n remember(runtime, view);\n const text = summarizeView(view);\n if (callback) await callback({ text });\n return { success: true, text, data: { view } };\n } catch (e) {\n const text = `The engine rejected the orders: ${handleGameError(runtime, e)}`;\n if (callback) await callback({ text });\n return { success: false, text };\n }\n },\n};\n\nconst leaderboardAction: Action = {\n name: \"SYNDICATE_LEADERBOARD\",\n description:\n \"Read The Syndicate's shared leaderboard — humans and agents on one board, scored by capital, with agent entries flagged by model.\",\n similes: [\"SYNDICATE_SCORES\", \"TOP_SYNDICATES\", \"CRIME_LEADERBOARD\"],\n parameters: [],\n examples: [\n [\n { name: \"{{user1}}\", content: { text: \"Who runs the city?\" } } as ActionExample,\n { name: \"{{agentName}}\", content: { text: \"Pulling the board...\", action: \"SYNDICATE_LEADERBOARD\" } } as ActionExample,\n ],\n ],\n validate: async () => true,\n handler: async (\n _runtime: IAgentRuntime,\n _message: Memory,\n _state?: State,\n _options?: Record<string, unknown>,\n callback?: HandlerCallback\n ): Promise<ActionResult | undefined> => {\n try {\n const res = await fetch(SCORES_API, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS) });\n const data = (await res.json()) as { scores?: { syndicate: string; headline: string; day: number; value: number; agent?: boolean; model?: string }[] };\n const rows = (data.scores || []).slice(0, 10);\n const text = rows.length\n ? rows\n .map(\n (s, i) =>\n `${i + 1}. ${s.syndicate} — $${s.value.toLocaleString()} (day ${s.day}) ${s.agent ? `[agent: ${s.model || \"unknown\"}]` : \"[human]\"} — ${s.headline}`\n )\n .join(\"\\n\")\n : \"The board is empty. The city is up for grabs.\";\n if (callback) await callback({ text });\n return { success: true, text, data: { scores: rows } };\n } catch (e) {\n const text = `Could not reach the leaderboard: ${e instanceof Error ? e.message : String(e)}`;\n if (callback) await callback({ text });\n return { success: false, text };\n }\n },\n};\n\n// ============================================================\n// Provider — narrates the cached game state into context on\n// every message, with ZERO extra API calls. The cache is only\n// written by the actions, so this can never spam the server.\n// ============================================================\n\nconst syndicateProvider: Provider = {\n name: \"syndicate-game-state\",\n description: \"Current state of the agent's Syndicate game (cached from the last action; no network calls)\",\n get: async (runtime: IAgentRuntime, _message: Memory, _state?: State): Promise<ProviderResult> => {\n const view = lastViews.get(String(runtime.agentId));\n if (!view || !sessionFor(runtime)) return { text: \"\" };\n const territory = (view.territory || {}) as Record<string, unknown>;\n const stash = (view.stash || {}) as Record<string, unknown>;\n return {\n text: `[The Syndicate — day ${view.day}: capital $${view.capital}, heat ${view.heat}, ` +\n `${territory.ownedTiles}/${territory.tilesToWin} tiles, stash $${stash.fenceValue}. ` +\n `Use SYNDICATE_STATE for detail, SYNDICATE_MOVE to play the day.]`,\n data: { view },\n };\n },\n};\n\n// ============================================================\n// Plugin\n// ============================================================\n\nexport const syndicatePlugin: Plugin = {\n name: \"plugin-syndicate\",\n description: `The Syndicate v${PLUGIN_VERSION} — agent-playable crime-city strategy with oracle-priced loot. Rules: ${SKILL_URL}`,\n actions: [newGameAction, stateAction, moveAction, leaderboardAction],\n providers: [syndicateProvider],\n evaluators: [],\n};\n\nexport default syndicatePlugin;\n"],"mappings":";AAoCA,IAAM,WAAW;AACjB,IAAM,aAAa;AACnB,IAAM,YAAY;AAClB,IAAM,iBAAiB;AACvB,IAAM,mBAAmB;AAWzB,IAAM,WAAW,oBAAI,IAAoB;AACzC,IAAM,YAAY,oBAAI,IAAqC;AAE3D,SAAS,WAAW,SAA4C;AAC9D,QAAM,aAAa,QAAQ,aAAa,sBAAsB;AAC9D,MAAI,cAAc,OAAO,eAAe,SAAU,QAAO;AACzD,SAAO,SAAS,IAAI,OAAO,QAAQ,OAAO,CAAC;AAC7C;AAGA,IAAM,YAAN,cAAwB,MAAM;AAAA,EAC5B,YAAY,SAA0B,UAAU,OAAO;AAAE,UAAM,OAAO;AAAhC;AAAA,EAAmC;AAAA,EAAnC;AACxC;AAEA,SAAS,YAAY,QAAgB,WAA8B;AACjE,MAAI,WAAW,IAAK,QAAO,IAAI,UAAU,gEAAgE,IAAI;AAC7G,MAAI,WAAW,IAAK,QAAO,IAAI,UAAU,4EAA4E;AACrH,MAAI,WAAW,IAAK,QAAO,IAAI,UAAU,aAAa,4DAAuD;AAC7G,SAAO,IAAI,UAAU,aAAa,QAAQ,MAAM,EAAE;AACpD;AAEA,eAAe,IAAI,MAAiE;AAClF,QAAM,MAAM,MAAM,MAAM,UAAU;AAAA,IAChC,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,IAC9C,MAAM,KAAK,UAAU,IAAI;AAAA,IACzB,QAAQ,YAAY,QAAQ,gBAAgB;AAAA,EAC9C,CAAC;AACD,QAAM,OAAQ,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AAC/C,MAAI,CAAC,IAAI,GAAI,OAAM,YAAY,IAAI,QAAQ,OAAQ,KAA4B,SAAS,EAAE,CAAC;AAC3F,SAAO;AACT;AAEA,eAAe,QAAQ,WAAqD;AAC1E,QAAM,MAAM,MAAM,MAAM,GAAG,QAAQ,OAAO,mBAAmB,SAAS,CAAC,IAAI;AAAA,IACzE,QAAQ,YAAY,QAAQ,gBAAgB;AAAA,EAC9C,CAAC;AACD,QAAM,OAAQ,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AAC/C,MAAI,CAAC,IAAI,GAAI,OAAM,YAAY,IAAI,QAAQ,OAAQ,KAA4B,SAAS,EAAE,CAAC;AAC3F,SAAO;AACT;AAGA,SAAS,gBAAgB,SAAwB,GAAoB;AACnE,MAAI,aAAa,aAAa,EAAE,SAAS;AACvC,aAAS,OAAO,OAAO,QAAQ,OAAO,CAAC;AACvC,cAAU,OAAO,OAAO,QAAQ,OAAO,CAAC;AACxC,WAAO,GAAG,EAAE,OAAO;AAAA,EACrB;AACA,MAAI,aAAa,SAAS,EAAE,SAAS,gBAAgB;AACnD,WAAO;AAAA,EACT;AACA,SAAO,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AAClD;AAGA,SAAS,cAAc,GAAoC;AACzD,QAAM,SAAS,MAAM,QAAQ,EAAE,MAAM,IAAK,EAAE,OAAoB,MAAM,GAAG,EAAE,IAAI,CAAC;AAChF,QAAM,OAAO,MAAM,QAAQ,EAAE,IAAI,IAAK,EAAE,OAAqC,CAAC;AAC9E,QAAM,QAAS,EAAE,SAAS,CAAC;AAC3B,QAAM,YAAa,EAAE,aAAa,CAAC;AACnC,QAAM,QAAS,EAAE,SAAS,CAAC;AAC3B,QAAM,UAAU,MAAM,QAAQ,EAAE,OAAO,IAAK,EAAE,UAAwC,CAAC;AACvF,QAAM,WAAW,QAAQ,OAAO,CAAC,MAAM,EAAE,aAAa,IAAI,EAAE,MAAM,GAAG,CAAC;AACtE,QAAM,UAAU,EAAE;AAClB,QAAM,WAAW,EAAE;AACnB,QAAM,OAAO,EAAE;AACf,QAAM,OAAO,EAAE;AACf,QAAM,QAAQ;AAAA,IACZ,OAAO,EAAE,GAAG,oBAAe,EAAE,OAAO,UAAU,EAAE,IAAI,YAAY,EAAE,WAAW;AAAA,IAC7E,GAAI,UAAU,CAAC,gDAAgD,QAAQ,SAAS,KAAK,QAAQ,KAAK,gBAAQ,QAAQ,IAAI,EAAE,IAAI,CAAC;AAAA,IAC7H,GAAI,WAAW,CAAC,wBAAyB,SAA+B,IAAI,EAAE,IAAI,CAAC;AAAA,IACnF,GAAI,OAAO,CAAC,yBAAyB,KAAK,KAAK,OAAO,KAAK,EAAE,EAAE,IAAI,CAAC;AAAA,IACpE,GAAI,OAAO,CAAC,wBAAwB,KAAK,KAAK,OAAO,KAAK,UAAU,KAAK,KAAK,IAAI,GAAG,IAAI,CAAC;AAAA,IAC1F,cAAc,UAAU,UAAU,IAAI,UAAU,UAAU;AAAA,IAC1D,UAAU,MAAM,KAAK,0BAA0B,MAAM,UAAU;AAAA,IAC/D,SAAS,KAAK,IAAI,CAAC,MAAM,GAAG,EAAE,IAAI,QAAQ,EAAE,EAAE,GAAI,EAA+B,cAAc,KAAM,EAA+B,WAAW,KAAK,EAAE,GAAG,EAAE,KAAK,QAAK,CAAC;AAAA,IACtK,oBAAoB,MAAM,QAAQ,KAAK,MAAM,iBAAiB,iBAAiB,MAAM,SAAS;AAAA,IAC9F,SAAS,SACL,iBAAiB,SAAS,IAAI,CAAC,MAAM,IAAI,EAAE,MAAM,IAAI,EAAE,IAAI,WAAW,EAAE,KAAK,KAAK,EAAE,QAAQ,GAAG,EAAE,KAAK,IAAI,CAAC,KAC3G;AAAA,EACN;AACA,MAAI,OAAO,OAAQ,OAAM,KAAK,IAAI,kBAAkB,GAAG,OAAO,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;AAClF,MAAI,EAAE,SAAU,OAAM,KAAK,IAAI,4DAAuD;AACtF,MAAI,EAAE,UAAW,OAAM,KAAK,IAAI,YAAY,EAAE,SAAS,gEAA2D;AAClH,SAAO,MAAM,KAAK,IAAI;AACxB;AAEA,SAAS,SAAS,SAAwB,MAAqC;AAC7E,YAAU,IAAI,OAAO,QAAQ,OAAO,GAAG,IAAI;AAC7C;AAMA,IAAM,gBAAwB;AAAA,EAC5B,MAAM;AAAA,EACN,aACE;AAAA,EACF,SAAS,CAAC,mBAAmB,oBAAoB,gBAAgB;AAAA,EACjE,YAAY;AAAA,IACV;AAAA,MACE,MAAM;AAAA,MACN,aAAa;AAAA,MACb,UAAU;AAAA,MACV,QAAQ,EAAE,MAAM,SAAS;AAAA,IAC3B;AAAA,EACF;AAAA,EACA,UAAU;AAAA,IACR;AAAA,MACE,EAAE,MAAM,aAAa,SAAS,EAAE,MAAM,0CAA0C,EAAE;AAAA,MAClF,EAAE,MAAM,iBAAiB,SAAS,EAAE,MAAM,8BAA8B,QAAQ,gBAAgB,EAAE;AAAA,IACpG;AAAA,EACF;AAAA,EACA,UAAU,YAAY;AAAA,EACtB,SAAS,OACP,SACA,SACA,QACA,SACA,aACsC;AACtC,UAAM,OACH,SAAS,kBACV,QAAQ,QAAQ,MAAM,MAAM,8BAA8B,IAAI,CAAC,KAC/D,GAAG,QAAQ,WAAW,QAAQ,OAAO;AACvC,QAAI;AACF,YAAM,OAAO,MAAM,IAAI,EAAE,QAAQ,OAAO,MAAM,KAAK,MAAM,GAAG,EAAE,GAAG,OAAO,WAAW,QAAQ,WAAW,QAAQ,OAAO,GAAG,CAAC;AACzH,eAAS,IAAI,OAAO,QAAQ,OAAO,GAAG,OAAO,KAAK,SAAS,CAAC;AAC5D,eAAS,SAAS,IAAI;AACtB,YAAM,OAAO,+CAA+C,SAAS;AAAA;AAAA,EAAO,cAAc,IAAI,CAAC;AAC/F,UAAI,SAAU,OAAM,SAAS,EAAE,KAAK,CAAC;AACrC,aAAO,EAAE,SAAS,MAAM,MAAM,MAAM,EAAE,WAAW,OAAO,KAAK,SAAS,GAAG,KAAK,EAAE;AAAA,IAClF,SAAS,GAAG;AACV,YAAM,OAAO,2BAA2B,gBAAgB,SAAS,CAAC,CAAC;AACnE,UAAI,SAAU,OAAM,SAAS,EAAE,KAAK,CAAC;AACrC,aAAO,EAAE,SAAS,OAAO,KAAK;AAAA,IAChC;AAAA,EACF;AACF;AAEA,IAAM,cAAsB;AAAA,EAC1B,MAAM;AAAA,EACN,aACE;AAAA,EACF,SAAS,CAAC,oBAAoB,mBAAmB,YAAY;AAAA,EAC7D,YAAY,CAAC;AAAA,EACb,UAAU;AAAA,IACR;AAAA,MACE,EAAE,MAAM,aAAa,SAAS,EAAE,MAAM,8BAA8B,EAAE;AAAA,MACtE,EAAE,MAAM,iBAAiB,SAAS,EAAE,MAAM,wBAAwB,QAAQ,kBAAkB,EAAE;AAAA,IAChG;AAAA,EACF;AAAA,EACA,UAAU,OAAO,YAA2B,WAAW,OAAO,MAAM;AAAA,EACpE,SAAS,OACP,SACA,UACA,QACA,UACA,aACsC;AACtC,UAAM,YAAY,WAAW,OAAO;AACpC,QAAI,CAAC,WAAW;AACd,YAAM,OAAO;AACb,UAAI,SAAU,OAAM,SAAS,EAAE,KAAK,CAAC;AACrC,aAAO,EAAE,SAAS,OAAO,KAAK;AAAA,IAChC;AACA,QAAI;AACF,YAAM,OAAO,MAAM,QAAQ,SAAS;AACpC,eAAS,SAAS,IAAI;AACtB,YAAM,OAAO,cAAc,IAAI;AAC/B,UAAI,SAAU,OAAM,SAAS,EAAE,KAAK,CAAC;AACrC,aAAO,EAAE,SAAS,MAAM,MAAM,MAAM,EAAE,KAAK,EAAE;AAAA,IAC/C,SAAS,GAAG;AACV,YAAM,OAAO,4BAA4B,gBAAgB,SAAS,CAAC,CAAC;AACpE,UAAI,SAAU,OAAM,SAAS,EAAE,KAAK,CAAC;AACrC,aAAO,EAAE,SAAS,OAAO,KAAK;AAAA,IAChC;AAAA,EACF;AACF;AAEA,IAAM,aAAqB;AAAA,EACzB,MAAM;AAAA,EACN,aACE;AAAA,EACF,SAAS,CAAC,oBAAoB,aAAa,aAAa;AAAA,EACxD,YAAY;AAAA,IACV;AAAA,MACE,MAAM;AAAA,MACN,aACE;AAAA,MACF,UAAU;AAAA,MACV,QAAQ,EAAE,MAAM,SAAS;AAAA,IAC3B;AAAA,EACF;AAAA,EACA,UAAU;AAAA,IACR;AAAA,MACE,EAAE,MAAM,aAAa,SAAS,EAAE,MAAM,gDAAgD,EAAE;AAAA,MACxF,EAAE,MAAM,iBAAiB,SAAS,EAAE,MAAM,sBAAsB,QAAQ,iBAAiB,EAAE;AAAA,IAC7F;AAAA,EACF;AAAA,EACA,UAAU,OAAO,YAA2B,WAAW,OAAO,MAAM;AAAA,EACpE,SAAS,OACP,SACA,SACA,QACA,SACA,aACsC;AACtC,UAAM,YAAY,WAAW,OAAO;AACpC,QAAI,CAAC,WAAW;AACd,YAAM,OAAO;AACb,UAAI,SAAU,OAAM,SAAS,EAAE,KAAK,CAAC;AACrC,aAAO,EAAE,SAAS,OAAO,KAAK;AAAA,IAChC;AACA,QAAI,SAAkB,CAAC;AACvB,UAAM,MAAO,SAAS,UAAqB,QAAQ,QAAQ,MAAM,MAAM,aAAa,IAAI,CAAC,KAAK;AAC9F,QAAI;AACF,eAAS,OAAO,QAAQ,WAAW,KAAK,MAAM,GAAG,IAAI;AACrD,UAAI,CAAC,MAAM,QAAQ,MAAM,EAAG,OAAM,IAAI,MAAM,6BAA6B;AAAA,IAC3E,SAAS,GAAG;AACV,YAAM,OAAO,2BAA2B,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC,CAAC;AAClF,UAAI,SAAU,OAAM,SAAS,EAAE,KAAK,CAAC;AACrC,aAAO,EAAE,SAAS,OAAO,KAAK;AAAA,IAChC;AACA,QAAI;AACF,YAAM,OAAO,MAAM,IAAI,EAAE,QAAQ,UAAU,WAAW,OAAO,CAAC;AAC9D,eAAS,SAAS,IAAI;AACtB,YAAM,OAAO,cAAc,IAAI;AAC/B,UAAI,SAAU,OAAM,SAAS,EAAE,KAAK,CAAC;AACrC,aAAO,EAAE,SAAS,MAAM,MAAM,MAAM,EAAE,KAAK,EAAE;AAAA,IAC/C,SAAS,GAAG;AACV,YAAM,OAAO,mCAAmC,gBAAgB,SAAS,CAAC,CAAC;AAC3E,UAAI,SAAU,OAAM,SAAS,EAAE,KAAK,CAAC;AACrC,aAAO,EAAE,SAAS,OAAO,KAAK;AAAA,IAChC;AAAA,EACF;AACF;AAEA,IAAM,oBAA4B;AAAA,EAChC,MAAM;AAAA,EACN,aACE;AAAA,EACF,SAAS,CAAC,oBAAoB,kBAAkB,mBAAmB;AAAA,EACnE,YAAY,CAAC;AAAA,EACb,UAAU;AAAA,IACR;AAAA,MACE,EAAE,MAAM,aAAa,SAAS,EAAE,MAAM,qBAAqB,EAAE;AAAA,MAC7D,EAAE,MAAM,iBAAiB,SAAS,EAAE,MAAM,wBAAwB,QAAQ,wBAAwB,EAAE;AAAA,IACtG;AAAA,EACF;AAAA,EACA,UAAU,YAAY;AAAA,EACtB,SAAS,OACP,UACA,UACA,QACA,UACA,aACsC;AACtC,QAAI;AACF,YAAM,MAAM,MAAM,MAAM,YAAY,EAAE,QAAQ,YAAY,QAAQ,gBAAgB,EAAE,CAAC;AACrF,YAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,YAAM,QAAQ,KAAK,UAAU,CAAC,GAAG,MAAM,GAAG,EAAE;AAC5C,YAAM,OAAO,KAAK,SACd,KACG;AAAA,QACC,CAAC,GAAG,MACF,GAAG,IAAI,CAAC,KAAK,EAAE,SAAS,YAAO,EAAE,MAAM,eAAe,CAAC,SAAS,EAAE,GAAG,KAAK,EAAE,QAAQ,WAAW,EAAE,SAAS,SAAS,MAAM,SAAS,WAAM,EAAE,QAAQ;AAAA,MACtJ,EACC,KAAK,IAAI,IACZ;AACJ,UAAI,SAAU,OAAM,SAAS,EAAE,KAAK,CAAC;AACrC,aAAO,EAAE,SAAS,MAAM,MAAM,MAAM,EAAE,QAAQ,KAAK,EAAE;AAAA,IACvD,SAAS,GAAG;AACV,YAAM,OAAO,oCAAoC,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC,CAAC;AAC3F,UAAI,SAAU,OAAM,SAAS,EAAE,KAAK,CAAC;AACrC,aAAO,EAAE,SAAS,OAAO,KAAK;AAAA,IAChC;AAAA,EACF;AACF;AAQA,IAAM,oBAA8B;AAAA,EAClC,MAAM;AAAA,EACN,aAAa;AAAA,EACb,KAAK,OAAO,SAAwB,UAAkB,WAA4C;AAChG,UAAM,OAAO,UAAU,IAAI,OAAO,QAAQ,OAAO,CAAC;AAClD,QAAI,CAAC,QAAQ,CAAC,WAAW,OAAO,EAAG,QAAO,EAAE,MAAM,GAAG;AACrD,UAAM,YAAa,KAAK,aAAa,CAAC;AACtC,UAAM,QAAS,KAAK,SAAS,CAAC;AAC9B,WAAO;AAAA,MACL,MAAM,6BAAwB,KAAK,GAAG,cAAc,KAAK,OAAO,UAAU,KAAK,IAAI,KAC9E,UAAU,UAAU,IAAI,UAAU,UAAU,kBAAkB,MAAM,UAAU;AAAA,MAEnF,MAAM,EAAE,KAAK;AAAA,IACf;AAAA,EACF;AACF;AAMO,IAAM,kBAA0B;AAAA,EACrC,MAAM;AAAA,EACN,aAAa,kBAAkB,cAAc,8EAAyE,SAAS;AAAA,EAC/H,SAAS,CAAC,eAAe,aAAa,YAAY,iBAAiB;AAAA,EACnE,WAAW,CAAC,iBAAiB;AAAA,EAC7B,YAAY,CAAC;AACf;AAEA,IAAO,gBAAQ;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "plugin-syndicate",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Play The Syndicate from any elizaOS agent — a deterministic, turn-based crime-city game where the loot is real trading cards priced by a live on-chain TCG oracle.
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Play The Syndicate from any elizaOS agent — a deterministic, turn-based crime-city game where the loot is real trading cards priced by a live on-chain TCG oracle. Each syndicate runs its own city; humans and agents compete on one shared leaderboard.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"module": "dist/index.js",
|