pyre-world-kit 3.0.1 → 3.0.3

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/dist/index.d.ts CHANGED
@@ -6,17 +6,15 @@
6
6
  * so agents think in factions, not tokens.
7
7
  */
8
8
  import { Connection } from '@solana/web3.js';
9
- import { ActionProvider } from './providers/action.provider';
10
- import { IntelProvider } from './providers/intel.provider';
11
- import { RegistryProvider } from './providers/registry.provider';
9
+ import { Action } from './types/action.types';
10
+ import { Intel } from './types/intel.types';
11
+ import { Registry } from './types/registry.types';
12
12
  import { StateProvider } from './providers/state.provider';
13
- import type { Action } from './types/action.types';
14
- import type { Intel } from './types/intel.types';
15
13
  import type { CheckpointConfig } from './types/state.types';
16
14
  export declare class PyreKit {
17
- readonly actions: ActionProvider;
18
- readonly intel: IntelProvider;
19
- readonly registry: RegistryProvider;
15
+ readonly actions: Action;
16
+ readonly intel: Intel;
17
+ readonly registry: Registry;
20
18
  readonly state: StateProvider;
21
19
  constructor(connection: Connection, publicKey: string);
22
20
  /** Callback fired when checkpoint interval is reached */
package/dist/index.js CHANGED
@@ -20,8 +20,8 @@ class PyreKit {
20
20
  state;
21
21
  constructor(connection, publicKey) {
22
22
  this.registry = new registry_provider_1.RegistryProvider(connection);
23
- this.state = new state_provider_1.StateProvider(connection, publicKey, this.registry);
24
- this.actions = new action_provider_1.ActionProvider(connection);
23
+ this.state = new state_provider_1.StateProvider(connection, this.registry, publicKey);
24
+ this.actions = new action_provider_1.ActionProvider(connection, this.registry);
25
25
  this.intel = new intel_provider_1.IntelProvider(connection, this.actions);
26
26
  // Wire auto-checkpoint callback
27
27
  this.state.onCheckpointDue = () => this.onCheckpointDue?.();
@@ -1,11 +1,13 @@
1
1
  import { Connection } from '@solana/web3.js';
2
- import { Action } from '../types/action.types';
3
2
  import { BuyQuoteResult, SellQuoteResult, TransactionResult } from 'torchsdk';
4
3
  import { AgentLink, AllWarLoansResult, AscendParams, ClaimSpoilsParams, CommsResult, CoupParams, CreateStrongholdParams, DefectParams, ExileAgentParams, FactionDetail, FactionListParams, FactionListResult, FactionStatus, FudFactionParams, FundStrongholdParams, JoinFactionParams, JoinFactionResult, LaunchFactionParams, LaunchFactionResult, MembersResult, MessageFactionParams, RallyParams, RazeParams, RecruitAgentParams, RepayWarLoanParams, RequestWarLoanParams, SiegeParams, Stronghold, TitheParams, WarChest, WarLoan, WarLoanQuote, WithdrawAssetsParams, WithdrawFromStrongholdParams } from '../types';
4
+ import { Action } from '../types/action.types';
5
+ import { Registry } from '../types/registry.types';
5
6
  export declare class ActionProvider implements Action {
6
7
  private connection;
8
+ private registryProvider;
7
9
  private mapper;
8
- constructor(connection: Connection);
10
+ constructor(connection: Connection, registryProvider: Registry);
9
11
  createStronghold(params: CreateStrongholdParams): Promise<TransactionResult>;
10
12
  coup(params: CoupParams): Promise<TransactionResult>;
11
13
  exileAgent(params: ExileAgentParams): Promise<TransactionResult>;
@@ -41,6 +43,7 @@ export declare class ActionProvider implements Action {
41
43
  raze(params: RazeParams): Promise<TransactionResult>;
42
44
  repayWarLoan(params: RepayWarLoanParams): Promise<TransactionResult>;
43
45
  requestWarLoan(params: RequestWarLoanParams): Promise<TransactionResult>;
46
+ scout(targetAddress: string): Promise<string>;
44
47
  siege(params: SiegeParams): Promise<TransactionResult>;
45
48
  tithe(params: TitheParams): Promise<TransactionResult>;
46
49
  }
@@ -8,9 +8,11 @@ const vanity_1 = require("../vanity");
8
8
  const util_1 = require("../util");
9
9
  class ActionProvider {
10
10
  connection;
11
+ registryProvider;
11
12
  mapper = new mapper_provider_1.MapperProvider();
12
- constructor(connection) {
13
+ constructor(connection, registryProvider) {
13
14
  this.connection = connection;
15
+ this.registryProvider = registryProvider;
14
16
  }
15
17
  async createStronghold(params) {
16
18
  return (0, torchsdk_1.buildCreateVaultTransaction)(this.connection, { creator: params.creator });
@@ -310,6 +312,55 @@ class ActionProvider {
310
312
  vault: params.stronghold,
311
313
  });
312
314
  }
315
+ async scout(targetAddress) {
316
+ try {
317
+ const p = await this.registryProvider.getProfile(targetAddress);
318
+ if (!p)
319
+ return ` @${targetAddress.slice(0, 8)}: no pyre identity found`;
320
+ const total = p.joins +
321
+ p.defects +
322
+ p.rallies +
323
+ p.launches +
324
+ p.messages +
325
+ p.fuds +
326
+ p.infiltrates +
327
+ p.reinforces +
328
+ p.war_loans +
329
+ p.repay_loans +
330
+ p.sieges +
331
+ p.ascends +
332
+ p.razes +
333
+ p.tithes;
334
+ const topActions = [
335
+ { n: 'joins', v: p.joins },
336
+ { n: 'defects', v: p.defects },
337
+ { n: 'rallies', v: p.rallies },
338
+ { n: 'messages', v: p.messages },
339
+ { n: 'fuds', v: p.fuds },
340
+ { n: 'infiltrates', v: p.infiltrates },
341
+ { n: 'reinforces', v: p.reinforces },
342
+ { n: 'war_loans', v: p.war_loans },
343
+ { n: 'sieges', v: p.sieges },
344
+ ]
345
+ .sort((a, b) => b.v - a.v)
346
+ .filter((a) => a.v > 0)
347
+ .slice(0, 4)
348
+ .map((a) => `${a.n}:${a.v}`)
349
+ .join(', ');
350
+ const personality = p.personality_summary || 'unknown';
351
+ const checkpoint = p.last_checkpoint > 0
352
+ ? new Date(p.last_checkpoint * 1000).toISOString().slice(0, 10)
353
+ : 'never';
354
+ const spent = (p.total_sol_spent ?? 0) / 1e9;
355
+ const received = (p.total_sol_received ?? 0) / 1e9;
356
+ const pnl = received - spent;
357
+ const pnlStr = pnl >= 0 ? `+${pnl.toFixed(3)}` : pnl.toFixed(3);
358
+ return ` @${targetAddress.slice(0, 8)}: "${personality}" | ${total} actions (${topActions}) | P&L: ${pnlStr} SOL | last seen: ${checkpoint}`;
359
+ }
360
+ catch {
361
+ return ` @${targetAddress.slice(0, 8)}: lookup failed`;
362
+ }
363
+ }
313
364
  async siege(params) {
314
365
  return (0, torchsdk_1.buildLiquidateTransaction)(this.connection, {
315
366
  mint: params.mint,
@@ -1,8 +1,3 @@
1
- /**
2
- * Pyre Kit Mappers
3
- *
4
- * Internal mapping functions between Torch SDK types and Pyre game types.
5
- */
6
1
  import type { AllLoanPositionsResult, BuyTransactionResult, CreateTokenResult, Holder, HoldersResult, LendingInfo, LoanPositionInfo, LoanPositionWithKey, MessagesResult, TokenDetail, TokenListResult, TokenMessage, TokenStatus, TokenSummary, VaultInfo, VaultWalletLinkInfo } from 'torchsdk';
7
2
  import type { FactionStatus, FactionStatusFilter, Strategy } from '../types';
8
3
  import { Mapper } from '../types/mapper.types';
@@ -1,9 +1,4 @@
1
1
  "use strict";
2
- /**
3
- * Pyre Kit Mappers
4
- *
5
- * Internal mapping functions between Torch SDK types and Pyre game types.
6
- */
7
2
  Object.defineProperty(exports, "__esModule", { value: true });
8
3
  exports.MapperProvider = void 0;
9
4
  const mapper_types_1 = require("../types/mapper.types");
@@ -1,22 +1,16 @@
1
- /**
2
- * Pyre World Agent Registry Provider
3
- *
4
- * On-chain agent identity and state persistence.
5
- * Agents checkpoint their action distributions and personality summaries
6
- * so any machine with the wallet key can reconstruct the agent.
7
- */
8
1
  import { Connection, PublicKey } from '@solana/web3.js';
9
2
  import type { TransactionResult } from 'torchsdk';
10
3
  import type { RegistryProfile, RegistryWalletLink, RegisterAgentParams, CheckpointParams, LinkAgentWalletParams, UnlinkAgentWalletParams, TransferAgentAuthorityParams } from '../types';
4
+ import { Registry } from '../types/registry.types';
11
5
  export declare const REGISTRY_PROGRAM_ID: PublicKey;
12
6
  export declare function getAgentProfilePda(creator: PublicKey): [PublicKey, number];
13
7
  export declare function getAgentWalletLinkPda(wallet: PublicKey): [PublicKey, number];
14
- export declare class RegistryProvider {
8
+ export declare class RegistryProvider implements Registry {
15
9
  private connection;
16
10
  constructor(connection: Connection);
17
11
  private getProgram;
18
- getProfile(creator: string): Promise<RegistryProfile | null>;
19
- getWalletLink(wallet: string): Promise<RegistryWalletLink | null>;
12
+ getProfile(creator: string): Promise<RegistryProfile | undefined>;
13
+ getWalletLink(wallet: string): Promise<RegistryWalletLink | undefined>;
20
14
  register(params: RegisterAgentParams): Promise<TransactionResult>;
21
15
  checkpoint(params: CheckpointParams): Promise<TransactionResult>;
22
16
  linkWallet(params: LinkAgentWalletParams): Promise<TransactionResult>;
@@ -1,11 +1,4 @@
1
1
  "use strict";
2
- /**
3
- * Pyre World Agent Registry Provider
4
- *
5
- * On-chain agent identity and state persistence.
6
- * Agents checkpoint their action distributions and personality summaries
7
- * so any machine with the wallet key can reconstruct the agent.
8
- */
9
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
10
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
11
4
  };
@@ -16,19 +9,15 @@ exports.getAgentWalletLinkPda = getAgentWalletLinkPda;
16
9
  const web3_js_1 = require("@solana/web3.js");
17
10
  const anchor_1 = require("@coral-xyz/anchor");
18
11
  const pyre_world_json_1 = __importDefault(require("../pyre_world.json"));
19
- // ─── Program ID ─────────────────────────────────────────────────────
20
12
  exports.REGISTRY_PROGRAM_ID = new web3_js_1.PublicKey(pyre_world_json_1.default.address);
21
- // ─── PDA Seeds ──────────────────────────────────────────────────────
22
13
  const AGENT_SEED = 'pyre_agent';
23
14
  const AGENT_WALLET_SEED = 'pyre_agent_wallet';
24
- // ─── PDA Helpers ────────────────────────────────────────────────────
25
15
  function getAgentProfilePda(creator) {
26
16
  return web3_js_1.PublicKey.findProgramAddressSync([Buffer.from(AGENT_SEED), creator.toBuffer()], exports.REGISTRY_PROGRAM_ID);
27
17
  }
28
18
  function getAgentWalletLinkPda(wallet) {
29
19
  return web3_js_1.PublicKey.findProgramAddressSync([Buffer.from(AGENT_WALLET_SEED), wallet.toBuffer()], exports.REGISTRY_PROGRAM_ID);
30
20
  }
31
- // ─── Anchor Program Helper ──────────────────────────────────────────
32
21
  function makeDummyProvider(connection, payer) {
33
22
  const dummyWallet = {
34
23
  publicKey: payer,
@@ -42,7 +31,6 @@ async function finalizeTransaction(connection, tx, feePayer) {
42
31
  tx.recentBlockhash = blockhash;
43
32
  tx.feePayer = feePayer;
44
33
  }
45
- // ─── Provider ───────────────────────────────────────────────────────
46
34
  class RegistryProvider {
47
35
  connection;
48
36
  constructor(connection) {
@@ -52,7 +40,6 @@ class RegistryProvider {
52
40
  const provider = makeDummyProvider(this.connection, payer);
53
41
  return new anchor_1.Program(pyre_world_json_1.default, provider);
54
42
  }
55
- // ─── Read Operations ──────────────────────────────────────────────
56
43
  async getProfile(creator) {
57
44
  const creatorPk = new web3_js_1.PublicKey(creator);
58
45
  const [profilePda] = getAgentProfilePda(creatorPk);
@@ -87,7 +74,7 @@ class RegistryProvider {
87
74
  };
88
75
  }
89
76
  catch {
90
- return null;
77
+ return undefined;
91
78
  }
92
79
  }
93
80
  async getWalletLink(wallet) {
@@ -105,10 +92,9 @@ class RegistryProvider {
105
92
  };
106
93
  }
107
94
  catch {
108
- return null;
95
+ return undefined;
109
96
  }
110
97
  }
111
- // ─── Transaction Builders ─────────────────────────────────────────
112
98
  async register(params) {
113
99
  const creator = new web3_js_1.PublicKey(params.creator);
114
100
  const [profile] = getAgentProfilePda(creator);
@@ -1,21 +1,14 @@
1
- /**
2
- * Pyre Kit State Provider
3
- *
4
- * Objective game state tracking for an agent.
5
- * Owns holdings, action counts, vault resolution, tick counter.
6
- * Injected into ActionProvider so every action automatically updates state.
7
- */
8
1
  import { Connection } from '@solana/web3.js';
9
2
  import type { State, AgentGameState, SerializedGameState, TrackedAction, CheckpointConfig } from '../types/state.types';
10
- import { RegistryProvider } from './registry.provider';
3
+ import { Registry } from '../types/registry.types';
11
4
  export declare class StateProvider implements State {
12
5
  private connection;
13
- private publicKey;
14
6
  private registry;
7
+ private publicKey;
15
8
  private _state;
16
9
  private checkpointConfig;
17
10
  private ticksSinceCheckpoint;
18
- constructor(connection: Connection, publicKey: string, registry: RegistryProvider);
11
+ constructor(connection: Connection, registry: Registry, publicKey: string);
19
12
  get state(): AgentGameState | null;
20
13
  get vaultCreator(): string | null;
21
14
  get initialized(): boolean;
@@ -24,9 +17,7 @@ export declare class StateProvider implements State {
24
17
  setCheckpointConfig(config: CheckpointConfig): void;
25
18
  init(): Promise<AgentGameState>;
26
19
  record(action: TrackedAction, mint?: string, description?: string): Promise<void>;
27
- /** Update sentiment score for a faction based on action type */
28
20
  private updateSentiment;
29
- /** Callback set by PyreKit to handle checkpoint triggers */
30
21
  onCheckpointDue: (() => void) | null;
31
22
  refreshHoldings(): Promise<void>;
32
23
  getSentiment(mint: string): number;
@@ -1,11 +1,4 @@
1
1
  "use strict";
2
- /**
3
- * Pyre Kit State Provider
4
- *
5
- * Objective game state tracking for an agent.
6
- * Owns holdings, action counts, vault resolution, tick counter.
7
- * Injected into ActionProvider so every action automatically updates state.
8
- */
9
2
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
10
3
  if (k2 === undefined) k2 = k;
11
4
  var desc = Object.getOwnPropertyDescriptor(m, k);
@@ -62,17 +55,16 @@ const EMPTY_COUNTS = {
62
55
  };
63
56
  class StateProvider {
64
57
  connection;
65
- publicKey;
66
58
  registry;
59
+ publicKey;
67
60
  _state = null;
68
61
  checkpointConfig = null;
69
62
  ticksSinceCheckpoint = 0;
70
- constructor(connection, publicKey, registry) {
63
+ constructor(connection, registry, publicKey) {
71
64
  this.connection = connection;
72
- this.publicKey = publicKey;
73
65
  this.registry = registry;
66
+ this.publicKey = publicKey;
74
67
  }
75
- // ─── Readonly accessors ─────────────────────────────────────────
76
68
  get state() {
77
69
  return this._state;
78
70
  }
@@ -85,12 +77,10 @@ class StateProvider {
85
77
  get tick() {
86
78
  return this._state?.tick ?? 0;
87
79
  }
88
- // ─── Configuration ──────────────────────────────────────────────
89
80
  /** Configure auto-checkpoint behavior */
90
81
  setCheckpointConfig(config) {
91
82
  this.checkpointConfig = config;
92
83
  }
93
- // ─── Initialization ─────────────────────────────────────────────
94
84
  async init() {
95
85
  if (this._state?.initialized)
96
86
  return this._state;
@@ -113,7 +103,7 @@ class StateProvider {
113
103
  initialized: false,
114
104
  };
115
105
  this._state = state;
116
- // Resolve vault link
106
+ // resolve vault link
117
107
  const { getVaultForWallet } = await Promise.resolve().then(() => __importStar(require('torchsdk')));
118
108
  try {
119
109
  const vault = await getVaultForWallet(this.connection, this.publicKey);
@@ -134,14 +124,12 @@ class StateProvider {
134
124
  }
135
125
  }
136
126
  catch { }
137
- // Load registry profile — personality, action counts, SOL totals
138
127
  try {
139
128
  const profile = await this.registry.getProfile(this.publicKey);
140
129
  if (profile) {
141
130
  state.personalitySummary = profile.personality_summary || null;
142
131
  state.totalSolSpent = profile.total_sol_spent;
143
132
  state.totalSolReceived = profile.total_sol_received;
144
- // Seed action counts from on-chain checkpoint
145
133
  state.actionCounts.join = Math.max(state.actionCounts.join, profile.joins);
146
134
  state.actionCounts.defect = Math.max(state.actionCounts.defect, profile.defects);
147
135
  state.actionCounts.rally = Math.max(state.actionCounts.rally, profile.rallies);
@@ -156,48 +144,39 @@ class StateProvider {
156
144
  state.actionCounts.ascend = Math.max(state.actionCounts.ascend, profile.ascends);
157
145
  state.actionCounts.raze = Math.max(state.actionCounts.raze, profile.razes);
158
146
  state.actionCounts.tithe = Math.max(state.actionCounts.tithe, profile.tithes);
159
- // Set tick to total actions from checkpoint
160
147
  const totalFromCheckpoint = Object.values(state.actionCounts).reduce((a, b) => a + b, 0);
161
148
  state.tick = totalFromCheckpoint;
162
149
  }
163
150
  }
164
151
  catch { }
165
- // Load holdings (wallet + vault token accounts)
166
152
  await this.refreshHoldings();
167
153
  state.initialized = true;
168
154
  return state;
169
155
  }
170
- // ─── Action Recording ───────────────────────────────────────────
171
156
  async record(action, mint, description) {
172
157
  if (!this._state)
173
158
  throw new Error('State not initialized — call init() first');
174
159
  this._state.tick++;
175
160
  this._state.actionCounts[action]++;
176
161
  this.ticksSinceCheckpoint++;
177
- // Track founded factions
178
162
  if (action === 'launch' && mint) {
179
163
  this._state.founded.push(mint);
180
164
  }
181
- // Update sentiment for the target faction
182
165
  if (mint) {
183
166
  this.updateSentiment(action, mint);
184
167
  }
185
- // Track recent history for LLM memory block
186
168
  if (description) {
187
169
  this._state.recentHistory.push(description);
188
170
  if (this._state.recentHistory.length > 20) {
189
171
  this._state.recentHistory = this._state.recentHistory.slice(-20);
190
172
  }
191
173
  }
192
- // Refresh holdings after any trade action
193
174
  await this.refreshHoldings();
194
- // Auto-checkpoint check
195
175
  if (this.checkpointConfig && this.ticksSinceCheckpoint >= this.checkpointConfig.interval) {
196
176
  this.ticksSinceCheckpoint = 0;
197
177
  this.onCheckpointDue?.();
198
178
  }
199
179
  }
200
- /** Update sentiment score for a faction based on action type */
201
180
  updateSentiment(action, mint) {
202
181
  if (!this._state)
203
182
  return;
@@ -218,15 +197,12 @@ class StateProvider {
218
197
  this._state.sentiment.set(mint, Math.max(-10, Math.min(10, current + delta)));
219
198
  }
220
199
  }
221
- /** Callback set by PyreKit to handle checkpoint triggers */
222
200
  onCheckpointDue = null;
223
- // ─── Holdings ───────────────────────────────────────────────────
224
201
  async refreshHoldings() {
225
202
  if (!this._state)
226
203
  return;
227
204
  const { TOKEN_2022_PROGRAM_ID } = await Promise.resolve().then(() => __importStar(require('@solana/spl-token')));
228
205
  const walletPk = new web3_js_1.PublicKey(this.publicKey);
229
- // Scan wallet token accounts
230
206
  let walletValues = [];
231
207
  try {
232
208
  const walletAccounts = await this.connection.getParsedTokenAccountsByOwner(walletPk, {
@@ -235,7 +211,6 @@ class StateProvider {
235
211
  walletValues = walletAccounts.value;
236
212
  }
237
213
  catch { }
238
- // Scan vault token accounts
239
214
  let vaultValues = [];
240
215
  if (this._state.stronghold) {
241
216
  try {
@@ -247,7 +222,6 @@ class StateProvider {
247
222
  }
248
223
  catch { }
249
224
  }
250
- // Merge balances
251
225
  const newHoldings = new Map();
252
226
  for (const a of [...walletValues, ...vaultValues]) {
253
227
  const mint = a.account.data.parsed.info.mint;
@@ -256,7 +230,6 @@ class StateProvider {
256
230
  newHoldings.set(mint, (newHoldings.get(mint) ?? 0) + balance);
257
231
  }
258
232
  }
259
- // Update — clear stale, set fresh
260
233
  this._state.holdings.clear();
261
234
  for (const [mint, balance] of newHoldings) {
262
235
  this._state.holdings.set(mint, balance);
@@ -274,7 +247,6 @@ class StateProvider {
274
247
  getBalance(mint) {
275
248
  return this._state?.holdings.get(mint) ?? 0;
276
249
  }
277
- // ─── Dedup Guards ───────────────────────────────────────────────
278
250
  hasVoted(mint) {
279
251
  return this._state?.voted.has(mint) ?? false;
280
252
  }
@@ -287,7 +259,6 @@ class StateProvider {
287
259
  markRallied(mint) {
288
260
  this._state?.rallied.add(mint);
289
261
  }
290
- // ─── Serialization ──────────────────────────────────────────────
291
262
  serialize() {
292
263
  if (!this._state) {
293
264
  return {
@@ -36,6 +36,7 @@ export interface Action {
36
36
  raze(params: RazeParams): Promise<TransactionResult>;
37
37
  repayWarLoan(params: RepayWarLoanParams): Promise<TransactionResult>;
38
38
  requestWarLoan(params: RequestWarLoanParams): Promise<TransactionResult>;
39
+ scout(targetAddress: string): Promise<string>;
39
40
  siege(params: SiegeParams): Promise<TransactionResult>;
40
41
  tithe(params: TitheParams): Promise<TransactionResult>;
41
42
  }
@@ -0,0 +1,10 @@
1
+ import { CheckpointParams, LinkAgentWalletParams, RegisterAgentParams, RegistryProfile, RegistryWalletLink, TransactionResult, TransferAgentAuthorityParams, UnlinkAgentWalletParams } from '../types';
2
+ export interface Registry {
3
+ getProfile(creator: string): Promise<RegistryProfile | undefined>;
4
+ getWalletLink(wallet: string): Promise<RegistryWalletLink | undefined>;
5
+ register(params: RegisterAgentParams): Promise<TransactionResult>;
6
+ checkpoint(params: CheckpointParams): Promise<TransactionResult>;
7
+ linkWallet(params: LinkAgentWalletParams): Promise<TransactionResult>;
8
+ unlinkWallet(params: UnlinkAgentWalletParams): Promise<TransactionResult>;
9
+ transferAuthority(params: TransferAgentAuthorityParams): Promise<TransactionResult>;
10
+ }
@@ -1 +1,2 @@
1
1
  "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pyre-world-kit",
3
- "version": "3.0.1",
3
+ "version": "3.0.3",
4
4
  "description": "Agent-first faction warfare kit — game-semantic wrapper over torchsdk",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/readme.md CHANGED
@@ -192,6 +192,7 @@ kit.actions.getMembers(mint) // top holders
192
192
  kit.actions.getComms(mint, opts) // trade-bundled messages
193
193
  kit.actions.getJoinQuote(mint, sol) // buy price quote
194
194
  kit.actions.getDefectQuote(mint, n) // sell price quote
195
+ kit.actions.scout(address) // look up agent's on-chain identity (read-only)
195
196
  ```
196
197
 
197
198
  ### StateProvider
@@ -260,6 +261,8 @@ score = (market_cap_sol * 0.4) + (members * 0.2) + (war_chest_sol * 0.2)
260
261
 
261
262
  ## Tests
262
263
 
264
+ 46/46 passing tests.
265
+
263
266
  Requires [surfpool](https://github.com/txtx/surfpool) running a local Solana fork:
264
267
 
265
268
  ```bash
package/src/index.ts CHANGED
@@ -7,26 +7,30 @@
7
7
  */
8
8
 
9
9
  import { Connection } from '@solana/web3.js'
10
+
11
+ import { Action } from './types/action.types'
12
+ import { Intel } from './types/intel.types'
13
+ import { Registry } from './types/registry.types'
14
+
10
15
  import { ActionProvider } from './providers/action.provider'
11
16
  import { IntelProvider } from './providers/intel.provider'
12
17
  import { RegistryProvider } from './providers/registry.provider'
13
18
  import { StateProvider } from './providers/state.provider'
14
- import type { Action } from './types/action.types'
15
- import type { Intel } from './types/intel.types'
16
- import type { State, CheckpointConfig, TrackedAction } from './types/state.types'
19
+
20
+ import type { CheckpointConfig, TrackedAction } from './types/state.types'
17
21
 
18
22
  // ─── Top-level Kit ────────────────────────────────────────────────
19
23
 
20
24
  export class PyreKit {
21
- readonly actions: ActionProvider
22
- readonly intel: IntelProvider
23
- readonly registry: RegistryProvider
25
+ readonly actions: Action
26
+ readonly intel: Intel
27
+ readonly registry: Registry
24
28
  readonly state: StateProvider
25
29
 
26
30
  constructor(connection: Connection, publicKey: string) {
27
31
  this.registry = new RegistryProvider(connection)
28
- this.state = new StateProvider(connection, publicKey, this.registry)
29
- this.actions = new ActionProvider(connection)
32
+ this.state = new StateProvider(connection, this.registry, publicKey)
33
+ this.actions = new ActionProvider(connection, this.registry)
30
34
  this.intel = new IntelProvider(connection, this.actions)
31
35
 
32
36
  // Wire auto-checkpoint callback
@@ -1,5 +1,4 @@
1
1
  import { Connection, GetProgramAccountsFilter, PublicKey } from '@solana/web3.js'
2
- import { Action } from '../types/action.types'
3
2
  import {
4
3
  buildBorrowTransaction,
5
4
  buildBuyTransaction,
@@ -37,6 +36,16 @@ import {
37
36
  SellQuoteResult,
38
37
  TransactionResult,
39
38
  } from 'torchsdk'
39
+
40
+ import { MapperProvider } from './mapper.provider'
41
+ import {
42
+ buildCreateFactionTransaction,
43
+ getBondingCurvePda,
44
+ getTokenTreasuryPda,
45
+ getTreasuryLockPda,
46
+ isPyreMint,
47
+ } from '../vanity'
48
+ import { isBlacklistedMint } from '../util'
40
49
  import {
41
50
  AgentLink,
42
51
  AllWarLoansResult,
@@ -74,19 +83,15 @@ import {
74
83
  WithdrawAssetsParams,
75
84
  WithdrawFromStrongholdParams,
76
85
  } from '../types'
77
- import { MapperProvider } from './mapper.provider'
78
- import {
79
- buildCreateFactionTransaction,
80
- getBondingCurvePda,
81
- getTokenTreasuryPda,
82
- getTreasuryLockPda,
83
- isPyreMint,
84
- } from '../vanity'
85
- import { isBlacklistedMint } from '../util'
86
+ import { Action } from '../types/action.types'
87
+ import { Registry } from '../types/registry.types'
86
88
 
87
89
  export class ActionProvider implements Action {
88
90
  private mapper = new MapperProvider()
89
- constructor(private connection: Connection) {}
91
+ constructor(
92
+ private connection: Connection,
93
+ private registryProvider: Registry,
94
+ ) {}
90
95
 
91
96
  async createStronghold(params: CreateStrongholdParams): Promise<TransactionResult> {
92
97
  return buildCreateVaultTransaction(this.connection, { creator: params.creator })
@@ -422,6 +427,61 @@ export class ActionProvider implements Action {
422
427
  })
423
428
  }
424
429
 
430
+ async scout(targetAddress: string): Promise<string> {
431
+ try {
432
+ const p = await this.registryProvider.getProfile(targetAddress)
433
+ if (!p) return ` @${targetAddress.slice(0, 8)}: no pyre identity found`
434
+
435
+ const total =
436
+ p.joins +
437
+ p.defects +
438
+ p.rallies +
439
+ p.launches +
440
+ p.messages +
441
+ p.fuds +
442
+ p.infiltrates +
443
+ p.reinforces +
444
+ p.war_loans +
445
+ p.repay_loans +
446
+ p.sieges +
447
+ p.ascends +
448
+ p.razes +
449
+ p.tithes
450
+
451
+ const topActions = [
452
+ { n: 'joins', v: p.joins },
453
+ { n: 'defects', v: p.defects },
454
+ { n: 'rallies', v: p.rallies },
455
+ { n: 'messages', v: p.messages },
456
+ { n: 'fuds', v: p.fuds },
457
+ { n: 'infiltrates', v: p.infiltrates },
458
+ { n: 'reinforces', v: p.reinforces },
459
+ { n: 'war_loans', v: p.war_loans },
460
+ { n: 'sieges', v: p.sieges },
461
+ ]
462
+ .sort((a, b) => b.v - a.v)
463
+ .filter((a) => a.v > 0)
464
+ .slice(0, 4)
465
+ .map((a) => `${a.n}:${a.v}`)
466
+ .join(', ')
467
+
468
+ const personality = p.personality_summary || 'unknown'
469
+ const checkpoint =
470
+ p.last_checkpoint > 0
471
+ ? new Date(p.last_checkpoint * 1000).toISOString().slice(0, 10)
472
+ : 'never'
473
+
474
+ const spent = (p.total_sol_spent ?? 0) / 1e9
475
+ const received = (p.total_sol_received ?? 0) / 1e9
476
+ const pnl = received - spent
477
+ const pnlStr = pnl >= 0 ? `+${pnl.toFixed(3)}` : pnl.toFixed(3)
478
+
479
+ return ` @${targetAddress.slice(0, 8)}: "${personality}" | ${total} actions (${topActions}) | P&L: ${pnlStr} SOL | last seen: ${checkpoint}`
480
+ } catch {
481
+ return ` @${targetAddress.slice(0, 8)}: lookup failed`
482
+ }
483
+ }
484
+
425
485
  async siege(params: SiegeParams): Promise<TransactionResult> {
426
486
  return buildLiquidateTransaction(this.connection, {
427
487
  mint: params.mint,
@@ -1,5 +1,7 @@
1
1
  import { Connection, PublicKey } from '@solana/web3.js'
2
- import { MapperProvider } from './mapper.provider'
2
+
3
+ import { getBondingCurvePda, getTokenTreasuryPda, getTreasuryLockPda, isPyreMint } from '../vanity'
4
+ import { isBlacklistedMint } from '../util'
3
5
  import {
4
6
  AgentFactionPosition,
5
7
  AgentProfile,
@@ -13,8 +15,6 @@ import {
13
15
  RivalFaction,
14
16
  } from '../types'
15
17
  import { Intel } from '../types/intel.types'
16
- import { getBondingCurvePda, getTokenTreasuryPda, getTreasuryLockPda, isPyreMint } from '../vanity'
17
- import { isBlacklistedMint } from '../util'
18
18
  import { Action } from '../types/action.types'
19
19
 
20
20
  export class IntelProvider implements Intel {
@@ -1,9 +1,3 @@
1
- /**
2
- * Pyre Kit Mappers
3
- *
4
- * Internal mapping functions between Torch SDK types and Pyre game types.
5
- */
6
-
7
1
  import type {
8
2
  AllLoanPositionsResult,
9
3
  BuyTransactionResult,
@@ -1,14 +1,7 @@
1
- /**
2
- * Pyre World Agent Registry Provider
3
- *
4
- * On-chain agent identity and state persistence.
5
- * Agents checkpoint their action distributions and personality summaries
6
- * so any machine with the wallet key can reconstruct the agent.
7
- */
8
-
9
1
  import { Connection, PublicKey, Transaction, SystemProgram } from '@solana/web3.js'
10
2
  import { BN, Program, AnchorProvider, type Wallet } from '@coral-xyz/anchor'
11
3
  import type { TransactionResult } from 'torchsdk'
4
+
12
5
  import type {
13
6
  RegistryProfile,
14
7
  RegistryWalletLink,
@@ -18,20 +11,14 @@ import type {
18
11
  UnlinkAgentWalletParams,
19
12
  TransferAgentAuthorityParams,
20
13
  } from '../types'
14
+ import { Registry } from '../types/registry.types'
21
15
 
22
16
  import idl from '../pyre_world.json'
23
17
 
24
- // ─── Program ID ─────────────────────────────────────────────────────
25
-
26
18
  export const REGISTRY_PROGRAM_ID = new PublicKey(idl.address)
27
-
28
- // ─── PDA Seeds ──────────────────────────────────────────────────────
29
-
30
19
  const AGENT_SEED = 'pyre_agent'
31
20
  const AGENT_WALLET_SEED = 'pyre_agent_wallet'
32
21
 
33
- // ─── PDA Helpers ────────────────────────────────────────────────────
34
-
35
22
  export function getAgentProfilePda(creator: PublicKey): [PublicKey, number] {
36
23
  return PublicKey.findProgramAddressSync(
37
24
  [Buffer.from(AGENT_SEED), creator.toBuffer()],
@@ -46,8 +33,6 @@ export function getAgentWalletLinkPda(wallet: PublicKey): [PublicKey, number] {
46
33
  )
47
34
  }
48
35
 
49
- // ─── Anchor Program Helper ──────────────────────────────────────────
50
-
51
36
  function makeDummyProvider(connection: Connection, payer: PublicKey): AnchorProvider {
52
37
  const dummyWallet = {
53
38
  publicKey: payer,
@@ -67,9 +52,7 @@ async function finalizeTransaction(
67
52
  tx.feePayer = feePayer
68
53
  }
69
54
 
70
- // ─── Provider ───────────────────────────────────────────────────────
71
-
72
- export class RegistryProvider {
55
+ export class RegistryProvider implements Registry {
73
56
  constructor(private connection: Connection) {}
74
57
 
75
58
  private getProgram(payer: PublicKey): Program {
@@ -77,9 +60,7 @@ export class RegistryProvider {
77
60
  return new Program(idl as any, provider)
78
61
  }
79
62
 
80
- // ─── Read Operations ──────────────────────────────────────────────
81
-
82
- async getProfile(creator: string): Promise<RegistryProfile | null> {
63
+ async getProfile(creator: string): Promise<RegistryProfile | undefined> {
83
64
  const creatorPk = new PublicKey(creator)
84
65
  const [profilePda] = getAgentProfilePda(creatorPk)
85
66
  const program = this.getProgram(creatorPk)
@@ -113,11 +94,11 @@ export class RegistryProvider {
113
94
  total_sol_received: account.totalSolReceived?.toNumber() ?? 0,
114
95
  }
115
96
  } catch {
116
- return null
97
+ return undefined
117
98
  }
118
99
  }
119
100
 
120
- async getWalletLink(wallet: string): Promise<RegistryWalletLink | null> {
101
+ async getWalletLink(wallet: string): Promise<RegistryWalletLink | undefined> {
121
102
  const walletPk = new PublicKey(wallet)
122
103
  const [linkPda] = getAgentWalletLinkPda(walletPk)
123
104
  const program = this.getProgram(walletPk)
@@ -132,12 +113,10 @@ export class RegistryProvider {
132
113
  bump: account.bump,
133
114
  }
134
115
  } catch {
135
- return null
116
+ return undefined
136
117
  }
137
118
  }
138
119
 
139
- // ─── Transaction Builders ─────────────────────────────────────────
140
-
141
120
  async register(params: RegisterAgentParams): Promise<TransactionResult> {
142
121
  const creator = new PublicKey(params.creator)
143
122
  const [profile] = getAgentProfilePda(creator)
@@ -1,12 +1,7 @@
1
- /**
2
- * Pyre Kit State Provider
3
- *
4
- * Objective game state tracking for an agent.
5
- * Owns holdings, action counts, vault resolution, tick counter.
6
- * Injected into ActionProvider so every action automatically updates state.
7
- */
8
-
9
1
  import { Connection, PublicKey } from '@solana/web3.js'
2
+
3
+ import { isPyreMint } from '../vanity'
4
+ import { isBlacklistedMint } from '../util'
10
5
  import type {
11
6
  State,
12
7
  AgentGameState,
@@ -14,9 +9,7 @@ import type {
14
9
  TrackedAction,
15
10
  CheckpointConfig,
16
11
  } from '../types/state.types'
17
- import { RegistryProvider } from './registry.provider'
18
- import { isPyreMint } from '../vanity'
19
- import { isBlacklistedMint } from '../util'
12
+ import { Registry } from '../types/registry.types'
20
13
 
21
14
  const EMPTY_COUNTS: Record<TrackedAction, number> = {
22
15
  join: 0,
@@ -42,12 +35,10 @@ export class StateProvider implements State {
42
35
 
43
36
  constructor(
44
37
  private connection: Connection,
38
+ private registry: Registry,
45
39
  private publicKey: string,
46
- private registry: RegistryProvider,
47
40
  ) {}
48
41
 
49
- // ─── Readonly accessors ─────────────────────────────────────────
50
-
51
42
  get state() {
52
43
  return this._state
53
44
  }
@@ -61,15 +52,11 @@ export class StateProvider implements State {
61
52
  return this._state?.tick ?? 0
62
53
  }
63
54
 
64
- // ─── Configuration ──────────────────────────────────────────────
65
-
66
55
  /** Configure auto-checkpoint behavior */
67
56
  setCheckpointConfig(config: CheckpointConfig) {
68
57
  this.checkpointConfig = config
69
58
  }
70
59
 
71
- // ─── Initialization ─────────────────────────────────────────────
72
-
73
60
  async init(): Promise<AgentGameState> {
74
61
  if (this._state?.initialized) return this._state
75
62
 
@@ -94,7 +81,7 @@ export class StateProvider implements State {
94
81
 
95
82
  this._state = state
96
83
 
97
- // Resolve vault link
84
+ // resolve vault link
98
85
  const { getVaultForWallet } = await import('torchsdk')
99
86
  try {
100
87
  const vault = await getVaultForWallet(this.connection, this.publicKey)
@@ -115,14 +102,13 @@ export class StateProvider implements State {
115
102
  }
116
103
  } catch {}
117
104
 
118
- // Load registry profile — personality, action counts, SOL totals
119
105
  try {
120
106
  const profile = await this.registry.getProfile(this.publicKey)
121
107
  if (profile) {
122
108
  state.personalitySummary = profile.personality_summary || null
123
109
  state.totalSolSpent = profile.total_sol_spent
124
110
  state.totalSolReceived = profile.total_sol_received
125
- // Seed action counts from on-chain checkpoint
111
+
126
112
  state.actionCounts.join = Math.max(state.actionCounts.join, profile.joins)
127
113
  state.actionCounts.defect = Math.max(state.actionCounts.defect, profile.defects)
128
114
  state.actionCounts.rally = Math.max(state.actionCounts.rally, profile.rallies)
@@ -137,21 +123,17 @@ export class StateProvider implements State {
137
123
  state.actionCounts.ascend = Math.max(state.actionCounts.ascend, profile.ascends)
138
124
  state.actionCounts.raze = Math.max(state.actionCounts.raze, profile.razes)
139
125
  state.actionCounts.tithe = Math.max(state.actionCounts.tithe, profile.tithes)
140
- // Set tick to total actions from checkpoint
126
+
141
127
  const totalFromCheckpoint = Object.values(state.actionCounts).reduce((a, b) => a + b, 0)
142
128
  state.tick = totalFromCheckpoint
143
129
  }
144
130
  } catch {}
145
131
 
146
- // Load holdings (wallet + vault token accounts)
147
132
  await this.refreshHoldings()
148
-
149
133
  state.initialized = true
150
134
  return state
151
135
  }
152
136
 
153
- // ─── Action Recording ───────────────────────────────────────────
154
-
155
137
  async record(action: TrackedAction, mint?: string, description?: string): Promise<void> {
156
138
  if (!this._state) throw new Error('State not initialized — call init() first')
157
139
 
@@ -159,17 +141,14 @@ export class StateProvider implements State {
159
141
  this._state.actionCounts[action]++
160
142
  this.ticksSinceCheckpoint++
161
143
 
162
- // Track founded factions
163
144
  if (action === 'launch' && mint) {
164
145
  this._state.founded.push(mint)
165
146
  }
166
147
 
167
- // Update sentiment for the target faction
168
148
  if (mint) {
169
149
  this.updateSentiment(action, mint)
170
150
  }
171
151
 
172
- // Track recent history for LLM memory block
173
152
  if (description) {
174
153
  this._state.recentHistory.push(description)
175
154
  if (this._state.recentHistory.length > 20) {
@@ -177,22 +156,16 @@ export class StateProvider implements State {
177
156
  }
178
157
  }
179
158
 
180
- // Refresh holdings after any trade action
181
159
  await this.refreshHoldings()
182
-
183
- // Auto-checkpoint check
184
160
  if (this.checkpointConfig && this.ticksSinceCheckpoint >= this.checkpointConfig.interval) {
185
161
  this.ticksSinceCheckpoint = 0
186
162
  this.onCheckpointDue?.()
187
163
  }
188
164
  }
189
165
 
190
- /** Update sentiment score for a faction based on action type */
191
166
  private updateSentiment(action: TrackedAction, mint: string): void {
192
167
  if (!this._state) return
193
-
194
168
  const current = this._state.sentiment.get(mint) ?? 0
195
-
196
169
  const SENTIMENT_DELTAS: Partial<Record<TrackedAction, number>> = {
197
170
  join: 1,
198
171
  reinforce: 1.5,
@@ -211,18 +184,14 @@ export class StateProvider implements State {
211
184
  }
212
185
  }
213
186
 
214
- /** Callback set by PyreKit to handle checkpoint triggers */
215
187
  onCheckpointDue: (() => void) | null = null
216
188
 
217
- // ─── Holdings ───────────────────────────────────────────────────
218
-
219
189
  async refreshHoldings(): Promise<void> {
220
190
  if (!this._state) return
221
191
 
222
192
  const { TOKEN_2022_PROGRAM_ID } = await import('@solana/spl-token')
223
193
  const walletPk = new PublicKey(this.publicKey)
224
194
 
225
- // Scan wallet token accounts
226
195
  let walletValues: any[] = []
227
196
  try {
228
197
  const walletAccounts = await this.connection.getParsedTokenAccountsByOwner(walletPk, {
@@ -231,7 +200,6 @@ export class StateProvider implements State {
231
200
  walletValues = walletAccounts.value
232
201
  } catch {}
233
202
 
234
- // Scan vault token accounts
235
203
  let vaultValues: any[] = []
236
204
  if (this._state.stronghold) {
237
205
  try {
@@ -243,7 +211,6 @@ export class StateProvider implements State {
243
211
  } catch {}
244
212
  }
245
213
 
246
- // Merge balances
247
214
  const newHoldings = new Map<string, number>()
248
215
  for (const a of [...walletValues, ...vaultValues]) {
249
216
  const mint = a.account.data.parsed.info.mint as string
@@ -253,7 +220,6 @@ export class StateProvider implements State {
253
220
  }
254
221
  }
255
222
 
256
- // Update — clear stale, set fresh
257
223
  this._state.holdings.clear()
258
224
  for (const [mint, balance] of newHoldings) {
259
225
  this._state.holdings.set(mint, balance)
@@ -276,8 +242,6 @@ export class StateProvider implements State {
276
242
  return this._state?.holdings.get(mint) ?? 0
277
243
  }
278
244
 
279
- // ─── Dedup Guards ───────────────────────────────────────────────
280
-
281
245
  hasVoted(mint: string): boolean {
282
246
  return this._state?.voted.has(mint) ?? false
283
247
  }
@@ -294,8 +258,6 @@ export class StateProvider implements State {
294
258
  this._state?.rallied.add(mint)
295
259
  }
296
260
 
297
- // ─── Serialization ──────────────────────────────────────────────
298
-
299
261
  serialize(): SerializedGameState {
300
262
  if (!this._state) {
301
263
  return {
@@ -71,6 +71,7 @@ export interface Action {
71
71
  raze(params: RazeParams): Promise<TransactionResult>
72
72
  repayWarLoan(params: RepayWarLoanParams): Promise<TransactionResult>
73
73
  requestWarLoan(params: RequestWarLoanParams): Promise<TransactionResult>
74
+ scout(targetAddress: string): Promise<string>
74
75
  siege(params: SiegeParams): Promise<TransactionResult>
75
76
  tithe(params: TitheParams): Promise<TransactionResult>
76
77
  }
@@ -0,0 +1,21 @@
1
+ import {
2
+ CheckpointParams,
3
+ LinkAgentWalletParams,
4
+ RegisterAgentParams,
5
+ RegistryProfile,
6
+ RegistryWalletLink,
7
+ TransactionResult,
8
+ TransferAgentAuthorityParams,
9
+ UnlinkAgentWalletParams,
10
+ } from '../types'
11
+
12
+ export interface Registry {
13
+ getProfile(creator: string): Promise<RegistryProfile | undefined>
14
+ getWalletLink(wallet: string): Promise<RegistryWalletLink | undefined>
15
+
16
+ register(params: RegisterAgentParams): Promise<TransactionResult>
17
+ checkpoint(params: CheckpointParams): Promise<TransactionResult>
18
+ linkWallet(params: LinkAgentWalletParams): Promise<TransactionResult>
19
+ unlinkWallet(params: UnlinkAgentWalletParams): Promise<TransactionResult>
20
+ transferAuthority(params: TransferAgentAuthorityParams): Promise<TransactionResult>
21
+ }
package/tests/test_e2e.ts CHANGED
@@ -345,6 +345,28 @@ async function main() {
345
345
  assert(kitRestored.state.state!.actionCounts.defect === kit.state.state!.actionCounts.defect, `hydrated defect count matches`)
346
346
  assert(kitRestored.state.history.length === kit.state.history.length, `hydrated history length matches: ${kitRestored.state.history.length}`)
347
347
 
348
+ // ═══════════════════════════════════════════════════════════════════
349
+ // TEST: SCOUT
350
+ // ═══════════════════════════════════════════════════════════════════
351
+
352
+ console.log('\n═══ TEST: Scout ═══')
353
+ // Scout agent 1 from agent 2's perspective
354
+ const scoutResult = await kit2.actions.scout(agent.publicKey)
355
+ console.log(` ${scoutResult}`)
356
+ assert(typeof scoutResult === 'string', `scout returns string`)
357
+ assert(scoutResult.includes(agent.publicKey.slice(0, 8)), `scout result contains target address: ${agent.publicKey.slice(0, 8)}`)
358
+
359
+ // Scout a nonexistent address
360
+ const fakeAddress = 'FakeAddress1111111111111111111111111111111111'
361
+ const scoutFake = await kit2.actions.scout(fakeAddress)
362
+ console.log(` ${scoutFake}`)
363
+ assert(scoutFake.includes('no pyre identity') || scoutFake.includes('lookup failed'), `scout handles unknown agent`)
364
+
365
+ // Scout via exec (read-only — no tick increment)
366
+ const { result: scoutExecResult } = await kit2.exec('actions', 'scout', agent.publicKey)
367
+ console.log(` exec scout: ${scoutExecResult}`)
368
+ assert(kit2.state.tick === 2, `agent 2 tick unchanged after scout (read-only): ${kit2.state.tick}`)
369
+
348
370
  // ═══════════════════════════════════════════════════════════════════
349
371
  // TEST: MEMBERS
350
372
  // ═══════════════════════════════════════════════════════════════════