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.
- package/dist/_chunks/agent.mjs +693 -599
- package/dist/_chunks/agent.mjs.map +1 -1
- package/dist/_chunks/assemble.mjs +3 -3
- package/dist/_chunks/author.mjs +51 -121
- package/dist/_chunks/author.mjs.map +1 -1
- package/dist/_chunks/cache.mjs +315 -9
- package/dist/_chunks/cache.mjs.map +1 -1
- package/dist/_chunks/cache2.mjs +2 -2
- package/dist/_chunks/cli-helpers.mjs +3 -3
- package/dist/_chunks/core.mjs +7 -4
- package/dist/_chunks/detect.mjs +1 -1
- package/dist/_chunks/embedding-cache2.mjs +2 -2
- package/dist/_chunks/index.d.mts +305 -112
- package/dist/_chunks/index.d.mts.map +1 -1
- package/dist/_chunks/index2.d.mts +267 -32
- package/dist/_chunks/index2.d.mts.map +1 -1
- package/dist/_chunks/index3.d.mts +32 -577
- package/dist/_chunks/index3.d.mts.map +1 -1
- package/dist/_chunks/index4.d.mts +553 -0
- package/dist/_chunks/index4.d.mts.map +1 -0
- package/dist/_chunks/install.mjs +48 -88
- package/dist/_chunks/install.mjs.map +1 -1
- package/dist/_chunks/list.mjs +1 -1
- package/dist/_chunks/lockfile.mjs +29 -6
- package/dist/_chunks/lockfile.mjs.map +1 -1
- package/dist/_chunks/monorepo.mjs +71 -0
- package/dist/_chunks/monorepo.mjs.map +1 -0
- package/dist/_chunks/{shared.mjs → package-registry.mjs} +2 -40
- package/dist/_chunks/package-registry.mjs.map +1 -0
- package/dist/_chunks/paths.mjs +49 -0
- package/dist/_chunks/paths.mjs.map +1 -0
- package/dist/_chunks/pool2.mjs +1 -1
- package/dist/_chunks/prepare.mjs +1 -1
- package/dist/_chunks/prepare2.mjs +5 -5
- package/dist/_chunks/prepare2.mjs.map +1 -1
- package/dist/_chunks/prompts.mjs +366 -18
- package/dist/_chunks/prompts.mjs.map +1 -1
- package/dist/_chunks/search-helpers.mjs +5 -6
- package/dist/_chunks/search-helpers.mjs.map +1 -1
- package/dist/_chunks/search-interactive.mjs +1 -1
- package/dist/_chunks/search.mjs +1 -2
- package/dist/_chunks/search.mjs.map +1 -1
- package/dist/_chunks/semver.mjs +13 -0
- package/dist/_chunks/semver.mjs.map +1 -0
- package/dist/_chunks/skill-installer.mjs +2 -0
- package/dist/_chunks/skill-installer2.mjs +155 -0
- package/dist/_chunks/skill-installer2.mjs.map +1 -0
- package/dist/_chunks/skills.mjs +10 -9
- package/dist/_chunks/skills.mjs.map +1 -1
- package/dist/_chunks/sources.mjs +549 -372
- package/dist/_chunks/sources.mjs.map +1 -1
- package/dist/_chunks/sync-pipeline.mjs +952 -0
- package/dist/_chunks/sync-pipeline.mjs.map +1 -0
- package/dist/_chunks/sync-registry.mjs +19 -13
- package/dist/_chunks/sync-registry.mjs.map +1 -1
- package/dist/_chunks/sync.mjs +797 -886
- package/dist/_chunks/sync.mjs.map +1 -1
- package/dist/_chunks/sync2.mjs +4 -2
- package/dist/_chunks/types.d.mts +65 -77
- package/dist/_chunks/types.d.mts.map +1 -1
- package/dist/_chunks/types2.d.mts +88 -0
- package/dist/_chunks/types2.d.mts.map +1 -0
- package/dist/_chunks/uninstall.mjs +7 -8
- package/dist/_chunks/uninstall.mjs.map +1 -1
- package/dist/_chunks/upload.mjs +2 -2
- package/dist/_chunks/validate.mjs +1 -1
- package/dist/_chunks/version.mjs +3 -13
- package/dist/_chunks/version.mjs.map +1 -1
- package/dist/_chunks/wizard.mjs +2 -2
- package/dist/agent/index.d.mts +2 -346
- package/dist/agent/index.mjs +2 -3
- package/dist/cache/index.d.mts +2 -2
- package/dist/cache/index.mjs +4 -3
- package/dist/cli.mjs +12 -13
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +5 -4
- package/dist/index.mjs +4 -3
- package/dist/prepare.mjs +2 -2
- package/dist/prepare.mjs.map +1 -1
- package/dist/retriv/index.d.mts +2 -2
- package/dist/retriv/worker.d.mts +1 -1
- package/dist/sources/index.d.mts +3 -2
- package/dist/sources/index.mjs +3 -3
- package/dist/types.d.mts +3 -3
- package/package.json +2 -2
- package/dist/_chunks/config.mjs +0 -122
- package/dist/_chunks/config.mjs.map +0 -1
- package/dist/_chunks/prefix.mjs +0 -108
- package/dist/_chunks/prefix.mjs.map +0 -1
- package/dist/_chunks/shared.mjs.map +0 -1
- package/dist/_chunks/skill.mjs +0 -329
- package/dist/_chunks/skill.mjs.map +0 -1
- package/dist/_chunks/sync-shared.mjs +0 -2
- package/dist/_chunks/sync-shared2.mjs +0 -1020
- package/dist/_chunks/sync-shared2.mjs.map +0 -1
- package/dist/agent/index.d.mts.map +0 -1
package/dist/_chunks/agent.mjs
CHANGED
|
@@ -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 {
|
|
6
|
-
import "
|
|
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 {
|
|
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 {
|
|
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
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
hint: "Best for everyday tasks"
|
|
68
|
+
Glob: {
|
|
69
|
+
canonical: "search",
|
|
70
|
+
verb: "Searching"
|
|
52
71
|
},
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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
|
|
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 (
|
|
91
|
-
|
|
92
|
-
|
|
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
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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 {
|
|
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
|
-
|
|
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
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
models: (
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
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
|
|
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 {
|
|
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
|
-
|
|
177
|
-
|
|
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
|
-
|
|
183
|
-
|
|
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
|
-
|
|
188
|
-
|
|
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
|
-
|
|
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 {
|
|
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
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
models: (
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
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
|
|
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 ? {
|
|
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
|
|
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
|
-
|
|
251
|
-
|
|
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
|
-
|
|
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 =
|
|
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(
|
|
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 =
|
|
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 <
|
|
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:
|
|
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
|
|
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
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
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 =
|
|
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
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
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(
|
|
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:
|
|
776
|
-
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
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
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
|
|
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
|
|
853
|
-
|
|
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
|
|
856
|
-
const
|
|
857
|
-
if (!
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
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
|
|
866
|
-
|
|
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
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
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
|
|
887
|
-
const
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
const
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
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
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
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
|
-
|
|
950
|
-
|
|
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: `
|
|
955
|
-
}
|
|
956
|
-
const
|
|
957
|
-
|
|
958
|
-
const
|
|
959
|
-
const
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1069
|
-
|
|
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
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
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
|
-
|
|
1111
|
-
|
|
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:
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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 ?
|
|
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
|
-
|
|
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
|