@blockrun/franklin 3.15.17 → 3.15.19

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.
@@ -61,6 +61,10 @@ export function runDataHygiene() {
61
61
  removeLegacyFiles();
62
62
  }
63
63
  catch { /* best effort */ }
64
+ try {
65
+ sweepOrphanToolResults();
66
+ }
67
+ catch { /* best effort */ }
64
68
  }
65
69
  function trimDataDir() {
66
70
  const dir = path.join(BLOCKRUN_DIR, 'data');
@@ -132,3 +136,57 @@ function removeLegacyFiles() {
132
136
  catch { /* ok */ }
133
137
  }
134
138
  }
139
+ /**
140
+ * `streaming-executor` writes large tool outputs to
141
+ * `~/.blockrun/tool-results/<sessionId>/<toolUseId>.txt`. When a session is
142
+ * pruned by `pruneOldSessions`, the meta + jsonl are deleted but the
143
+ * tool-results dir is left dangling. Verified on a real machine: 5 dirs,
144
+ * oldest from 4/14 (3 weeks past MAX_SESSIONS=20 retention).
145
+ *
146
+ * A tool-results dir is considered orphan when its name (the session id)
147
+ * has no `<sessionId>.meta.json` partner in the sessions/ dir. The active
148
+ * session is implicitly protected because its meta exists.
149
+ */
150
+ function sweepOrphanToolResults() {
151
+ const toolResultsDir = path.join(BLOCKRUN_DIR, 'tool-results');
152
+ const sessionsDir = path.join(BLOCKRUN_DIR, 'sessions');
153
+ if (!fs.existsSync(toolResultsDir))
154
+ return;
155
+ const knownSessionIds = new Set();
156
+ if (fs.existsSync(sessionsDir)) {
157
+ try {
158
+ for (const f of fs.readdirSync(sessionsDir)) {
159
+ if (f.endsWith('.meta.json')) {
160
+ knownSessionIds.add(f.slice(0, -'.meta.json'.length));
161
+ }
162
+ }
163
+ }
164
+ catch {
165
+ // Best-effort — if we can't read sessions/, skip the sweep so
166
+ // we never delete tool-results that might still belong to a
167
+ // live session.
168
+ return;
169
+ }
170
+ }
171
+ let entries;
172
+ try {
173
+ entries = fs.readdirSync(toolResultsDir);
174
+ }
175
+ catch {
176
+ return;
177
+ }
178
+ for (const name of entries) {
179
+ if (knownSessionIds.has(name))
180
+ continue;
181
+ const dir = path.join(toolResultsDir, name);
182
+ try {
183
+ const stat = fs.statSync(dir);
184
+ if (!stat.isDirectory())
185
+ continue;
186
+ fs.rmSync(dir, { recursive: true, force: true });
187
+ }
188
+ catch {
189
+ // Skip — best-effort cleanup.
190
+ }
191
+ }
192
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blockrun/franklin",
3
- "version": "3.15.17",
3
+ "version": "3.15.19",
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": {