@agentgrant.cash/cli 1.1.0 → 1.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.
@@ -141,7 +141,7 @@ async function gatherExtras(ctx) {
141
141
  }
142
142
  async function gather(cmd) {
143
143
  const ctx = buildContext(cmd);
144
- const [prefsR, moneyR, extrasR, agentR] = await Promise.allSettled([
144
+ const [prefsR, moneyR, extrasR, agentR, creditR] = await Promise.allSettled([
145
145
  ctx.money.connected ? loadDisplayPrefs(ctx) : Promise.resolve(DEFAULT_PREFS),
146
146
  ctx.money.connected
147
147
  ? ctx.money.getPortfolio("full")
@@ -150,6 +150,9 @@ async function gather(cmd) {
150
150
  ctx.agent.connected
151
151
  ? ctx.agent.balance()
152
152
  : Promise.resolve(null),
153
+ ctx.agent.connected
154
+ ? ctx.agent.credit()
155
+ : Promise.resolve(null),
153
156
  ]);
154
157
  return {
155
158
  ctx,
@@ -159,6 +162,7 @@ async function gather(cmd) {
159
162
  moneyFailed: moneyR.status === "rejected",
160
163
  agent: agentR.status === "fulfilled" ? agentR.value : null,
161
164
  agentFailed: agentR.status === "rejected",
165
+ credit: creditR.status === "fulfilled" ? creditR.value : null,
162
166
  };
163
167
  }
164
168
  /** Indent every line of a block by two spaces. */
@@ -171,7 +175,7 @@ function indent(block) {
171
175
  export function registerPortfolio(program) {
172
176
  const run = async (cmd) => {
173
177
  const g = await gather(cmd);
174
- const { ctx, prefs, money, extras, moneyFailed, agent, agentFailed } = g;
178
+ const { ctx, prefs, money, extras, moneyFailed, agent, agentFailed, credit } = g;
175
179
  emit(ctx, {
176
180
  investments: money
177
181
  ? {
@@ -186,6 +190,8 @@ export function registerPortfolio(program) {
186
190
  }
187
191
  : null,
188
192
  spending: agent,
193
+ // The free-credit / wallet split (parity with the app's Spending screen).
194
+ credit,
189
195
  }, () => {
190
196
  if (!ctx.money.connected && !ctx.agent.connected)
191
197
  return "Not connected yet. Run `grant login`.";
@@ -208,7 +214,7 @@ export function registerPortfolio(program) {
208
214
  lines.push(ui.dim(" Not connected."));
209
215
  }
210
216
  else if (agent) {
211
- lines.push(formatAgentFunds(agent));
217
+ lines.push(formatAgentFunds(agent, credit));
212
218
  }
213
219
  else {
214
220
  lines.push(ui.amber(` ${agentFailed ? "Temporarily unavailable." : "—"}`));
@@ -74,6 +74,15 @@ export class AgentClient {
74
74
  balance() {
75
75
  return this.request("GET", "/balance", { auth: true });
76
76
  }
77
+ /**
78
+ * The chain-agnostic spendable split — sign-up free credit + funds you added +
79
+ * total. Hits `GET /credit` (dual-auth, so the api-key works). This is the same
80
+ * figure the app shows on the Spending screen; `balance()` (/balance) carries
81
+ * the session status, so the portfolio uses both.
82
+ */
83
+ credit() {
84
+ return this.request("GET", "/credit", { auth: true });
85
+ }
77
86
  /**
78
87
  * Find a payable endpoint in the curated catalog. Hits `GET /marketplace/x402`
79
88
  * (the grouped, public catalog route) — NOT `/marketplace`, which does not
@@ -189,8 +189,15 @@ function usdcMinorPlain(minor) {
189
189
  const n = Number(minor) / 1e6;
190
190
  return `$${n.toFixed(n !== 0 && Math.abs(n) < 0.01 ? 4 : 2)}`;
191
191
  }
192
- /** Render the agent (spending) funds block as indented lines (no section title). */
193
- export function formatAgentFunds(bal) {
192
+ /**
193
+ * Render the agent (spending) funds block as indented lines (no section title).
194
+ *
195
+ * When the chain-agnostic `credit` read (GET /credit) is supplied, we render the
196
+ * full split — total spendable, the sign-up free credit, and (if the user has
197
+ * funded a wallet) the funds they added — for parity with the app. Without it we
198
+ * fall back to the `/balance` status shape (USDC/USDT or sign-up-credit total).
199
+ */
200
+ export function formatAgentFunds(bal, credit) {
194
201
  const status = bal.status;
195
202
  if (status === "not_set_up" || status === "no_active_session") {
196
203
  return [
@@ -203,10 +210,22 @@ export function formatAgentFunds(bal) {
203
210
  }
204
211
  if (status === "credit_exhausted") {
205
212
  return [
206
- ` Sign-up credit used up — balance ${usdcMinorPlain(bal.totalMinor)}`,
213
+ ` Sign-up credit used up — balance ${usdcMinorPlain(bal.totalMinor ?? credit?.totalMinor)}`,
207
214
  " Add funds to keep spending (`grant fetch`/`grant transfer` need a balance).",
208
215
  ].join("\n");
209
216
  }
217
+ // Prefer the chain-agnostic credit split (free credit + funds you added) when
218
+ // available — this is the same figure the app shows on the Spending screen.
219
+ if (credit && credit.totalMinor !== undefined) {
220
+ const lines = [` Spendable: ${usdcMinorPlain(credit.totalMinor)}`];
221
+ lines.push(` Free credit: ${usdcMinorPlain(credit.grantMinor)}`);
222
+ if (credit.walletMinor !== undefined) {
223
+ lines.push(` Your wallet: ${usdcMinorPlain(credit.walletMinor)}`);
224
+ }
225
+ if (bal.address)
226
+ lines.push(` Address: ${bal.address}`);
227
+ return lines.join("\n");
228
+ }
210
229
  // active. A funded on-chain session carries live USDC/USDT; a grant-only user
211
230
  // carries the chain-agnostic sign-up credit total in minor units.
212
231
  if (bal.USDC !== undefined || bal.USDT !== undefined) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentgrant.cash/cli",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Grant Cash — one CLI for your money (gold) and your agent (pay-per-use services). Routes to the Perfolio backend and the Agent-mode backend behind a single, plain-language surface.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -126,10 +126,18 @@ Every **cash** amount is in the user's display currency — a bare `50` means
126
126
  - `grant schema <slug>` — the exact pay contract for a catalogued service (no charge).
127
127
  - `grant fetch <url> [-m POST] [-b '<json>'] [--price <amount>] [--asset USDC|USDT]` (alias `pay`) — pay for and run a service.
128
128
  - `grant transfer <recipient> <amount>` — send money to an address.
129
+ - `grant spending deposit --amount <cash>` (aliases `add`, `top-up`) — move cash from the Investments side into the Spending balance (the agent's pay-per-use money). Amount is in the user's currency — a bare `50` means ₹50 for an INR user, $50 for a USD user. Funds land a few minutes after submitting. There is no reverse: Spending is funded from cash, not the other way around.
129
130
  - `grant redeem <code>` — claim an invite or bonus credit toward spending.
130
131
  - `grant upgrade` — get a one-time link to secure a full account and add spending funds.
131
132
  - `grant revoke` (alias `stop`) — stop all agent spending immediately.
132
133
 
134
+ **Keeping Spending funded (assistant guidance).** The Spending balance only goes down as the agent pays for services — top it up from the user's cash with `grant spending deposit`:
135
+ - **User asks explicitly** ("move ₹2,000 to spending", "top up my spending balance") → run `grant spending deposit --amount <cash>` directly. No need to ask again.
136
+ - **Running low** (a paid action is about to exceed — or only barely fits — the remaining Spending balance) → before paying, tell the user the balance is low and ask whether to transfer some cash over first. Don't transfer without a yes.
137
+ - **Empty / zero balance** (a `grant fetch`/pay fails for lack of funds, or `grant portfolio` shows Spending at 0) → tell the user their Spending account is empty and suggest moving some money in, **quoted in their local currency** — e.g. *"Your spending balance is empty — shall I move ₹2,000 (≈ $24) over from your cash?"* Then, on confirmation, run `grant spending deposit`.
138
+
139
+ Always state amounts in the user's display currency (never raw USD/USDT or chains), and only transfer proactively after the user agrees — an explicit request is the go-ahead; a low/empty balance is a prompt to ask.
140
+
133
141
  ### Transactions & self-orientation
134
142
  - `grant tx status <txHash>` — check whether a transaction confirmed. `grant tx history [--limit <n>]` — recent transactions.
135
143
  - `grant session status` / `grant session grant` — your agent-access (session) status and how to enable it.
@@ -164,6 +172,7 @@ grant polymarket bet 0x1234 --side yes --amount 25 # bet $25 on "yes"
164
172
  grant search "web search" --limit 5 # find a live service (Spending)
165
173
  grant check https://api.example.com/run # what it costs + needs, no charge
166
174
  grant fetch https://api.example.com/run -b '{"q":"gold news today"}' # pay + run
175
+ grant spending deposit --amount 25 # move $25 of cash into Spending
167
176
  grant activity --json # full combined history
168
177
  grant revoke # stop all agent spending
169
178
  ```