@dfm-fi/agent 0.2.2084 → 0.2.2103

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.
@@ -301,11 +301,12 @@ export class DfmApiClient {
301
301
  }
302
302
  /** The caller's XP plus the top of the leaderboard. */
303
303
  async getXp() {
304
- const [mine, leaderboard] = await Promise.all([
304
+ const [mine, leaderboard, rules] = await Promise.all([
305
305
  this.authRequest('/xp/me', { method: 'GET' }),
306
306
  this.publicRequest('/xp/leaderboard?limit=10'),
307
+ this.publicRequest('/xp/rules'),
307
308
  ]);
308
- return { mine, leaderboard };
309
+ return { mine, leaderboard, rules };
309
310
  }
310
311
  async getProfile() {
311
312
  return this.authRequest('/profile', { method: 'GET' });
@@ -63,7 +63,7 @@ import { loadConfig } from './config.js';
63
63
  import { leanTokenRows, MAX_TOKEN_LIMIT } from './token-search.js';
64
64
  import { SiwsSession } from './session.js';
65
65
  import { DfmApiClient } from './api-client.js';
66
- import { isKeylessMode, executeAppWalletWrite, KEYLESS_SETUP_HINT, } from './keyless.js';
66
+ import { isKeylessMode, hasLocalKeypair, executeAppWalletWrite, KEYLESS_SETUP_HINT, } from './keyless.js';
67
67
  import { runAcceptAdminTransfer, } from './manager-flow.js';
68
68
  import { submitSignedTx } from './submit.js';
69
69
  import { DEFAULT_OWNER_KEY_PATH, ownerKeyPath, policyUpdateNotice, runCreateAppWallet } from './app-wallet-owner.js';
@@ -759,7 +759,9 @@ server.registerTool('close_empty_accounts', {
759
759
  });
760
760
  server.registerTool('xp_status', {
761
761
  title: 'XP',
762
- description: "The user's XP (total and by kind: deposit, launch, profile, referral) and the top of the XP leaderboard.",
762
+ description: "The user's XP (total and by kind: deposit, launch, profile, referral), the top of the XP leaderboard, and HOW XP is " +
763
+ 'earned: `rules.howToEarn` lists every action with what it pays and what it waits for, `rules.doesNotEarn` what never ' +
764
+ 'counts. Answer any "how do I earn XP / why did this not pay" from here, never from memory.',
763
765
  inputSchema: {},
764
766
  annotations: { readOnlyHint: true, openWorldHint: true },
765
767
  }, async () => {
@@ -778,6 +780,25 @@ server.registerTool('whoami', {
778
780
  inputSchema: {},
779
781
  annotations: { readOnlyHint: true, openWorldHint: true },
780
782
  }, async () => {
783
+ // A fresh headless agent has neither an API key nor an identity keypair
784
+ // yet. That is the START of onboarding, not a failure: answering with the
785
+ // signing layer's "No test keypair configured" error sent a model that
786
+ // followed "call whoami first" off to hand-install a keypair.
787
+ if (!isKeylessMode(config) && !hasLocalKeypair(config)) {
788
+ return text({
789
+ onboarded: false,
790
+ displayName: null,
791
+ signInWallet: null,
792
+ appWalletAddress: null,
793
+ setupHint: 'No DFM identity on this machine yet. Run onboard (it creates the identity keypair, signs in, ' +
794
+ `sets the profile and creates the app wallet): ${ONBOARDING_ORDER}. To operate a human's account ` +
795
+ 'instead, install with --api-key dfm_… (minted at app.dfm.finance → Agent → Keys).',
796
+ confirmPhraseRequired: process.env.DFM_MCP_CONFIRM_REQUIRED === '1' && process.env.DFM_MCP_NONINTERACTIVE_WRITES !== '1',
797
+ apiUrl: config.apiUrl,
798
+ cluster: config.cluster,
799
+ writeEnabled: config.writeEnabled,
800
+ });
801
+ }
781
802
  try {
782
803
  const [{ identity, op }, profile, float] = await Promise.all([
783
804
  resolveWalletIdentityWithOp(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dfm-fi/agent",
3
- "version": "0.2.2084",
3
+ "version": "0.2.2103",
4
4
  "description": "DFM v2 MCP server — drive the full fund launch → deposit → redeem (+ manage) lifecycle from an AI agent against the live API.",
5
5
  "homepage": "https://app.dfm.finance/docs/agent",
6
6
  "mcpName": "io.github.DFM-Finance/dfm-agent",
package/skills.md CHANGED
@@ -61,6 +61,10 @@ https://app.dfm.finance/account); `app_wallet_fund` is refused in key-only mode
61
61
  already in use is refused.
62
62
  - **Season 0 cap:** every fund is capped at $1,000 of value; a deposit that would pass it is refused with the
63
63
  room that is left.
64
+ - **XP:** never quote XP amounts or conditions from memory. `xp_status` returns the person's XP and the live
65
+ rules: `rules.howToEarn` (each action, what it pays, what it waits for) and `rules.doesNotEarn`. XP comes from
66
+ deposits, a completed profile, a linked X account, launching funds that keep money in them, and referrals;
67
+ redeeming earns nothing and never takes XP away.
64
68
  - **Fund policy:** every fund runs the same default policy; creator-set policies are coming in v2. There is
65
69
  no tool to change it.
66
70
  - **Writes need `DFM_AGENT_WRITE_ENABLED=true`** on the MCP process. Path A needs no API key for writes; path B
@@ -100,6 +104,7 @@ https://app.dfm.finance/account); `app_wallet_fund` is refused in key-only mode
100
104
  | "Swap 5 USDC to JUP" | `swap_quote` → `swap {inputMint, outputMint, amountRaw}` | signature, or "approve it in the app" | — |
101
105
  | "Withdraw my USDC" | `app_wallet_withdraw` · `withdraw_asset` | signature | — |
102
106
  | "My positions" | `get_portfolio` | shares and value | — |
107
+ | "My XP" / "how do I earn XP?" | `xp_status` | total, by kind, `rules.howToEarn` | point to the next bonus the person can reach |
103
108
  | "Report a bug" | `report_bug {title, description}` | confirmation | — |
104
109
 
105
110
  `transfer_admin` and new `accept_admin_transfer` acceptances are **not available yet in this MCP**: they