skill-distill 1.0.1 → 1.0.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/cli.js CHANGED
@@ -42,54 +42,144 @@ var SessionLoader = class {
42
42
 
43
43
  // src/loaders/claude.ts
44
44
  var ClaudeSessionLoader = class extends SessionLoader {
45
+ transcriptsPath;
46
+ projectsPath;
45
47
  constructor(options = {}) {
46
48
  super(options);
49
+ const claudeDir = join(homedir(), ".claude");
50
+ this.transcriptsPath = join(claudeDir, "transcripts");
51
+ this.projectsPath = join(claudeDir, "projects");
47
52
  }
48
53
  getDefaultBasePath() {
49
- return join(homedir(), ".claude", "transcripts");
54
+ return join(homedir(), ".claude");
50
55
  }
51
56
  async listSessions() {
57
+ const sessions = [];
58
+ const transcriptSessions = await this.listTranscriptSessions();
59
+ const projectSessions = await this.listProjectSessions();
60
+ sessions.push(...transcriptSessions, ...projectSessions);
61
+ return sessions.sort(
62
+ (a, b) => new Date(b.startTime).getTime() - new Date(a.startTime).getTime()
63
+ );
64
+ }
65
+ async listTranscriptSessions() {
52
66
  const sessions = [];
53
67
  try {
54
- const files = await fs.readdir(this.basePath);
68
+ const files = await fs.readdir(this.transcriptsPath);
55
69
  for (const file of files) {
56
70
  if (!file.endsWith(".jsonl") || !file.startsWith("ses_")) continue;
57
- const filePath = join(this.basePath, file);
58
- const stat = await fs.stat(filePath);
71
+ const filePath = join(this.transcriptsPath, file);
59
72
  const sessionId = file.replace(".jsonl", "");
60
- const entries = await this.readTranscriptFile(filePath);
61
- if (entries.length === 0) continue;
62
- const userMessages = entries.filter((e) => e.type === "user");
63
- const firstEntry = entries[0];
64
- const lastEntry = entries[entries.length - 1];
65
- sessions.push({
66
- id: sessionId,
67
- projectPath: "",
68
- startTime: firstEntry.timestamp,
69
- endTime: lastEntry.timestamp,
70
- messageCount: userMessages.length,
71
- summary: this.extractSummary(entries)
72
- });
73
+ try {
74
+ const entries = await this.readTranscriptFile(filePath);
75
+ if (entries.length === 0) continue;
76
+ const userMessages = entries.filter((e) => e.type === "user");
77
+ const firstEntry = entries[0];
78
+ const lastEntry = entries[entries.length - 1];
79
+ sessions.push({
80
+ id: sessionId,
81
+ projectPath: "[transcripts]",
82
+ startTime: firstEntry.timestamp,
83
+ endTime: lastEntry.timestamp,
84
+ messageCount: userMessages.length,
85
+ summary: this.extractTranscriptSummary(entries)
86
+ });
87
+ } catch {
88
+ continue;
89
+ }
73
90
  }
74
- } catch (error) {
75
- throw new Error(`Failed to list sessions: ${error}`);
91
+ } catch {
76
92
  }
77
- return sessions.sort(
78
- (a, b) => new Date(b.startTime).getTime() - new Date(a.startTime).getTime()
79
- );
93
+ return sessions;
94
+ }
95
+ async listProjectSessions() {
96
+ const sessions = [];
97
+ const sessionMap = /* @__PURE__ */ new Map();
98
+ try {
99
+ const projectDirs = await fs.readdir(this.projectsPath);
100
+ for (const projectDir of projectDirs) {
101
+ if (projectDir.startsWith(".")) continue;
102
+ const projectPath = join(this.projectsPath, projectDir);
103
+ const stat = await fs.stat(projectPath);
104
+ if (!stat.isDirectory()) continue;
105
+ const files = await fs.readdir(projectPath);
106
+ for (const file of files) {
107
+ if (!file.endsWith(".jsonl")) continue;
108
+ if (file.startsWith("agent-")) continue;
109
+ const filePath = join(projectPath, file);
110
+ const sessionId = file.replace(".jsonl", "");
111
+ sessionMap.set(sessionId, {
112
+ id: sessionId,
113
+ filePath,
114
+ projectPath: this.decodeProjectPath(projectDir),
115
+ source: "projects"
116
+ });
117
+ }
118
+ }
119
+ for (const [sessionId, source] of sessionMap) {
120
+ try {
121
+ const entries = await this.readProjectFile(source.filePath);
122
+ if (entries.length === 0) continue;
123
+ const userMessages = entries.filter(
124
+ (e) => e.type === "user" && e.message?.role === "user"
125
+ );
126
+ const timestamps = entries.filter((e) => e.timestamp).map((e) => e.timestamp);
127
+ if (timestamps.length === 0) continue;
128
+ sessions.push({
129
+ id: sessionId,
130
+ projectPath: source.projectPath,
131
+ startTime: timestamps[0],
132
+ endTime: timestamps[timestamps.length - 1],
133
+ messageCount: userMessages.length,
134
+ summary: this.extractProjectSummary(entries)
135
+ });
136
+ } catch {
137
+ continue;
138
+ }
139
+ }
140
+ } catch {
141
+ }
142
+ return sessions;
80
143
  }
81
144
  async getSession(id) {
82
- const filePath = join(this.basePath, `${id}.jsonl`);
145
+ const transcriptPath = join(this.transcriptsPath, `${id}.jsonl`);
83
146
  try {
84
- await fs.access(filePath);
147
+ await fs.access(transcriptPath);
148
+ const entries = await this.readTranscriptFile(transcriptPath);
149
+ if (entries.length > 0) {
150
+ return this.transformTranscriptSession(id, entries);
151
+ }
85
152
  } catch {
86
- throw new Error(`Session not found: ${id}`);
87
153
  }
88
- const entries = await this.readTranscriptFile(filePath);
89
- if (entries.length === 0) {
90
- throw new Error(`Empty session: ${id}`);
154
+ const projectFile = await this.findProjectSessionFile(id);
155
+ if (projectFile) {
156
+ const entries = await this.readProjectFile(projectFile.filePath);
157
+ return this.transformProjectSession(id, entries, projectFile.projectPath);
91
158
  }
92
- return this.transformSession(id, entries);
159
+ throw new Error(`Session not found: ${id}`);
160
+ }
161
+ async findProjectSessionFile(sessionId) {
162
+ try {
163
+ const projectDirs = await fs.readdir(this.projectsPath);
164
+ for (const projectDir of projectDirs) {
165
+ if (projectDir.startsWith(".")) continue;
166
+ const projectPath = join(this.projectsPath, projectDir);
167
+ const stat = await fs.stat(projectPath);
168
+ if (!stat.isDirectory()) continue;
169
+ const sessionFile = join(projectPath, `${sessionId}.jsonl`);
170
+ try {
171
+ await fs.access(sessionFile);
172
+ return {
173
+ filePath: sessionFile,
174
+ projectPath: this.decodeProjectPath(projectDir)
175
+ };
176
+ } catch {
177
+ continue;
178
+ }
179
+ }
180
+ } catch {
181
+ }
182
+ return null;
93
183
  }
94
184
  async readTranscriptFile(path) {
95
185
  try {
@@ -100,7 +190,16 @@ var ClaudeSessionLoader = class extends SessionLoader {
100
190
  return [];
101
191
  }
102
192
  }
103
- transformSession(id, entries) {
193
+ async readProjectFile(path) {
194
+ try {
195
+ const content = await fs.readFile(path, "utf-8");
196
+ const lines = content.trim().split("\n").filter(Boolean);
197
+ return lines.map((line) => JSON.parse(line));
198
+ } catch {
199
+ return [];
200
+ }
201
+ }
202
+ transformTranscriptSession(id, entries) {
104
203
  const messages = [];
105
204
  let currentAssistantContent = "";
106
205
  let currentToolCalls = [];
@@ -111,7 +210,7 @@ var ClaudeSessionLoader = class extends SessionLoader {
111
210
  if (currentAssistantContent || currentToolCalls?.length) {
112
211
  messages.push({
113
212
  role: "assistant",
114
- content: currentAssistantContent,
213
+ content: currentAssistantContent.trim(),
115
214
  timestamp: lastTimestamp,
116
215
  toolCalls: currentToolCalls.length > 0 ? currentToolCalls : void 0,
117
216
  toolResults: currentToolResults.length > 0 ? currentToolResults : void 0
@@ -156,19 +255,64 @@ var ClaudeSessionLoader = class extends SessionLoader {
156
255
  const lastEntry = entries[entries.length - 1];
157
256
  return {
158
257
  id,
159
- projectPath: "",
258
+ projectPath: "[transcripts]",
160
259
  startTime: firstEntry.timestamp,
161
260
  endTime: lastEntry.timestamp,
162
261
  messages
163
262
  };
164
263
  }
165
- extractSummary(entries) {
264
+ transformProjectSession(id, entries, projectPath) {
265
+ const messages = [];
266
+ for (const entry of entries) {
267
+ if (entry.type === "file-history-snapshot") continue;
268
+ if (entry.message) {
269
+ const content = this.extractMessageContent(entry.message.content);
270
+ if (content) {
271
+ messages.push({
272
+ role: entry.message.role === "user" ? "user" : "assistant",
273
+ content,
274
+ timestamp: entry.timestamp
275
+ });
276
+ }
277
+ }
278
+ }
279
+ const timestamps = entries.filter((e) => e.timestamp).map((e) => e.timestamp);
280
+ return {
281
+ id,
282
+ projectPath,
283
+ startTime: timestamps[0] ?? "",
284
+ endTime: timestamps[timestamps.length - 1] ?? "",
285
+ messages
286
+ };
287
+ }
288
+ extractMessageContent(content) {
289
+ if (typeof content === "string") {
290
+ return content;
291
+ }
292
+ if (Array.isArray(content)) {
293
+ return content.filter((c) => c.type === "text" && c.text).map((c) => c.text).join("\n");
294
+ }
295
+ return "";
296
+ }
297
+ decodeProjectPath(encoded) {
298
+ return encoded.replace(/-/g, "/").replace(/^\//, "");
299
+ }
300
+ extractTranscriptSummary(entries) {
166
301
  const firstUserEntry = entries.find((e) => e.type === "user");
167
302
  if (!firstUserEntry?.content) return "";
168
303
  const content = firstUserEntry.content;
169
304
  const firstLine = content.split("\n")[0];
170
305
  return firstLine.length > 80 ? firstLine.slice(0, 80) + "..." : firstLine;
171
306
  }
307
+ extractProjectSummary(entries) {
308
+ const firstUserEntry = entries.find(
309
+ (e) => e.type === "user" && e.message?.role === "user"
310
+ );
311
+ if (!firstUserEntry?.message) return "";
312
+ const content = this.extractMessageContent(firstUserEntry.message.content);
313
+ const firstLine = content.split("\n")[0];
314
+ return firstLine.length > 80 ? firstLine.slice(0, 80) + "..." : firstLine;
315
+ }
172
316
  };
173
317
 
174
318
  // src/loaders/codex.ts
@@ -413,7 +557,41 @@ ${userPrompts.map((p) => `- ${p}`).join("\n")}` : "";
413
557
  qualityEnhancement(JSON.stringify(skill, null, 2)),
414
558
  SYSTEM_SKILL_WRITER
415
559
  );
416
- return this.parseJson(response, z.any());
560
+ try {
561
+ const enhanced = this.parseJson(response, z.any());
562
+ const mergedSteps = (enhanced.steps ?? skill.steps ?? []).map((step) => {
563
+ if (typeof step === "object" && step !== null) {
564
+ const s = step;
565
+ return {
566
+ title: String(s.title ?? s.name ?? "Step"),
567
+ description: String(s.description ?? s.content ?? ""),
568
+ substeps: Array.isArray(s.substeps) ? s.substeps.map(String) : void 0
569
+ };
570
+ }
571
+ return { title: "Step", description: String(step) };
572
+ });
573
+ const mergedExamples = (enhanced.examples ?? skill.examples ?? []).map((ex) => {
574
+ if (typeof ex === "string") return ex;
575
+ if (typeof ex === "object" && ex !== null) {
576
+ const e = ex;
577
+ return String(e.text ?? e.example ?? e.content ?? JSON.stringify(ex));
578
+ }
579
+ return String(ex);
580
+ });
581
+ return {
582
+ metadata: enhanced.metadata ?? skill.metadata ?? { name: "Untitled", description: "", version: "1.0.0" },
583
+ overview: enhanced.overview ?? skill.overview ?? "",
584
+ triggers: enhanced.triggers ?? skill.triggers ?? [],
585
+ prerequisites: enhanced.prerequisites ?? skill.prerequisites ?? [],
586
+ steps: mergedSteps,
587
+ parameters: enhanced.parameters ?? skill.parameters ?? [],
588
+ errorHandling: enhanced.errorHandling ?? skill.errorHandling ?? {},
589
+ examples: mergedExamples,
590
+ notes: enhanced.notes ?? skill.notes ?? []
591
+ };
592
+ } catch {
593
+ return skill;
594
+ }
417
595
  }
418
596
  async generateDescription(intent) {
419
597
  const response = await this.chat(
@@ -805,7 +983,7 @@ var Distiller = class {
805
983
 
806
984
  // src/generators/skill-generator.ts
807
985
  import { promises as fs4 } from "fs";
808
- import { join as join5 } from "path";
986
+ import { join as join6 } from "path";
809
987
 
810
988
  // src/generators/frontmatter-builder.ts
811
989
  import { stringify } from "yaml";
@@ -1044,6 +1222,14 @@ var TemplateValidator = class {
1044
1222
 
1045
1223
  // src/utils/fs.ts
1046
1224
  import { promises as fs3 } from "fs";
1225
+ import { homedir as homedir4 } from "os";
1226
+ import { join as join5 } from "path";
1227
+ function expandHome(path) {
1228
+ if (path.startsWith("~")) {
1229
+ return join5(homedir4(), path.slice(1));
1230
+ }
1231
+ return path;
1232
+ }
1047
1233
  async function ensureDir(path) {
1048
1234
  await fs3.mkdir(path, { recursive: true });
1049
1235
  }
@@ -1071,7 +1257,7 @@ var SkillGenerator = class {
1071
1257
  async generate(skill, options) {
1072
1258
  const { outputDir, overwrite = false, includeReferences = true } = options;
1073
1259
  const skillDirName = this.toKebabCase(skill.metadata.name);
1074
- const skillDir = join5(outputDir, skillDirName);
1260
+ const skillDir = join6(outputDir, skillDirName);
1075
1261
  if (!overwrite && await this.exists(skillDir)) {
1076
1262
  throw new Error(`Skill directory already exists: ${skillDir}`);
1077
1263
  }
@@ -1081,7 +1267,7 @@ var SkillGenerator = class {
1081
1267
  });
1082
1268
  const content = this.renderSkill(skill);
1083
1269
  const validation = this.validator.validate(content, skill);
1084
- const skillPath = join5(skillDir, "SKILL.md");
1270
+ const skillPath = join6(skillDir, "SKILL.md");
1085
1271
  await fs4.writeFile(skillPath, content, "utf-8");
1086
1272
  const files = [skillPath];
1087
1273
  if (includeReferences && skill.references?.length) {
@@ -1122,9 +1308,9 @@ var SkillGenerator = class {
1122
1308
  return parts.join("\n\n");
1123
1309
  }
1124
1310
  async generateReferences(skillDir, skill) {
1125
- const refDir = join5(skillDir, "references");
1311
+ const refDir = join6(skillDir, "references");
1126
1312
  await ensureDir(refDir);
1127
- const patternsPath = join5(refDir, "patterns.md");
1313
+ const patternsPath = join6(refDir, "patterns.md");
1128
1314
  const patternsContent = `# Patterns and Best Practices
1129
1315
 
1130
1316
  This file contains detailed patterns extracted from the original conversation.
@@ -1190,8 +1376,8 @@ async function collectPromptsInteractively() {
1190
1376
 
1191
1377
  // src/installers/claude.ts
1192
1378
  import { promises as fs5 } from "fs";
1193
- import { join as join6 } from "path";
1194
- import { homedir as homedir4 } from "os";
1379
+ import { join as join7 } from "path";
1380
+ import { homedir as homedir5 } from "os";
1195
1381
 
1196
1382
  // src/installers/base.ts
1197
1383
  var AgentInstaller = class {
@@ -1213,7 +1399,7 @@ var ClaudeCodeInstaller = class extends AgentInstaller {
1213
1399
  this.generator = new SkillGenerator();
1214
1400
  }
1215
1401
  getDefaultBasePath() {
1216
- return join6(homedir4(), ".claude", "plugins", "local", "skills");
1402
+ return join7(homedir5(), ".claude", "plugins", "local", "skills");
1217
1403
  }
1218
1404
  getPlatformName() {
1219
1405
  return "Claude Code";
@@ -1221,7 +1407,7 @@ var ClaudeCodeInstaller = class extends AgentInstaller {
1221
1407
  async install(skill, options = {}) {
1222
1408
  const { overwrite = false, backup = true, verify = true } = options;
1223
1409
  const skillDirName = this.toKebabCase(skill.metadata.name);
1224
- const skillPath = join6(this.basePath, skillDirName);
1410
+ const skillPath = join7(this.basePath, skillDirName);
1225
1411
  if (await fileExists(skillPath)) {
1226
1412
  if (!overwrite) {
1227
1413
  return {
@@ -1257,7 +1443,7 @@ var ClaudeCodeInstaller = class extends AgentInstaller {
1257
1443
  };
1258
1444
  }
1259
1445
  async uninstall(skillName) {
1260
- const skillPath = join6(this.basePath, this.toKebabCase(skillName));
1446
+ const skillPath = join7(this.basePath, this.toKebabCase(skillName));
1261
1447
  if (!await fileExists(skillPath)) {
1262
1448
  throw new Error(`Skill not found: ${skillName}`);
1263
1449
  }
@@ -1269,14 +1455,14 @@ var ClaudeCodeInstaller = class extends AgentInstaller {
1269
1455
  const entries = await fs5.readdir(this.basePath, { withFileTypes: true });
1270
1456
  for (const entry of entries) {
1271
1457
  if (!entry.isDirectory()) continue;
1272
- const skillMdPath = join6(this.basePath, entry.name, "SKILL.md");
1458
+ const skillMdPath = join7(this.basePath, entry.name, "SKILL.md");
1273
1459
  if (await fileExists(skillMdPath)) {
1274
1460
  const content = await fs5.readFile(skillMdPath, "utf-8");
1275
1461
  const metadata = this.parseMetadata(content);
1276
1462
  const stat = await fs5.stat(skillMdPath);
1277
1463
  skills.push({
1278
1464
  name: metadata.name ?? entry.name,
1279
- path: join6(this.basePath, entry.name),
1465
+ path: join7(this.basePath, entry.name),
1280
1466
  version: metadata.version ?? "0.0.0",
1281
1467
  installedAt: stat.mtime.toISOString()
1282
1468
  });
@@ -1287,7 +1473,7 @@ var ClaudeCodeInstaller = class extends AgentInstaller {
1287
1473
  return skills;
1288
1474
  }
1289
1475
  async verifyInstallation(skillPath) {
1290
- const skillMd = join6(skillPath, "SKILL.md");
1476
+ const skillMd = join7(skillPath, "SKILL.md");
1291
1477
  if (!await fileExists(skillMd)) {
1292
1478
  return false;
1293
1479
  }
@@ -1320,8 +1506,8 @@ var ClaudeCodeInstaller = class extends AgentInstaller {
1320
1506
 
1321
1507
  // src/installers/codex.ts
1322
1508
  import { promises as fs6 } from "fs";
1323
- import { join as join7 } from "path";
1324
- import { homedir as homedir5 } from "os";
1509
+ import { join as join8 } from "path";
1510
+ import { homedir as homedir6 } from "os";
1325
1511
 
1326
1512
  // src/formatters/claude-formatter.ts
1327
1513
  import { stringify as stringify2 } from "yaml";
@@ -1584,7 +1770,7 @@ var CodexInstaller = class extends AgentInstaller {
1584
1770
  this.converter = new FormatConverter();
1585
1771
  }
1586
1772
  getDefaultBasePath() {
1587
- return join7(homedir5(), ".codex", "agents");
1773
+ return join8(homedir6(), ".codex", "agents");
1588
1774
  }
1589
1775
  getPlatformName() {
1590
1776
  return "Codex CLI";
@@ -1592,7 +1778,7 @@ var CodexInstaller = class extends AgentInstaller {
1592
1778
  async install(skill, options = {}) {
1593
1779
  const { overwrite = false } = options;
1594
1780
  const agentName = this.toKebabCase(skill.metadata.name);
1595
- const agentPath = join7(this.basePath, `${agentName}.md`);
1781
+ const agentPath = join8(this.basePath, `${agentName}.md`);
1596
1782
  if (await fileExists(agentPath) && !overwrite) {
1597
1783
  return {
1598
1784
  success: false,
@@ -1610,7 +1796,7 @@ var CodexInstaller = class extends AgentInstaller {
1610
1796
  };
1611
1797
  }
1612
1798
  async uninstall(skillName) {
1613
- const agentPath = join7(this.basePath, `${this.toKebabCase(skillName)}.md`);
1799
+ const agentPath = join8(this.basePath, `${this.toKebabCase(skillName)}.md`);
1614
1800
  if (!await fileExists(agentPath)) {
1615
1801
  throw new Error(`Agent not found: ${skillName}`);
1616
1802
  }
@@ -1622,7 +1808,7 @@ var CodexInstaller = class extends AgentInstaller {
1622
1808
  const files = await fs6.readdir(this.basePath);
1623
1809
  for (const file of files) {
1624
1810
  if (!file.endsWith(".md")) continue;
1625
- const agentPath = join7(this.basePath, file);
1811
+ const agentPath = join8(this.basePath, file);
1626
1812
  const stat = await fs6.stat(agentPath);
1627
1813
  skills.push({
1628
1814
  name: file.replace(".md", ""),
@@ -1642,7 +1828,7 @@ var CodexInstaller = class extends AgentInstaller {
1642
1828
 
1643
1829
  // src/installers/cursor.ts
1644
1830
  import { promises as fs7 } from "fs";
1645
- import { join as join8 } from "path";
1831
+ import { join as join9 } from "path";
1646
1832
  var CursorInstaller = class extends AgentInstaller {
1647
1833
  converter;
1648
1834
  projectPath;
@@ -1659,7 +1845,7 @@ var CursorInstaller = class extends AgentInstaller {
1659
1845
  }
1660
1846
  async install(skill, options = {}) {
1661
1847
  const { overwrite = false, backup = true } = options;
1662
- const rulesPath = join8(this.basePath, ".cursorrules");
1848
+ const rulesPath = join9(this.basePath, ".cursorrules");
1663
1849
  if (await fileExists(rulesPath)) {
1664
1850
  if (!overwrite) {
1665
1851
  return {
@@ -1682,14 +1868,14 @@ var CursorInstaller = class extends AgentInstaller {
1682
1868
  };
1683
1869
  }
1684
1870
  async uninstall(_skillName) {
1685
- const rulesPath = join8(this.basePath, ".cursorrules");
1871
+ const rulesPath = join9(this.basePath, ".cursorrules");
1686
1872
  if (!await fileExists(rulesPath)) {
1687
1873
  throw new Error(".cursorrules not found");
1688
1874
  }
1689
1875
  await fs7.unlink(rulesPath);
1690
1876
  }
1691
1877
  async list() {
1692
- const rulesPath = join8(this.basePath, ".cursorrules");
1878
+ const rulesPath = join9(this.basePath, ".cursorrules");
1693
1879
  if (!await fileExists(rulesPath)) {
1694
1880
  return [];
1695
1881
  }
@@ -1724,16 +1910,16 @@ function createInstaller(platform, options = {}) {
1724
1910
 
1725
1911
  // src/cli/config.ts
1726
1912
  import { promises as fs8 } from "fs";
1727
- import { join as join9 } from "path";
1728
- import { homedir as homedir6 } from "os";
1729
- var CONFIG_DIR = join9(homedir6(), ".skill-distill");
1730
- var CONFIG_FILE = join9(CONFIG_DIR, "config.json");
1913
+ import { join as join10 } from "path";
1914
+ import { homedir as homedir7 } from "os";
1915
+ var CONFIG_DIR = join10(homedir7(), ".skill-distill");
1916
+ var CONFIG_FILE = join10(CONFIG_DIR, "config.json");
1731
1917
  var DEFAULT_CONFIG = {
1732
1918
  defaultPlatform: "claude",
1733
- outputDir: join9(homedir6(), ".skills"),
1919
+ outputDir: join10(homedir7(), ".skills"),
1734
1920
  autoInstall: false,
1735
1921
  sessionSources: {
1736
- claude: join9(homedir6(), ".claude", "projects")
1922
+ claude: join10(homedir7(), ".claude", "projects")
1737
1923
  }
1738
1924
  };
1739
1925
  async function loadConfig() {
@@ -1817,7 +2003,7 @@ async function runDistill(sessionArg, options) {
1817
2003
  ` Token usage: ${chalk3.white(result.metadata.tokenUsage.input + result.metadata.tokenUsage.output)}`
1818
2004
  )
1819
2005
  );
1820
- const outputDir = options.output ?? config.outputDir ?? "./skills";
2006
+ const outputDir = expandHome(options.output ?? config.outputDir ?? "~/.skills");
1821
2007
  spinner.start("Generating Skill files...");
1822
2008
  const generator = new SkillGenerator();
1823
2009
  const genResult = await generator.generate(result.skill, {