pyre-world-kit 3.0.2 → 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,16 +6,14 @@
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';
9
+ import { Action } from './types/action.types';
10
+ import { Intel } from './types/intel.types';
11
+ import { Registry } from './types/registry.types';
11
12
  import { StateProvider } from './providers/state.provider';
12
- import type { Action } from './types/action.types';
13
- import type { Intel } from './types/intel.types';
14
13
  import type { CheckpointConfig } from './types/state.types';
15
- import { Registry } from './types/registry.types';
16
14
  export declare class PyreKit {
17
- readonly actions: ActionProvider;
18
- readonly intel: IntelProvider;
15
+ readonly actions: Action;
16
+ readonly intel: Intel;
19
17
  readonly registry: Registry;
20
18
  readonly state: StateProvider;
21
19
  constructor(connection: Connection, publicKey: string);
@@ -1,7 +1,7 @@
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
5
  import { Registry } from '../types/registry.types';
6
6
  export declare class ActionProvider implements Action {
7
7
  private connection;
@@ -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,10 +1,3 @@
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';
@@ -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);
@@ -108,7 +95,6 @@ class RegistryProvider {
108
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,10 +1,3 @@
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
3
  import { Registry } from '../types/registry.types';
@@ -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);
@@ -72,7 +65,6 @@ class StateProvider {
72
65
  this.registry = registry;
73
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 {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pyre-world-kit",
3
- "version": "3.0.2",
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,20 +7,23 @@
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'
17
- import { Registry } from './types/registry.types'
19
+
20
+ import type { CheckpointConfig, TrackedAction } from './types/state.types'
18
21
 
19
22
  // ─── Top-level Kit ────────────────────────────────────────────────
20
23
 
21
24
  export class PyreKit {
22
- readonly actions: ActionProvider
23
- readonly intel: IntelProvider
25
+ readonly actions: Action
26
+ readonly intel: Intel
24
27
  readonly registry: Registry
25
28
  readonly state: StateProvider
26
29
 
@@ -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,15 +83,7 @@ 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'
86
87
  import { Registry } from '../types/registry.types'
87
88
 
88
89
  export class ActionProvider implements Action {
@@ -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,21 +11,14 @@ import type {
18
11
  UnlinkAgentWalletParams,
19
12
  TransferAgentAuthorityParams,
20
13
  } from '../types'
21
-
22
- import idl from '../pyre_world.json'
23
14
  import { Registry } from '../types/registry.types'
24
15
 
25
- // ─── Program ID ─────────────────────────────────────────────────────
16
+ import idl from '../pyre_world.json'
26
17
 
27
18
  export const REGISTRY_PROGRAM_ID = new PublicKey(idl.address)
28
-
29
- // ─── PDA Seeds ──────────────────────────────────────────────────────
30
-
31
19
  const AGENT_SEED = 'pyre_agent'
32
20
  const AGENT_WALLET_SEED = 'pyre_agent_wallet'
33
21
 
34
- // ─── PDA Helpers ────────────────────────────────────────────────────
35
-
36
22
  export function getAgentProfilePda(creator: PublicKey): [PublicKey, number] {
37
23
  return PublicKey.findProgramAddressSync(
38
24
  [Buffer.from(AGENT_SEED), creator.toBuffer()],
@@ -47,8 +33,6 @@ export function getAgentWalletLinkPda(wallet: PublicKey): [PublicKey, number] {
47
33
  )
48
34
  }
49
35
 
50
- // ─── Anchor Program Helper ──────────────────────────────────────────
51
-
52
36
  function makeDummyProvider(connection: Connection, payer: PublicKey): AnchorProvider {
53
37
  const dummyWallet = {
54
38
  publicKey: payer,
@@ -68,8 +52,6 @@ async function finalizeTransaction(
68
52
  tx.feePayer = feePayer
69
53
  }
70
54
 
71
- // ─── Provider ───────────────────────────────────────────────────────
72
-
73
55
  export class RegistryProvider implements Registry {
74
56
  constructor(private connection: Connection) {}
75
57
 
@@ -78,8 +60,6 @@ export class RegistryProvider implements Registry {
78
60
  return new Program(idl as any, provider)
79
61
  }
80
62
 
81
- // ─── Read Operations ──────────────────────────────────────────────
82
-
83
63
  async getProfile(creator: string): Promise<RegistryProfile | undefined> {
84
64
  const creatorPk = new PublicKey(creator)
85
65
  const [profilePda] = getAgentProfilePda(creatorPk)
@@ -137,8 +117,6 @@ export class RegistryProvider implements Registry {
137
117
  }
138
118
  }
139
119
 
140
- // ─── Transaction Builders ─────────────────────────────────────────
141
-
142
120
  async register(params: RegisterAgentParams): Promise<TransactionResult> {
143
121
  const creator = new PublicKey(params.creator)
144
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,6 @@ 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'
20
12
  import { Registry } from '../types/registry.types'
21
13
 
22
14
  const EMPTY_COUNTS: Record<TrackedAction, number> = {
@@ -41,9 +33,11 @@ export class StateProvider implements State {
41
33
  private checkpointConfig: CheckpointConfig | null = null
42
34
  private ticksSinceCheckpoint = 0
43
35
 
44
- constructor(private connection: Connection, private registry: Registry, private publicKey: string) {}
45
-
46
- // ─── Readonly accessors ─────────────────────────────────────────
36
+ constructor(
37
+ private connection: Connection,
38
+ private registry: Registry,
39
+ private publicKey: string,
40
+ ) {}
47
41
 
48
42
  get state() {
49
43
  return this._state
@@ -58,15 +52,11 @@ export class StateProvider implements State {
58
52
  return this._state?.tick ?? 0
59
53
  }
60
54
 
61
- // ─── Configuration ──────────────────────────────────────────────
62
-
63
55
  /** Configure auto-checkpoint behavior */
64
56
  setCheckpointConfig(config: CheckpointConfig) {
65
57
  this.checkpointConfig = config
66
58
  }
67
59
 
68
- // ─── Initialization ─────────────────────────────────────────────
69
-
70
60
  async init(): Promise<AgentGameState> {
71
61
  if (this._state?.initialized) return this._state
72
62
 
@@ -91,7 +81,7 @@ export class StateProvider implements State {
91
81
 
92
82
  this._state = state
93
83
 
94
- // Resolve vault link
84
+ // resolve vault link
95
85
  const { getVaultForWallet } = await import('torchsdk')
96
86
  try {
97
87
  const vault = await getVaultForWallet(this.connection, this.publicKey)
@@ -112,14 +102,13 @@ export class StateProvider implements State {
112
102
  }
113
103
  } catch {}
114
104
 
115
- // Load registry profile — personality, action counts, SOL totals
116
105
  try {
117
106
  const profile = await this.registry.getProfile(this.publicKey)
118
107
  if (profile) {
119
108
  state.personalitySummary = profile.personality_summary || null
120
109
  state.totalSolSpent = profile.total_sol_spent
121
110
  state.totalSolReceived = profile.total_sol_received
122
- // Seed action counts from on-chain checkpoint
111
+
123
112
  state.actionCounts.join = Math.max(state.actionCounts.join, profile.joins)
124
113
  state.actionCounts.defect = Math.max(state.actionCounts.defect, profile.defects)
125
114
  state.actionCounts.rally = Math.max(state.actionCounts.rally, profile.rallies)
@@ -134,21 +123,17 @@ export class StateProvider implements State {
134
123
  state.actionCounts.ascend = Math.max(state.actionCounts.ascend, profile.ascends)
135
124
  state.actionCounts.raze = Math.max(state.actionCounts.raze, profile.razes)
136
125
  state.actionCounts.tithe = Math.max(state.actionCounts.tithe, profile.tithes)
137
- // Set tick to total actions from checkpoint
126
+
138
127
  const totalFromCheckpoint = Object.values(state.actionCounts).reduce((a, b) => a + b, 0)
139
128
  state.tick = totalFromCheckpoint
140
129
  }
141
130
  } catch {}
142
131
 
143
- // Load holdings (wallet + vault token accounts)
144
132
  await this.refreshHoldings()
145
-
146
133
  state.initialized = true
147
134
  return state
148
135
  }
149
136
 
150
- // ─── Action Recording ───────────────────────────────────────────
151
-
152
137
  async record(action: TrackedAction, mint?: string, description?: string): Promise<void> {
153
138
  if (!this._state) throw new Error('State not initialized — call init() first')
154
139
 
@@ -156,17 +141,14 @@ export class StateProvider implements State {
156
141
  this._state.actionCounts[action]++
157
142
  this.ticksSinceCheckpoint++
158
143
 
159
- // Track founded factions
160
144
  if (action === 'launch' && mint) {
161
145
  this._state.founded.push(mint)
162
146
  }
163
147
 
164
- // Update sentiment for the target faction
165
148
  if (mint) {
166
149
  this.updateSentiment(action, mint)
167
150
  }
168
151
 
169
- // Track recent history for LLM memory block
170
152
  if (description) {
171
153
  this._state.recentHistory.push(description)
172
154
  if (this._state.recentHistory.length > 20) {
@@ -174,22 +156,16 @@ export class StateProvider implements State {
174
156
  }
175
157
  }
176
158
 
177
- // Refresh holdings after any trade action
178
159
  await this.refreshHoldings()
179
-
180
- // Auto-checkpoint check
181
160
  if (this.checkpointConfig && this.ticksSinceCheckpoint >= this.checkpointConfig.interval) {
182
161
  this.ticksSinceCheckpoint = 0
183
162
  this.onCheckpointDue?.()
184
163
  }
185
164
  }
186
165
 
187
- /** Update sentiment score for a faction based on action type */
188
166
  private updateSentiment(action: TrackedAction, mint: string): void {
189
167
  if (!this._state) return
190
-
191
168
  const current = this._state.sentiment.get(mint) ?? 0
192
-
193
169
  const SENTIMENT_DELTAS: Partial<Record<TrackedAction, number>> = {
194
170
  join: 1,
195
171
  reinforce: 1.5,
@@ -208,18 +184,14 @@ export class StateProvider implements State {
208
184
  }
209
185
  }
210
186
 
211
- /** Callback set by PyreKit to handle checkpoint triggers */
212
187
  onCheckpointDue: (() => void) | null = null
213
188
 
214
- // ─── Holdings ───────────────────────────────────────────────────
215
-
216
189
  async refreshHoldings(): Promise<void> {
217
190
  if (!this._state) return
218
191
 
219
192
  const { TOKEN_2022_PROGRAM_ID } = await import('@solana/spl-token')
220
193
  const walletPk = new PublicKey(this.publicKey)
221
194
 
222
- // Scan wallet token accounts
223
195
  let walletValues: any[] = []
224
196
  try {
225
197
  const walletAccounts = await this.connection.getParsedTokenAccountsByOwner(walletPk, {
@@ -228,7 +200,6 @@ export class StateProvider implements State {
228
200
  walletValues = walletAccounts.value
229
201
  } catch {}
230
202
 
231
- // Scan vault token accounts
232
203
  let vaultValues: any[] = []
233
204
  if (this._state.stronghold) {
234
205
  try {
@@ -240,7 +211,6 @@ export class StateProvider implements State {
240
211
  } catch {}
241
212
  }
242
213
 
243
- // Merge balances
244
214
  const newHoldings = new Map<string, number>()
245
215
  for (const a of [...walletValues, ...vaultValues]) {
246
216
  const mint = a.account.data.parsed.info.mint as string
@@ -250,7 +220,6 @@ export class StateProvider implements State {
250
220
  }
251
221
  }
252
222
 
253
- // Update — clear stale, set fresh
254
223
  this._state.holdings.clear()
255
224
  for (const [mint, balance] of newHoldings) {
256
225
  this._state.holdings.set(mint, balance)
@@ -273,8 +242,6 @@ export class StateProvider implements State {
273
242
  return this._state?.holdings.get(mint) ?? 0
274
243
  }
275
244
 
276
- // ─── Dedup Guards ───────────────────────────────────────────────
277
-
278
245
  hasVoted(mint: string): boolean {
279
246
  return this._state?.voted.has(mint) ?? false
280
247
  }
@@ -291,8 +258,6 @@ export class StateProvider implements State {
291
258
  this._state?.rallied.add(mint)
292
259
  }
293
260
 
294
- // ─── Serialization ──────────────────────────────────────────────
295
-
296
261
  serialize(): SerializedGameState {
297
262
  if (!this._state) {
298
263
  return {
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
  // ═══════════════════════════════════════════════════════════════════