forge-remote 0.1.23 → 0.1.25
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 +1 -1
- package/src/cli.js +3 -1
- package/src/init.js +57 -4
- package/src/logger.js +1 -0
- package/src/session-manager.js +28 -3
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -210,8 +210,10 @@ program
|
|
|
210
210
|
if (!sdkConfig) {
|
|
211
211
|
console.error("\nCould not load Firebase SDK config.");
|
|
212
212
|
console.error(
|
|
213
|
-
"Run `forge-remote init` first, or ensure the Firebase CLI is installed
|
|
213
|
+
"Run `npx forge-remote init` first, or ensure the Firebase CLI is installed.",
|
|
214
214
|
);
|
|
215
|
+
console.error(" Install Firebase CLI: npm install -g firebase-tools");
|
|
216
|
+
console.error(` Setup guide: https://forgeremote.com/#how-it-works\n`);
|
|
215
217
|
process.exit(1);
|
|
216
218
|
}
|
|
217
219
|
|
package/src/init.js
CHANGED
|
@@ -200,21 +200,74 @@ export async function runInit({ projectId: overrideProjectId } = {}) {
|
|
|
200
200
|
console.log(
|
|
201
201
|
chalk.dim(" a QR code to pair with the mobile app. Fully automated.\n"),
|
|
202
202
|
);
|
|
203
|
+
console.log(
|
|
204
|
+
chalk.dim(
|
|
205
|
+
` Full setup guide: ${chalk.cyan("https://forgeremote.com/#how-it-works")}`,
|
|
206
|
+
),
|
|
207
|
+
);
|
|
203
208
|
|
|
204
|
-
// ──
|
|
209
|
+
// ── Prerequisites check ──────────────────────────────────────────────────
|
|
205
210
|
|
|
206
|
-
console.log(chalk.bold("\n📋
|
|
211
|
+
console.log(chalk.bold("\n📋 Prerequisites Check\n"));
|
|
207
212
|
|
|
213
|
+
const nodeVersion = run(["node", "--version"], { silent: true });
|
|
214
|
+
const npmVersion = run(["npm", "--version"], { silent: true });
|
|
208
215
|
const firebaseVersion = run(["firebase", "--version"], { silent: true });
|
|
216
|
+
|
|
217
|
+
console.log(
|
|
218
|
+
nodeVersion
|
|
219
|
+
? chalk.green(` ✓ Node.js ${nodeVersion}`)
|
|
220
|
+
: chalk.red(" ✗ Node.js — not found"),
|
|
221
|
+
);
|
|
222
|
+
console.log(
|
|
223
|
+
npmVersion
|
|
224
|
+
? chalk.green(` ✓ npm ${npmVersion}`)
|
|
225
|
+
: chalk.red(" ✗ npm — not found"),
|
|
226
|
+
);
|
|
227
|
+
console.log(
|
|
228
|
+
firebaseVersion
|
|
229
|
+
? chalk.green(` ✓ Firebase CLI ${firebaseVersion}`)
|
|
230
|
+
: chalk.red(" ✗ Firebase CLI — not found"),
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
if (!nodeVersion) {
|
|
234
|
+
console.error(chalk.red("\n Node.js is required (v18 or later).\n"));
|
|
235
|
+
console.error(chalk.bold(" Install it from:\n"));
|
|
236
|
+
console.error(chalk.cyan(" https://nodejs.org\n"));
|
|
237
|
+
process.exit(1);
|
|
238
|
+
}
|
|
239
|
+
|
|
209
240
|
if (!firebaseVersion) {
|
|
210
|
-
console.error(
|
|
241
|
+
console.error(
|
|
242
|
+
chalk.red("\n Firebase CLI is required but not installed.\n"),
|
|
243
|
+
);
|
|
244
|
+
console.error(
|
|
245
|
+
chalk.dim(
|
|
246
|
+
" The Firebase CLI is a free command-line tool from Google that lets",
|
|
247
|
+
),
|
|
248
|
+
);
|
|
249
|
+
console.error(
|
|
250
|
+
chalk.dim(
|
|
251
|
+
" Forge Remote create and manage your Firebase project automatically.\n",
|
|
252
|
+
),
|
|
253
|
+
);
|
|
211
254
|
console.error(chalk.bold(" Install it with:\n"));
|
|
212
255
|
console.error(chalk.cyan(" npm install -g firebase-tools\n"));
|
|
256
|
+
console.error(chalk.dim(" Then run this command again:\n"));
|
|
257
|
+
console.error(chalk.cyan(" npx forge-remote init\n"));
|
|
213
258
|
console.error(
|
|
214
|
-
chalk.dim(
|
|
259
|
+
chalk.dim(
|
|
260
|
+
` For more info: ${chalk.cyan("https://forgeremote.com/#how-it-works")}\n`,
|
|
261
|
+
),
|
|
215
262
|
);
|
|
216
263
|
process.exit(1);
|
|
217
264
|
}
|
|
265
|
+
|
|
266
|
+
console.log(chalk.green("\n All prerequisites met!\n"));
|
|
267
|
+
|
|
268
|
+
// ── Step 1: Check Firebase CLI ──────────────────────────────────────────
|
|
269
|
+
|
|
270
|
+
console.log(chalk.bold("\n📋 Step 1/11 — Checking Firebase CLI...\n"));
|
|
218
271
|
console.log(chalk.green(` ✓ Firebase CLI ${firebaseVersion}`));
|
|
219
272
|
|
|
220
273
|
// ── Step 2: Firebase login ──────────────────────────────────────────────
|
package/src/logger.js
CHANGED
|
@@ -134,6 +134,7 @@ export function banner(hostname, platform, desktopId, projectCount) {
|
|
|
134
134
|
console.log(` ${BOLD}Projects:${RESET} ${projectCount} found`);
|
|
135
135
|
console.log(`${BOLD}${CYAN}${line}${RESET}`);
|
|
136
136
|
console.log(` ${GREEN}Listening for commands...${RESET}`);
|
|
137
|
+
console.log(` ${DIM}Docs: https://forgeremote.com${RESET}`);
|
|
137
138
|
console.log(` ${DIM}Press Ctrl+C to stop${RESET}\n`);
|
|
138
139
|
}
|
|
139
140
|
|
package/src/session-manager.js
CHANGED
|
@@ -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)
|
|
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)
|
|
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 =
|