@blockrun/franklin 3.16.2 → 3.16.4
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/dist/agent/commands.js +48 -1
- package/dist/tools/posttox.js +14 -1
- package/dist/tools/searchx.js +16 -1
- package/package.json +1 -1
package/dist/agent/commands.js
CHANGED
|
@@ -233,7 +233,7 @@ const DIRECT_COMMANDS = {
|
|
|
233
233
|
` **Coding:** /commit /review /test /fix /debug /explain /search /find /refactor /scaffold\n` +
|
|
234
234
|
` **Git:** /push /pr /undo /status /diff /log /branch /stash /unstash\n` +
|
|
235
235
|
` **Analysis:** /security /lint /optimize /todo /deps /clean /migrate /doc\n` +
|
|
236
|
-
` **Session:** /plan /ultraplan /execute /compact /retry /sessions /resume /session-search /context /tasks\n` +
|
|
236
|
+
` **Session:** /plan /ultraplan /execute /compact /retry /sessions /resume /session-search /context /tasks /history /transcript\n` +
|
|
237
237
|
` **Power:** /ultrathink [query] /ultraplan /noplan /moa [query] /dump\n` +
|
|
238
238
|
` **Info:** /model /auto /wallet /cost /tokens /learnings /brain /mcp /doctor /version /bug /help\n` +
|
|
239
239
|
` **UI:** /clear /exit\n` +
|
|
@@ -259,6 +259,53 @@ const DIRECT_COMMANDS = {
|
|
|
259
259
|
}
|
|
260
260
|
}
|
|
261
261
|
output += 'Use `/delete <number>` to remove exchanges (e.g., `/delete 2` or `/delete 3-5`).\n';
|
|
262
|
+
output += 'Use `/transcript` for the full, un-truncated transcript.\n';
|
|
263
|
+
ctx.onEvent({ kind: 'text_delta', text: output });
|
|
264
|
+
emitDone(ctx);
|
|
265
|
+
},
|
|
266
|
+
'/transcript': (ctx) => {
|
|
267
|
+
// Dump the FULL, un-truncated conversation as a single fresh stdout
|
|
268
|
+
// block. Works around the limitation that the terminal's native
|
|
269
|
+
// scrollback fills up faster than we can render long Franklin sessions
|
|
270
|
+
// — by the time you scroll up to look for the first message, the
|
|
271
|
+
// older Ink output has been pushed out of the terminal's ring buffer.
|
|
272
|
+
// The fresh emit here becomes one contiguous block, so the user can
|
|
273
|
+
// scroll *that* to read everything in order.
|
|
274
|
+
const { history, config } = ctx;
|
|
275
|
+
const modelName = config.model.split('/').pop() || config.model;
|
|
276
|
+
const exchanges = buildExchanges(history);
|
|
277
|
+
if (exchanges.length === 0) {
|
|
278
|
+
ctx.onEvent({ kind: 'text_delta', text: 'No history in the current session yet.\n' });
|
|
279
|
+
emitDone(ctx);
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
let output = `**Full Transcript** — ${exchanges.length} exchange${exchanges.length === 1 ? '' : 's'}, session \`${ctx.sessionId}\`\n\n`;
|
|
283
|
+
output += '─'.repeat(70) + '\n\n';
|
|
284
|
+
for (let i = 0; i < exchanges.length; i++) {
|
|
285
|
+
const ex = exchanges[i];
|
|
286
|
+
// Re-read full text from raw history (buildExchanges truncated).
|
|
287
|
+
const userMsg = history[ex.startIdx];
|
|
288
|
+
const fullUser = extractText(userMsg);
|
|
289
|
+
// Find first assistant text in this exchange (full, not truncated).
|
|
290
|
+
let fullAssistant = '';
|
|
291
|
+
for (let j = ex.startIdx + 1; j <= ex.endIdx; j++) {
|
|
292
|
+
const m = history[j];
|
|
293
|
+
if (m.role === 'assistant') {
|
|
294
|
+
const t = extractText(m);
|
|
295
|
+
if (t && !fullAssistant)
|
|
296
|
+
fullAssistant = t;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
output += `❯ [${i + 1}] ${fullUser}\n\n`;
|
|
300
|
+
if (fullAssistant)
|
|
301
|
+
output += `${fullAssistant}\n`;
|
|
302
|
+
if (ex.toolNames.length > 0) {
|
|
303
|
+
output += `\n _tools: ${ex.toolNames.join(', ')}_\n`;
|
|
304
|
+
}
|
|
305
|
+
output += `\n[${modelName}]\n\n`;
|
|
306
|
+
output += '─'.repeat(70) + '\n\n';
|
|
307
|
+
}
|
|
308
|
+
output += `End of transcript — ${history.length} raw messages, ${exchanges.length} user/assistant exchanges.\n`;
|
|
262
309
|
ctx.onEvent({ kind: 'text_delta', text: output });
|
|
263
310
|
emitDone(ctx);
|
|
264
311
|
},
|
package/dist/tools/posttox.js
CHANGED
|
@@ -36,7 +36,20 @@ async function execute(input, _ctx) {
|
|
|
36
36
|
const searchUrl = `https://x.com/search?q=${encodeURIComponent(search_query)}&src=typed_query&f=live`;
|
|
37
37
|
await browser.open(searchUrl);
|
|
38
38
|
await browser.waitForTimeout(3500);
|
|
39
|
-
|
|
39
|
+
// Same defensive guard as SearchX — Playwright can drop the page out
|
|
40
|
+
// from under us during the wait. Surface a useful hint instead of
|
|
41
|
+
// "Cannot read properties of undefined (reading 'snapshot')".
|
|
42
|
+
let tree;
|
|
43
|
+
try {
|
|
44
|
+
tree = await browser.snapshot();
|
|
45
|
+
}
|
|
46
|
+
catch (snapErr) {
|
|
47
|
+
const snapMsg = snapErr instanceof Error ? snapErr.message : String(snapErr);
|
|
48
|
+
return {
|
|
49
|
+
output: `PostToX: Page snapshot failed (${snapMsg.slice(0, 100)}). The browser session likely closed mid-flight — retry, or run \`franklin social setup\` to refresh.`,
|
|
50
|
+
isError: true,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
40
53
|
// ── Find the article matching the given pre_key ──────────────────
|
|
41
54
|
const articles = extractArticleBlocks(tree);
|
|
42
55
|
let matchedTimeRef = null;
|
package/dist/tools/searchx.js
CHANGED
|
@@ -122,7 +122,22 @@ async function execute(input, _ctx) {
|
|
|
122
122
|
return { output: `SearchX: Failed to open X.com: ${msg.slice(0, 200)}`, isError: true };
|
|
123
123
|
}
|
|
124
124
|
await browser.waitForTimeout(4000);
|
|
125
|
-
|
|
125
|
+
// Defensive: snapshot() has historically thrown "Cannot read properties
|
|
126
|
+
// of undefined (reading 'snapshot')" when Playwright's underlying page
|
|
127
|
+
// closes between waitForTimeout and the snapshot call (verified in
|
|
128
|
+
// failures.jsonl 2026-04-20). Convert the cryptic error into a useful
|
|
129
|
+
// hint instead of leaking it into the audit log unchanged.
|
|
130
|
+
let tree;
|
|
131
|
+
try {
|
|
132
|
+
tree = await browser.snapshot();
|
|
133
|
+
}
|
|
134
|
+
catch (snapErr) {
|
|
135
|
+
const snapMsg = snapErr instanceof Error ? snapErr.message : String(snapErr);
|
|
136
|
+
return {
|
|
137
|
+
output: `SearchX: Page snapshot failed (${snapMsg.slice(0, 100)}). The browser session likely closed mid-flight — retry, or run \`franklin social setup\` to refresh.`,
|
|
138
|
+
isError: true,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
126
141
|
// ── Diagnose page state ───────────────────────────────────────────
|
|
127
142
|
const isLoginWall = tree.includes('Sign in') && tree.includes('Create account');
|
|
128
143
|
const isRateLimit = tree.includes('Rate limit') || tree.includes('Something went wrong');
|
package/package.json
CHANGED