skilld 1.7.3 → 1.7.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.
Files changed (96) hide show
  1. package/dist/_chunks/agent.mjs +693 -599
  2. package/dist/_chunks/agent.mjs.map +1 -1
  3. package/dist/_chunks/assemble.mjs +3 -3
  4. package/dist/_chunks/author.mjs +51 -121
  5. package/dist/_chunks/author.mjs.map +1 -1
  6. package/dist/_chunks/cache.mjs +315 -9
  7. package/dist/_chunks/cache.mjs.map +1 -1
  8. package/dist/_chunks/cache2.mjs +2 -2
  9. package/dist/_chunks/cli-helpers.mjs +3 -3
  10. package/dist/_chunks/core.mjs +7 -4
  11. package/dist/_chunks/detect.mjs +1 -1
  12. package/dist/_chunks/embedding-cache2.mjs +2 -2
  13. package/dist/_chunks/index.d.mts +305 -112
  14. package/dist/_chunks/index.d.mts.map +1 -1
  15. package/dist/_chunks/index2.d.mts +267 -32
  16. package/dist/_chunks/index2.d.mts.map +1 -1
  17. package/dist/_chunks/index3.d.mts +32 -577
  18. package/dist/_chunks/index3.d.mts.map +1 -1
  19. package/dist/_chunks/index4.d.mts +553 -0
  20. package/dist/_chunks/index4.d.mts.map +1 -0
  21. package/dist/_chunks/install.mjs +48 -88
  22. package/dist/_chunks/install.mjs.map +1 -1
  23. package/dist/_chunks/list.mjs +1 -1
  24. package/dist/_chunks/lockfile.mjs +29 -6
  25. package/dist/_chunks/lockfile.mjs.map +1 -1
  26. package/dist/_chunks/monorepo.mjs +71 -0
  27. package/dist/_chunks/monorepo.mjs.map +1 -0
  28. package/dist/_chunks/{shared.mjs → package-registry.mjs} +2 -40
  29. package/dist/_chunks/package-registry.mjs.map +1 -0
  30. package/dist/_chunks/paths.mjs +49 -0
  31. package/dist/_chunks/paths.mjs.map +1 -0
  32. package/dist/_chunks/pool2.mjs +1 -1
  33. package/dist/_chunks/prepare.mjs +1 -1
  34. package/dist/_chunks/prepare2.mjs +5 -5
  35. package/dist/_chunks/prepare2.mjs.map +1 -1
  36. package/dist/_chunks/prompts.mjs +366 -18
  37. package/dist/_chunks/prompts.mjs.map +1 -1
  38. package/dist/_chunks/search-helpers.mjs +5 -6
  39. package/dist/_chunks/search-helpers.mjs.map +1 -1
  40. package/dist/_chunks/search-interactive.mjs +1 -1
  41. package/dist/_chunks/search.mjs +1 -2
  42. package/dist/_chunks/search.mjs.map +1 -1
  43. package/dist/_chunks/semver.mjs +13 -0
  44. package/dist/_chunks/semver.mjs.map +1 -0
  45. package/dist/_chunks/skill-installer.mjs +2 -0
  46. package/dist/_chunks/skill-installer2.mjs +155 -0
  47. package/dist/_chunks/skill-installer2.mjs.map +1 -0
  48. package/dist/_chunks/skills.mjs +10 -9
  49. package/dist/_chunks/skills.mjs.map +1 -1
  50. package/dist/_chunks/sources.mjs +549 -372
  51. package/dist/_chunks/sources.mjs.map +1 -1
  52. package/dist/_chunks/sync-pipeline.mjs +952 -0
  53. package/dist/_chunks/sync-pipeline.mjs.map +1 -0
  54. package/dist/_chunks/sync-registry.mjs +19 -13
  55. package/dist/_chunks/sync-registry.mjs.map +1 -1
  56. package/dist/_chunks/sync.mjs +797 -886
  57. package/dist/_chunks/sync.mjs.map +1 -1
  58. package/dist/_chunks/sync2.mjs +4 -2
  59. package/dist/_chunks/types.d.mts +65 -77
  60. package/dist/_chunks/types.d.mts.map +1 -1
  61. package/dist/_chunks/types2.d.mts +88 -0
  62. package/dist/_chunks/types2.d.mts.map +1 -0
  63. package/dist/_chunks/uninstall.mjs +7 -8
  64. package/dist/_chunks/uninstall.mjs.map +1 -1
  65. package/dist/_chunks/upload.mjs +2 -2
  66. package/dist/_chunks/validate.mjs +1 -1
  67. package/dist/_chunks/version.mjs +3 -13
  68. package/dist/_chunks/version.mjs.map +1 -1
  69. package/dist/_chunks/wizard.mjs +2 -2
  70. package/dist/agent/index.d.mts +2 -346
  71. package/dist/agent/index.mjs +2 -3
  72. package/dist/cache/index.d.mts +2 -2
  73. package/dist/cache/index.mjs +4 -3
  74. package/dist/cli.mjs +12 -13
  75. package/dist/cli.mjs.map +1 -1
  76. package/dist/index.d.mts +5 -4
  77. package/dist/index.mjs +4 -3
  78. package/dist/prepare.mjs +2 -2
  79. package/dist/prepare.mjs.map +1 -1
  80. package/dist/retriv/index.d.mts +2 -2
  81. package/dist/retriv/worker.d.mts +1 -1
  82. package/dist/sources/index.d.mts +3 -2
  83. package/dist/sources/index.mjs +3 -3
  84. package/dist/types.d.mts +3 -3
  85. package/package.json +2 -2
  86. package/dist/_chunks/config.mjs +0 -122
  87. package/dist/_chunks/config.mjs.map +0 -1
  88. package/dist/_chunks/prefix.mjs +0 -108
  89. package/dist/_chunks/prefix.mjs.map +0 -1
  90. package/dist/_chunks/shared.mjs.map +0 -1
  91. package/dist/_chunks/skill.mjs +0 -329
  92. package/dist/_chunks/skill.mjs.map +0 -1
  93. package/dist/_chunks/sync-shared.mjs +0 -2
  94. package/dist/_chunks/sync-shared2.mjs +0 -1020
  95. package/dist/_chunks/sync-shared2.mjs.map +0 -1
  96. package/dist/agent/index.d.mts.map +0 -1
@@ -1,62 +1,126 @@
1
+ import { a as PI_AI_AUTH_PATH, h as skillLogDir, p as skillInternalDir, r as LLM_CACHE_DIR, t as CACHE_DIR } from "./paths.mjs";
2
+ import { E as getSkillReferenceDirs, t as createReferenceCache } from "./cache.mjs";
1
3
  import { n as sanitizeMarkdown } from "./sanitize.mjs";
2
- import { _ as writeSections, g as readCachedSection } from "./cache.mjs";
3
- import { i as resolveSkilldCommand } from "./shared.mjs";
4
4
  import { a as targets, t as detectInstalledAgents } from "./detect.mjs";
5
- import { c as wrapSection, n as SECTION_OUTPUT_FILES, o as getSectionValidator, r as buildAllSectionPrompts, t as SECTION_MERGE_ORDER } from "./prompts.mjs";
6
- import "./skill.mjs";
5
+ import { E as SECTION_OUTPUT_FILES, S as getSectionValidator, T as SECTION_MERGE_ORDER, k as resolveSkilldCommand, w as wrapSection, y as buildAllSectionPrompts } from "./prompts.mjs";
6
+ import { existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, unlinkSync, writeFileSync } from "node:fs";
7
7
  import { homedir } from "node:os";
8
- import { dirname, join } from "pathe";
9
- import { existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, realpathSync, unlinkSync, writeFileSync } from "node:fs";
8
+ import { join } from "pathe";
10
9
  import { exec, execFileSync, spawn } from "node:child_process";
11
- import { isWindows } from "std-env";
12
10
  import { glob } from "tinyglobby";
13
11
  import { findDynamicImports, findStaticImports } from "mlly";
14
- import { createHash } from "node:crypto";
15
- import { setTimeout as setTimeout$1 } from "node:timers/promises";
16
12
  import { promisify } from "node:util";
17
- import { resolve as resolve$1 } from "node:path";
18
- import { getEnvApiKey, getModel, getModels, getProviders, streamSimple } from "@mariozechner/pi-ai";
13
+ import { isWindows } from "std-env";
14
+ import { getEnvApiKey, getEnvApiKey as getEnvApiKey$1, getModel, getModels, getProviders, streamSimple } from "@mariozechner/pi-ai";
19
15
  import { getOAuthApiKey, getOAuthProvider, getOAuthProviders } from "@mariozechner/pi-ai/oauth";
16
+ import { resolve as resolve$1 } from "node:path";
20
17
  import { Type } from "typebox";
21
18
  import { readFile } from "node:fs/promises";
22
19
  import { parseSync } from "oxc-parser";
