skill-distill 1.0.0 → 1.0.1

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/index.d.ts CHANGED
@@ -149,9 +149,8 @@ declare class ClaudeSessionLoader extends SessionLoader {
149
149
  getDefaultBasePath(): string;
150
150
  listSessions(): Promise<SessionInfo[]>;
151
151
  getSession(id: string): Promise<Session>;
152
- private readSessionFile;
152
+ private readTranscriptFile;
153
153
  private transformSession;
154
- private transformMessage;
155
154
  private extractSummary;
156
155
  }
157
156
 
package/dist/index.js CHANGED
@@ -95,94 +95,128 @@ var ClaudeSessionLoader = class extends SessionLoader {
95
95
  super(options);
96
96
  }
97
97
  getDefaultBasePath() {
98
- return join2(homedir2(), ".claude", "projects");
98
+ return join2(homedir2(), ".claude", "transcripts");
99
99
  }
100
100
  async listSessions() {
101
101
  const sessions = [];
102
102
  try {
103
- const projectDirs = await fs2.readdir(this.basePath);
104
- for (const projectDir of projectDirs) {
105
- const projectPath = join2(this.basePath, projectDir);
106
- const stat = await fs2.stat(projectPath);
107
- if (!stat.isDirectory()) continue;
108
- const sessionsPath = join2(projectPath, "sessions");
109
- try {
110
- const sessionFiles = await fs2.readdir(sessionsPath);
111
- for (const file of sessionFiles) {
112
- if (!file.endsWith(".json")) continue;
113
- const sessionPath = join2(sessionsPath, file);
114
- const sessionData = await this.readSessionFile(sessionPath);
115
- if (sessionData) {
116
- sessions.push({
117
- id: sessionData.id,
118
- projectPath: projectDir,
119
- startTime: sessionData.createdAt,
120
- endTime: sessionData.updatedAt,
121
- messageCount: sessionData.messages.length,
122
- summary: this.extractSummary(sessionData.messages)
123
- });
124
- }
125
- }
126
- } catch {
127
- continue;
128
- }
103
+ const files = await fs2.readdir(this.basePath);
104
+ for (const file of files) {
105
+ if (!file.endsWith(".jsonl") || !file.startsWith("ses_")) continue;
106
+ const filePath = join2(this.basePath, file);
107
+ const stat = await fs2.stat(filePath);
108
+ const sessionId = file.replace(".jsonl", "");
109
+ const entries = await this.readTranscriptFile(filePath);
110
+ if (entries.length === 0) continue;
111
+ const userMessages = entries.filter((e) => e.type === "user");
112
+ const firstEntry = entries[0];
113
+ const lastEntry = entries[entries.length - 1];
114
+ sessions.push({
115
+ id: sessionId,
116
+ projectPath: "",
117
+ startTime: firstEntry.timestamp,
118
+ endTime: lastEntry.timestamp,
119
+ messageCount: userMessages.length,
120
+ summary: this.extractSummary(entries)
121
+ });
129
122
  }
130
123
  } catch (error) {
131
124
  throw new Error(`Failed to list sessions: ${error}`);
132
125
  }
133
- return sessions;
126
+ return sessions.sort(
127
+ (a, b) => new Date(b.startTime).getTime() - new Date(a.startTime).getTime()
128
+ );
134
129
  }
135
130
  async getSession(id) {
136
- const sessions = await this.listSessions();
137
- const sessionInfo = sessions.find((s) => s.id === id);
138
- if (!sessionInfo) {
131
+ const filePath = join2(this.basePath, `${id}.jsonl`);
132
+ try {
133
+ await fs2.access(filePath);
134
+ } catch {
139
135
  throw new Error(`Session not found: ${id}`);
140
136
  }
141
- const sessionPath = join2(this.basePath, sessionInfo.projectPath, "sessions", `${id}.json`);
142
- const data = await this.readSessionFile(sessionPath);
143
- if (!data) {
144
- throw new Error(`Failed to read session: ${id}`);
137
+ const entries = await this.readTranscriptFile(filePath);
138
+ if (entries.length === 0) {
139
+ throw new Error(`Empty session: ${id}`);
145
140
  }
146
- return this.transformSession(data, sessionInfo.projectPath);
141
+ return this.transformSession(id, entries);
147
142
  }
148
- async readSessionFile(path) {
143
+ async readTranscriptFile(path) {
149
144
  try {
150
145
  const content = await fs2.readFile(path, "utf-8");
151
- return JSON.parse(content);
146
+ const lines = content.trim().split("\n").filter(Boolean);
147
+ return lines.map((line) => JSON.parse(line));
152
148
  } catch {
153
- return null;
149
+ return [];
154
150
  }
155
151
  }
156
- transformSession(data, projectPath) {
157
- return {
158
- id: data.id,
159
- projectPath,
160
- startTime: data.createdAt,
161
- endTime: data.updatedAt,
162
- messages: data.messages.map((msg) => this.transformMessage(msg))
163
- };
164
- }
165
- transformMessage(msg) {
152
+ transformSession(id, entries) {
153
+ const messages = [];
154
+ let currentAssistantContent = "";
155
+ let currentToolCalls = [];
156
+ let currentToolResults = [];
157
+ let lastTimestamp = "";
158
+ for (const entry of entries) {
159
+ if (entry.type === "user") {
160
+ if (currentAssistantContent || currentToolCalls?.length) {
161
+ messages.push({
162
+ role: "assistant",
163
+ content: currentAssistantContent,
164
+ timestamp: lastTimestamp,
165
+ toolCalls: currentToolCalls.length > 0 ? currentToolCalls : void 0,
166
+ toolResults: currentToolResults.length > 0 ? currentToolResults : void 0
167
+ });
168
+ currentAssistantContent = "";
169
+ currentToolCalls = [];
170
+ currentToolResults = [];
171
+ }
172
+ messages.push({
173
+ role: "user",
174
+ content: entry.content ?? "",
175
+ timestamp: entry.timestamp
176
+ });
177
+ } else if (entry.type === "assistant") {
178
+ currentAssistantContent += (entry.content ?? "") + "\n";
179
+ lastTimestamp = entry.timestamp;
180
+ } else if (entry.type === "tool_use") {
181
+ currentToolCalls.push({
182
+ name: entry.tool_name ?? "unknown",
183
+ input: entry.tool_input ?? {}
184
+ });
185
+ lastTimestamp = entry.timestamp;
186
+ } else if (entry.type === "tool_result") {
187
+ currentToolResults.push({
188
+ name: entry.tool_name ?? "unknown",
189
+ output: entry.tool_output?.preview ?? "",
190
+ success: true
191
+ });
192
+ lastTimestamp = entry.timestamp;
193
+ }
194
+ }
195
+ if (currentAssistantContent || currentToolCalls?.length) {
196
+ messages.push({
197
+ role: "assistant",
198
+ content: currentAssistantContent.trim(),
199
+ timestamp: lastTimestamp,
200
+ toolCalls: currentToolCalls.length > 0 ? currentToolCalls : void 0,
201
+ toolResults: currentToolResults.length > 0 ? currentToolResults : void 0
202
+ });
203
+ }
204
+ const firstEntry = entries[0];
205
+ const lastEntry = entries[entries.length - 1];
166
206
  return {
167
- role: msg.role === "human" ? "user" : "assistant",
168
- content: msg.content,
169
- timestamp: msg.createdAt,
170
- toolCalls: msg.toolUseBlocks?.map((t) => ({
171
- name: t.name,
172
- input: t.input
173
- })),
174
- toolResults: msg.toolResultBlocks?.map((t) => ({
175
- name: t.toolUseId,
176
- output: t.content,
177
- success: !t.isError
178
- }))
207
+ id,
208
+ projectPath: "",
209
+ startTime: firstEntry.timestamp,
210
+ endTime: lastEntry.timestamp,
211
+ messages
179
212
  };
180
213
  }
181
- extractSummary(messages) {
182
- const firstUserMessage = messages.find((m) => m.role === "human");
183
- if (!firstUserMessage) return "";
184
- const content = firstUserMessage.content;
185
- return content.length > 100 ? content.slice(0, 100) + "..." : content;
214
+ extractSummary(entries) {
215
+ const firstUserEntry = entries.find((e) => e.type === "user");
216
+ if (!firstUserEntry?.content) return "";
217
+ const content = firstUserEntry.content;
218
+ const firstLine = content.split("\n")[0];
219
+ return firstLine.length > 80 ? firstLine.slice(0, 80) + "..." : firstLine;
186
220
  }
187
221
  };
188
222