#!/usr/bin/env node // Print a compact transcript of a local DSH session (tool calls, results, answers). // node deploy/session-log.mjs [sinceSeq] import fs from 'node:fs' import os from 'node:os' import path from 'node:path' import { mintCookie } from '../lib/auth-cookie.mjs' const [sid, since = '-1'] = process.argv.slice(2) const port = process.env.DSH_PORT || '3081' const home = process.env.DSH_HOME || path.join(os.homedir(), '.dsh') const secret = fs.readFileSync(path.join(home, '.credentials.yaml'), 'utf8').match(/browser-session:[\s\S]*?secret:\s*([A-Za-z0-9_-]{43})/)[1] const authority = `127.0.0.1:${port}` const device = process.env.DEVICE ? `&device=${encodeURIComponent(process.env.DEVICE)}` : '' const res = await fetch(`http://${authority}/dsh-remote/debug/inspect?sessionId=${encodeURIComponent(sid)}${device}`, { headers: { cookie: mintCookie(authority, secret, 1) } }) const j = await res.json() if (!res.ok) { console.error(res.status, j); process.exit(1) } const short = (s, n = 300) => { const t = String(s ?? '').replace(/\s+/g, ' '); return t.length > n ? t.slice(0, n) + '…' : t } for (const e of j.events) { if (e.seq <= Number(since)) continue const d = e.data || {} if (e.type === 'user/message') console.log(`#${e.seq} USER: ${short(d.content?.map((c) => c.text).join(' '), 200)}`) else if (e.type === 'tool/call') console.log(`#${e.seq} CALL ${d.name}: ${short(JSON.stringify(d.arguments), 260)}`) else if (e.type === 'tool/result') { const c = d.message?.content || [] console.log(`#${e.seq} → ${short(c.map((x) => x.text ?? JSON.stringify(x)).join(' '), 360)}`) } else if (e.type === 'assistant/message') { const t = (d.message?.content || []).filter((c) => c.type === 'text').map((c) => c.text).join(' ') if (t) console.log(`#${e.seq} AI: ${short(t, 1200)}`) } else if (e.type === 'turn/end') console.log(`#${e.seq} TURN END ${JSON.stringify(d.reason)}`) }