23
- var __defProp = Object.defineProperty;
24
- var __exportAll = (all, no_symbols) => {
25
- let target = {};
26
- for (var name in all) __defProp(target, name, {
27
- get: all[name],
28
- enumerable: true
29
- });
30
- if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
31
- return target;
32
- };
33
- var claude_exports = /* @__PURE__ */ __exportAll({
34
- agentId: () => agentId$2,
35
- buildArgs: () => buildArgs$2,
36
- cli: () => cli$2,
37
- models: () => models$2,
38
- parseLine: () => parseLine$2
39
- });
40
- const cli$2 = "claude";
41
- const agentId$2 = "claude-code";
42
- const models$2 = {
43
- opus: {
44
- model: "opus",
45
- name: "Opus 4.6",
46
- hint: "Most capable for complex work"
20
+ import { setTimeout as setTimeout$1 } from "node:timers/promises";
21
+ import { createHash } from "node:crypto";
22
+ function isStableId(id) {
23
+ if (/-\d{8}$/.test(id)) return false;
24
+ if (/-\d{4}-\d{2}-\d{2}$/.test(id)) return false;
25
+ if (/-preview/.test(id)) return false;
26
+ return true;
27
+ }
28
+ function compareVersions(a, b) {
29
+ const versionOf = (id) => {
30
+ return (id.match(/\d+(?:\.\d+)?/g) ?? []).flatMap((n) => n.split(".").map(Number));
31
+ };
32
+ const av = versionOf(a);
33
+ const bv = versionOf(b);
34
+ for (let i = 0; i < Math.max(av.length, bv.length); i++) {
35
+ const x = av[i] ?? 0;
36
+ const y = bv[i] ?? 0;
37
+ if (x !== y) return y - x;
38
+ }
39
+ return 0;
40
+ }
41
+ function resolve$2(opts) {
42
+ const { provider, prefix, contains, exclude } = opts;
43
+ return getModels(provider).filter((m) => isStableId(m.id)).filter((m) => m.id.startsWith(prefix)).filter((m) => !contains || m.id.includes(contains)).filter((m) => !exclude?.some((e) => m.id.includes(e))).sort((a, b) => compareVersions(a.id, b.id))[0];
44
+ }
45
+ function buildModelEntry(opts) {
46
+ const found = resolve$2(opts);
47
+ const piName = found?.name;
48
+ const transformed = piName && opts.nameTransform ? opts.nameTransform(piName) : piName;
49
+ const name = opts.name ?? transformed ?? opts.model ?? opts.prefix;
50
+ return {
51
+ model: opts.model ?? found?.id ?? opts.prefix,
52
+ name,
53
+ hint: opts.hint,
54
+ recommended: opts.recommended
55
+ };
56
+ }
57
+ function buildModels(entries) {
58
+ return Object.fromEntries(entries.map((e) => {
59
+ const entry = buildModelEntry(e);
60
+ return [entry.model, entry];
61
+ }));
62
+ }
63
+ const TOOL_NAMES = {
64
+ Read: {
65
+ canonical: "read",
66
+ verb: "Reading"
47
67
  },
48
- sonnet: {
49
- model: "sonnet",
50
- name: "Sonnet 4.6",
51
- hint: "Best for everyday tasks"
68
+ Glob: {
69
+ canonical: "search",
70
+ verb: "Searching"
52
71
  },
53
- haiku: {
54
- model: "haiku",
55
- name: "Haiku 4.5",
56
- hint: "Fastest for quick answers",
57
- recommended: true
72
+ Grep: {
73
+ canonical: "search",
74
+ verb: "Searching"
75
+ },
76
+ Write: {
77
+ canonical: "write",
78
+ verb: "Writing"
79
+ },
80
+ Bash: {
81
+ canonical: "shell",
82
+ verb: "Running"
83
+ },
84
+ read_file: {
85
+ canonical: "read",
86
+ verb: "Reading"
87
+ },
88
+ glob_tool: {
89
+ canonical: "search",
90
+ verb: "Searching"
91
+ },
92
+ write_file: {
93
+ canonical: "write",
94
+ verb: "Writing"
95
+ },
96
+ list_directory: {
97
+ canonical: "list",
98
+ verb: "Listing"
99
+ },
100
+ search_file_content: {
101
+ canonical: "search",
102
+ verb: "Searching"
103
+ },
104
+ run_shell_command: {
105
+ canonical: "shell",
106
+ verb: "Running"
58
107
  }
59
108
  };
109
+ function extractToolHint(input) {
110
+ if (!input) return void 0;
111
+ for (const k of [
112
+ "file_path",
113
+ "path",
114
+ "dir_path",
115
+ "pattern",
116
+ "query",
117
+ "command"
118
+ ]) {
119
+ const v = input[k];
120
+ if (typeof v === "string" && v) return v;
121
+ }
122
+ }
123
+ const stripClaude = (n) => n.replace(/^Claude\s+/, "").replace(/\s*\(latest\)\s*$/i, "");
60
124
  function buildArgs$2(model, skillDir, symlinkDirs) {
61
125
  return [
62
126
  "-p",
@@ -82,38 +146,36 @@ function buildArgs$2(model, skillDir, symlinkDirs) {
82
146
  "--no-session-persistence"
83
147
  ];
84
148
  }
85
- function parseLine$2(line) {
149
+ function parseEvent$2(line) {
86
150
  try {
87
151
  const obj = JSON.parse(line);
88
152
  if (obj.type === "stream_event") {
89
153
  const evt = obj.event;
90
- if (!evt) return {};
91
- if (evt.type === "content_block_delta" && evt.delta?.type === "text_delta") return { textDelta: evt.delta.text };
92
- return {};
154
+ if (evt?.type === "content_block_delta" && evt.delta?.type === "text_delta") return {
155
+ kind: "text",
156
+ delta: evt.delta.text
157
+ };
158
+ return { kind: "noop" };
93
159
  }
94
160
  if (obj.type === "assistant" && obj.message?.content) {
95
161
  const content = obj.message.content;
96
162
  const tools = content.filter((c) => c.type === "tool_use");
97
- if (tools.length) {
98
- const names = tools.map((t) => t.name);
99
- const hint = tools.map((t) => {
100
- const input = t.input || {};
101
- return input.file_path || input.path || input.pattern || input.query || input.command || "";
102
- }).filter(Boolean).join(", ");
103
- const writeTool = tools.find((t) => t.name === "Write" && t.input?.content);
104
- return {
105
- toolName: names.join(", "),
106
- toolHint: hint || void 0,
107
- writeContent: writeTool?.input?.content
108
- };
109
- }
163
+ if (tools.length) return {
164
+ kind: "tool-call",
165
+ tool: tools.map((t) => t.name).join(", "),
166
+ hint: tools.map((t) => extractToolHint(t.input) ?? "").filter(Boolean).join(", ") || void 0,
167
+ writeContent: tools.find((t) => t.name === "Write" && t.input?.content)?.input?.content
168
+ };
110
169
  const text = content.filter((c) => c.type === "text").map((c) => c.text).join("");
111
- if (text) return { fullText: text };
170
+ if (text) return {
171
+ kind: "text",
172
+ full: text
173
+ };
112
174
  }
113
175
  if (obj.type === "result") {
114
176
  const u = obj.usage;
115
177
  return {
116
- done: true,
178
+ kind: "done",
117
179
  usage: u ? {
118
180
  input: u.input_tokens ?? u.inputTokens ?? 0,
119
181
  output: u.output_tokens ?? u.outputTokens ?? 0
@@ -123,34 +185,38 @@ function parseLine$2(line) {
123
185
  };
124
186
  }
125
187
  } catch {}
126
- return {};
188
+ return { kind: "noop" };
127
189
  }
128
- var codex_exports = /* @__PURE__ */ __exportAll({
129
- agentId: () => agentId$1,
130
- buildArgs: () => buildArgs$1,
131
- cli: () => cli$1,
132
- models: () => models$1,
133
- parseLine: () => parseLine$1
134
- });
135
- const cli$1 = "codex";
136
- const agentId$1 = "codex";
137
- const models$1 = {
138
- "gpt-5.3-codex": {
139
- model: "gpt-5.3-codex",
140
- name: "GPT-5.3 Codex",
141
- hint: "Latest frontier Codex model"
142
- },
143
- "gpt-5.3-codex-spark": {
144
- model: "gpt-5.3-codex-spark",
145
- name: "GPT-5.3 Codex Spark",
146
- hint: "Faster GPT-5.3 Codex variant",
147
- recommended: true
148
- },
149
- "gpt-5.2-codex": {
150
- model: "gpt-5.2-codex",
151
- name: "GPT-5.2 Codex",
152
- hint: "Frontier agentic coding model"
153
- }
190
+ const adapter$2 = {
191
+ cli: "claude",
192
+ agentId: "claude-code",
193
+ providerName: "Anthropic",
194
+ models: buildModels([
195
+ {
196
+ model: "opus",
197
+ provider: "anthropic",
198
+ prefix: "claude-opus-",
199
+ nameTransform: stripClaude,
200
+ hint: "Most capable for complex work"
201
+ },
202
+ {
203
+ model: "sonnet",
204
+ provider: "anthropic",
205
+ prefix: "claude-sonnet-",
206
+ nameTransform: stripClaude,
207
+ hint: "Best for everyday tasks"
208
+ },
209
+ {
210
+ model: "haiku",
211
+ provider: "anthropic",
212
+ prefix: "claude-haiku-",
213
+ nameTransform: stripClaude,
214
+ hint: "Fastest for quick answers",
215
+ recommended: true
216
+ }
217
+ ]),
218
+ buildArgs: buildArgs$2,
219
+ parseEvent: parseEvent$2
154
220
  };
155
221
  function buildArgs$1(model, _skillDir, _symlinkDirs) {
156
222
  return [
@@ -163,62 +229,82 @@ function buildArgs$1(model, _skillDir, _symlinkDirs) {
163
229
  "-"
164
230
  ];
165
231
  }
166
- function parseLine$1(line) {
232
+ function parseEvent$1(line) {
167
233
  try {
168
234
  const obj = JSON.parse(line);
169
235
  if (obj.type === "item.completed" && obj.item) {
170
236
  const item = obj.item;
171
- if (item.type === "agent_message" && item.text) return { fullText: item.text };
237
+ if (item.type === "agent_message" && item.text) return {
238
+ kind: "text",
239
+ full: item.text
240
+ };
172
241
  if (item.type === "command_execution" && item.aggregated_output) {
173
242
  const cmd = item.command || "";
174
243
  const writeContent = /^cat\s*>|>/.test(cmd) ? item.aggregated_output : void 0;
175
244
  return {
176
- toolName: "Bash",
177
- toolHint: `(${item.aggregated_output.length} chars output)`,
245
+ kind: "tool-call",
246
+ tool: "Bash",
247
+ hint: `(${item.aggregated_output.length} chars output)`,
178
248
  writeContent
179
249
  };
180
250
  }
181
251
  if (item.type === "file_change" && item.changes?.length) return {
182
- toolName: "Write",
183
- toolHint: item.changes.map((c) => c.path).join(", ")
252
+ kind: "tool-call",
253
+ tool: "Write",
254
+ hint: item.changes.map((c) => c.path).join(", ")
184
255
  };
185
256
  }
186
257
  if (obj.type === "item.started" && obj.item?.type === "command_execution") return {
187
- toolName: "Bash",
188
- toolHint: obj.item.command
258
+ kind: "tool-call",
259
+ tool: "Bash",
260
+ hint: obj.item.command
189
261
  };
190
262
  if (obj.type === "turn.completed" && obj.usage) return {
191
- done: true,
263
+ kind: "done",
192
264
  usage: {
193
265
  input: obj.usage.input_tokens ?? 0,
194
266
  output: obj.usage.output_tokens ?? 0
195
267
  }
196
268
  };
197
- if (obj.type === "turn.failed" || obj.type === "error") return { done: true };
269
+ if (obj.type === "turn.failed" || obj.type === "error") return {
270
+ kind: "error",
271
+ message: obj.message
272
+ };
198
273
  } catch {}
199
- return {};
274
+ return { kind: "noop" };
200
275
  }
201
- var gemini_exports = /* @__PURE__ */ __exportAll({
202
- agentId: () => agentId,
203
- buildArgs: () => buildArgs,
204
- cli: () => cli,
205
- models: () => models,
206
- parseLine: () => parseLine
207
- });
208
- const cli = "gemini";
209
- const agentId = "gemini-cli";
210
- const models = {
211
- "gemini-3.1-pro": {
212
- model: "gemini-3.1-pro",
213
- name: "Gemini 3.1 Pro",
214
- hint: "Most capable"
215
- },
216
- "gemini-3-flash": {
217
- model: "gemini-3-flash",
218
- name: "Gemini 3 Flash",
219
- hint: "Balanced",
220
- recommended: true
221
- }
276
+ const adapter$1 = {
277
+ cli: "codex",
278
+ agentId: "codex",
279
+ providerName: "OpenAI",
280
+ models: buildModels([
281
+ {
282
+ provider: "openai",
283
+ prefix: "gpt-",
284
+ contains: "codex",
285
+ exclude: [
286
+ "spark",
287
+ "mini",
288
+ "max"
289
+ ],
290
+ hint: "Latest frontier Codex model"
291
+ },
292
+ {
293
+ provider: "openai",
294
+ prefix: "gpt-",
295
+ contains: "codex-spark",
296
+ hint: "Faster Codex variant",
297
+ recommended: true
298
+ },
299
+ {
300
+ provider: "openai",
301
+ prefix: "gpt-",
302
+ contains: "codex-mini",
303
+ hint: "Cheapest Codex variant"
304
+ }
305
+ ]),
306
+ buildArgs: buildArgs$1,
307
+ parseEvent: parseEvent$1
222
308
  };
223
309
  function buildArgs(model, skillDir, symlinkDirs) {
224
310
  return [
@@ -233,28 +319,30 @@ function buildArgs(model, skillDir, symlinkDirs) {
233
319
  ...symlinkDirs.flatMap((d) => ["--include-directories", d])
234
320
  ];
235
321
  }
236
- function parseLine(line) {
322
+ function parseEvent(line) {
237
323
  try {
238
324
  const obj = JSON.parse(line);
239
- if (obj.type === "message" && obj.role === "assistant" && obj.content) return obj.delta ? { textDelta: obj.content } : { fullText: obj.content };
325
+ if (obj.type === "message" && obj.role === "assistant" && obj.content) return obj.delta ? {
326
+ kind: "text",
327
+ delta: obj.content
328
+ } : {
329
+ kind: "text",
330
+ full: obj.content
331
+ };
240
332
  if (obj.type === "tool_use" || obj.type === "tool_call") {
241
- const name = obj.tool_name || obj.name || obj.tool || "tool";
333
+ const tool = obj.tool_name || obj.name || obj.tool || "tool";
242
334
  const params = obj.parameters || obj.args || obj.input || {};
243
- const hint = params.file_path || params.path || params.dir_path || params.pattern || params.query || params.command || "";
244
- if (name === "write_file" && params.content) return {
245
- toolName: name,
246
- toolHint: hint || void 0,
247
- writeContent: params.content
248
- };
249
335
  return {
250
- toolName: name,
251
- toolHint: hint || void 0
336
+ kind: "tool-call",
337
+ tool,
338
+ hint: extractToolHint(params),
339
+ writeContent: tool === "write_file" && typeof params.content === "string" ? params.content : void 0
252
340
  };
253
341
  }
254
342
  if (obj.type === "result") {
255
343
  const s = obj.stats;
256
344
  return {
257
- done: true,
345
+ kind: "done",
258
346
  usage: s ? {
259
347
  input: s.input_tokens ?? s.input ?? 0,
260
348
  output: s.output_tokens ?? s.output ?? 0
@@ -263,21 +351,37 @@ function parseLine(line) {
263
351
  };
264
352
  }
265
353
  } catch {}
266
- return {};
267
- }
268
- function isPiAiModel(model) {
269
- return model.startsWith("pi:");
270
- }
271
- function parsePiAiModelId(model) {
272
- if (!model.startsWith("pi:")) return null;
273
- const rest = model.slice(3);
274
- const slashIdx = rest.indexOf("/");
275
- if (slashIdx === -1) return null;
276
- return {
277
- provider: rest.slice(0, slashIdx),
278
- modelId: rest.slice(slashIdx + 1)
279
- };
354
+ return { kind: "noop" };
280
355
  }
356
+ const adapter = {
357
+ cli: "gemini",
358
+ agentId: "gemini-cli",
359
+ providerName: "Google",
360
+ models: buildModels([{
361
+ provider: "google",
362
+ prefix: "gemini-",
363
+ contains: "pro",
364
+ exclude: [
365
+ "flash",
366
+ "live",
367
+ "gemma"
368
+ ],
369
+ hint: "Most capable"
370
+ }, {
371
+ provider: "google",
372
+ prefix: "gemini-",
373
+ contains: "flash",
374
+ exclude: [
375
+ "lite",
376
+ "live",
377
+ "preview"
378
+ ],
379
+ hint: "Balanced",
380
+ recommended: true
381
+ }]),
382
+ buildArgs,
383
+ parseEvent
384
+ };
281
385
  const BLOCKED_OAUTH_PROVIDERS = new Set([
282
386
  "google-antigravity",
283
387
  "google-gemini-cli",
@@ -286,7 +390,11 @@ const BLOCKED_OAUTH_PROVIDERS = new Set([
286
390
  "openai-codex"
287
391
  ]);
288
392
  const PI_AGENT_AUTH_PATH = join(process.env.PI_CODING_AGENT_DIR || join(homedir(), ".pi", "agent"), "auth.json");
289
- const SKILLD_AUTH_PATH = join(homedir(), ".skilld", "pi-ai-auth.json");
393
+ const SKILLD_AUTH_PATH = PI_AI_AUTH_PATH;
394
+ const OAUTH_PROVIDER_OVERRIDES = {
395
+ google: "google-gemini-cli",
396
+ openai: "openai-codex"
397
+ };
290
398
  function readAuthFile(path) {
291
399
  if (!existsSync(path)) return {};
292
400
  try {
@@ -303,16 +411,12 @@ function loadAuth() {
303
411
  };
304
412
  }
305
413
  function saveAuth(auth) {
306
- mkdirSync(join(homedir(), ".skilld"), {
414
+ mkdirSync(CACHE_DIR, {
307
415
  recursive: true,
308
416
  mode: 448
309
417
  });
310
418
  writeFileSync(SKILLD_AUTH_PATH, JSON.stringify(auth, null, 2), { mode: 384 });
311
419
  }
312
- const OAUTH_PROVIDER_OVERRIDES = {
313
- google: "google-gemini-cli",
314
- openai: "openai-codex"
315
- };
316
420
  function resolveOAuthProviderId(modelProvider) {
317
421
  const oauthId = OAUTH_PROVIDER_OVERRIDES[modelProvider] ?? modelProvider;
318
422
  if (BLOCKED_OAUTH_PROVIDERS.has(oauthId)) return null;
@@ -321,7 +425,7 @@ function resolveOAuthProviderId(modelProvider) {
321
425
  return null;
322
426
  }
323
427
  async function resolveApiKey(provider) {
324
- const envKey = getEnvApiKey(provider);
428
+ const envKey = getEnvApiKey$1(provider);
325
429
  if (envKey) return envKey;
326
430
  const oauthProviderId = resolveOAuthProviderId(provider);
327
431
  if (!oauthProviderId) return null;
@@ -366,6 +470,19 @@ function logoutOAuthProvider(providerId) {
366
470
  delete auth[providerId];
367
471
  saveAuth(auth);
368
472
  }
473
+ function isPiAiModel(model) {
474
+ return model.startsWith("pi:");
475
+ }
476
+ function parsePiAiModelId(model) {
477
+ if (!model.startsWith("pi:")) return null;
478
+ const rest = model.slice(3);
479
+ const slashIdx = rest.indexOf("/");
480
+ if (slashIdx === -1) return null;
481
+ return {
482
+ provider: rest.slice(0, slashIdx),
483
+ modelId: rest.slice(slashIdx + 1)
484
+ };
485
+ }
369
486
  const MIN_CONTEXT_WINDOW = 32e3;
370
487
  const LEGACY_MODEL_PATTERNS = [
371
488
  /^claude-3-/,
@@ -457,7 +574,6 @@ const TOOLS = [
457
574
  parameters: Type.Object({ command: Type.String({ description: "Shell command to run" }) })
458
575
  }
459
576
  ];
460
- const MAX_TOOL_TURNS = 30;
461
577
  const SAFE_COMMANDS = new Set([
462
578
  "skilld",
463
579
  "ls",
@@ -559,12 +675,13 @@ function executeTool(toolCall, skilldDir) {
559
675
  default: return `Unknown tool: ${toolCall.name}`;
560
676
  }
561
677
  }
678
+ const SYSTEM_PROMPT = "You are a technical documentation expert generating SKILL.md sections for AI agent skills. Follow the format instructions exactly. Use the provided tools to explore reference files in ./.skilld/ before writing your output.";
562
679
  async function optimizeSectionPiAi(opts) {
563
680
  const parsed = parsePiAiModelId(opts.model);
564
681
  if (!parsed) throw new Error(`Invalid pi-ai model ID: ${opts.model}. Expected format: pi:provider/model-id`);
565
682
  const model = getModel(parsed.provider, parsed.modelId);
566
683
  const apiKey = await resolveApiKey(parsed.provider);
567
- const skilldDir = join(opts.skillDir, ".skilld");
684
+ const skilldDir = skillInternalDir(opts.skillDir);
568
685
  const fullPrompt = opts.prompt;
569
686
  opts.onProgress?.({
570
687
  chunk: "[starting...]",
@@ -586,10 +703,10 @@ async function optimizeSectionPiAi(opts) {
586
703
  let totalUsage;
587
704
  let totalCost;
588
705
  let lastWriteContent = "";
589
- for (let turn = 0; turn < MAX_TOOL_TURNS; turn++) {
706
+ for (let turn = 0; turn < 30; turn++) {
590
707
  if (opts.signal?.aborted) throw new Error("pi-ai request timed out");
591
708
  const eventStream = streamSimple(model, {
592
- systemPrompt: "You are a technical documentation expert generating SKILL.md sections for AI agent skills. Follow the format instructions exactly. Use the provided tools to explore reference files in ./.skilld/ before writing your output.",
709
+ systemPrompt: SYSTEM_PROMPT,
593
710
  messages,
594
711
  tools: TOOLS
595
712
  }, {
@@ -664,7 +781,7 @@ async function optimizeSectionPiAi(opts) {
664
781
  });
665
782
  }
666
783
  }
667
- if (!completed) throw new Error(`pi-ai exceeded ${MAX_TOOL_TURNS} tool turns without completing`);
784
+ if (!completed) throw new Error(`pi-ai exceeded 30 tool turns without completing`);
668
785
  return {
669
786
  text: text || lastWriteContent,
670
787
  fullPrompt,
@@ -672,19 +789,41 @@ async function optimizeSectionPiAi(opts) {
672
789
  cost: totalCost
673
790
  };
674
791
  }
675
- const TOOL_VERBS = {
676
- Read: "Reading",
677
- Glob: "Searching",
678
- Grep: "Searching",
679
- Write: "Writing",
680
- Bash: "Running",
681
- read_file: "Reading",
682
- glob_tool: "Searching",
683
- write_file: "Writing",
684
- list_directory: "Listing",
685
- search_file_content: "Searching",
686
- run_shell_command: "Running"
687
- };
792
+ function cleanSectionOutput(content) {
793
+ let cleaned = content.trim();
794
+ const wrapMatch = cleaned.match(/^```(?:markdown|md)?[^\S\n]*\n([\s\S]+)\n```[^\S\n]*$/);
795
+ if (wrapMatch) {
796
+ const inner = wrapMatch[1].trim();
797
+ if (/^```(?:markdown|md)/.test(cleaned) || /^##\s/m.test(inner) || /^- (?:BREAKING|DEPRECATED|NEW): /m.test(inner)) cleaned = inner;
798
+ }
799
+ cleaned = cleaned.replace(/^# (?!#)/gm, "## ");
800
+ const fmMatch = cleaned.match(/^-{3,}\n/);
801
+ if (fmMatch) {
802
+ const afterOpen = fmMatch[0].length;
803
+ const closeMatch = cleaned.slice(afterOpen).match(/\n-{3,}/);
804
+ if (closeMatch) cleaned = cleaned.slice(afterOpen + closeMatch.index + closeMatch[0].length).trim();
805
+ else cleaned = cleaned.slice(afterOpen).trim();
806
+ }
807
+ const firstMarker = cleaned.match(/^(##\s|- (?:BREAKING|DEPRECATED|NEW): )/m);
808
+ if (firstMarker?.index && firstMarker.index > 0) cleaned = cleaned.slice(firstMarker.index).trim();
809
+ const headingMatch = cleaned.match(/^(## .+)\n/);
810
+ if (headingMatch) {
811
+ const heading = headingMatch[1];
812
+ const afterFirst = headingMatch[0].length;
813
+ const secondIdx = cleaned.indexOf(heading, afterFirst);
814
+ if (secondIdx !== -1) {
815
+ if (secondIdx - afterFirst < 200) cleaned = cleaned.slice(secondIdx).trim();
816
+ }
817
+ }
818
+ cleaned = cleaned.replace(/\(?\[`?\.\/(?:\.skilld\/|references\/)[^)\]]*\]\(([^)]+)\)\)?/g, (match, url) => {
819
+ if (/^\.\/(?:\.skilld\/|references\/)/.test(url)) return `[source](${url})`;
820
+ return match;
821
+ });
822
+ cleaned = cleaned.replace(/\[source\]\(\.\/((docs|issues|discussions|releases|pkg|guide)\/)/g, "[source](./.skilld/$1");
823
+ cleaned = sanitizeMarkdown(cleaned);
824
+ if (!/^##\s/m.test(cleaned) && !/^- (?:BREAKING|DEPRECATED|NEW): /m.test(cleaned) && !/\[source\]/.test(cleaned)) return "";
825
+ return cleaned;
826
+ }
688
827
  function createToolProgress(log) {
689
828
  let lastMsg = "";
690
829
  let repeatCount = 0;
@@ -723,7 +862,7 @@ function createToolProgress(log) {
723
862
  for (let i = 0; i < names.length; i++) {
724
863
  const rawName = names[i];
725
864
  const hint = hints[i] ?? hints[0] ?? "";
726
- const verb = TOOL_VERBS[rawName] ?? rawName;
865
+ const verb = TOOL_NAMES[rawName]?.verb ?? rawName;
727
866
  const prefix = section ? `\x1B[90m[${section}]\x1B[0m ` : "";
728
867
  if ((rawName === "Bash" || rawName === "run_shell_command") && hint) {
729
868
  const searchMatch = hint.match(/skilld search\s+"([^"]+)"/);
@@ -737,26 +876,24 @@ function createToolProgress(log) {
737
876
  }
738
877
  };
739
878
  }
740
- const CLI_DEFS = [
741
- claude_exports,
742
- gemini_exports,
743
- codex_exports
744
- ];
745
- const CLI_BUILD_ARGS = {
746
- claude: buildArgs$2,
747
- gemini: buildArgs,
748
- codex: buildArgs$1
749
- };
750
- const CLI_PARSE_LINE = {
751
- claude: parseLine$2,
752
- gemini: parseLine,
753
- codex: parseLine$1
754
- };
755
- const CLI_PROVIDER_NAMES = {
756
- "claude-code": "Anthropic",
757
- "gemini-cli": "Google",
758
- "codex": "OpenAI"
879
+ function shortenPath(p) {
880
+ const refIdx = p.indexOf(".skilld/");
881
+ if (refIdx !== -1) return p.slice(refIdx + 8);
882
+ const parts = p.split("/");
883
+ return parts.length > 2 ? `.../${parts.slice(-2).join("/")}` : p;
884
+ }
885
+ function shortenCommand(cmd) {
886
+ return cmd.replace(/\/[^\s"']+/g, (match) => {
887
+ if (match.includes(".claude/") || match.includes(".skilld/") || match.includes("node_modules/")) return `.../${match.split("/").slice(-2).join("/")}`;
888
+ return match;
889
+ });
890
+ }
891
+ const CLI_ADAPTERS = {
892
+ claude: adapter$2,
893
+ gemini: adapter,
894
+ codex: adapter$1
759
895
  };
896
+ const CLI_PROVIDER_NAMES = Object.fromEntries(Object.values(CLI_ADAPTERS).map((a) => [a.agentId, a.providerName]));
760
897
  const PI_PROVIDER_NAMES = {
761
898
  "anthropic": "Anthropic",
762
899
  "google": "Google",
@@ -770,10 +907,10 @@ const PI_PROVIDER_NAMES = {
770
907
  "mistral": "Mistral",
771
908
  "xai": "xAI"
772
909
  };
773
- const CLI_MODELS = Object.fromEntries(CLI_DEFS.flatMap((def) => Object.entries(def.models).map(([id, entry]) => [id, {
910
+ const CLI_MODELS = Object.fromEntries(Object.values(CLI_ADAPTERS).flatMap((adapter) => Object.entries(adapter.models).map(([id, entry]) => [id, {
774
911
  ...entry,
775
- cli: def.cli,
776
- agentId: def.agentId
912
+ cli: adapter.cli,
913
+ agentId: adapter.agentId
777
914
  }])));
778
915
  function getModelName(id) {
779
916
  if (isPiAiModel(id)) return parsePiAiModelId(id)?.modelId ?? id;
@@ -834,135 +971,248 @@ async function getAvailableModels() {
834
971
  });
835
972
  return [...cliModels, ...piAiEntries];
836
973
  }
837
- function resolveReferenceDirs(skillDir) {
838
- const refsDir = join(skillDir, ".skilld");
839
- if (!existsSync(refsDir)) return [];
840
- const resolved = readdirSync(refsDir).map((entry) => join(refsDir, entry)).filter((p) => lstatSync(p).isSymbolicLink() && existsSync(p)).map((p) => realpathSync(p));
841
- const parents = /* @__PURE__ */ new Set();
842
- for (const p of resolved) {
843
- const parent = dirname(p);
844
- if (!resolved.includes(parent)) parents.add(parent);
974
+ const NUXT_CONFIG_FILES = [
975
+ "nuxt.config.ts",
976
+ "nuxt.config.js",
977
+ "nuxt.config.mjs"
978
+ ];
979
+ const NUXT_ECOSYSTEM = [
980
+ "vue",
981
+ "nitro",
982
+ "h3"
983
+ ];
984
+ async function findNuxtConfig(cwd) {
985
+ for (const name of NUXT_CONFIG_FILES) {
986
+ const path = join(cwd, name);
987
+ const content = await readFile(path, "utf8").catch(() => null);
988
+ if (content) return {
989
+ path,
990
+ content
991
+ };
845
992
  }
846
- return [...resolved, ...parents];
847
- }
848
- const CACHE_DIR = join(homedir(), ".skilld", "llm-cache");
849
- function normalizePromptForHash(prompt) {
850
- return prompt.replace(/\/[^\s`]*\.(?:claude|codex|gemini)\/skills\/[^\s/`]+/g, "<SKILL_DIR>");
993
+ return null;
851
994
  }
852
- function hashPrompt(prompt, model, section) {
853
- return createHash("sha256").update(`exec:${model}:${section}:${normalizePromptForHash(prompt)}`).digest("hex").slice(0, 16);
995
+ function extractModuleStrings(node) {
996
+ if (!node || typeof node !== "object") return [];
997
+ if (node.type === "Property" && !node.computed && node.key?.type === "Identifier" && node.key.name === "modules" && node.value?.type === "ArrayExpression") return node.value.elements.filter((el) => el?.type === "Literal" && typeof el.value === "string").map((el) => el.value);
998
+ const results = [];
999
+ if (Array.isArray(node)) for (const child of node) results.push(...extractModuleStrings(child));
1000
+ else for (const key of Object.keys(node)) {
1001
+ if (key === "start" || key === "end" || key === "type") continue;
1002
+ const val = node[key];
1003
+ if (val && typeof val === "object") results.push(...extractModuleStrings(val));
1004
+ }
1005
+ return results;
854
1006
  }
855
- function getCached(prompt, model, section, maxAge = 10080 * 60 * 1e3) {
856
- const path = join(CACHE_DIR, `${hashPrompt(prompt, model, section)}.json`);
857
- if (!existsSync(path)) return null;
858
- try {
859
- const { text, timestamp } = JSON.parse(readFileSync(path, "utf-8"));
860
- return Date.now() - timestamp > maxAge ? null : text;
861
- } catch {
862
- return null;
1007
+ async function detectNuxtModules(cwd) {
1008
+ const config = await findNuxtConfig(cwd);
1009
+ if (!config) return [];
1010
+ const modules = extractModuleStrings(parseSync(config.path, config.content).program);
1011
+ const seen = /* @__PURE__ */ new Set();
1012
+ const packages = [];
1013
+ for (const mod of modules) if (!seen.has(mod)) {
1014
+ seen.add(mod);
1015
+ packages.push({
1016
+ name: mod,
1017
+ count: 0,
1018
+ source: "preset"
1019
+ });
1020
+ }
1021
+ for (const pkg of NUXT_ECOSYSTEM) if (!seen.has(pkg)) {
1022
+ seen.add(pkg);
1023
+ packages.push({
1024
+ name: pkg,
1025
+ count: 0,
1026
+ source: "preset"
1027
+ });
863
1028
  }
1029
+ return packages;
864
1030
  }
865
- function setCache(prompt, model, section, text) {
866
- mkdirSync(CACHE_DIR, {
867
- recursive: true,
868
- mode: 448
869
- });
870
- writeFileSync(join(CACHE_DIR, `${hashPrompt(prompt, model, section)}.json`), JSON.stringify({
871
- text,
872
- model,
873
- section,
874
- timestamp: Date.now()
875
- }), { mode: 384 });
1031
+ async function detectPresetPackages(cwd) {
1032
+ return detectNuxtModules(cwd);
876
1033
  }
877
- async function optimizeSectionViaPiAi(opts) {
878
- const { section, prompt, outputFile, skillDir, model, onProgress, timeout, debug } = opts;
879
- const skilldDir = join(skillDir, ".skilld");
880
- const outputPath = join(skilldDir, outputFile);
881
- const logsDir = join(skilldDir, "logs");
882
- const logName = section.toUpperCase().replace(/-/g, "_");
883
- if (existsSync(outputPath)) unlinkSync(outputPath);
884
- writeFileSync(join(skilldDir, `PROMPT_${section}.md`), prompt);
1034
+ const PATTERNS = ["**/*.{ts,js,vue,mjs,cjs,tsx,jsx,mts,cts}"];
1035
+ const IGNORE = [
1036
+ "**/node_modules/**",
1037
+ "**/dist/**",
1038
+ "**/.nuxt/**",
1039
+ "**/.output/**",
1040
+ "**/coverage/**"
1041
+ ];
1042
+ function addPackage(counts, specifier) {
1043
+ if (!specifier || specifier.startsWith(".") || specifier.startsWith("/")) return;
1044
+ const name = specifier.startsWith("@") ? specifier.split("/").slice(0, 2).join("/") : specifier.split("/")[0];
1045
+ if (!isNodeBuiltin(name)) counts.set(name, (counts.get(name) || 0) + 1);
1046
+ }
1047
+ async function detectImportedPackages(cwd = process.cwd()) {
885
1048
  try {
886
- const ac = new AbortController();
887
- const timer = setTimeout(() => ac.abort(), timeout);
888
- const result = await optimizeSectionPiAi({
889
- section,
890
- prompt,
891
- skillDir,
892
- model,
893
- onProgress,
894
- signal: ac.signal
895
- }).finally(() => clearTimeout(timer));
896
- const raw = result.text.trim();
897
- if (debug) {
898
- mkdirSync(logsDir, { recursive: true });
899
- writeFileSync(join(skilldDir, `PROMPT_${section}.md`), result.fullPrompt);
900
- if (raw) writeFileSync(join(logsDir, `${logName}.md`), raw);
901
- }
902
- if (!raw) return {
903
- section,
904
- content: "",
905
- wasOptimized: false,
906
- error: "pi-ai returned empty response"
907
- };
908
- const content = cleanSectionOutput(raw);
909
- if (content) writeFileSync(outputPath, content);
910
- const validator = getSectionValidator(section);
911
- const warnings = (content && validator ? validator(content) : []).map((w) => ({
912
- section,
913
- warning: w.warning
914
- }));
915
- return {
916
- section,
917
- content,
918
- wasOptimized: !!content,
919
- warnings: warnings?.length ? warnings : void 0,
920
- usage: result.usage,
921
- cost: result.cost
922
- };
923
- } catch (err) {
924
- const errMsg = err.message;
925
- if (debug || errMsg) {
926
- mkdirSync(logsDir, { recursive: true });
927
- writeFileSync(join(logsDir, `${logName}.stderr.log`), errMsg);
928
- }
929
- return {
930
- section,
931
- content: "",
932
- wasOptimized: false,
933
- error: errMsg
1049
+ const counts = /* @__PURE__ */ new Map();
1050
+ const files = await glob(PATTERNS, {
1051
+ cwd,
1052
+ ignore: IGNORE,
1053
+ absolute: true,
1054
+ expandDirectories: false
1055
+ });
1056
+ await Promise.all(files.map(async (file) => {
1057
+ const content = await readFile(file, "utf8");
1058
+ for (const imp of findStaticImports(content)) addPackage(counts, imp.specifier);
1059
+ for (const imp of findDynamicImports(content)) {
1060
+ const match = imp.expression.match(/^['"]([^'"]+)['"]$/);
1061
+ if (match) addPackage(counts, match[1]);
1062
+ }
1063
+ }));
1064
+ const packages = Array.from(counts.entries(), ([name, count]) => ({
1065
+ name,
1066
+ count,
1067
+ source: "import"
1068
+ })).sort((a, b) => b.count - a.count || a.name.localeCompare(b.name));
1069
+ const presets = await detectPresetPackages(cwd);
1070
+ const importNames = new Set(packages.map((p) => p.name));
1071
+ for (const preset of presets) if (!importNames.has(preset.name)) packages.push(preset);
1072
+ return { packages };
1073
+ } catch (err) {
1074
+ return {
1075
+ packages: [],
1076
+ error: String(err)
934
1077
  };
935
1078
  }
936
1079
  }
937
- function optimizeSection(opts) {
938
- const { section, prompt, outputFile, skillDir, model, onProgress, timeout, debug, preExistingFiles } = opts;
939
- if (isPiAiModel(model)) return optimizeSectionViaPiAi({
940
- section,
941
- prompt,
942
- outputFile,
943
- skillDir,
944
- model,
945
- onProgress,
946
- timeout,
947
- debug
1080
+ const NODE_BUILTINS = new Set([
1081
+ "assert",
1082
+ "async_hooks",
1083
+ "buffer",
1084
+ "child_process",
1085
+ "cluster",
1086
+ "console",
1087
+ "constants",
1088
+ "crypto",
1089
+ "dgram",
1090
+ "diagnostics_channel",
1091
+ "dns",
1092
+ "domain",
1093
+ "events",
1094
+ "fs",
1095
+ "http",
1096
+ "http2",
1097
+ "https",
1098
+ "inspector",
1099
+ "module",
1100
+ "net",
1101
+ "os",
1102
+ "path",
1103
+ "perf_hooks",
1104
+ "process",
1105
+ "punycode",
1106
+ "querystring",
1107
+ "readline",
1108
+ "repl",
1109
+ "sea",
1110
+ "sqlite",
1111
+ "stream",
1112
+ "string_decoder",
1113
+ "sys",
1114
+ "test",
1115
+ "timers",
1116
+ "tls",
1117
+ "trace_events",
1118
+ "tty",
1119
+ "url",
1120
+ "util",
1121
+ "v8",
1122
+ "vm",
1123
+ "wasi",
1124
+ "worker_threads",
1125
+ "zlib"
1126
+ ]);
1127
+ function isNodeBuiltin(pkg) {
1128
+ const base = pkg.startsWith("node:") ? pkg.slice(5) : pkg;
1129
+ return NODE_BUILTINS.has(base.split("/")[0]);
1130
+ }
1131
+ const DEFAULT_MAX_AGE = 10080 * 60 * 1e3;
1132
+ function normalizePromptForHash(prompt) {
1133
+ return prompt.replace(/\/[^\s`]*\.(?:claude|codex|gemini)\/skills\/[^\s/`]+/g, "<SKILL_DIR>");
1134
+ }
1135
+ function hashPrompt(prompt, model, section) {
1136
+ return createHash("sha256").update(`exec:${model}:${section}:${normalizePromptForHash(prompt)}`).digest("hex").slice(0, 16);
1137
+ }
1138
+ function getCached(prompt, model, section, maxAge = DEFAULT_MAX_AGE) {
1139
+ const path = join(LLM_CACHE_DIR, `${hashPrompt(prompt, model, section)}.json`);
1140
+ if (!existsSync(path)) return null;
1141
+ try {
1142
+ const { text, timestamp } = JSON.parse(readFileSync(path, "utf-8"));
1143
+ return Date.now() - timestamp > maxAge ? null : text;
1144
+ } catch {
1145
+ return null;
1146
+ }
1147
+ }
1148
+ function setCache(prompt, model, section, text) {
1149
+ mkdirSync(LLM_CACHE_DIR, {
1150
+ recursive: true,
1151
+ mode: 448
948
1152
  });
949
- const cliConfig = CLI_MODELS[model];
950
- if (!cliConfig) return Promise.resolve({
1153
+ writeFileSync(join(LLM_CACHE_DIR, `${hashPrompt(prompt, model, section)}.json`), JSON.stringify({
1154
+ text,
1155
+ model,
1156
+ section,
1157
+ timestamp: Date.now()
1158
+ }), { mode: 384 });
1159
+ }
1160
+ function prepareSection(opts) {
1161
+ if (existsSync(opts.outputPath)) unlinkSync(opts.outputPath);
1162
+ writeFileSync(join(opts.skilldDir, `PROMPT_${opts.section}.md`), opts.prompt);
1163
+ }
1164
+ function finalizeSection(opts) {
1165
+ const { section, raw, outputFile, outputPath, skilldDir, debug, cliCleanup } = opts;
1166
+ if (cliCleanup) for (const entry of readdirSync(skilldDir)) {
1167
+ if (entry === outputFile || cliCleanup.preExistingFiles.has(entry)) continue;
1168
+ if (Object.values(SECTION_OUTPUT_FILES).includes(entry)) continue;
1169
+ if (entry.startsWith("PROMPT_") || entry === "logs") continue;
1170
+ try {
1171
+ unlinkSync(join(skilldDir, entry));
1172
+ } catch {}
1173
+ }
1174
+ const logsDir = join(skilldDir, "logs");
1175
+ const logName = section.toUpperCase().replace(/-/g, "_");
1176
+ const text = ((existsSync(outputPath) ? readFileSync(outputPath, "utf-8") : "") || raw.writeContent || raw.text).trim();
1177
+ const stderr = raw.stderr ?? "";
1178
+ const code = raw.exitCode ?? 0;
1179
+ if (debug || stderr && (!text || code !== 0)) {
1180
+ mkdirSync(logsDir, { recursive: true });
1181
+ if (stderr) writeFileSync(join(logsDir, `${logName}.stderr.log`), stderr);
1182
+ }
1183
+ if (debug) {
1184
+ mkdirSync(logsDir, { recursive: true });
1185
+ if (raw.rawLines?.length) writeFileSync(join(logsDir, `${logName}.jsonl`), raw.rawLines.join("\n"));
1186
+ if (text) writeFileSync(join(logsDir, `${logName}.md`), text);
1187
+ }
1188
+ if (!text && code !== 0) return {
951
1189
  section,
952
1190
  content: "",
953
1191
  wasOptimized: false,
954
- error: `No CLI mapping for model: ${model}`
955
- });
956
- const { cli, model: cliModel } = cliConfig;
957
- const symlinkDirs = resolveReferenceDirs(skillDir);
958
- const args = CLI_BUILD_ARGS[cli](cliModel, skillDir, symlinkDirs);
959
- const parseLine = CLI_PARSE_LINE[cli];
960
- const skilldDir = join(skillDir, ".skilld");
961
- const outputPath = join(skilldDir, outputFile);
962
- if (existsSync(outputPath)) unlinkSync(outputPath);
963
- writeFileSync(join(skilldDir, `PROMPT_${section}.md`), prompt);
1192
+ error: stderr.trim() || `CLI exited with code ${code}`
1193
+ };
1194
+ const content = text ? cleanSectionOutput(text) : "";
1195
+ if (content) writeFileSync(outputPath, content);
1196
+ const validator = getSectionValidator(section);
1197
+ const warnings = (content && validator ? validator(content) : []).map((w) => ({
1198
+ section,
1199
+ warning: w.warning
1200
+ }));
1201
+ return {
1202
+ section,
1203
+ content,
1204
+ wasOptimized: !!content,
1205
+ warnings: warnings.length ? warnings : void 0,
1206
+ usage: raw.usage,
1207
+ cost: raw.cost
1208
+ };
1209
+ }
1210
+ function spawnCliAndStream(opts) {
1211
+ const { adapter, cliModel, prompt, skillDir, skilldDir, symlinkDirs, timeout, debug, section, onProgress } = opts;
1212
+ const args = adapter.buildArgs(cliModel, skillDir, symlinkDirs);
1213
+ const parseEvent = adapter.parseEvent;
964
1214
  return new Promise((resolve) => {
965
- const proc = spawn(cli, args, {
1215
+ const proc = spawn(adapter.cli, args, {
966
1216
  cwd: skilldDir,
967
1217
  stdio: [
968
1218
  "pipe",
@@ -991,6 +1241,32 @@ function optimizeSection(opts) {
991
1241
  });
992
1242
  proc.stdin.write(prompt);
993
1243
  proc.stdin.end();
1244
+ function applyEvent(evt) {
1245
+ switch (evt.kind) {
1246
+ case "text":
1247
+ if (evt.delta) accumulatedText += evt.delta;
1248
+ if (evt.full !== void 0) accumulatedText = evt.full;
1249
+ break;
1250
+ case "tool-call": {
1251
+ if (evt.writeContent) lastWriteContent = evt.writeContent;
1252
+ const chunk = evt.hint ? `[${evt.tool}: ${evt.hint}]` : `[${evt.tool}]`;
1253
+ onProgress?.({
1254
+ chunk,
1255
+ type: "reasoning",
1256
+ text: "",
1257
+ reasoning: chunk,
1258
+ section
1259
+ });
1260
+ break;
1261
+ }
1262
+ case "done":
1263
+ if (evt.usage) usage = evt.usage;
1264
+ if (evt.cost != null) cost = evt.cost;
1265
+ break;
1266
+ case "error":
1267
+ case "noop": break;
1268
+ }
1269
+ }
994
1270
  proc.stdout.on("data", (chunk) => {
995
1271
  buffer += chunk.toString();
996
1272
  const lines = buffer.split("\n");
@@ -998,22 +1274,7 @@ function optimizeSection(opts) {
998
1274
  for (const line of lines) {
999
1275
  if (!line.trim()) continue;
1000
1276
  if (debug) rawLines.push(line);
1001
- const evt = parseLine(line);
1002
- if (evt.textDelta) accumulatedText += evt.textDelta;
1003
- if (evt.fullText) accumulatedText = evt.fullText;
1004
- if (evt.writeContent) lastWriteContent = evt.writeContent;
1005
- if (evt.toolName) {
1006
- const hint = evt.toolHint ? `[${evt.toolName}: ${evt.toolHint}]` : `[${evt.toolName}]`;
1007
- onProgress?.({
1008
- chunk: hint,
1009
- type: "reasoning",
1010
- text: "",
1011
- reasoning: hint,
1012
- section
1013
- });
1014
- }
1015
- if (evt.usage) usage = evt.usage;
1016
- if (evt.cost != null) cost = evt.cost;
1277
+ applyEvent(parseEvent(line));
1017
1278
  }
1018
1279
  });
1019
1280
  let stderr = "";
@@ -1021,70 +1282,113 @@ function optimizeSection(opts) {
1021
1282
  stderr += chunk.toString();
1022
1283
  });
1023
1284
  proc.on("close", (code) => {
1024
- if (buffer.trim()) {
1025
- const evt = parseLine(buffer);
1026
- if (evt.textDelta) accumulatedText += evt.textDelta;
1027
- if (evt.fullText) accumulatedText = evt.fullText;
1028
- if (evt.writeContent) lastWriteContent = evt.writeContent;
1029
- if (evt.usage) usage = evt.usage;
1030
- if (evt.cost != null) cost = evt.cost;
1031
- }
1032
- for (const entry of readdirSync(skilldDir)) if (entry !== outputFile && !preExistingFiles.has(entry)) {
1033
- if (Object.values(SECTION_OUTPUT_FILES).includes(entry)) continue;
1034
- if (entry.startsWith("PROMPT_") || entry === "logs") continue;
1035
- try {
1036
- unlinkSync(join(skilldDir, entry));
1037
- } catch {}
1038
- }
1039
- const raw = (existsSync(outputPath) ? readFileSync(outputPath, "utf-8") : lastWriteContent || accumulatedText).trim();
1040
- const logsDir = join(skilldDir, "logs");
1041
- const logName = section.toUpperCase().replace(/-/g, "_");
1042
- if (debug || stderr && (!raw || code !== 0)) {
1043
- mkdirSync(logsDir, { recursive: true });
1044
- if (stderr) writeFileSync(join(logsDir, `${logName}.stderr.log`), stderr);
1045
- }
1046
- if (debug) {
1047
- mkdirSync(logsDir, { recursive: true });
1048
- if (rawLines.length) writeFileSync(join(logsDir, `${logName}.jsonl`), rawLines.join("\n"));
1049
- if (raw) writeFileSync(join(logsDir, `${logName}.md`), raw);
1050
- }
1051
- if (!raw && code !== 0) {
1052
- resolve({
1053
- section,
1054
- content: "",
1055
- wasOptimized: false,
1056
- error: stderr.trim() || `CLI exited with code ${code}`
1057
- });
1058
- return;
1059
- }
1060
- const content = raw ? cleanSectionOutput(raw) : "";
1061
- if (content) writeFileSync(outputPath, content);
1062
- const validator = getSectionValidator(section);
1063
- const warnings = (content && validator ? validator(content) : []).map((w) => ({
1064
- section,
1065
- warning: w.warning
1066
- }));
1285
+ if (buffer.trim()) applyEvent(parseEvent(buffer));
1067
1286
  resolve({
1068
- section,
1069
- content,
1070
- wasOptimized: !!content,
1071
- warnings: warnings?.length ? warnings : void 0,
1287
+ text: accumulatedText,
1288
+ writeContent: lastWriteContent || void 0,
1072
1289
  usage,
1073
- cost
1290
+ cost,
1291
+ stderr,
1292
+ exitCode: code ?? 0,
1293
+ rawLines: debug ? rawLines : void 0
1074
1294
  });
1075
1295
  });
1076
1296
  proc.on("error", (err) => {
1077
1297
  resolve({
1078
- section,
1079
- content: "",
1080
- wasOptimized: false,
1081
- error: err.message
1298
+ text: "",
1299
+ stderr: err.message,
1300
+ exitCode: 1
1082
1301
  });
1083
1302
  });
1084
1303
  });
1085
1304
  }
1305
+ function cliExecutor(model) {
1306
+ const cliConfig = CLI_MODELS[model];
1307
+ if (!cliConfig) return { error: `No CLI mapping for model: ${model}` };
1308
+ const adapter = CLI_ADAPTERS[cliConfig.cli];
1309
+ return {
1310
+ cliCleanup: true,
1311
+ run: ({ section, prompt, skillDir, skilldDir, timeout, debug, onProgress }) => spawnCliAndStream({
1312
+ adapter,
1313
+ cliModel: cliConfig.model,
1314
+ prompt,
1315
+ skillDir,
1316
+ skilldDir,
1317
+ symlinkDirs: getSkillReferenceDirs(skillDir),
1318
+ timeout,
1319
+ debug,
1320
+ section,
1321
+ onProgress
1322
+ })
1323
+ };
1324
+ }
1325
+ function piAiExecutor(model) {
1326
+ if (!new Set(getAvailablePiAiModels().map((m) => m.id)).has(model)) return { error: `Pi model unavailable or not authenticated: ${model}` };
1327
+ return {
1328
+ cliCleanup: false,
1329
+ run: async ({ section, prompt, skillDir, timeout, onProgress }) => {
1330
+ const ac = new AbortController();
1331
+ const timer = setTimeout(() => ac.abort(), timeout);
1332
+ try {
1333
+ const result = await optimizeSectionPiAi({
1334
+ section,
1335
+ prompt,
1336
+ skillDir,
1337
+ model,
1338
+ onProgress,
1339
+ signal: ac.signal
1340
+ });
1341
+ return {
1342
+ text: result.text.trim(),
1343
+ usage: result.usage,
1344
+ cost: result.cost
1345
+ };
1346
+ } catch (err) {
1347
+ return {
1348
+ text: "",
1349
+ stderr: err.message,
1350
+ exitCode: 1
1351
+ };
1352
+ } finally {
1353
+ clearTimeout(timer);
1354
+ }
1355
+ }
1356
+ };
1357
+ }
1358
+ function selectExecutor(model) {
1359
+ return isPiAiModel(model) ? piAiExecutor(model) : cliExecutor(model);
1360
+ }
1361
+ async function optimizeSection(opts) {
1362
+ const { section, prompt, outputFile, skillDir, executor, onProgress, timeout, debug, preExistingFiles } = opts;
1363
+ const skilldDir = skillInternalDir(skillDir);
1364
+ const outputPath = join(skilldDir, outputFile);
1365
+ prepareSection({
1366
+ section,
1367
+ prompt,
1368
+ outputPath,
1369
+ skilldDir
1370
+ });
1371
+ return finalizeSection({
1372
+ section,
1373
+ raw: await executor.run({
1374
+ section,
1375
+ prompt,
1376
+ skillDir,
1377
+ skilldDir,
1378
+ timeout,
1379
+ debug,
1380
+ onProgress
1381
+ }),
1382
+ outputFile,
1383
+ outputPath,
1384
+ skilldDir,
1385
+ debug: !!debug,
1386
+ cliCleanup: executor.cliCleanup ? { preExistingFiles } : void 0
1387
+ });
1388
+ }
1086
1389
  async function optimizeDocs(opts) {
1087
1390
  const { packageName, skillDir, model = "sonnet", version, hasGithub, hasReleases, hasChangelog, docFiles, docsType, hasShippedDocs, onProgress, timeout = 18e4, debug, noCache, sections, customPrompt, features, pkgFiles, overheadLines } = opts;
1391
+ const cache = createReferenceCache(packageName, version);
1088
1392
  const sectionPrompts = buildAllSectionPrompts({
1089
1393
  packageName,
1090
1394
  skillDir,
@@ -1107,24 +1411,20 @@ async function optimizeDocs(opts) {
1107
1411
  wasOptimized: false,
1108
1412
  error: "No valid sections to generate"
1109
1413
  };
1110
- if (isPiAiModel(model)) {
1111
- if (!new Set(getAvailablePiAiModels().map((m) => m.id)).has(model)) return {
1112
- optimized: "",
1113
- wasOptimized: false,
1114
- error: `Pi model unavailable or not authenticated: ${model}`
1115
- };
1116
- } else if (!CLI_MODELS[model]) return {
1414
+ const executorOrError = selectExecutor(model);
1415
+ if ("error" in executorOrError) return {
1117
1416
  optimized: "",
1118
1417
  wasOptimized: false,
1119
- error: `No CLI mapping for model: ${model}`
1418
+ error: executorOrError.error
1120
1419
  };
1420
+ const executor = executorOrError;
1121
1421
  const cachedResults = [];
1122
1422
  const uncachedSections = [];
1123
1423
  for (const [section, prompt] of sectionPrompts) {
1124
1424
  if (!noCache) {
1125
1425
  if (version) {
1126
1426
  const outputFile = SECTION_OUTPUT_FILES[section];
1127
- const refCached = readCachedSection(packageName, version, outputFile);
1427
+ const refCached = cache.readSection(outputFile);
1128
1428
  if (refCached) {
1129
1429
  onProgress?.({
1130
1430
  chunk: `[${section}: cached]`,
@@ -1163,7 +1463,7 @@ async function optimizeDocs(opts) {
1163
1463
  prompt
1164
1464
  });
1165
1465
  }
1166
- const skilldDir = join(skillDir, ".skilld");
1466
+ const skilldDir = skillInternalDir(skillDir);
1167
1467
  mkdirSync(skilldDir, { recursive: true });
1168
1468
  for (const entry of readdirSync(skilldDir)) {
1169
1469
  const entryPath = join(skilldDir, entry);
@@ -1185,8 +1485,7 @@ async function optimizeDocs(opts) {
1185
1485
  prompt,
1186
1486
  outputFile,
1187
1487
  skillDir,
1188
- model,
1189
- packageName,
1488
+ executor,
1190
1489
  onProgress,
1191
1490
  timeout,
1192
1491
  debug,
@@ -1247,8 +1546,7 @@ async function optimizeDocs(opts) {
1247
1546
  prompt,
1248
1547
  outputFile: SECTION_OUTPUT_FILES[section],
1249
1548
  skillDir,
1250
- model,
1251
- packageName,
1549
+ executor,
1252
1550
  onProgress,
1253
1551
  timeout,
1254
1552
  debug,
@@ -1276,7 +1574,7 @@ async function optimizeDocs(opts) {
1276
1574
  file: SECTION_OUTPUT_FILES[r.section],
1277
1575
  content: r.content
1278
1576
  }));
1279
- if (sectionFiles.length > 0) writeSections(packageName, version, sectionFiles);
1577
+ if (sectionFiles.length > 0) cache.writeSections(sectionFiles);
1280
1578
  }
1281
1579
  const mergedParts = [];
1282
1580
  for (const section of SECTION_MERGE_ORDER) {
@@ -1292,7 +1590,7 @@ async function optimizeDocs(opts) {
1292
1590
  } : void 0;
1293
1591
  const errors = allResults.filter((r) => r.error).map((r) => `${r.section}: ${r.error}`);
1294
1592
  const warnings = allResults.flatMap((r) => r.warnings ?? []).map((w) => `${w.section}: ${w.warning}`);
1295
- const debugLogsDir = debug && uncachedSections.length > 0 ? join(skillDir, ".skilld", "logs") : void 0;
1593
+ const debugLogsDir = debug && uncachedSections.length > 0 ? skillLogDir(skillDir) : void 0;
1296
1594
  return {
1297
1595
  optimized,
1298
1596
  wasOptimized,
@@ -1317,210 +1615,6 @@ function getRetryError(result) {
1317
1615
  if (result.status === "rejected") return String(result.reason);
1318
1616
  return result.value.error;
1319
1617
  }
1320
- function shortenPath(p) {
1321
- const refIdx = p.indexOf(".skilld/");
1322
- if (refIdx !== -1) return p.slice(refIdx + 8);
1323
- const parts = p.split("/");
1324
- return parts.length > 2 ? `.../${parts.slice(-2).join("/")}` : p;
1325
- }
1326
- function shortenCommand(cmd) {
1327
- return cmd.replace(/\/[^\s"']+/g, (match) => {
1328
- if (match.includes(".claude/") || match.includes(".skilld/") || match.includes("node_modules/")) return `.../${match.split("/").slice(-2).join("/")}`;
1329
- return match;
1330
- });
1331
- }
1332
- function cleanSectionOutput(content) {
1333
- let cleaned = content.trim();
1334
- const wrapMatch = cleaned.match(/^```(?:markdown|md)?[^\S\n]*\n([\s\S]+)\n```[^\S\n]*$/);
1335
- if (wrapMatch) {
1336
- const inner = wrapMatch[1].trim();
1337
- if (/^```(?:markdown|md)/.test(cleaned) || /^##\s/m.test(inner) || /^- (?:BREAKING|DEPRECATED|NEW): /m.test(inner)) cleaned = inner;
1338
- }
1339
- cleaned = cleaned.replace(/^# (?!#)/gm, "## ");
1340
- const fmMatch = cleaned.match(/^-{3,}\n/);
1341
- if (fmMatch) {
1342
- const afterOpen = fmMatch[0].length;
1343
- const closeMatch = cleaned.slice(afterOpen).match(/\n-{3,}/);
1344
- if (closeMatch) cleaned = cleaned.slice(afterOpen + closeMatch.index + closeMatch[0].length).trim();
1345
- else cleaned = cleaned.slice(afterOpen).trim();
1346
- }
1347
- const firstMarker = cleaned.match(/^(##\s|- (?:BREAKING|DEPRECATED|NEW): )/m);
1348
- if (firstMarker?.index && firstMarker.index > 0) cleaned = cleaned.slice(firstMarker.index).trim();
1349
- const headingMatch = cleaned.match(/^(## .+)\n/);
1350
- if (headingMatch) {
1351
- const heading = headingMatch[1];
1352
- const afterFirst = headingMatch[0].length;
1353
- const secondIdx = cleaned.indexOf(heading, afterFirst);
1354
- if (secondIdx !== -1) {
1355
- if (secondIdx - afterFirst < 200) cleaned = cleaned.slice(secondIdx).trim();
1356
- }
1357
- }
1358
- cleaned = cleaned.replace(/\(?\[`?\.\/(?:\.skilld\/|references\/)[^)\]]*\]\(([^)]+)\)\)?/g, (match, url) => {
1359
- if (/^\.\/(?:\.skilld\/|references\/)/.test(url)) return `[source](${url})`;
1360
- return match;
1361
- });
1362
- cleaned = cleaned.replace(/\[source\]\(\.\/((docs|issues|discussions|releases|pkg|guide)\/)/g, "[source](./.skilld/$1");
1363
- cleaned = sanitizeMarkdown(cleaned);
1364
- if (!/^##\s/m.test(cleaned) && !/^- (?:BREAKING|DEPRECATED|NEW): /m.test(cleaned) && !/\[source\]/.test(cleaned)) return "";
1365
- return cleaned;
1366
- }
1367
- const NUXT_CONFIG_FILES = [
1368
- "nuxt.config.ts",
1369
- "nuxt.config.js",
1370
- "nuxt.config.mjs"
1371
- ];
1372
- const NUXT_ECOSYSTEM = [
1373
- "vue",
1374
- "nitro",
1375
- "h3"
1376
- ];
1377
- async function findNuxtConfig(cwd) {
1378
- for (const name of NUXT_CONFIG_FILES) {
1379
- const path = join(cwd, name);
1380
- const content = await readFile(path, "utf8").catch(() => null);
1381
- if (content) return {
1382
- path,
1383
- content
1384
- };
1385
- }
1386
- return null;
1387
- }
1388
- function extractModuleStrings(node) {
1389
- if (!node || typeof node !== "object") return [];
1390
- if (node.type === "Property" && !node.computed && node.key?.type === "Identifier" && node.key.name === "modules" && node.value?.type === "ArrayExpression") return node.value.elements.filter((el) => el?.type === "Literal" && typeof el.value === "string").map((el) => el.value);
1391
- const results = [];
1392
- if (Array.isArray(node)) for (const child of node) results.push(...extractModuleStrings(child));
1393
- else for (const key of Object.keys(node)) {
1394
- if (key === "start" || key === "end" || key === "type") continue;
1395
- const val = node[key];
1396
- if (val && typeof val === "object") results.push(...extractModuleStrings(val));
1397
- }
1398
- return results;
1399
- }
1400
- async function detectNuxtModules(cwd) {
1401
- const config = await findNuxtConfig(cwd);
1402
- if (!config) return [];
1403
- const modules = extractModuleStrings(parseSync(config.path, config.content).program);
1404
- const seen = /* @__PURE__ */ new Set();
1405
- const packages = [];
1406
- for (const mod of modules) if (!seen.has(mod)) {
1407
- seen.add(mod);
1408
- packages.push({
1409
- name: mod,
1410
- count: 0,
1411
- source: "preset"
1412
- });
1413
- }
1414
- for (const pkg of NUXT_ECOSYSTEM) if (!seen.has(pkg)) {
1415
- seen.add(pkg);
1416
- packages.push({
1417
- name: pkg,
1418
- count: 0,
1419
- source: "preset"
1420
- });
1421
- }
1422
- return packages;
1423
- }
1424
- async function detectPresetPackages(cwd) {
1425
- return detectNuxtModules(cwd);
1426
- }
1427
- const PATTERNS = ["**/*.{ts,js,vue,mjs,cjs,tsx,jsx,mts,cts}"];
1428
- const IGNORE = [
1429
- "**/node_modules/**",
1430
- "**/dist/**",
1431
- "**/.nuxt/**",
1432
- "**/.output/**",
1433
- "**/coverage/**"
1434
- ];
1435
- function addPackage(counts, specifier) {
1436
- if (!specifier || specifier.startsWith(".") || specifier.startsWith("/")) return;
1437
- const name = specifier.startsWith("@") ? specifier.split("/").slice(0, 2).join("/") : specifier.split("/")[0];
1438
- if (!isNodeBuiltin(name)) counts.set(name, (counts.get(name) || 0) + 1);
1439
- }
1440
- async function detectImportedPackages(cwd = process.cwd()) {
1441
- try {
1442
- const counts = /* @__PURE__ */ new Map();
1443
- const files = await glob(PATTERNS, {
1444
- cwd,
1445
- ignore: IGNORE,
1446
- absolute: true,
1447
- expandDirectories: false
1448
- });
1449
- await Promise.all(files.map(async (file) => {
1450
- const content = await readFile(file, "utf8");
1451
- for (const imp of findStaticImports(content)) addPackage(counts, imp.specifier);
1452
- for (const imp of findDynamicImports(content)) {
1453
- const match = imp.expression.match(/^['"]([^'"]+)['"]$/);
1454
- if (match) addPackage(counts, match[1]);
1455
- }
1456
- }));
1457
- const packages = Array.from(counts.entries(), ([name, count]) => ({
1458
- name,
1459
- count,
1460
- source: "import"
1461
- })).sort((a, b) => b.count - a.count || a.name.localeCompare(b.name));
1462
- const presets = await detectPresetPackages(cwd);
1463
- const importNames = new Set(packages.map((p) => p.name));
1464
- for (const preset of presets) if (!importNames.has(preset.name)) packages.push(preset);
1465
- return { packages };
1466
- } catch (err) {
1467
- return {
1468
- packages: [],
1469
- error: String(err)
1470
- };
1471
- }
1472
- }
1473
- const NODE_BUILTINS = new Set([
1474
- "assert",
1475
- "async_hooks",
1476
- "buffer",
1477
- "child_process",
1478
- "cluster",
1479
- "console",
1480
- "constants",
1481
- "crypto",
1482
- "dgram",
1483
- "diagnostics_channel",
1484
- "dns",
1485
- "domain",
1486
- "events",
1487
- "fs",
1488
- "http",
1489
- "http2",
1490
- "https",
1491
- "inspector",
1492
- "module",
1493
- "net",
1494
- "os",
1495
- "path",
1496
- "perf_hooks",
1497
- "process",
1498
- "punycode",
1499
- "querystring",
1500
- "readline",
1501
- "repl",
1502
- "sea",
1503
- "sqlite",
1504
- "stream",
1505
- "string_decoder",
1506
- "sys",
1507
- "test",
1508
- "timers",
1509
- "tls",
1510
- "trace_events",
1511
- "tty",
1512
- "url",
1513
- "util",
1514
- "v8",
1515
- "vm",
1516
- "wasi",
1517
- "worker_threads",
1518
- "zlib"
1519
- ]);
1520
- function isNodeBuiltin(pkg) {
1521
- const base = pkg.startsWith("node:") ? pkg.slice(5) : pkg;
1522
- return NODE_BUILTINS.has(base.split("/")[0]);
1523
- }
1524
- export { getModelLabel as a, getOAuthProviderList as c, getAvailableModels as i, loginOAuthProvider as l, cleanSectionOutput as n, getModelName as o, createToolProgress as r, optimizeDocs as s, detectImportedPackages as t, logoutOAuthProvider as u };
1618
+ export { getModelName as a, getOAuthProviderList as c, getModelLabel as i, loginOAuthProvider as l, detectImportedPackages as n, createToolProgress as o, getAvailableModels as r, cleanSectionOutput as s, optimizeDocs as t, logoutOAuthProvider as u };
1525
1619
 
1526
1620
  //# sourceMappingURL=agent.mjs.map