forge-remote 0.1.23 → 0.1.24

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "forge-remote",
3
- "version": "0.1.23",
3
+ "version": "0.1.24",
4
4
  "description": "Desktop relay for Forge Remote — monitor and control Claude Code sessions from your phone",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
@@ -570,6 +570,9 @@ export async function startNewSession(desktopId, payload) {
570
570
  startTime: Date.now(),
571
571
  messageCount: 0,
572
572
  toolCallCount: 0,
573
+ turnToolCalls: 0, // Tool calls this turn (reset on each prompt)
574
+ turnTokensInput: 0, // Input tokens this turn
575
+ turnTokensOutput: 0, // Output tokens this turn
573
576
  isFirstPrompt: true,
574
577
  lastToolCall: null, // Last tool_use block (for permission requests)
575
578
  permissionNeeded: false, // True when Claude reports permission denial
@@ -690,10 +693,13 @@ async function runClaudeProcess(sessionId, prompt) {
690
693
  const session = activeSessions.get(sessionId);
691
694
  if (!session) return;
692
695
 
693
- // Reset permission state for this new turn.
696
+ // Reset permission state and per-turn stats for this new turn.
694
697
  session.permissionNeeded = false;
695
698
  session.deniedToolCall = null;
696
699
  session.lastToolCall = null;
700
+ session.turnToolCalls = 0;
701
+ session.turnTokensInput = 0;
702
+ session.turnTokensOutput = 0;
697
703
 
698
704
  const db = getDb();
699
705
  const sessionRef = db.collection("sessions").doc(sessionId);
@@ -1031,6 +1037,17 @@ async function runClaudeProcess(sessionId, prompt) {
1031
1037
  timestamp: FieldValue.serverTimestamp(),
1032
1038
  });
1033
1039
 
1040
+ // Award XP for completed turn.
1041
+ awardSessionXp(sessionId, {
1042
+ toolCalls: sess?.turnToolCalls || 0,
1043
+ tokensUsed:
1044
+ (sess?.turnTokensInput || 0) + (sess?.turnTokensOutput || 0),
1045
+ }).catch((e) =>
1046
+ log.warn(
1047
+ `Failed to award XP for ${sessionId.slice(0, 8)}: ${e.message}`,
1048
+ ),
1049
+ );
1050
+
1034
1051
  // Push notification for idle.
1035
1052
  notifySessionIdle(sess.desktopId, sessionId, {
1036
1053
  projectName: sess.projectName || "Unknown",
@@ -1310,7 +1327,12 @@ async function handleStreamEvent(sessionId, sessionRef, event) {
1310
1327
  lastActivity: FieldValue.serverTimestamp(),
1311
1328
  });
1312
1329
 
1313
- if (session) session.tokenUsage = tokenUsage;
1330
+ if (session) {
1331
+ session.tokenUsage = tokenUsage;
1332
+ // Track per-turn tokens for XP calculation.
1333
+ session.turnTokensInput = tokenUsage.input;
1334
+ session.turnTokensOutput = tokenUsage.output;
1335
+ }
1314
1336
 
1315
1337
  log.session(
1316
1338
  sessionId,
@@ -1509,7 +1531,10 @@ const toolCallDocIds = new Map();
1509
1531
  async function storeToolCall(sessionId, block) {
1510
1532
  const db = getDb();
1511
1533
  const session = activeSessions.get(sessionId);
1512
- if (session) session.toolCallCount = (session.toolCallCount || 0) + 1;
1534
+ if (session) {
1535
+ session.toolCallCount = (session.toolCallCount || 0) + 1;
1536
+ session.turnToolCalls = (session.turnToolCalls || 0) + 1;
1537
+ }
1513
1538
 
1514
1539
  const toolName = block.name || "unknown";
1515
1540
  const toolInput =