skilld 1.7.3 → 2.0.0
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/add.mjs +66 -0
- package/dist/_chunks/add.mjs.map +1 -0
- package/dist/_chunks/agent-prompt.mjs +88 -0
- package/dist/_chunks/agent-prompt.mjs.map +1 -0
- package/dist/_chunks/agent.mjs +737 -619
- package/dist/_chunks/agent.mjs.map +1 -1
- package/dist/_chunks/args.mjs +42 -0
- package/dist/_chunks/args.mjs.map +1 -0
- package/dist/_chunks/assemble.mjs +11 -8
- package/dist/_chunks/assemble.mjs.map +1 -1
- package/dist/_chunks/author.mjs +77 -131
- package/dist/_chunks/author.mjs.map +1 -1
- package/dist/_chunks/cache.mjs +320 -54
- package/dist/_chunks/cache.mjs.map +1 -1
- package/dist/_chunks/cache2.mjs +7 -6
- package/dist/_chunks/cache2.mjs.map +1 -1
- package/dist/_chunks/client.mjs +117 -0
- package/dist/_chunks/client.mjs.map +1 -0
- package/dist/_chunks/core.mjs +7 -4
- package/dist/_chunks/detect.mjs +54 -44
- package/dist/_chunks/detect.mjs.map +1 -1
- package/dist/_chunks/eject.mjs +69 -0
- package/dist/_chunks/eject.mjs.map +1 -0
- package/dist/_chunks/embedding-cache2.mjs +2 -2
- package/dist/_chunks/env.mjs +19 -0
- package/dist/_chunks/env.mjs.map +1 -0
- package/dist/_chunks/install-many.mjs +376 -0
- package/dist/_chunks/install-many.mjs.map +1 -0
- package/dist/_chunks/install.mjs +86 -371
- package/dist/_chunks/install.mjs.map +1 -1
- package/dist/_chunks/intro.mjs +63 -0
- package/dist/_chunks/intro.mjs.map +1 -0
- package/dist/_chunks/list.mjs +2 -2
- package/dist/_chunks/list.mjs.map +1 -1
- package/dist/_chunks/lockfile.mjs +31 -7
- package/dist/_chunks/lockfile.mjs.map +1 -1
- package/dist/_chunks/login.mjs +233 -0
- package/dist/_chunks/login.mjs.map +1 -0
- package/dist/_chunks/logout.mjs +27 -0
- package/dist/_chunks/logout.mjs.map +1 -0
- package/dist/_chunks/map.mjs +11 -0
- package/dist/_chunks/map.mjs.map +1 -0
- package/dist/_chunks/markdown.mjs +79 -54
- package/dist/_chunks/markdown.mjs.map +1 -1
- package/dist/_chunks/menu.mjs +33 -0
- package/dist/_chunks/menu.mjs.map +1 -0
- package/dist/_chunks/model-picker.mjs +61 -0
- package/dist/_chunks/model-picker.mjs.map +1 -0
- package/dist/_chunks/monorepo.mjs +73 -0
- package/dist/_chunks/monorepo.mjs.map +1 -0
- package/dist/_chunks/package-json.mjs.map +1 -1
- package/dist/_chunks/paths.mjs +47 -0
- package/dist/_chunks/paths.mjs.map +1 -0
- package/dist/_chunks/pipeline.mjs +985 -0
- package/dist/_chunks/pipeline.mjs.map +1 -0
- package/dist/_chunks/pool2.mjs +2 -2
- package/dist/_chunks/portable.mjs +151 -0
- package/dist/_chunks/portable.mjs.map +1 -0
- package/dist/_chunks/prepare-hook.mjs +2 -0
- package/dist/_chunks/prepare-hook2.mjs +61 -0
- package/dist/_chunks/prepare-hook2.mjs.map +1 -0
- package/dist/_chunks/prepare.mjs +47 -3
- package/dist/_chunks/prepare.mjs.map +1 -1
- package/dist/_chunks/prepare2.mjs +9 -8
- package/dist/_chunks/prepare2.mjs.map +1 -1
- package/dist/_chunks/prompts.mjs +784 -26
- package/dist/_chunks/prompts.mjs.map +1 -1
- package/dist/_chunks/pull.mjs +219 -0
- package/dist/_chunks/pull.mjs.map +1 -0
- package/dist/_chunks/regex.mjs +19 -0
- package/dist/_chunks/regex.mjs.map +1 -0
- package/dist/_chunks/retriv.mjs +2 -171
- package/dist/_chunks/retriv2.mjs +159 -0
- package/dist/_chunks/retriv2.mjs.map +1 -0
- package/dist/_chunks/sanitize.mjs +12 -9
- package/dist/_chunks/sanitize.mjs.map +1 -1
- package/dist/_chunks/search-helpers.mjs +9 -8
- package/dist/_chunks/search-helpers.mjs.map +1 -1
- package/dist/_chunks/search-interactive.mjs +23 -20
- package/dist/_chunks/search-interactive.mjs.map +1 -1
- package/dist/_chunks/search.mjs +3 -4
- package/dist/_chunks/search.mjs.map +1 -1
- package/dist/_chunks/{sources.mjs → semver.mjs} +1128 -838
- package/dist/_chunks/semver.mjs.map +1 -0
- package/dist/_chunks/skill-installer.mjs +2 -0
- package/dist/_chunks/skill-installer2.mjs +154 -0
- package/dist/_chunks/skill-installer2.mjs.map +1 -0
- package/dist/_chunks/skills.mjs +12 -12
- package/dist/_chunks/skills.mjs.map +1 -1
- package/dist/_chunks/store.mjs +107 -0
- package/dist/_chunks/store.mjs.map +1 -0
- package/dist/_chunks/sync.mjs +761 -1349
- package/dist/_chunks/sync.mjs.map +1 -1
- package/dist/_chunks/sync2.mjs +2 -3
- package/dist/_chunks/telemetry.mjs +26 -0
- package/dist/_chunks/telemetry.mjs.map +1 -0
- package/dist/_chunks/uninstall.mjs +15 -13
- package/dist/_chunks/uninstall.mjs.map +1 -1
- package/dist/_chunks/update.mjs +171 -0
- package/dist/_chunks/update.mjs.map +1 -0
- package/dist/_chunks/upload.mjs +4 -4
- package/dist/_chunks/validate.mjs +1 -1
- package/dist/_chunks/version.mjs +16 -27
- package/dist/_chunks/version.mjs.map +1 -1
- package/dist/_chunks/whoami.mjs +21 -0
- package/dist/_chunks/whoami.mjs.map +1 -0
- package/dist/_chunks/wizard.mjs +2 -190
- package/dist/_chunks/wizard2.mjs +200 -0
- package/dist/_chunks/wizard2.mjs.map +1 -0
- package/dist/cli.mjs +77 -59
- package/dist/cli.mjs.map +1 -1
- package/dist/prepare.mjs +5 -4
- package/dist/prepare.mjs.map +1 -1
- package/dist/retriv/worker.d.mts +5 -1
- package/dist/retriv/worker.d.mts.map +1 -1
- package/dist/retriv/worker.mjs +1 -1
- package/package.json +20 -29
- package/dist/_chunks/author-group.mjs +0 -17
- package/dist/_chunks/author-group.mjs.map +0 -1
- package/dist/_chunks/cli-helpers.mjs +0 -335
- package/dist/_chunks/cli-helpers.mjs.map +0 -1
- package/dist/_chunks/cli-helpers2.mjs +0 -2
- package/dist/_chunks/config.mjs +0 -122
- package/dist/_chunks/config.mjs.map +0 -1
- package/dist/_chunks/index.d.mts +0 -151
- package/dist/_chunks/index.d.mts.map +0 -1
- package/dist/_chunks/index2.d.mts +0 -44
- package/dist/_chunks/index2.d.mts.map +0 -1
- package/dist/_chunks/index3.d.mts +0 -589
- package/dist/_chunks/index3.d.mts.map +0 -1
- package/dist/_chunks/prefix.mjs +0 -108
- package/dist/_chunks/prefix.mjs.map +0 -1
- package/dist/_chunks/retriv.mjs.map +0 -1
- package/dist/_chunks/setup.mjs +0 -17
- package/dist/_chunks/setup.mjs.map +0 -1
- package/dist/_chunks/shared.mjs +0 -503
- 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/sources.mjs.map +0 -1
- package/dist/_chunks/sync-registry.mjs +0 -59
- package/dist/_chunks/sync-registry.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/_chunks/types.d.mts +0 -88
- package/dist/_chunks/types.d.mts.map +0 -1
- package/dist/_chunks/wizard.mjs.map +0 -1
- package/dist/agent/index.d.mts +0 -346
- package/dist/agent/index.d.mts.map +0 -1
- package/dist/agent/index.mjs +0 -5
- package/dist/cache/index.d.mts +0 -2
- package/dist/cache/index.mjs +0 -4
- package/dist/index.d.mts +0 -5
- package/dist/index.mjs +0 -5
- package/dist/retriv/index.d.mts +0 -3
- package/dist/retriv/index.mjs +0 -2
- package/dist/sources/index.d.mts +0 -2
- package/dist/sources/index.mjs +0 -3
- package/dist/types.d.mts +0 -4
- package/dist/types.mjs +0 -1
package/dist/_chunks/agent.mjs
CHANGED
|
@@ -1,62 +1,130 @@
|
|
|
1
|
-
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
1
|
import { a as targets, t as detectInstalledAgents } from "./detect.mjs";
|
|
5
|
-
import {
|
|
6
|
-
import "./
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
2
|
+
import { A as resolveSkilldCommand, C as SECTION_OUTPUT_FILES, S as SECTION_MERGE_ORDER, _ as buildAllSectionPrompts, x as wrapSection, y as getSectionValidator } from "./prompts.mjs";
|
|
3
|
+
import { g as skillLogDir, i as LLM_CACHE_DIR, m as skillInternalDir, n as CACHE_DIR, o as PI_AI_AUTH_PATH } from "./paths.mjs";
|
|
4
|
+
import { d as SECTION_HEADING_RE, m as TRAILING_SLASH_RE, p as SOURCE_LINK_RE, t as API_CHANGE_BULLET_RE } from "./regex.mjs";
|
|
5
|
+
import { n as sanitizeMarkdown } from "./sanitize.mjs";
|
|
6
|
+
import { n as getSkillReferenceDirs, t as createReferenceCache } from "./cache.mjs";
|
|
7
|
+
import { existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, unlinkSync, writeFileSync } from "node:fs";
|
|
8
|
+
import { promisify, styleText } from "node:util";
|
|
9
|
+
import { join } from "pathe";
|
|
10
10
|
import { exec, execFileSync, spawn } from "node:child_process";
|
|
11
11
|
import { isWindows } from "std-env";
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import { setTimeout as setTimeout$1 } from "node:timers/promises";
|
|
16
|
-
import { promisify } from "node:util";
|
|
12
|
+
import { homedir } from "node:os";
|
|
13
|
+
import { getEnvApiKey, getEnvApiKey as getEnvApiKey$1, getModel, getModels, getProviders, streamSimple } from "@earendil-works/pi-ai";
|
|
14
|
+
import { getOAuthApiKey, getOAuthProvider, getOAuthProviders } from "@earendil-works/pi-ai/oauth";
|
|
17
15
|
import { resolve as resolve$1 } from "node:path";
|
|
18
|
-
import { getEnvApiKey, getModel, getModels, getProviders, streamSimple } from "@mariozechner/pi-ai";
|
|
19
|
-
import { getOAuthApiKey, getOAuthProvider, getOAuthProviders } from "@mariozechner/pi-ai/oauth";
|
|
20
16
|
import { Type } from "typebox";
|
|
21
|
-
import { readFile } from "node:fs/promises";
|
|
17
|
+
import { glob, readFile } from "node:fs/promises";
|
|
22
18
|
import { parseSync } from "oxc-parser";
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
if (
|
|
31
|
-
return
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
const
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
19
|
+
import { setTimeout as setTimeout$1 } from "node:timers/promises";
|
|
20
|
+
import { createHash } from "node:crypto";
|
|
21
|
+
const STATIC_REGEX_1$6 = /-\d{8}$/;
|
|
22
|
+
const STATIC_REGEX_2$5 = /-\d{4}-\d{2}-\d{2}$/;
|
|
23
|
+
const STATIC_REGEX_3$3 = /-preview/;
|
|
24
|
+
function isStableId(id) {
|
|
25
|
+
if (STATIC_REGEX_1$6.test(id)) return false;
|
|
26
|
+
if (STATIC_REGEX_2$5.test(id)) return false;
|
|
27
|
+
if (STATIC_REGEX_3$3.test(id)) return false;
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
function compareVersions(a, b) {
|
|
31
|
+
const versionOf = (id) => {
|
|
32
|
+
return (id.match(/\d+(?:\.\d+)?/g) ?? []).flatMap((n) => n.split(".").map(Number));
|
|
33
|
+
};
|
|
34
|
+
const av = versionOf(a);
|
|
35
|
+
const bv = versionOf(b);
|
|
36
|
+
for (let i = 0; i < Math.max(av.length, bv.length); i++) {
|
|
37
|
+
const x = av[i] ?? 0;
|
|
38
|
+
const y = bv[i] ?? 0;
|
|
39
|
+
if (x !== y) return y - x;
|
|
40
|
+
}
|
|
41
|
+
return 0;
|
|
42
|
+
}
|
|
43
|
+
function resolve$2(opts) {
|
|
44
|
+
const { provider, prefix, contains, exclude } = opts;
|
|
45
|
+
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];
|
|
46
|
+
}
|
|
47
|
+
function buildModelEntry(opts) {
|
|
48
|
+
const found = resolve$2(opts);
|
|
49
|
+
const piName = found?.name;
|
|
50
|
+
const transformed = piName && opts.nameTransform ? opts.nameTransform(piName) : piName;
|
|
51
|
+
const name = opts.name ?? transformed ?? opts.model ?? opts.prefix;
|
|
52
|
+
return {
|
|
53
|
+
model: opts.model ?? found?.id ?? opts.prefix,
|
|
54
|
+
name,
|
|
55
|
+
hint: opts.hint,
|
|
56
|
+
recommended: opts.recommended
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function buildModels(entries) {
|
|
60
|
+
return Object.fromEntries(entries.map((e) => {
|
|
61
|
+
const entry = buildModelEntry(e);
|
|
62
|
+
return [entry.model, entry];
|
|
63
|
+
}));
|
|
64
|
+
}
|
|
65
|
+
const TOOL_NAMES = {
|
|
66
|
+
Read: {
|
|
67
|
+
canonical: "read",
|
|
68
|
+
verb: "Reading"
|
|
47
69
|
},
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
hint: "Best for everyday tasks"
|
|
70
|
+
Glob: {
|
|
71
|
+
canonical: "search",
|
|
72
|
+
verb: "Searching"
|
|
52
73
|
},
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
74
|
+
Grep: {
|
|
75
|
+
canonical: "search",
|
|
76
|
+
verb: "Searching"
|
|
77
|
+
},
|
|
78
|
+
Write: {
|
|
79
|
+
canonical: "write",
|
|
80
|
+
verb: "Writing"
|
|
81
|
+
},
|
|
82
|
+
Bash: {
|
|
83
|
+
canonical: "shell",
|
|
84
|
+
verb: "Running"
|
|
85
|
+
},
|
|
86
|
+
read_file: {
|
|
87
|
+
canonical: "read",
|
|
88
|
+
verb: "Reading"
|
|
89
|
+
},
|
|
90
|
+
glob_tool: {
|
|
91
|
+
canonical: "search",
|
|
92
|
+
verb: "Searching"
|
|
93
|
+
},
|
|
94
|
+
write_file: {
|
|
95
|
+
canonical: "write",
|
|
96
|
+
verb: "Writing"
|
|
97
|
+
},
|
|
98
|
+
list_directory: {
|
|
99
|
+
canonical: "list",
|
|
100
|
+
verb: "Listing"
|
|
101
|
+
},
|
|
102
|
+
search_file_content: {
|
|
103
|
+
canonical: "search",
|
|
104
|
+
verb: "Searching"
|
|
105
|
+
},
|
|
106
|
+
run_shell_command: {
|
|
107
|
+
canonical: "shell",
|
|
108
|
+
verb: "Running"
|
|
58
109
|
}
|
|
59
110
|
};
|
|
111
|
+
function extractToolHint(input) {
|
|
112
|
+
if (!input) return void 0;
|
|
113
|
+
for (const k of [
|
|
114
|
+
"file_path",
|
|
115
|
+
"path",
|
|
116
|
+
"dir_path",
|
|
117
|
+
"pattern",
|
|
118
|
+
"query",
|
|
119
|
+
"command"
|
|
120
|
+
]) {
|
|
121
|
+
const v = input[k];
|
|
122
|
+
if (typeof v === "string" && v) return v;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
const STATIC_REGEX_1$5 = /^Claude\s+/;
|
|
126
|
+
const STATIC_REGEX_2$4 = /\s*\(latest\)\s*$/i;
|
|
127
|
+
const stripClaude = (n) => n.replace(STATIC_REGEX_1$5, "").replace(STATIC_REGEX_2$4, "");
|
|
60
128
|
function buildArgs$2(model, skillDir, symlinkDirs) {
|
|
61
129
|
return [
|
|
62
130
|
"-p",
|
|
@@ -82,38 +150,36 @@ function buildArgs$2(model, skillDir, symlinkDirs) {
|
|
|
82
150
|
"--no-session-persistence"
|
|
83
151
|
];
|
|
84
152
|
}
|
|
85
|
-
function
|
|
153
|
+
function parseEvent$2(line) {
|
|
86
154
|
try {
|
|
87
155
|
const obj = JSON.parse(line);
|
|
88
156
|
if (obj.type === "stream_event") {
|
|
89
157
|
const evt = obj.event;
|
|
90
|
-
if (
|
|
91
|
-
|
|
92
|
-
|
|
158
|
+
if (evt?.type === "content_block_delta" && evt.delta?.type === "text_delta") return {
|
|
159
|
+
kind: "text",
|
|
160
|
+
delta: evt.delta.text
|
|
161
|
+
};
|
|
162
|
+
return { kind: "noop" };
|
|
93
163
|
}
|
|
94
164
|
if (obj.type === "assistant" && obj.message?.content) {
|
|
95
165
|
const content = obj.message.content;
|
|
96
166
|
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
|
-
}
|
|
167
|
+
if (tools.length) return {
|
|
168
|
+
kind: "tool-call",
|
|
169
|
+
tool: tools.map((t) => t.name).join(", "),
|
|
170
|
+
hint: tools.map((t) => extractToolHint(t.input) ?? "").filter(Boolean).join(", ") || void 0,
|
|
171
|
+
writeContent: tools.find((t) => t.name === "Write" && t.input?.content)?.input?.content
|
|
172
|
+
};
|
|
110
173
|
const text = content.filter((c) => c.type === "text").map((c) => c.text).join("");
|
|
111
|
-
if (text) return {
|
|
174
|
+
if (text) return {
|
|
175
|
+
kind: "text",
|
|
176
|
+
full: text
|
|
177
|
+
};
|
|
112
178
|
}
|
|
113
179
|
if (obj.type === "result") {
|
|
114
180
|
const u = obj.usage;
|
|
115
181
|
return {
|
|
116
|
-
|
|
182
|
+
kind: "done",
|
|
117
183
|
usage: u ? {
|
|
118
184
|
input: u.input_tokens ?? u.inputTokens ?? 0,
|
|
119
185
|
output: u.output_tokens ?? u.outputTokens ?? 0
|
|
@@ -123,35 +189,40 @@ function parseLine$2(line) {
|
|
|
123
189
|
};
|
|
124
190
|
}
|
|
125
191
|
} catch {}
|
|
126
|
-
return {};
|
|
192
|
+
return { kind: "noop" };
|
|
127
193
|
}
|
|
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
|
-
|
|
194
|
+
const adapter$2 = {
|
|
195
|
+
cli: "claude",
|
|
196
|
+
agentId: "claude-code",
|
|
197
|
+
providerName: "Anthropic",
|
|
198
|
+
models: buildModels([
|
|
199
|
+
{
|
|
200
|
+
model: "opus",
|
|
201
|
+
provider: "anthropic",
|
|
202
|
+
prefix: "claude-opus-",
|
|
203
|
+
nameTransform: stripClaude,
|
|
204
|
+
hint: "Most capable for complex work"
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
model: "sonnet",
|
|
208
|
+
provider: "anthropic",
|
|
209
|
+
prefix: "claude-sonnet-",
|
|
210
|
+
nameTransform: stripClaude,
|
|
211
|
+
hint: "Best for everyday tasks"
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
model: "haiku",
|
|
215
|
+
provider: "anthropic",
|
|
216
|
+
prefix: "claude-haiku-",
|
|
217
|
+
nameTransform: stripClaude,
|
|
218
|
+
hint: "Fastest for quick answers",
|
|
219
|
+
recommended: true
|
|
220
|
+
}
|
|
221
|
+
]),
|
|
222
|
+
buildArgs: buildArgs$2,
|
|
223
|
+
parseEvent: parseEvent$2
|
|
154
224
|
};
|
|
225
|
+
const STATIC_REGEX_1$4 = /^cat\s*>|>/;
|
|
155
226
|
function buildArgs$1(model, _skillDir, _symlinkDirs) {
|
|
156
227
|
return [
|
|
157
228
|
"exec",
|
|
@@ -163,62 +234,82 @@ function buildArgs$1(model, _skillDir, _symlinkDirs) {
|
|
|
163
234
|
"-"
|
|
164
235
|
];
|
|
165
236
|
}
|
|
166
|
-
function
|
|
237
|
+
function parseEvent$1(line) {
|
|
167
238
|
try {
|
|
168
239
|
const obj = JSON.parse(line);
|
|
169
240
|
if (obj.type === "item.completed" && obj.item) {
|
|
170
241
|
const item = obj.item;
|
|
171
|
-
if (item.type === "agent_message" && item.text) return {
|
|
242
|
+
if (item.type === "agent_message" && item.text) return {
|
|
243
|
+
kind: "text",
|
|
244
|
+
full: item.text
|
|
245
|
+
};
|
|
172
246
|
if (item.type === "command_execution" && item.aggregated_output) {
|
|
173
247
|
const cmd = item.command || "";
|
|
174
|
-
const writeContent =
|
|
248
|
+
const writeContent = STATIC_REGEX_1$4.test(cmd) ? item.aggregated_output : void 0;
|
|
175
249
|
return {
|
|
176
|
-
|
|
177
|
-
|
|
250
|
+
kind: "tool-call",
|
|
251
|
+
tool: "Bash",
|
|
252
|
+
hint: `(${item.aggregated_output.length} chars output)`,
|
|
178
253
|
writeContent
|
|
179
254
|
};
|
|
180
255
|
}
|
|
181
256
|
if (item.type === "file_change" && item.changes?.length) return {
|
|
182
|
-
|
|
183
|
-
|
|
257
|
+
kind: "tool-call",
|
|
258
|
+
tool: "Write",
|
|
259
|
+
hint: item.changes.map((c) => c.path).join(", ")
|
|
184
260
|
};
|
|
185
261
|
}
|
|
186
262
|
if (obj.type === "item.started" && obj.item?.type === "command_execution") return {
|
|
187
|
-
|
|
188
|
-
|
|
263
|
+
kind: "tool-call",
|
|
264
|
+
tool: "Bash",
|
|
265
|
+
hint: obj.item.command
|
|
189
266
|
};
|
|
190
267
|
if (obj.type === "turn.completed" && obj.usage) return {
|
|
191
|
-
|
|
268
|
+
kind: "done",
|
|
192
269
|
usage: {
|
|
193
270
|
input: obj.usage.input_tokens ?? 0,
|
|
194
271
|
output: obj.usage.output_tokens ?? 0
|
|
195
272
|
}
|
|
196
273
|
};
|
|
197
|
-
if (obj.type === "turn.failed" || obj.type === "error") return {
|
|
274
|
+
if (obj.type === "turn.failed" || obj.type === "error") return {
|
|
275
|
+
kind: "error",
|
|
276
|
+
message: obj.message
|
|
277
|
+
};
|
|
198
278
|
} catch {}
|
|
199
|
-
return {};
|
|
279
|
+
return { kind: "noop" };
|
|
200
280
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
models: (
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
281
|
+
const adapter$1 = {
|
|
282
|
+
cli: "codex",
|
|
283
|
+
agentId: "codex",
|
|
284
|
+
providerName: "OpenAI",
|
|
285
|
+
models: buildModels([
|
|
286
|
+
{
|
|
287
|
+
provider: "openai",
|
|
288
|
+
prefix: "gpt-",
|
|
289
|
+
contains: "codex",
|
|
290
|
+
exclude: [
|
|
291
|
+
"spark",
|
|
292
|
+
"mini",
|
|
293
|
+
"max"
|
|
294
|
+
],
|
|
295
|
+
hint: "Latest frontier Codex model"
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
provider: "openai",
|
|
299
|
+
prefix: "gpt-",
|
|
300
|
+
contains: "codex-spark",
|
|
301
|
+
hint: "Faster Codex variant",
|
|
302
|
+
recommended: true
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
provider: "openai",
|
|
306
|
+
prefix: "gpt-",
|
|
307
|
+
contains: "codex-mini",
|
|
308
|
+
hint: "Cheapest Codex variant"
|
|
309
|
+
}
|
|
310
|
+
]),
|
|
311
|
+
buildArgs: buildArgs$1,
|
|
312
|
+
parseEvent: parseEvent$1
|
|
222
313
|
};
|
|
223
314
|
function buildArgs(model, skillDir, symlinkDirs) {
|
|
224
315
|
return [
|
|
@@ -233,28 +324,30 @@ function buildArgs(model, skillDir, symlinkDirs) {
|
|
|
233
324
|
...symlinkDirs.flatMap((d) => ["--include-directories", d])
|
|
234
325
|
];
|
|
235
326
|
}
|
|
236
|
-
function
|
|
327
|
+
function parseEvent(line) {
|
|
237
328
|
try {
|
|
238
329
|
const obj = JSON.parse(line);
|
|
239
|
-
if (obj.type === "message" && obj.role === "assistant" && obj.content) return obj.delta ? {
|
|
330
|
+
if (obj.type === "message" && obj.role === "assistant" && obj.content) return obj.delta ? {
|
|
331
|
+
kind: "text",
|
|
332
|
+
delta: obj.content
|
|
333
|
+
} : {
|
|
334
|
+
kind: "text",
|
|
335
|
+
full: obj.content
|
|
336
|
+
};
|
|
240
337
|
if (obj.type === "tool_use" || obj.type === "tool_call") {
|
|
241
|
-
const
|
|
338
|
+
const tool = obj.tool_name || obj.name || obj.tool || "tool";
|
|
242
339
|
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
340
|
return {
|
|
250
|
-
|
|
251
|
-
|
|
341
|
+
kind: "tool-call",
|
|
342
|
+
tool,
|
|
343
|
+
hint: extractToolHint(params),
|
|
344
|
+
writeContent: tool === "write_file" && typeof params.content === "string" ? params.content : void 0
|
|
252
345
|
};
|
|
253
346
|
}
|
|
254
347
|
if (obj.type === "result") {
|
|
255
348
|
const s = obj.stats;
|
|
256
349
|
return {
|
|
257
|
-
|
|
350
|
+
kind: "done",
|
|
258
351
|
usage: s ? {
|
|
259
352
|
input: s.input_tokens ?? s.input ?? 0,
|
|
260
353
|
output: s.output_tokens ?? s.output ?? 0
|
|
@@ -263,21 +356,37 @@ function parseLine(line) {
|
|
|
263
356
|
};
|
|
264
357
|
}
|
|
265
358
|
} 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
|
-
};
|
|
359
|
+
return { kind: "noop" };
|
|
280
360
|
}
|
|
361
|
+
const adapter = {
|
|
362
|
+
cli: "gemini",
|
|
363
|
+
agentId: "gemini-cli",
|
|
364
|
+
providerName: "Google",
|
|
365
|
+
models: buildModels([{
|
|
366
|
+
provider: "google",
|
|
367
|
+
prefix: "gemini-",
|
|
368
|
+
contains: "pro",
|
|
369
|
+
exclude: [
|
|
370
|
+
"flash",
|
|
371
|
+
"live",
|
|
372
|
+
"gemma"
|
|
373
|
+
],
|
|
374
|
+
hint: "Most capable"
|
|
375
|
+
}, {
|
|
376
|
+
provider: "google",
|
|
377
|
+
prefix: "gemini-",
|
|
378
|
+
contains: "flash",
|
|
379
|
+
exclude: [
|
|
380
|
+
"lite",
|
|
381
|
+
"live",
|
|
382
|
+
"preview"
|
|
383
|
+
],
|
|
384
|
+
hint: "Balanced",
|
|
385
|
+
recommended: true
|
|
386
|
+
}]),
|
|
387
|
+
buildArgs,
|
|
388
|
+
parseEvent
|
|
389
|
+
};
|
|
281
390
|
const BLOCKED_OAUTH_PROVIDERS = new Set([
|
|
282
391
|
"google-antigravity",
|
|
283
392
|
"google-gemini-cli",
|
|
@@ -286,7 +395,11 @@ const BLOCKED_OAUTH_PROVIDERS = new Set([
|
|
|
286
395
|
"openai-codex"
|
|
287
396
|
]);
|
|
288
397
|
const PI_AGENT_AUTH_PATH = join(process.env.PI_CODING_AGENT_DIR || join(homedir(), ".pi", "agent"), "auth.json");
|
|
289
|
-
const SKILLD_AUTH_PATH =
|
|
398
|
+
const SKILLD_AUTH_PATH = PI_AI_AUTH_PATH;
|
|
399
|
+
const OAUTH_PROVIDER_OVERRIDES = {
|
|
400
|
+
google: "google-gemini-cli",
|
|
401
|
+
openai: "openai-codex"
|
|
402
|
+
};
|
|
290
403
|
function readAuthFile(path) {
|
|
291
404
|
if (!existsSync(path)) return {};
|
|
292
405
|
try {
|
|
@@ -303,16 +416,12 @@ function loadAuth() {
|
|
|
303
416
|
};
|
|
304
417
|
}
|
|
305
418
|
function saveAuth(auth) {
|
|
306
|
-
mkdirSync(
|
|
419
|
+
mkdirSync(CACHE_DIR, {
|
|
307
420
|
recursive: true,
|
|
308
421
|
mode: 448
|
|
309
422
|
});
|
|
310
423
|
writeFileSync(SKILLD_AUTH_PATH, JSON.stringify(auth, null, 2), { mode: 384 });
|
|
311
424
|
}
|
|
312
|
-
const OAUTH_PROVIDER_OVERRIDES = {
|
|
313
|
-
google: "google-gemini-cli",
|
|
314
|
-
openai: "openai-codex"
|
|
315
|
-
};
|
|
316
425
|
function resolveOAuthProviderId(modelProvider) {
|
|
317
426
|
const oauthId = OAUTH_PROVIDER_OVERRIDES[modelProvider] ?? modelProvider;
|
|
318
427
|
if (BLOCKED_OAUTH_PROVIDERS.has(oauthId)) return null;
|
|
@@ -321,7 +430,7 @@ function resolveOAuthProviderId(modelProvider) {
|
|
|
321
430
|
return null;
|
|
322
431
|
}
|
|
323
432
|
async function resolveApiKey(provider) {
|
|
324
|
-
const envKey = getEnvApiKey(provider);
|
|
433
|
+
const envKey = getEnvApiKey$1(provider);
|
|
325
434
|
if (envKey) return envKey;
|
|
326
435
|
const oauthProviderId = resolveOAuthProviderId(provider);
|
|
327
436
|
if (!oauthProviderId) return null;
|
|
@@ -366,6 +475,19 @@ function logoutOAuthProvider(providerId) {
|
|
|
366
475
|
delete auth[providerId];
|
|
367
476
|
saveAuth(auth);
|
|
368
477
|
}
|
|
478
|
+
function isPiAiModel(model) {
|
|
479
|
+
return model.startsWith("pi:");
|
|
480
|
+
}
|
|
481
|
+
function parsePiAiModelId(model) {
|
|
482
|
+
if (!model.startsWith("pi:")) return null;
|
|
483
|
+
const rest = model.slice(3);
|
|
484
|
+
const slashIdx = rest.indexOf("/");
|
|
485
|
+
if (slashIdx === -1) return null;
|
|
486
|
+
return {
|
|
487
|
+
provider: rest.slice(0, slashIdx),
|
|
488
|
+
modelId: rest.slice(slashIdx + 1)
|
|
489
|
+
};
|
|
490
|
+
}
|
|
369
491
|
const MIN_CONTEXT_WINDOW = 32e3;
|
|
370
492
|
const LEGACY_MODEL_PATTERNS = [
|
|
371
493
|
/^claude-3-/,
|
|
@@ -429,6 +551,10 @@ function getAvailablePiAiModels() {
|
|
|
429
551
|
}
|
|
430
552
|
return available;
|
|
431
553
|
}
|
|
554
|
+
const STATIC_REGEX_1$3 = /^\.\/\.skilld\//;
|
|
555
|
+
const STATIC_REGEX_2$3 = /^\.skilld\//;
|
|
556
|
+
const STATIC_REGEX_3$2 = /^\.\//;
|
|
557
|
+
const STATIC_REGEX_5$2 = /\s+/;
|
|
432
558
|
const TOOLS = [
|
|
433
559
|
{
|
|
434
560
|
name: "Read",
|
|
@@ -457,7 +583,6 @@ const TOOLS = [
|
|
|
457
583
|
parameters: Type.Object({ command: Type.String({ description: "Shell command to run" }) })
|
|
458
584
|
}
|
|
459
585
|
];
|
|
460
|
-
const MAX_TOOL_TURNS = 30;
|
|
461
586
|
const SAFE_COMMANDS = new Set([
|
|
462
587
|
"skilld",
|
|
463
588
|
"ls",
|
|
@@ -466,7 +591,7 @@ const SAFE_COMMANDS = new Set([
|
|
|
466
591
|
]);
|
|
467
592
|
const SHELL_META_RE = /[;&|`$()<>]/;
|
|
468
593
|
function resolveSandboxedPath(p, skilldDir) {
|
|
469
|
-
const resolved = resolve$1(skilldDir, String(p).replace(
|
|
594
|
+
const resolved = resolve$1(skilldDir, String(p).replace(STATIC_REGEX_1$3, "./").replace(STATIC_REGEX_2$3, "./").replace(STATIC_REGEX_3$2, ""));
|
|
470
595
|
if (!resolved.startsWith(`${skilldDir}/`) && resolved !== skilldDir) throw new Error(`Path traversal blocked: ${p}`);
|
|
471
596
|
return resolved;
|
|
472
597
|
}
|
|
@@ -522,7 +647,7 @@ function executeTool(toolCall, skilldDir) {
|
|
|
522
647
|
return sanitizeMarkdown(readFileSync(filePath, "utf-8"));
|
|
523
648
|
}
|
|
524
649
|
case "Glob": {
|
|
525
|
-
const pattern = String(args.pattern).replace(
|
|
650
|
+
const pattern = String(args.pattern).replace(STATIC_REGEX_1$3, "./").replace(STATIC_REGEX_2$3, "./").replace(STATIC_REGEX_3$2, "");
|
|
526
651
|
const results = [];
|
|
527
652
|
const walkDir = (dir, prefix) => {
|
|
528
653
|
if (!existsSync(dir)) return;
|
|
@@ -532,9 +657,9 @@ function executeTool(toolCall, skilldDir) {
|
|
|
532
657
|
else results.push(`./.skilld/${relPath}`);
|
|
533
658
|
}
|
|
534
659
|
};
|
|
535
|
-
const baseDir = pattern.split("*")[0]?.replace(
|
|
660
|
+
const baseDir = pattern.split("*")[0]?.replace(TRAILING_SLASH_RE, "") ?? "";
|
|
536
661
|
walkDir(join(skilldDir, baseDir), baseDir);
|
|
537
|
-
const matched = results.filter((r) => globMatch(r.replace(
|
|
662
|
+
const matched = results.filter((r) => globMatch(r.replace(STATIC_REGEX_1$3, ""), pattern));
|
|
538
663
|
return matched.length > 0 ? matched.join("\n") : `No files matching: ${args.pattern}`;
|
|
539
664
|
}
|
|
540
665
|
case "Write":
|
|
@@ -542,7 +667,7 @@ function executeTool(toolCall, skilldDir) {
|
|
|
542
667
|
return "File written successfully.";
|
|
543
668
|
case "Bash": {
|
|
544
669
|
const cmd = String(args.command).trim();
|
|
545
|
-
const parts = cmd.split(
|
|
670
|
+
const parts = cmd.split(STATIC_REGEX_5$2);
|
|
546
671
|
const bin = parts[0] ?? "";
|
|
547
672
|
if (!SAFE_COMMANDS.has(bin) || SHELL_META_RE.test(cmd)) return `Error: command not allowed. Only skilld, ls, cat, find commands are permitted.`;
|
|
548
673
|
try {
|
|
@@ -559,12 +684,13 @@ function executeTool(toolCall, skilldDir) {
|
|
|
559
684
|
default: return `Unknown tool: ${toolCall.name}`;
|
|
560
685
|
}
|
|
561
686
|
}
|
|
687
|
+
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
688
|
async function optimizeSectionPiAi(opts) {
|
|
563
689
|
const parsed = parsePiAiModelId(opts.model);
|
|
564
690
|
if (!parsed) throw new Error(`Invalid pi-ai model ID: ${opts.model}. Expected format: pi:provider/model-id`);
|
|
565
691
|
const model = getModel(parsed.provider, parsed.modelId);
|
|
566
692
|
const apiKey = await resolveApiKey(parsed.provider);
|
|
567
|
-
const skilldDir =
|
|
693
|
+
const skilldDir = skillInternalDir(opts.skillDir);
|
|
568
694
|
const fullPrompt = opts.prompt;
|
|
569
695
|
opts.onProgress?.({
|
|
570
696
|
chunk: "[starting...]",
|
|
@@ -586,10 +712,10 @@ async function optimizeSectionPiAi(opts) {
|
|
|
586
712
|
let totalUsage;
|
|
587
713
|
let totalCost;
|
|
588
714
|
let lastWriteContent = "";
|
|
589
|
-
for (let turn = 0; turn <
|
|
715
|
+
for (let turn = 0; turn < 30; turn++) {
|
|
590
716
|
if (opts.signal?.aborted) throw new Error("pi-ai request timed out");
|
|
591
717
|
const eventStream = streamSimple(model, {
|
|
592
|
-
systemPrompt:
|
|
718
|
+
systemPrompt: SYSTEM_PROMPT,
|
|
593
719
|
messages,
|
|
594
720
|
tools: TOOLS
|
|
595
721
|
}, {
|
|
@@ -664,7 +790,7 @@ async function optimizeSectionPiAi(opts) {
|
|
|
664
790
|
});
|
|
665
791
|
}
|
|
666
792
|
}
|
|
667
|
-
if (!completed) throw new Error(`pi-ai exceeded
|
|
793
|
+
if (!completed) throw new Error(`pi-ai exceeded 30 tool turns without completing`);
|
|
668
794
|
return {
|
|
669
795
|
text: text || lastWriteContent,
|
|
670
796
|
fullPrompt,
|
|
@@ -672,19 +798,51 @@ async function optimizeSectionPiAi(opts) {
|
|
|
672
798
|
cost: totalCost
|
|
673
799
|
};
|
|
674
800
|
}
|
|
675
|
-
const
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
801
|
+
const STATIC_REGEX_1$2 = /^```(?:markdown|md)?[^\S\n]*\n([\s\S]+)\n```[^\S\n]*$/;
|
|
802
|
+
const STATIC_REGEX_2$2 = /^```(?:markdown|md)/;
|
|
803
|
+
const STATIC_REGEX_5$1 = /^-{3,}\n/;
|
|
804
|
+
const STATIC_REGEX_6 = /\n-{3,}/;
|
|
805
|
+
const STATIC_REGEX_7 = /^(##\s|- (?:BREAKING|DEPRECATED|NEW): )/m;
|
|
806
|
+
const STATIC_REGEX_8 = /^(## .+)\n/;
|
|
807
|
+
const STATIC_REGEX_9 = /^\.\/(?:\.skilld\/|references\/)/;
|
|
808
|
+
function cleanSectionOutput(content) {
|
|
809
|
+
let cleaned = content.trim();
|
|
810
|
+
const wrapMatch = cleaned.match(STATIC_REGEX_1$2);
|
|
811
|
+
if (wrapMatch) {
|
|
812
|
+
const inner = wrapMatch[1].trim();
|
|
813
|
+
if (STATIC_REGEX_2$2.test(cleaned) || SECTION_HEADING_RE.test(inner) || API_CHANGE_BULLET_RE.test(inner)) cleaned = inner;
|
|
814
|
+
}
|
|
815
|
+
cleaned = cleaned.replace(/^# (?!#)/gm, "## ");
|
|
816
|
+
const fmMatch = cleaned.match(STATIC_REGEX_5$1);
|
|
817
|
+
if (fmMatch) {
|
|
818
|
+
const afterOpen = fmMatch[0].length;
|
|
819
|
+
const closeMatch = cleaned.slice(afterOpen).match(STATIC_REGEX_6);
|
|
820
|
+
if (closeMatch) cleaned = cleaned.slice(afterOpen + closeMatch.index + closeMatch[0].length).trim();
|
|
821
|
+
else cleaned = cleaned.slice(afterOpen).trim();
|
|
822
|
+
}
|
|
823
|
+
const firstMarker = cleaned.match(STATIC_REGEX_7);
|
|
824
|
+
if (firstMarker?.index && firstMarker.index > 0) cleaned = cleaned.slice(firstMarker.index).trim();
|
|
825
|
+
const headingMatch = cleaned.match(STATIC_REGEX_8);
|
|
826
|
+
if (headingMatch) {
|
|
827
|
+
const heading = headingMatch[1];
|
|
828
|
+
const afterFirst = headingMatch[0].length;
|
|
829
|
+
const secondIdx = cleaned.indexOf(heading, afterFirst);
|
|
830
|
+
if (secondIdx !== -1) {
|
|
831
|
+
if (secondIdx - afterFirst < 200) cleaned = cleaned.slice(secondIdx).trim();
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
cleaned = cleaned.replace(/\(?\[`?\.\/(?:\.skilld\/|references\/)[^)\]]*\]\(([^)]+)\)\)?/g, (match, url) => {
|
|
835
|
+
if (STATIC_REGEX_9.test(url)) return `[source](${url})`;
|
|
836
|
+
return match;
|
|
837
|
+
});
|
|
838
|
+
cleaned = cleaned.replace(/\[source\]\(\.\/((docs|issues|discussions|releases|pkg|guide)\/)/g, "[source](./.skilld/$1");
|
|
839
|
+
cleaned = sanitizeMarkdown(cleaned);
|
|
840
|
+
if (!SECTION_HEADING_RE.test(cleaned) && !API_CHANGE_BULLET_RE.test(cleaned) && !SOURCE_LINK_RE.test(cleaned)) return "";
|
|
841
|
+
return cleaned;
|
|
842
|
+
}
|
|
843
|
+
const STATIC_REGEX_1$1 = /^\[(?:starting|retrying|cached)/;
|
|
844
|
+
const STATIC_REGEX_2$1 = /^\[([^:[\]]+)(?::\s(.+))?\]$/;
|
|
845
|
+
const STATIC_REGEX_3$1 = /skilld search\s+"([^"]+)"/;
|
|
688
846
|
function createToolProgress(log) {
|
|
689
847
|
let lastMsg = "";
|
|
690
848
|
let repeatCount = 0;
|
|
@@ -693,7 +851,7 @@ function createToolProgress(log) {
|
|
|
693
851
|
function emit(msg) {
|
|
694
852
|
if (msg === lastMsg) {
|
|
695
853
|
repeatCount++;
|
|
696
|
-
log.message(`${msg}
|
|
854
|
+
log.message(`${msg} ${styleText("gray", `(+${repeatCount})`)}`);
|
|
697
855
|
} else {
|
|
698
856
|
lastMsg = msg;
|
|
699
857
|
repeatCount = 0;
|
|
@@ -706,57 +864,55 @@ function createToolProgress(log) {
|
|
|
706
864
|
const now = Date.now();
|
|
707
865
|
if (now - (lastTextEmit.get(key) ?? 0) < TEXT_THROTTLE_MS) return;
|
|
708
866
|
lastTextEmit.set(key, now);
|
|
709
|
-
const prefix = section ?
|
|
867
|
+
const prefix = section ? `${styleText("gray", `[${section}]`)} ` : "";
|
|
710
868
|
const items = text ? text.match(/^- (?:BREAKING|DEPRECATED|NEW|CHANGED|REMOVED|Use |Do |Set |Add |Avoid |Always |Never |Prefer |Check |Ensure )/gm)?.length ?? 0 : 0;
|
|
711
|
-
emit(items > 0 ? `${prefix}Writing...
|
|
869
|
+
emit(items > 0 ? `${prefix}Writing... ${styleText("gray", `(${items} items)`)}` : `${prefix}Writing...`);
|
|
712
870
|
return;
|
|
713
871
|
}
|
|
714
872
|
if (type !== "reasoning" || !chunk.startsWith("[")) return;
|
|
715
|
-
if (
|
|
716
|
-
emit(`${section ?
|
|
873
|
+
if (STATIC_REGEX_1$1.test(chunk)) {
|
|
874
|
+
emit(`${section ? `${styleText("gray", `[${section}]`)} ` : ""}${chunk.slice(1, -1)}`);
|
|
717
875
|
return;
|
|
718
876
|
}
|
|
719
|
-
const match = chunk.match(
|
|
877
|
+
const match = chunk.match(STATIC_REGEX_2$1);
|
|
720
878
|
if (!match) return;
|
|
721
879
|
const names = match[1].split(",").map((n) => n.trim());
|
|
722
880
|
const hints = match[2]?.split(",").map((h) => h.trim()) ?? [];
|
|
723
881
|
for (let i = 0; i < names.length; i++) {
|
|
724
882
|
const rawName = names[i];
|
|
725
883
|
const hint = hints[i] ?? hints[0] ?? "";
|
|
726
|
-
const verb =
|
|
727
|
-
const prefix = section ?
|
|
884
|
+
const verb = TOOL_NAMES[rawName]?.verb ?? rawName;
|
|
885
|
+
const prefix = section ? `${styleText("gray", `[${section}]`)} ` : "";
|
|
728
886
|
if ((rawName === "Bash" || rawName === "run_shell_command") && hint) {
|
|
729
|
-
const searchMatch = hint.match(
|
|
730
|
-
if (searchMatch) emit(`${prefix}Searching
|
|
887
|
+
const searchMatch = hint.match(STATIC_REGEX_3$1);
|
|
888
|
+
if (searchMatch) emit(`${prefix}Searching ${styleText("cyan", `"${searchMatch[1]}"`)}`);
|
|
731
889
|
else if (hint.includes("skilld validate")) emit(`${prefix}Validating...`);
|
|
732
890
|
else {
|
|
733
891
|
const shortened = shortenCommand(hint);
|
|
734
892
|
emit(`${prefix}Running ${shortened.length > 50 ? `${shortened.slice(0, 47)}...` : shortened}`);
|
|
735
893
|
}
|
|
736
|
-
} else emit(`${prefix}${verb}
|
|
894
|
+
} else emit(`${prefix}${verb} ${styleText("gray", shortenPath(hint || "..."))}`);
|
|
737
895
|
}
|
|
738
896
|
};
|
|
739
897
|
}
|
|
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"
|
|
898
|
+
function shortenPath(p) {
|
|
899
|
+
const refIdx = p.indexOf(".skilld/");
|
|
900
|
+
if (refIdx !== -1) return p.slice(refIdx + 8);
|
|
901
|
+
const parts = p.split("/");
|
|
902
|
+
return parts.length > 2 ? `.../${parts.slice(-2).join("/")}` : p;
|
|
903
|
+
}
|
|
904
|
+
function shortenCommand(cmd) {
|
|
905
|
+
return cmd.replace(/\/[^\s"']+/g, (match) => {
|
|
906
|
+
if (match.includes(".claude/") || match.includes(".skilld/") || match.includes("node_modules/")) return `.../${match.split("/").slice(-2).join("/")}`;
|
|
907
|
+
return match;
|
|
908
|
+
});
|
|
909
|
+
}
|
|
910
|
+
const CLI_ADAPTERS = {
|
|
911
|
+
claude: adapter$2,
|
|
912
|
+
gemini: adapter,
|
|
913
|
+
codex: adapter$1
|
|
759
914
|
};
|
|
915
|
+
const CLI_PROVIDER_NAMES = Object.fromEntries(Object.values(CLI_ADAPTERS).map((a) => [a.agentId, a.providerName]));
|
|
760
916
|
const PI_PROVIDER_NAMES = {
|
|
761
917
|
"anthropic": "Anthropic",
|
|
762
918
|
"google": "Google",
|
|
@@ -770,10 +926,10 @@ const PI_PROVIDER_NAMES = {
|
|
|
770
926
|
"mistral": "Mistral",
|
|
771
927
|
"xai": "xAI"
|
|
772
928
|
};
|
|
773
|
-
const CLI_MODELS = Object.fromEntries(
|
|
929
|
+
const CLI_MODELS = Object.fromEntries(Object.values(CLI_ADAPTERS).flatMap((adapter) => Object.entries(adapter.models).map(([id, entry]) => [id, {
|
|
774
930
|
...entry,
|
|
775
|
-
cli:
|
|
776
|
-
agentId:
|
|
931
|
+
cli: adapter.cli,
|
|
932
|
+
agentId: adapter.agentId
|
|
777
933
|
}])));
|
|
778
934
|
function getModelName(id) {
|
|
779
935
|
if (isPiAiModel(id)) return parsePiAiModelId(id)?.modelId ?? id;
|
|
@@ -834,135 +990,248 @@ async function getAvailableModels() {
|
|
|
834
990
|
});
|
|
835
991
|
return [...cliModels, ...piAiEntries];
|
|
836
992
|
}
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
993
|
+
const NUXT_CONFIG_FILES = [
|
|
994
|
+
"nuxt.config.ts",
|
|
995
|
+
"nuxt.config.js",
|
|
996
|
+
"nuxt.config.mjs"
|
|
997
|
+
];
|
|
998
|
+
const NUXT_ECOSYSTEM = [
|
|
999
|
+
"vue",
|
|
1000
|
+
"nitro",
|
|
1001
|
+
"h3"
|
|
1002
|
+
];
|
|
1003
|
+
async function findNuxtConfig(cwd) {
|
|
1004
|
+
for (const name of NUXT_CONFIG_FILES) {
|
|
1005
|
+
const path = join(cwd, name);
|
|
1006
|
+
const content = await readFile(path, "utf8").catch(() => null);
|
|
1007
|
+
if (content) return {
|
|
1008
|
+
path,
|
|
1009
|
+
content
|
|
1010
|
+
};
|
|
845
1011
|
}
|
|
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>");
|
|
1012
|
+
return null;
|
|
851
1013
|
}
|
|
852
|
-
function
|
|
853
|
-
|
|
1014
|
+
function extractModuleStrings(node) {
|
|
1015
|
+
if (!node || typeof node !== "object") return [];
|
|
1016
|
+
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);
|
|
1017
|
+
const results = [];
|
|
1018
|
+
if (Array.isArray(node)) for (const child of node) results.push(...extractModuleStrings(child));
|
|
1019
|
+
else for (const key of Object.keys(node)) {
|
|
1020
|
+
if (key === "start" || key === "end" || key === "type") continue;
|
|
1021
|
+
const val = node[key];
|
|
1022
|
+
if (val && typeof val === "object") results.push(...extractModuleStrings(val));
|
|
1023
|
+
}
|
|
1024
|
+
return results;
|
|
854
1025
|
}
|
|
855
|
-
function
|
|
856
|
-
const
|
|
857
|
-
if (!
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
1026
|
+
async function detectNuxtModules(cwd) {
|
|
1027
|
+
const config = await findNuxtConfig(cwd);
|
|
1028
|
+
if (!config) return [];
|
|
1029
|
+
const modules = extractModuleStrings(parseSync(config.path, config.content).program);
|
|
1030
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1031
|
+
const packages = [];
|
|
1032
|
+
for (const mod of modules) if (!seen.has(mod)) {
|
|
1033
|
+
seen.add(mod);
|
|
1034
|
+
packages.push({
|
|
1035
|
+
name: mod,
|
|
1036
|
+
count: 0,
|
|
1037
|
+
source: "preset"
|
|
1038
|
+
});
|
|
1039
|
+
}
|
|
1040
|
+
for (const pkg of NUXT_ECOSYSTEM) if (!seen.has(pkg)) {
|
|
1041
|
+
seen.add(pkg);
|
|
1042
|
+
packages.push({
|
|
1043
|
+
name: pkg,
|
|
1044
|
+
count: 0,
|
|
1045
|
+
source: "preset"
|
|
1046
|
+
});
|
|
863
1047
|
}
|
|
1048
|
+
return packages;
|
|
864
1049
|
}
|
|
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 });
|
|
1050
|
+
async function detectPresetPackages(cwd) {
|
|
1051
|
+
return detectNuxtModules(cwd);
|
|
876
1052
|
}
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
1053
|
+
const FROM_STATIC_IMPORT_RE = /\bfrom\s*['"]([^'"\n]+)['"]/g;
|
|
1054
|
+
const SIDE_EFFECT_IMPORT_RE = /\bimport\s*['"]([^'"\n]+)['"]/g;
|
|
1055
|
+
const DYNAMIC_IMPORT_RE = /\bimport\s*\(\s*['"]([^'"\n]+)['"]\s*\)/g;
|
|
1056
|
+
const PATTERNS = ["**/*.{ts,js,vue,mjs,cjs,tsx,jsx,mts,cts}"];
|
|
1057
|
+
const IGNORE_DIRS = [
|
|
1058
|
+
"node_modules",
|
|
1059
|
+
"dist",
|
|
1060
|
+
".nuxt",
|
|
1061
|
+
".output",
|
|
1062
|
+
"coverage"
|
|
1063
|
+
];
|
|
1064
|
+
function addPackage(counts, specifier) {
|
|
1065
|
+
if (!specifier || specifier.startsWith(".") || specifier.startsWith("/")) return;
|
|
1066
|
+
const name = specifier.startsWith("@") ? specifier.split("/").slice(0, 2).join("/") : specifier.split("/")[0];
|
|
1067
|
+
if (!isNodeBuiltin(name)) counts.set(name, (counts.get(name) || 0) + 1);
|
|
1068
|
+
}
|
|
1069
|
+
async function detectImportedPackages(cwd = process.cwd()) {
|
|
885
1070
|
try {
|
|
886
|
-
const
|
|
887
|
-
const
|
|
888
|
-
const
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
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
|
|
1071
|
+
const counts = /* @__PURE__ */ new Map();
|
|
1072
|
+
const files = [];
|
|
1073
|
+
for await (const file of glob(PATTERNS, {
|
|
1074
|
+
cwd,
|
|
1075
|
+
exclude: (p) => IGNORE_DIRS.some((dir) => p === dir || p.endsWith(`/${dir}`))
|
|
1076
|
+
})) files.push(join(cwd, file));
|
|
1077
|
+
await Promise.all(files.map(async (file) => {
|
|
1078
|
+
const content = await readFile(file, "utf8");
|
|
1079
|
+
for (const m of content.matchAll(FROM_STATIC_IMPORT_RE)) addPackage(counts, m[1]);
|
|
1080
|
+
for (const m of content.matchAll(SIDE_EFFECT_IMPORT_RE)) addPackage(counts, m[1]);
|
|
1081
|
+
for (const m of content.matchAll(DYNAMIC_IMPORT_RE)) addPackage(counts, m[1]);
|
|
914
1082
|
}));
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
1083
|
+
const packages = Array.from(counts.entries(), ([name, count]) => ({
|
|
1084
|
+
name,
|
|
1085
|
+
count,
|
|
1086
|
+
source: "import"
|
|
1087
|
+
})).sort((a, b) => b.count - a.count || a.name.localeCompare(b.name));
|
|
1088
|
+
const presets = await detectPresetPackages(cwd);
|
|
1089
|
+
const importNames = new Set(packages.map((p) => p.name));
|
|
1090
|
+
for (const preset of presets) if (!importNames.has(preset.name)) packages.push(preset);
|
|
1091
|
+
return { packages };
|
|
923
1092
|
} 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
1093
|
return {
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
wasOptimized: false,
|
|
933
|
-
error: errMsg
|
|
1094
|
+
packages: [],
|
|
1095
|
+
error: String(err)
|
|
934
1096
|
};
|
|
935
1097
|
}
|
|
936
1098
|
}
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
1099
|
+
const NODE_BUILTINS = new Set([
|
|
1100
|
+
"assert",
|
|
1101
|
+
"async_hooks",
|
|
1102
|
+
"buffer",
|
|
1103
|
+
"child_process",
|
|
1104
|
+
"cluster",
|
|
1105
|
+
"console",
|
|
1106
|
+
"constants",
|
|
1107
|
+
"crypto",
|
|
1108
|
+
"dgram",
|
|
1109
|
+
"diagnostics_channel",
|
|
1110
|
+
"dns",
|
|
1111
|
+
"domain",
|
|
1112
|
+
"events",
|
|
1113
|
+
"fs",
|
|
1114
|
+
"http",
|
|
1115
|
+
"http2",
|
|
1116
|
+
"https",
|
|
1117
|
+
"inspector",
|
|
1118
|
+
"module",
|
|
1119
|
+
"net",
|
|
1120
|
+
"os",
|
|
1121
|
+
"path",
|
|
1122
|
+
"perf_hooks",
|
|
1123
|
+
"process",
|
|
1124
|
+
"punycode",
|
|
1125
|
+
"querystring",
|
|
1126
|
+
"readline",
|
|
1127
|
+
"repl",
|
|
1128
|
+
"sea",
|
|
1129
|
+
"sqlite",
|
|
1130
|
+
"stream",
|
|
1131
|
+
"string_decoder",
|
|
1132
|
+
"sys",
|
|
1133
|
+
"test",
|
|
1134
|
+
"timers",
|
|
1135
|
+
"tls",
|
|
1136
|
+
"trace_events",
|
|
1137
|
+
"tty",
|
|
1138
|
+
"url",
|
|
1139
|
+
"util",
|
|
1140
|
+
"v8",
|
|
1141
|
+
"vm",
|
|
1142
|
+
"wasi",
|
|
1143
|
+
"worker_threads",
|
|
1144
|
+
"zlib"
|
|
1145
|
+
]);
|
|
1146
|
+
function isNodeBuiltin(pkg) {
|
|
1147
|
+
const base = pkg.startsWith("node:") ? pkg.slice(5) : pkg;
|
|
1148
|
+
return NODE_BUILTINS.has(base.split("/")[0]);
|
|
1149
|
+
}
|
|
1150
|
+
const DEFAULT_MAX_AGE = 10080 * 60 * 1e3;
|
|
1151
|
+
function normalizePromptForHash(prompt) {
|
|
1152
|
+
return prompt.replace(/\/[^\s`]*\.(?:claude|codex|gemini)\/skills\/[^\s/`]+/g, "<SKILL_DIR>");
|
|
1153
|
+
}
|
|
1154
|
+
function hashPrompt(prompt, model, section) {
|
|
1155
|
+
return createHash("sha256").update(`exec:${model}:${section}:${normalizePromptForHash(prompt)}`).digest("hex").slice(0, 16);
|
|
1156
|
+
}
|
|
1157
|
+
function getCached(prompt, model, section, maxAge = DEFAULT_MAX_AGE) {
|
|
1158
|
+
const path = join(LLM_CACHE_DIR, `${hashPrompt(prompt, model, section)}.json`);
|
|
1159
|
+
if (!existsSync(path)) return null;
|
|
1160
|
+
try {
|
|
1161
|
+
const { text, timestamp } = JSON.parse(readFileSync(path, "utf-8"));
|
|
1162
|
+
return Date.now() - timestamp > maxAge ? null : text;
|
|
1163
|
+
} catch {
|
|
1164
|
+
return null;
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
function setCache(prompt, model, section, text) {
|
|
1168
|
+
mkdirSync(LLM_CACHE_DIR, {
|
|
1169
|
+
recursive: true,
|
|
1170
|
+
mode: 448
|
|
948
1171
|
});
|
|
949
|
-
|
|
950
|
-
|
|
1172
|
+
writeFileSync(join(LLM_CACHE_DIR, `${hashPrompt(prompt, model, section)}.json`), JSON.stringify({
|
|
1173
|
+
text,
|
|
1174
|
+
model,
|
|
1175
|
+
section,
|
|
1176
|
+
timestamp: Date.now()
|
|
1177
|
+
}), { mode: 384 });
|
|
1178
|
+
}
|
|
1179
|
+
function prepareSection(opts) {
|
|
1180
|
+
if (existsSync(opts.outputPath)) unlinkSync(opts.outputPath);
|
|
1181
|
+
writeFileSync(join(opts.skilldDir, `PROMPT_${opts.section}.md`), opts.prompt);
|
|
1182
|
+
}
|
|
1183
|
+
function finalizeSection(opts) {
|
|
1184
|
+
const { section, raw, outputFile, outputPath, skilldDir, debug, cliCleanup } = opts;
|
|
1185
|
+
if (cliCleanup) for (const entry of readdirSync(skilldDir)) {
|
|
1186
|
+
if (entry === outputFile || cliCleanup.preExistingFiles.has(entry)) continue;
|
|
1187
|
+
if (Object.values(SECTION_OUTPUT_FILES).includes(entry)) continue;
|
|
1188
|
+
if (entry.startsWith("PROMPT_") || entry === "logs") continue;
|
|
1189
|
+
try {
|
|
1190
|
+
unlinkSync(join(skilldDir, entry));
|
|
1191
|
+
} catch {}
|
|
1192
|
+
}
|
|
1193
|
+
const logsDir = join(skilldDir, "logs");
|
|
1194
|
+
const logName = section.toUpperCase().replace(/-/g, "_");
|
|
1195
|
+
const text = ((existsSync(outputPath) ? readFileSync(outputPath, "utf-8") : "") || raw.writeContent || raw.text).trim();
|
|
1196
|
+
const stderr = raw.stderr ?? "";
|
|
1197
|
+
const code = raw.exitCode ?? 0;
|
|
1198
|
+
if (debug || stderr && (!text || code !== 0)) {
|
|
1199
|
+
mkdirSync(logsDir, { recursive: true });
|
|
1200
|
+
if (stderr) writeFileSync(join(logsDir, `${logName}.stderr.log`), stderr);
|
|
1201
|
+
}
|
|
1202
|
+
if (debug) {
|
|
1203
|
+
mkdirSync(logsDir, { recursive: true });
|
|
1204
|
+
if (raw.rawLines?.length) writeFileSync(join(logsDir, `${logName}.jsonl`), raw.rawLines.join("\n"));
|
|
1205
|
+
if (text) writeFileSync(join(logsDir, `${logName}.md`), text);
|
|
1206
|
+
}
|
|
1207
|
+
if (!text && code !== 0) return {
|
|
951
1208
|
section,
|
|
952
1209
|
content: "",
|
|
953
1210
|
wasOptimized: false,
|
|
954
|
-
error: `
|
|
955
|
-
}
|
|
956
|
-
const
|
|
957
|
-
|
|
958
|
-
const
|
|
959
|
-
const
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
1211
|
+
error: stderr.trim() || `CLI exited with code ${code}`
|
|
1212
|
+
};
|
|
1213
|
+
const content = text ? cleanSectionOutput(text) : "";
|
|
1214
|
+
if (content) writeFileSync(outputPath, content);
|
|
1215
|
+
const validator = getSectionValidator(section);
|
|
1216
|
+
const warnings = (content && validator ? validator(content) : []).map((w) => ({
|
|
1217
|
+
section,
|
|
1218
|
+
warning: w.warning
|
|
1219
|
+
}));
|
|
1220
|
+
return {
|
|
1221
|
+
section,
|
|
1222
|
+
content,
|
|
1223
|
+
wasOptimized: !!content,
|
|
1224
|
+
warnings: warnings.length ? warnings : void 0,
|
|
1225
|
+
usage: raw.usage,
|
|
1226
|
+
cost: raw.cost
|
|
1227
|
+
};
|
|
1228
|
+
}
|
|
1229
|
+
function spawnCliAndStream(opts) {
|
|
1230
|
+
const { adapter, cliModel, prompt, skillDir, skilldDir, symlinkDirs, timeout, debug, section, onProgress } = opts;
|
|
1231
|
+
const args = adapter.buildArgs(cliModel, skillDir, symlinkDirs);
|
|
1232
|
+
const parseEvent = adapter.parseEvent;
|
|
964
1233
|
return new Promise((resolve) => {
|
|
965
|
-
const proc = spawn(cli, args, {
|
|
1234
|
+
const proc = spawn(adapter.cli, args, {
|
|
966
1235
|
cwd: skilldDir,
|
|
967
1236
|
stdio: [
|
|
968
1237
|
"pipe",
|
|
@@ -991,6 +1260,32 @@ function optimizeSection(opts) {
|
|
|
991
1260
|
});
|
|
992
1261
|
proc.stdin.write(prompt);
|
|
993
1262
|
proc.stdin.end();
|
|
1263
|
+
function applyEvent(evt) {
|
|
1264
|
+
switch (evt.kind) {
|
|
1265
|
+
case "text":
|
|
1266
|
+
if (evt.delta) accumulatedText += evt.delta;
|
|
1267
|
+
if (evt.full !== void 0) accumulatedText = evt.full;
|
|
1268
|
+
break;
|
|
1269
|
+
case "tool-call": {
|
|
1270
|
+
if (evt.writeContent) lastWriteContent = evt.writeContent;
|
|
1271
|
+
const chunk = evt.hint ? `[${evt.tool}: ${evt.hint}]` : `[${evt.tool}]`;
|
|
1272
|
+
onProgress?.({
|
|
1273
|
+
chunk,
|
|
1274
|
+
type: "reasoning",
|
|
1275
|
+
text: "",
|
|
1276
|
+
reasoning: chunk,
|
|
1277
|
+
section
|
|
1278
|
+
});
|
|
1279
|
+
break;
|
|
1280
|
+
}
|
|
1281
|
+
case "done":
|
|
1282
|
+
if (evt.usage) usage = evt.usage;
|
|
1283
|
+
if (evt.cost != null) cost = evt.cost;
|
|
1284
|
+
break;
|
|
1285
|
+
case "error":
|
|
1286
|
+
case "noop": break;
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
994
1289
|
proc.stdout.on("data", (chunk) => {
|
|
995
1290
|
buffer += chunk.toString();
|
|
996
1291
|
const lines = buffer.split("\n");
|
|
@@ -998,22 +1293,7 @@ function optimizeSection(opts) {
|
|
|
998
1293
|
for (const line of lines) {
|
|
999
1294
|
if (!line.trim()) continue;
|
|
1000
1295
|
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;
|
|
1296
|
+
applyEvent(parseEvent(line));
|
|
1017
1297
|
}
|
|
1018
1298
|
});
|
|
1019
1299
|
let stderr = "";
|
|
@@ -1021,70 +1301,118 @@ function optimizeSection(opts) {
|
|
|
1021
1301
|
stderr += chunk.toString();
|
|
1022
1302
|
});
|
|
1023
1303
|
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
|
-
}));
|
|
1304
|
+
if (buffer.trim()) applyEvent(parseEvent(buffer));
|
|
1067
1305
|
resolve({
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
wasOptimized: !!content,
|
|
1071
|
-
warnings: warnings?.length ? warnings : void 0,
|
|
1306
|
+
text: accumulatedText,
|
|
1307
|
+
writeContent: lastWriteContent || void 0,
|
|
1072
1308
|
usage,
|
|
1073
|
-
cost
|
|
1309
|
+
cost,
|
|
1310
|
+
stderr,
|
|
1311
|
+
exitCode: code ?? 0,
|
|
1312
|
+
rawLines: debug ? rawLines : void 0
|
|
1074
1313
|
});
|
|
1075
1314
|
});
|
|
1076
1315
|
proc.on("error", (err) => {
|
|
1077
1316
|
resolve({
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
error: err.message
|
|
1317
|
+
text: "",
|
|
1318
|
+
stderr: err.message,
|
|
1319
|
+
exitCode: 1
|
|
1082
1320
|
});
|
|
1083
1321
|
});
|
|
1084
1322
|
});
|
|
1085
1323
|
}
|
|
1324
|
+
function cliExecutor(model) {
|
|
1325
|
+
const cliConfig = CLI_MODELS[model];
|
|
1326
|
+
if (!cliConfig) return { error: `No CLI mapping for model: ${model}` };
|
|
1327
|
+
const adapter = CLI_ADAPTERS[cliConfig.cli];
|
|
1328
|
+
return {
|
|
1329
|
+
cliCleanup: true,
|
|
1330
|
+
run: ({ section, prompt, skillDir, skilldDir, timeout, debug, onProgress }) => spawnCliAndStream({
|
|
1331
|
+
adapter,
|
|
1332
|
+
cliModel: cliConfig.model,
|
|
1333
|
+
prompt,
|
|
1334
|
+
skillDir,
|
|
1335
|
+
skilldDir,
|
|
1336
|
+
symlinkDirs: getSkillReferenceDirs(skillDir),
|
|
1337
|
+
timeout,
|
|
1338
|
+
debug,
|
|
1339
|
+
section,
|
|
1340
|
+
onProgress
|
|
1341
|
+
})
|
|
1342
|
+
};
|
|
1343
|
+
}
|
|
1344
|
+
function piAiExecutor(model) {
|
|
1345
|
+
if (!new Set(getAvailablePiAiModels().map((m) => m.id)).has(model)) return { error: `Pi model unavailable or not authenticated: ${model}` };
|
|
1346
|
+
return {
|
|
1347
|
+
cliCleanup: false,
|
|
1348
|
+
run: async ({ section, prompt, skillDir, timeout, onProgress }) => {
|
|
1349
|
+
const ac = new AbortController();
|
|
1350
|
+
const timer = setTimeout(() => ac.abort(), timeout);
|
|
1351
|
+
try {
|
|
1352
|
+
const result = await optimizeSectionPiAi({
|
|
1353
|
+
section,
|
|
1354
|
+
prompt,
|
|
1355
|
+
skillDir,
|
|
1356
|
+
model,
|
|
1357
|
+
onProgress,
|
|
1358
|
+
signal: ac.signal
|
|
1359
|
+
});
|
|
1360
|
+
return {
|
|
1361
|
+
text: result.text.trim(),
|
|
1362
|
+
usage: result.usage,
|
|
1363
|
+
cost: result.cost
|
|
1364
|
+
};
|
|
1365
|
+
} catch (err) {
|
|
1366
|
+
return {
|
|
1367
|
+
text: "",
|
|
1368
|
+
stderr: err.message,
|
|
1369
|
+
exitCode: 1
|
|
1370
|
+
};
|
|
1371
|
+
} finally {
|
|
1372
|
+
clearTimeout(timer);
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
};
|
|
1376
|
+
}
|
|
1377
|
+
function selectExecutor(model) {
|
|
1378
|
+
return isPiAiModel(model) ? piAiExecutor(model) : cliExecutor(model);
|
|
1379
|
+
}
|
|
1380
|
+
const STATIC_REGEX_1 = /\b429\b/;
|
|
1381
|
+
const STATIC_REGEX_2 = /rate.?limit/i;
|
|
1382
|
+
const STATIC_REGEX_3 = /exhausted.*capacity/i;
|
|
1383
|
+
const STATIC_REGEX_4 = /quota.*reset/i;
|
|
1384
|
+
const STATIC_REGEX_5 = /reset\s+after\s+(\d+)s/i;
|
|
1385
|
+
async function optimizeSection(opts) {
|
|
1386
|
+
const { section, prompt, outputFile, skillDir, executor, onProgress, timeout, debug, preExistingFiles } = opts;
|
|
1387
|
+
const skilldDir = skillInternalDir(skillDir);
|
|
1388
|
+
const outputPath = join(skilldDir, outputFile);
|
|
1389
|
+
prepareSection({
|
|
1390
|
+
section,
|
|
1391
|
+
prompt,
|
|
1392
|
+
outputPath,
|
|
1393
|
+
skilldDir
|
|
1394
|
+
});
|
|
1395
|
+
return finalizeSection({
|
|
1396
|
+
section,
|
|
1397
|
+
raw: await executor.run({
|
|
1398
|
+
section,
|
|
1399
|
+
prompt,
|
|
1400
|
+
skillDir,
|
|
1401
|
+
skilldDir,
|
|
1402
|
+
timeout,
|
|
1403
|
+
debug,
|
|
1404
|
+
onProgress
|
|
1405
|
+
}),
|
|
1406
|
+
outputFile,
|
|
1407
|
+
outputPath,
|
|
1408
|
+
skilldDir,
|
|
1409
|
+
debug: !!debug,
|
|
1410
|
+
cliCleanup: executor.cliCleanup ? { preExistingFiles } : void 0
|
|
1411
|
+
});
|
|
1412
|
+
}
|
|
1086
1413
|
async function optimizeDocs(opts) {
|
|
1087
1414
|
const { packageName, skillDir, model = "sonnet", version, hasGithub, hasReleases, hasChangelog, docFiles, docsType, hasShippedDocs, onProgress, timeout = 18e4, debug, noCache, sections, customPrompt, features, pkgFiles, overheadLines } = opts;
|
|
1415
|
+
const cache = createReferenceCache(packageName, version);
|
|
1088
1416
|
const sectionPrompts = buildAllSectionPrompts({
|
|
1089
1417
|
packageName,
|
|
1090
1418
|
skillDir,
|
|
@@ -1107,24 +1435,20 @@ async function optimizeDocs(opts) {
|
|
|
1107
1435
|
wasOptimized: false,
|
|
1108
1436
|
error: "No valid sections to generate"
|
|
1109
1437
|
};
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
optimized: "",
|
|
1113
|
-
wasOptimized: false,
|
|
1114
|
-
error: `Pi model unavailable or not authenticated: ${model}`
|
|
1115
|
-
};
|
|
1116
|
-
} else if (!CLI_MODELS[model]) return {
|
|
1438
|
+
const executorOrError = selectExecutor(model);
|
|
1439
|
+
if ("error" in executorOrError) return {
|
|
1117
1440
|
optimized: "",
|
|
1118
1441
|
wasOptimized: false,
|
|
1119
|
-
error:
|
|
1442
|
+
error: executorOrError.error
|
|
1120
1443
|
};
|
|
1444
|
+
const executor = executorOrError;
|
|
1121
1445
|
const cachedResults = [];
|
|
1122
1446
|
const uncachedSections = [];
|
|
1123
1447
|
for (const [section, prompt] of sectionPrompts) {
|
|
1124
1448
|
if (!noCache) {
|
|
1125
1449
|
if (version) {
|
|
1126
1450
|
const outputFile = SECTION_OUTPUT_FILES[section];
|
|
1127
|
-
const refCached =
|
|
1451
|
+
const refCached = cache.readSection(outputFile);
|
|
1128
1452
|
if (refCached) {
|
|
1129
1453
|
onProgress?.({
|
|
1130
1454
|
chunk: `[${section}: cached]`,
|
|
@@ -1163,7 +1487,7 @@ async function optimizeDocs(opts) {
|
|
|
1163
1487
|
prompt
|
|
1164
1488
|
});
|
|
1165
1489
|
}
|
|
1166
|
-
const skilldDir =
|
|
1490
|
+
const skilldDir = skillInternalDir(skillDir);
|
|
1167
1491
|
mkdirSync(skilldDir, { recursive: true });
|
|
1168
1492
|
for (const entry of readdirSync(skilldDir)) {
|
|
1169
1493
|
const entryPath = join(skilldDir, entry);
|
|
@@ -1185,8 +1509,7 @@ async function optimizeDocs(opts) {
|
|
|
1185
1509
|
prompt,
|
|
1186
1510
|
outputFile,
|
|
1187
1511
|
skillDir,
|
|
1188
|
-
|
|
1189
|
-
packageName,
|
|
1512
|
+
executor,
|
|
1190
1513
|
onProgress,
|
|
1191
1514
|
timeout,
|
|
1192
1515
|
debug,
|
|
@@ -1247,8 +1570,7 @@ async function optimizeDocs(opts) {
|
|
|
1247
1570
|
prompt,
|
|
1248
1571
|
outputFile: SECTION_OUTPUT_FILES[section],
|
|
1249
1572
|
skillDir,
|
|
1250
|
-
|
|
1251
|
-
packageName,
|
|
1573
|
+
executor,
|
|
1252
1574
|
onProgress,
|
|
1253
1575
|
timeout,
|
|
1254
1576
|
debug,
|
|
@@ -1276,7 +1598,7 @@ async function optimizeDocs(opts) {
|
|
|
1276
1598
|
file: SECTION_OUTPUT_FILES[r.section],
|
|
1277
1599
|
content: r.content
|
|
1278
1600
|
}));
|
|
1279
|
-
if (sectionFiles.length > 0) writeSections(
|
|
1601
|
+
if (sectionFiles.length > 0) cache.writeSections(sectionFiles);
|
|
1280
1602
|
}
|
|
1281
1603
|
const mergedParts = [];
|
|
1282
1604
|
for (const section of SECTION_MERGE_ORDER) {
|
|
@@ -1292,7 +1614,7 @@ async function optimizeDocs(opts) {
|
|
|
1292
1614
|
} : void 0;
|
|
1293
1615
|
const errors = allResults.filter((r) => r.error).map((r) => `${r.section}: ${r.error}`);
|
|
1294
1616
|
const warnings = allResults.flatMap((r) => r.warnings ?? []).map((w) => `${w.section}: ${w.warning}`);
|
|
1295
|
-
const debugLogsDir = debug && uncachedSections.length > 0 ?
|
|
1617
|
+
const debugLogsDir = debug && uncachedSections.length > 0 ? skillLogDir(skillDir) : void 0;
|
|
1296
1618
|
return {
|
|
1297
1619
|
optimized,
|
|
1298
1620
|
wasOptimized,
|
|
@@ -1306,221 +1628,17 @@ async function optimizeDocs(opts) {
|
|
|
1306
1628
|
}
|
|
1307
1629
|
function isRateLimitError(error) {
|
|
1308
1630
|
if (!error) return false;
|
|
1309
|
-
return
|
|
1631
|
+
return STATIC_REGEX_1.test(error) || STATIC_REGEX_2.test(error) || STATIC_REGEX_3.test(error) || STATIC_REGEX_4.test(error);
|
|
1310
1632
|
}
|
|
1311
1633
|
function parseRateLimitDelay(error) {
|
|
1312
1634
|
if (!error || !isRateLimitError(error)) return void 0;
|
|
1313
|
-
const match = error.match(
|
|
1635
|
+
const match = error.match(STATIC_REGEX_5);
|
|
1314
1636
|
return match ? Number(match[1]) : 10;
|
|
1315
1637
|
}
|
|
1316
1638
|
function getRetryError(result) {
|
|
1317
1639
|
if (result.status === "rejected") return String(result.reason);
|
|
1318
1640
|
return result.value.error;
|
|
1319
1641
|
}
|
|
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 };
|
|
1642
|
+
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
1643
|
|
|
1526
1644
|
//# sourceMappingURL=agent.mjs.map
|