@blockrun/franklin 3.6.4 → 3.6.5

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.
@@ -236,6 +236,18 @@ async function runWithInkUI(agentConfig, model, workDir, version, walletInfo, on
236
236
  catch { /* extraction is best-effort */ }
237
237
  }
238
238
  await disconnectMcpServers();
239
+ // Session summary — show cost and usage before goodbye
240
+ try {
241
+ const { getStatsSummary } = await import('../stats/tracker.js');
242
+ const { stats, saved } = getStatsSummary();
243
+ if (stats.totalRequests > 0) {
244
+ const cost = stats.totalCostUsd.toFixed(4);
245
+ const savedStr = saved > 0.001 ? ` · saved $${saved.toFixed(2)} vs Opus` : '';
246
+ const tokens = `${(stats.totalInputTokens / 1000).toFixed(0)}k in / ${(stats.totalOutputTokens / 1000).toFixed(0)}k out`;
247
+ console.log(chalk.dim(`\n Session: ${stats.totalRequests} requests · $${cost} USDC${savedStr} · ${tokens}`));
248
+ }
249
+ }
250
+ catch { /* stats unavailable */ }
239
251
  console.log(chalk.dim('\nGoodbye.\n'));
240
252
  }
241
253
  // ─── Basic readline UI (piped input) ───────────────────────────────────────
@@ -288,6 +300,18 @@ async function runWithBasicUI(agentConfig, model, workDir) {
288
300
  console.error(chalk.red(`\nError: ${err.message}`));
289
301
  }
290
302
  }
303
+ // Session summary for piped mode
304
+ try {
305
+ const { getStatsSummary } = await import('../stats/tracker.js');
306
+ const { stats, saved } = getStatsSummary();
307
+ if (stats.totalRequests > 0) {
308
+ const cost = stats.totalCostUsd.toFixed(4);
309
+ const savedStr = saved > 0.001 ? ` · saved $${saved.toFixed(2)} vs Opus` : '';
310
+ const tokens = `${(stats.totalInputTokens / 1000).toFixed(0)}k in / ${(stats.totalOutputTokens / 1000).toFixed(0)}k out`;
311
+ console.error(`Session: ${stats.totalRequests} requests · $${cost} USDC${savedStr} · ${tokens}`);
312
+ }
313
+ }
314
+ catch { /* stats unavailable */ }
291
315
  ui.printGoodbye();
292
316
  flushStats();
293
317
  }
@@ -118,9 +118,34 @@ async function execute(input, ctx) {
118
118
  : '';
119
119
  return { output: `No files matched pattern "${pattern}" in ${baseDir}.${hint}` };
120
120
  }
121
- let output = sorted.join('\n');
121
+ // Group by directory for compact output (saves 30-40% tokens on large results)
122
+ let output;
123
+ if (sorted.length > 10) {
124
+ const grouped = new Map();
125
+ for (const p of sorted) {
126
+ const dir = path.dirname(p);
127
+ if (!grouped.has(dir))
128
+ grouped.set(dir, []);
129
+ grouped.get(dir).push(path.basename(p));
130
+ }
131
+ const parts = [];
132
+ for (const [dir, files] of grouped) {
133
+ if (files.length === 1) {
134
+ parts.push(`${dir}/${files[0]}`);
135
+ }
136
+ else {
137
+ parts.push(`${dir}/ (${files.length} files)`);
138
+ for (const f of files)
139
+ parts.push(` ${f}`);
140
+ }
141
+ }
142
+ output = parts.join('\n');
143
+ }
144
+ else {
145
+ output = sorted.join('\n');
146
+ }
122
147
  if (sorted.length >= MAX_RESULTS) {
123
- output += `\n\n... (limited to ${MAX_RESULTS} results. Use a more specific pattern to narrow results.)`;
148
+ output += `\n\n... (limited to ${MAX_RESULTS} results. Use a more specific pattern.)`;
124
149
  }
125
150
  // Cap total output length to prevent context bloat
126
151
  if (output.length > MAX_OUTPUT_CHARS) {
@@ -135,7 +160,7 @@ async function execute(input, ctx) {
135
160
  }
136
161
  const remaining = lines.length - count;
137
162
  if (remaining > 0) {
138
- output = `${trimmed}\n... (${remaining} more paths not shown — use a more specific pattern)`;
163
+ output = `${trimmed}\n... (${remaining} more not shown — use a more specific pattern)`;
139
164
  }
140
165
  }
141
166
  return { output };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blockrun/franklin",
3
- "version": "3.6.4",
3
+ "version": "3.6.5",
4
4
  "description": "Franklin — The AI agent with a wallet. Spends USDC autonomously to get real work done. Pay per action, no subscriptions.",
5
5
  "type": "module",
6
6
  "exports": {