Live map of files Claude Read this session; /files lists them.

Live map of files Claude Read this session; /files lists them.
claude plugin marketplace add kenhuangus/claude-code-mods-pack
claude plugin install session-map@kenhuang-modshooks/session-map.mjs 39 lines1const MAP = { plugin: "session-map", key: "map" };
2export function register(on) {
3 on("session.start", async ($, e, next) => {
4 const r = await next(e);
5 await $.state.set(MAP, { files: [] });
6 await $.command.register({ name: "files", description: "List files read in this session" });
7 return r;
8 });
9 on("tool.call", { tool: "Read" }, async ($, e, next) => {
10 const result = await next(e);
11 const path = e.file_path || e.path || e.filePath;
12 if (path) {
13 const { value: map } = await $.state.get(MAP);
14 const files = [...(map?.files ?? [])];
15 if (!files.includes(path)) files.push(path);
16 await $.state.set(MAP, { files: files.slice(-40) });
17 }
18 return result;
19 });
20 on("command.run", { command: "files" }, async ($) => {
21 const { value: map } = await $.state.get(MAP);
22 const files = map?.files ?? [];
23 if (!files.length) return { text: "No files read yet." };
24 return { text: files.map((f, i) => `${i + 1}. ${f}`).join("\n") };
25 });
26 on("ui.render", { component: "AbovePrompt" }, async ($, e, next) => {
27 if (e.props?.hasSurvey) return next(e);
28 const { value: map } = await $.state.get(MAP);
29 const n = map?.files?.length ?? 0;
30 if (!n) return next(e);
31 const last = map.files[map.files.length - 1];
32 const { Box, Text } = $.ui.resolve(e);
33 return Box({
34 paddingX: 1,
35 children: [Text({ color: "blue", bold: true, children: `FILES ${n} last:${last}` })],
36 });
37 });
38}
39types/index.d.ts 8 lines1declare module "claude-code" {
2 interface PluginState {
3 "session-map": {
4 map: { files: string[] };
5 };
6 }
7}
8