diff --git a/plugin/dashboard/app/sessions/[sessionId]/page.tsx b/plugin/dashboard/app/sessions/[sessionId]/page.tsx
index 84ee3c8..c1be6d9 100644
--- a/plugin/dashboard/app/sessions/[sessionId]/page.tsx
+++ b/plugin/dashboard/app/sessions/[sessionId]/page.tsx
@@ -144,9 +144,12 @@ export default function InteractionDetailPage({
{turn.tools_used.map((t, ti) => {
const input = t.tool_data?.input;
+ const output = t.tool_data?.output;
const hasInput =
input && Object.keys(input).length > 0;
- if (!hasInput) {
+ const hasOutput =
+ typeof output === "string" && output.length > 0;
+ if (!hasInput && !hasOutput) {
return (
-
- {JSON.stringify(input, null, 2)}
-
+
+ {hasInput && (
+
+
+ input
+
+
+ {JSON.stringify(input, null, 2)}
+
+
+ )}
+ {hasOutput && (
+
+
+ output
+
+
+ {output}
+
+
+ )}
+
);
})}
diff --git a/plugin/dashboard/lib/session-reader.ts b/plugin/dashboard/lib/session-reader.ts
index 76f9e94..a6b31f3 100644
--- a/plugin/dashboard/lib/session-reader.ts
+++ b/plugin/dashboard/lib/session-reader.ts
@@ -17,6 +17,18 @@ import type {
UserActionType,
} from "./types";
+// Mirrors _TOOL_DATA_FIELD_MAX_LEN in plugin/src/claude_smart/state.py — we
+// truncate to the same length the publisher ships to reflexio so the
+// dashboard renders the exact bytes the extractor sees.
+const TOOL_DATA_FIELD_MAX_LEN = 256;
+
+function truncateToolField(value: T): T {
+ if (typeof value === "string" && value.length > TOOL_DATA_FIELD_MAX_LEN) {
+ return value.slice(0, TOOL_DATA_FIELD_MAX_LEN) as T;
+ }
+ return value;
+}
+
export function stateDir(): string {
const override = process.env.CLAUDE_SMART_STATE_DIR;
if (override) return override;
@@ -30,6 +42,7 @@ type RawRecord = {
user_id?: string;
tool_name?: string;
tool_input?: Record;
+ tool_output?: string;
status?: string;
user_action?: UserActionType;
user_action_description?: string;
@@ -81,8 +94,19 @@ function foldTurns(records: RawRecord[]): {
tool_name: rec.tool_name ?? "",
status: rec.status ?? "success",
};
+ const toolData: { input?: Record; output?: string } = {};
if (rec.tool_input && Object.keys(rec.tool_input).length > 0) {
- entry.tool_data = { input: rec.tool_input };
+ const input: Record = {};
+ for (const [k, v] of Object.entries(rec.tool_input)) {
+ input[k] = truncateToolField(v);
+ }
+ toolData.input = input;
+ }
+ if (typeof rec.tool_output === "string" && rec.tool_output.length > 0) {
+ toolData.output = truncateToolField(rec.tool_output);
+ }
+ if (toolData.input || toolData.output) {
+ entry.tool_data = toolData;
}
pendingTools.push(entry);
continue;
diff --git a/plugin/dashboard/lib/types.ts b/plugin/dashboard/lib/types.ts
index 16f31a4..f478180 100644
--- a/plugin/dashboard/lib/types.ts
+++ b/plugin/dashboard/lib/types.ts
@@ -12,7 +12,7 @@ export type ProfileStatus = "CURRENT" | "ARCHIVED" | "PENDING";
export interface ToolUsed {
tool_name: string;
status: string;
- tool_data?: { input?: Record };
+ tool_data?: { input?: Record; output?: string };
}
export interface CitedItem {