@webskill/sdk 0.0.5 → 0.1.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.
@@ -1,4 +1,6 @@
1
- import { B as SKILL_MANIFEST_FILE, G as WebSkillError, M as normalizeToolContent, N as parseBridgeRequest, Z as isValidSkillName, a as CapabilityApproval, at as verifyManifest, c as FsMemoryStore, et as parseSkillMarkdown, it as validateSkills, j as networkUrlHost, k as isNetworkAllowed, q as buildManifest, rt as resolveInsideRoot, s as FsArtifactStore, w as bridgeError, z as SKILLS_LOCKFILE } from "./dist-D405AlPD.js";
1
+ import { D as verifyManifest, E as validateSkills, S as parseSkillPackManifest, T as resolveInsideRoot, _ as exportSkills, f as buildManifest, i as SKILL_MANIFEST_FILE, r as SKILLS_LOCKFILE, s as SKILL_PACK_FILE, u as WebSkillError, v as isValidSkillName, x as parseSkillMarkdown } from "./memoryArtifactStore-C9lFVqPF-U8nXvqL9.js";
2
+ import { A as normalizeToolContent, D as isNetworkAllowed, a as CapabilityApproval, b as bridgeError, c as FsMemoryStore, j as parseBridgeRequest, k as networkUrlHost, s as FsArtifactStore } from "./dist-CiYRkm71.js";
3
+ import { unzipSync, zipSync } from "fflate";
2
4
  import { existsSync, promises, readFileSync } from "node:fs";
3
5
  import path from "node:path";
4
6
  import { fileURLToPath, pathToFileURL } from "node:url";
@@ -8,7 +10,6 @@ import { parseSync } from "oxc-parser";
8
10
  import { createInterface } from "node:readline/promises";
9
11
  import { mkdtemp } from "node:fs/promises";
10
12
  import { tmpdir } from "node:os";
11
- import { unzipSync, zipSync } from "fflate";
12
13
  import * as tar from "tar";
13
14
  import { execFile } from "node:child_process";
14
15
  import { createHash } from "node:crypto";
@@ -971,6 +972,15 @@ async function stageHttp(source, ctx, expectedSha256) {
971
972
  await ctx.fs.writeBinary(archivePath, data);
972
973
  await extractTarFile(toPlatform(archivePath), toPlatform(contentDir));
973
974
  }
975
+ const packFilePath = `${contentDir}/${SKILL_PACK_FILE}`;
976
+ if (await ctx.fs.exists(packFilePath)) return {
977
+ skillDir: "",
978
+ source,
979
+ pack: {
980
+ contentDir,
981
+ manifest: parseSkillPackManifest(await ctx.fs.readText(packFilePath))
982
+ }
983
+ };
974
984
  if (await ctx.fs.exists(`${contentDir}/SKILL.md`)) return {
975
985
  skillDir: contentDir,
976
986
  source
@@ -1117,6 +1127,7 @@ const asInstallFailed = (e) => e instanceof WebSkillError && e.code === "INSTALL
1117
1127
  /**
1118
1128
  * 技能管理门面:统一安装管线(staging → 解析 name → 校验 → 拷贝 → manifest → lockfile),
1119
1129
  * 任何失败清理现场抛 INSTALL_FAILED。
1130
+ * @stable
1120
1131
  */
1121
1132
  var SkillManager = class {
1122
1133
  #managedRoot;
@@ -1157,6 +1168,7 @@ var SkillManager = class {
1157
1168
  break;
1158
1169
  case "archive": throw new WebSkillError("TOOL_UNSUPPORTED", "The \"archive\" install source is only supported by the browser skill manager");
1159
1170
  }
1171
+ if (staged.pack) return (await this.#installPack(staged.pack, staged.source, stagingRoot))[0];
1160
1172
  let name;
1161
1173
  let version;
1162
1174
  try {
@@ -1198,6 +1210,61 @@ var SkillManager = class {
1198
1210
  }
1199
1211
  }
1200
1212
  /**
1213
+ * 包集安装:逐技能走单技能管线(归一 → 汇总校验 → 落 managed root → manifest → digest 比对)。
1214
+ * 任一失败整体回滚(删除本次已落目录;lockfile 在全部成功后才写入,天然零残留)。
1215
+ * 包是封闭产物:跳过安装期 schema 推导(sidecar 已随包携带,保证 digest 逐字节一致)。
1216
+ */
1217
+ async #installPack(pack, source, stagingRoot) {
1218
+ const fs = this.#fs;
1219
+ const finalRoot = `${stagingRoot}/final`;
1220
+ const installed = [];
1221
+ try {
1222
+ const versions = /* @__PURE__ */ new Map();
1223
+ for (const entry of pack.manifest.skills) {
1224
+ const skillDir = `${pack.contentDir}/${entry.name}`;
1225
+ if (!await fs.exists(`${skillDir}/SKILL.md`)) throw new WebSkillError("INSTALL_FAILED", `Skill pack is missing a directory for skill "${entry.name}"`);
1226
+ let name;
1227
+ try {
1228
+ const { metadata } = parseSkillMarkdown(await fs.readText(`${skillDir}/SKILL.md`));
1229
+ name = metadata.name;
1230
+ versions.set(name, typeof metadata["version"] === "string" ? metadata["version"] : void 0);
1231
+ } catch (e) {
1232
+ throw new WebSkillError("INSTALL_FAILED", `Failed to read skill name from SKILL.md of pack entry "${entry.name}": ${messageOf(e)}`, e);
1233
+ }
1234
+ if (name !== entry.name) throw new WebSkillError("INSTALL_FAILED", `Skill pack entry "${entry.name}" does not match the SKILL.md name "${name}"`);
1235
+ await copyDir(fs, skillDir, `${finalRoot}/${name}`);
1236
+ }
1237
+ const report = await validateSkills(fs, [finalRoot]);
1238
+ if (!report.ok) {
1239
+ const errors = report.issues.filter((i) => i.severity === "error");
1240
+ throw new WebSkillError("INSTALL_FAILED", `Skill pack failed validation: ${errors.map((i) => i.message).join("; ")}`, errors);
1241
+ }
1242
+ const manifests = [];
1243
+ for (const entry of pack.manifest.skills) {
1244
+ const targetDir = `${this.#managedRoot}/${entry.name}`;
1245
+ if (await fs.exists(targetDir)) await fs.remove(targetDir, { recursive: true });
1246
+ await copyDir(fs, `${finalRoot}/${entry.name}`, targetDir);
1247
+ installed.push(targetDir);
1248
+ const manifest = await createManifest(fs, targetDir, {
1249
+ name: entry.name,
1250
+ ...versions.get(entry.name) ? { version: versions.get(entry.name) } : {},
1251
+ source
1252
+ });
1253
+ if (manifest.integrity.digest !== entry.digest) throw new WebSkillError("INSTALL_FAILED", `Skill "${entry.name}" digest mismatch: expected ${entry.digest}, got ${manifest.integrity.digest}`);
1254
+ manifests.push(manifest);
1255
+ }
1256
+ for (const manifest of manifests) await upsertLockEntry(fs, this.#managedRoot, manifest.name, {
1257
+ digest: manifest.integrity.digest,
1258
+ installedAt: manifest.installedAt,
1259
+ source
1260
+ });
1261
+ return manifests;
1262
+ } catch (e) {
1263
+ for (const targetDir of installed) await removeDirQuiet(fs, targetDir);
1264
+ throw asInstallFailed(e);
1265
+ }
1266
+ }
1267
+ /**
1201
1268
  * D2 安装期预推导:scripts/ 下无显式 inputSchema 导出且无 sidecar 的脚本,
1202
1269
  * 经 OXC 推导写 sidecar(计入 manifest.files;重装重新生成)
1203
1270
  */
@@ -1243,6 +1310,21 @@ var SkillManager = class {
1243
1310
  if (!await this.#fs.exists(skillRoot)) throw new WebSkillError("EXPORT_FAILED", `Skill "${name}" is not installed`);
1244
1311
  return exportArchive(this.#fs, skillRoot, options);
1245
1312
  }
1313
+ /** 多技能包集导出(webskill.skill-pack.json + 各技能目录含 manifest),写 outPath 并返回 */
1314
+ async exportPack(names, options) {
1315
+ if (names.length === 0) throw new WebSkillError("EXPORT_FAILED", "exportPack requires at least one skill name");
1316
+ const roots = names.map((name) => {
1317
+ if (!isValidSkillName(name)) throw new WebSkillError("EXPORT_FAILED", `Invalid skill name (path traversal rejected): ${JSON.stringify(name)}`);
1318
+ return `${this.#managedRoot}/${name}`;
1319
+ });
1320
+ for (const [index, root] of roots.entries()) if (!await this.#fs.exists(root)) throw new WebSkillError("EXPORT_FAILED", `Skill "${names[index]}" is not installed`);
1321
+ const bytes = await exportSkills(this.#fs, {
1322
+ roots,
1323
+ manifestBuilder: (root) => readManifest(this.#fs, root)
1324
+ });
1325
+ await this.#fs.writeBinary(options.outPath, bytes);
1326
+ return options.outPath;
1327
+ }
1246
1328
  };
1247
1329
  /**
1248
1330
  * 解析 .env(简单 KEY=VALUE 行解析,不引依赖),
@@ -190,9 +190,222 @@ function renderMiniMarkdown(text, doc) {
190
190
  }
191
191
  return root;
192
192
  }
193
- /** RenderBlock → DOM(markdown/json/table/image/file 五种) */
193
+ /**
194
+ * 轻量 SVG 图表自绘(bar/line/pie,零依赖,三端复用单一来源)。
195
+ * 全部经 doc.createElementNS 构建(内容来自技能输出,不拼 innerHTML)。
196
+ */
197
+ const SVG_NS = "http://www.w3.org/2000/svg";
198
+ /** 固定 8 色循环调色板 */
199
+ const CHART_PALETTE = [
200
+ "#4e79a7",
201
+ "#f28e2b",
202
+ "#e15759",
203
+ "#76b7b2",
204
+ "#59a14f",
205
+ "#edc948",
206
+ "#b07aa1",
207
+ "#ff9da7"
208
+ ];
209
+ const WIDTH = 320;
210
+ const HEIGHT = 200;
211
+ function el(doc, name, attrs) {
212
+ const node = doc.createElementNS(SVG_NS, name);
213
+ for (const [key, value] of Object.entries(attrs)) node.setAttribute(key, value);
214
+ return node;
215
+ }
216
+ function text$1(doc, x, y, content, attrs = {}) {
217
+ const node = el(doc, "text", {
218
+ x: String(x),
219
+ y: String(y),
220
+ "font-size": "9",
221
+ fill: "#555",
222
+ ...attrs
223
+ });
224
+ node.textContent = content;
225
+ return node;
226
+ }
227
+ const fmt = (n) => Number.isInteger(n) ? String(n) : n.toFixed(1);
228
+ function maxValue(chart) {
229
+ let max = 0;
230
+ for (const s of chart.series) for (const v of s.data) if (v > max) max = v;
231
+ return max;
232
+ }
233
+ function renderBar(chart, svg, doc) {
234
+ const plot = {
235
+ x0: 30,
236
+ y0: 24,
237
+ x1: 312,
238
+ y1: 164
239
+ };
240
+ const max = maxValue(chart);
241
+ svg.appendChild(el(doc, "line", {
242
+ x1: String(plot.x0),
243
+ y1: String(plot.y0),
244
+ x2: String(plot.x0),
245
+ y2: String(plot.y1),
246
+ stroke: "#999"
247
+ }));
248
+ svg.appendChild(el(doc, "line", {
249
+ x1: String(plot.x0),
250
+ y1: String(plot.y1),
251
+ x2: String(plot.x1),
252
+ y2: String(plot.y1),
253
+ stroke: "#999"
254
+ }));
255
+ if (max <= 0 || chart.labels.length === 0 || chart.series.length === 0) return;
256
+ const groupWidth = (plot.x1 - plot.x0) / chart.labels.length;
257
+ const barWidth = Math.max(1, groupWidth / chart.series.length * .7);
258
+ chart.series.forEach((series, si) => {
259
+ const color = CHART_PALETTE[si % CHART_PALETTE.length];
260
+ series.data.forEach((value, li) => {
261
+ if (li >= chart.labels.length) return;
262
+ const height = (plot.y1 - plot.y0) * value / max;
263
+ const x = plot.x0 + li * groupWidth + (groupWidth - barWidth * chart.series.length) / 2 + si * barWidth;
264
+ const y = plot.y1 - height;
265
+ svg.appendChild(el(doc, "rect", {
266
+ x: String(x),
267
+ y: String(y),
268
+ width: String(barWidth),
269
+ height: String(height),
270
+ fill: color,
271
+ "data-series": series.name ?? String(si)
272
+ }));
273
+ if (chart.series.length === 1) svg.appendChild(text$1(doc, x + barWidth / 2, y - 2, fmt(value), { "text-anchor": "middle" }));
274
+ });
275
+ });
276
+ chart.labels.forEach((label, li) => {
277
+ svg.appendChild(text$1(doc, plot.x0 + li * groupWidth + groupWidth / 2, plot.y1 + 12, label, { "text-anchor": "middle" }));
278
+ });
279
+ }
280
+ function renderLine(chart, svg, doc) {
281
+ const plot = {
282
+ x0: 30,
283
+ y0: 24,
284
+ x1: 312,
285
+ y1: 164
286
+ };
287
+ const max = maxValue(chart);
288
+ svg.appendChild(el(doc, "line", {
289
+ x1: String(plot.x0),
290
+ y1: String(plot.y0),
291
+ x2: String(plot.x0),
292
+ y2: String(plot.y1),
293
+ stroke: "#999"
294
+ }));
295
+ svg.appendChild(el(doc, "line", {
296
+ x1: String(plot.x0),
297
+ y1: String(plot.y1),
298
+ x2: String(plot.x1),
299
+ y2: String(plot.y1),
300
+ stroke: "#999"
301
+ }));
302
+ if (max <= 0 || chart.labels.length === 0 || chart.series.length === 0) return;
303
+ const step = chart.labels.length > 1 ? (plot.x1 - plot.x0) / (chart.labels.length - 1) : 0;
304
+ const px = (li) => chart.labels.length > 1 ? plot.x0 + li * step : (plot.x0 + plot.x1) / 2;
305
+ const py = (v) => plot.y1 - (plot.y1 - plot.y0) * v / max;
306
+ chart.series.forEach((series, si) => {
307
+ const color = CHART_PALETTE[si % CHART_PALETTE.length];
308
+ const points = series.data.slice(0, chart.labels.length).map((v, li) => `${px(li)},${py(v)}`).join(" ");
309
+ if (points !== "") svg.appendChild(el(doc, "polyline", {
310
+ points,
311
+ fill: "none",
312
+ stroke: color,
313
+ "stroke-width": "1.5"
314
+ }));
315
+ series.data.slice(0, chart.labels.length).forEach((v, li) => {
316
+ svg.appendChild(el(doc, "circle", {
317
+ cx: String(px(li)),
318
+ cy: String(py(v)),
319
+ r: "2",
320
+ fill: color
321
+ }));
322
+ });
323
+ });
324
+ chart.labels.forEach((label, li) => {
325
+ svg.appendChild(text$1(doc, px(li), plot.y1 + 12, label, { "text-anchor": "middle" }));
326
+ });
327
+ }
328
+ function renderPie(chart, svg, doc) {
329
+ const data = (chart.series[0]?.data ?? []).slice(0, chart.labels.length);
330
+ const total = data.reduce((sum, v) => sum + (v > 0 ? v : 0), 0);
331
+ const cx = 90;
332
+ const cy = 104;
333
+ const r = 72;
334
+ if (total <= 0) {
335
+ svg.appendChild(text$1(doc, cx, cy, "No data", { "text-anchor": "middle" }));
336
+ return;
337
+ }
338
+ let angle = -Math.PI / 2;
339
+ data.forEach((value, i) => {
340
+ const label = chart.labels[i] ?? String(i);
341
+ const color = CHART_PALETTE[i % CHART_PALETTE.length];
342
+ const slice = Math.max(value, 0) / total * Math.PI * 2;
343
+ const x0 = cx + r * Math.cos(angle);
344
+ const y0 = cy + r * Math.sin(angle);
345
+ const x1 = cx + r * Math.cos(angle + slice);
346
+ const y1 = cy + r * Math.sin(angle + slice);
347
+ const path = el(doc, "path", {
348
+ d: `M ${cx} ${cy} L ${x0} ${y0} A ${r} ${r} 0 ${slice > Math.PI ? "1" : "0"} 1 ${x1} ${y1} Z`,
349
+ fill: color,
350
+ "data-label": label
351
+ });
352
+ svg.appendChild(path);
353
+ angle += slice;
354
+ const ly = 40 + i * 14;
355
+ svg.appendChild(el(doc, "rect", {
356
+ x: "190",
357
+ y: String(ly - 7),
358
+ width: "8",
359
+ height: "8",
360
+ fill: color
361
+ }));
362
+ svg.appendChild(text$1(doc, 202, ly, `${label} (${fmt(value)})`));
363
+ });
364
+ }
365
+ /**
366
+ * ChartSpec → SVG(bar 等宽柱 + 值标签;line 折线 + 点;pie 扇形 + 图例;空数据容错)
367
+ * @stable
368
+ */
369
+ function renderMiniChart(chart, doc) {
370
+ const svg = el(doc, "svg", {
371
+ viewBox: `0 0 ${WIDTH} ${HEIGHT}`,
372
+ width: String(WIDTH),
373
+ height: String(HEIGHT),
374
+ class: `webskill-chart webskill-chart--${chart.kind}`,
375
+ role: "img"
376
+ });
377
+ if (chart.title) svg.appendChild(text$1(doc, WIDTH / 2, 14, chart.title, {
378
+ "text-anchor": "middle",
379
+ "font-size": "11",
380
+ fill: "#333"
381
+ }));
382
+ switch (chart.kind) {
383
+ case "bar":
384
+ renderBar(chart, svg, doc);
385
+ break;
386
+ case "line":
387
+ renderLine(chart, svg, doc);
388
+ break;
389
+ case "pie":
390
+ renderPie(chart, svg, doc);
391
+ break;
392
+ }
393
+ return svg;
394
+ }
395
+ /** A2UI/OpenUI 降级:chart → table(labels 为首列,series 各为一列) */
396
+ function chartToTable(chart) {
397
+ return {
398
+ type: "table",
399
+ columns: ["label", ...chart.series.map((s, i) => s.name ?? `series ${i + 1}`)],
400
+ rows: chart.labels.map((label, li) => [label, ...chart.series.map((s) => s.data[li] ?? null)])
401
+ };
402
+ }
403
+ /** RenderBlock → DOM(markdown/json/table/image/file/chart 六种) */
194
404
  function renderBlocks(container, blocks, doc) {
195
405
  for (const block of blocks) switch (block.type) {
406
+ case "chart":
407
+ container.appendChild(renderMiniChart(block.chart, doc));
408
+ break;
196
409
  case "markdown":
197
410
  container.appendChild(renderMiniMarkdown(block.text, doc));
198
411
  break;
@@ -517,6 +730,7 @@ function fieldStatements(fields) {
517
730
  }
518
731
  });
519
732
  }
733
+ /** @experimental */
520
734
  function toOpenUiLang(request) {
521
735
  const lines = [];
522
736
  let fields = [];
@@ -581,7 +795,10 @@ function toOpenUiLang(request) {
581
795
  ].join(", ")}])`);
582
796
  return lines.join("\n");
583
797
  }
584
- /** OpenUI ActionEvent → InteractionResponse(formState 优先,取消单独分支) */
798
+ /**
799
+ * OpenUI ActionEvent → InteractionResponse(formState 优先,取消单独分支)
800
+ * @experimental
801
+ */
585
802
  function fromOpenUiAction(action) {
586
803
  const a = action ?? {};
587
804
  const id = String(a.params?.["id"] ?? "");
@@ -626,6 +843,7 @@ const text = (id, content, variant) => ({
626
843
  text: content,
627
844
  ...variant ? { variant } : {}
628
845
  });
846
+ /** @experimental */
629
847
  function toA2uiMessages(request) {
630
848
  const surfaceId = `webskill-${request.id}`;
631
849
  const components = [];
@@ -751,7 +969,10 @@ function toA2uiMessages(request) {
751
969
  });
752
970
  return messages;
753
971
  }
754
- /** A2UI client→server action 事件 → InteractionResponse */
972
+ /**
973
+ * A2UI client→server action 事件 → InteractionResponse
974
+ * @experimental
975
+ */
755
976
  function fromA2uiAction(event) {
756
977
  const e = event ?? {};
757
978
  const id = String(e.context?.["requestId"] ?? "");
@@ -15363,6 +15584,7 @@ const basicCatalog = new Catalog("https://a2ui.org/specification/v0_9/catalogs/b
15363
15584
  *
15364
15585
  * 版本对齐:渲染器 @a2ui/lit@0.10.x 经 v0_9 入口同时接受 v0.9 / v0.9.1 消息
15365
15586
  * (schema 枚举 ['v0.9','v0.9.1']),与 7A v0.9.1 转换产物直接兼容。
15587
+ * @experimental
15366
15588
  */
15367
15589
  var LitRendererBridge = class {
15368
15590
  #mount;
@@ -15403,4 +15625,4 @@ var LitRendererBridge = class {
15403
15625
  };
15404
15626
 
15405
15627
  //#endregion
15406
- export { toOpenUiLang as C, toA2uiMessages as S, interactionToFormModel as _, LitRendererBridge as a, renderRenderResult as b, VERCEL_INTERACTION_TOOL_NAME as c, WebFormBridge as d, collectValues as f, fromVercelToolResult as g, fromOpenUiAction as h, A2UI_VERSION as i, VercelUiBridge as l, fromA2uiAction as m, A2UI_CANCEL_ACTION as n, OPENUI_CANCEL_ACTION as o, ensureStyles as p, A2UI_SUBMIT_ACTION as r, OPENUI_SUBMIT_ACTION as s, A2UI_BASIC_CATALOG_ID as t, WEBSKILL_STYLES_CSS as u, renderBlocks as v, toVercelToolInvocation as w, shapeInteractionValue as x, renderMiniMarkdown as y };
15628
+ export { renderRenderResult as C, toVercelToolInvocation as D, toOpenUiLang as E, renderMiniMarkdown as S, toA2uiMessages as T, fromOpenUiAction as _, CHART_PALETTE as a, renderBlocks as b, OPENUI_SUBMIT_ACTION as c, WEBSKILL_STYLES_CSS as d, WebFormBridge as f, fromA2uiAction as g, ensureStyles as h, A2UI_VERSION as i, VERCEL_INTERACTION_TOOL_NAME as l, collectValues as m, A2UI_CANCEL_ACTION as n, LitRendererBridge as o, chartToTable as p, A2UI_SUBMIT_ACTION as r, OPENUI_CANCEL_ACTION as s, A2UI_BASIC_CATALOG_ID as t, VercelUiBridge as u, fromVercelToolResult as v, shapeInteractionValue as w, renderMiniChart as x, interactionToFormModel as y };
@@ -1,5 +1,6 @@
1
- import { $t as SkillCatalogEntry, Et as WebSkillRuntime, F as LlmClient, Gt as FileSystemProvider, L as LlmMessage, an as SkillManifest, dt as RuntimeRun, wt as UiBridge } from "./index-BQDc-U1x.js";
2
- import { d as SkillManager } from "./index-aEple804.js";
1
+ import { L as SkillManifest, N as SkillDocument, S as FileSystemProvider, c as LlmClient, j as SkillCatalogEntry, u as LlmMessage, v as UiBridge } from "./types-CgNC-oQu-DCklnS0h.js";
2
+ import { U as RuntimeRun, it as WebSkillRuntime } from "./index-S8uza3ld.js";
3
+ import { d as SkillManager } from "./index-DuodMfQw.js";
3
4
  //#region ../governance/dist/index.d.ts
4
5
  //#region src/types.d.ts
5
6
  type CandidateStatus = 'draft' | 'pending-review' | 'approved' | 'published' | 'rejected';
@@ -374,10 +375,11 @@ declare class SimilarityDetector {
374
375
  }
375
376
  //#endregion
376
377
  //#region src/scoring/dependencyGraph.d.ts
377
- /** 技能引用依赖图(references/ 中引用其他技能的声明关系) */
378
378
  declare class DependencyGraph {
379
379
  #private;
380
380
  addDependency(from: string, to: string): void;
381
+ /** 从 frontmatter dependencies 声明建图(0.0.6 装配函数;只收录 Catalog 内技能之间的边) */
382
+ static buildFromCatalog(entries: SkillCatalogEntry[], documents: SkillDocument[]): DependencyGraph;
381
383
  dependenciesOf(name: string): string[];
382
384
  dependentsOf(name: string): string[];
383
385
  }
@@ -1,5 +1,5 @@
1
- import { G as WebSkillError, Z as isValidSkillName, it as validateSkills, rt as resolveInsideRoot } from "./dist-D405AlPD.js";
2
- import { i as NodeFS } from "./dist-Ixnb-hNR.js";
1
+ import { E as validateSkills, T as resolveInsideRoot, u as WebSkillError, v as isValidSkillName } from "./memoryArtifactStore-C9lFVqPF-U8nXvqL9.js";
2
+ import { i as NodeFS } from "./dist-DfKKj86A.js";
3
3
  import path from "node:path";
4
4
  import { mkdtemp } from "node:fs/promises";
5
5
  import { tmpdir } from "node:os";
@@ -731,8 +731,7 @@ var SimilarityDetector = class {
731
731
  for (const skill of existing) if (jaccardSimilarity(description, skill.description) >= this.#threshold) return skill.name;
732
732
  }
733
733
  };
734
- /** 技能引用依赖图(references/ 中引用其他技能的声明关系) */
735
- var DependencyGraph = class {
734
+ var DependencyGraph = class DependencyGraph {
736
735
  #edges = /* @__PURE__ */ new Map();
737
736
  addDependency(from, to) {
738
737
  if (from === to) return;
@@ -740,6 +739,16 @@ var DependencyGraph = class {
740
739
  set.add(to);
741
740
  this.#edges.set(from, set);
742
741
  }
742
+ /** 从 frontmatter dependencies 声明建图(0.0.6 装配函数;只收录 Catalog 内技能之间的边) */
743
+ static buildFromCatalog(entries, documents) {
744
+ const names = new Set(entries.map((e) => e.name));
745
+ const graph = new DependencyGraph();
746
+ for (const doc of documents) {
747
+ if (!names.has(doc.metadata.name)) continue;
748
+ for (const dep of doc.metadata.dependencies ?? []) if (names.has(dep)) graph.addDependency(doc.metadata.name, dep);
749
+ }
750
+ return graph;
751
+ }
743
752
  dependenciesOf(name) {
744
753
  return [...this.#edges.get(name) ?? []].sort();
745
754
  }
@@ -1,4 +1,5 @@
1
- import { A as InteractionResponse, Gt as FileSystemProvider, Kt as JsonSchema, S as FsMemoryStore, Wt as FileStat, Y as NetworkPolicy, _t as ToolDefinition, an as SkillManifest, c as ApprovalScope, d as BridgeCapabilities, dn as VerifyResult, ht as ScriptExecutor, it as RenderResultRequest, k as InteractionRequest, ln as SkillsLockfile, mt as ScriptExecutionContext, nn as SkillInstallSource, pt as SchemaInferer, wt as UiBridge, x as FsArtifactStore, yt as ToolResult } from "./index-BQDc-U1x.js";
1
+ import { C as JsonSchema, H as SkillsLockfile, L as SkillManifest, P as SkillInstallSource, S as FileSystemProvider, W as VerifyResult, _ as RenderResultRequest, o as InteractionRequest, s as InteractionResponse, v as UiBridge, x as FileStat } from "./types-CgNC-oQu-DCklnS0h.js";
2
+ import { G as SchemaInferer, K as ScriptExecutionContext, Y as ToolDefinition, Z as ToolResult, c as ApprovalScope, k as NetworkPolicy, l as BridgeCapabilities, q as ScriptExecutor, v as FsArtifactStore, y as FsMemoryStore } from "./index-S8uza3ld.js";
2
3
  import { Readable, Writable } from "node:stream";
3
4
  //#region ../node/dist/index.d.ts
4
5
  //#region src/fs/nodeFs.d.ts
@@ -134,6 +135,7 @@ declare class CliUiBridge implements UiBridge {
134
135
  /**
135
136
  * 技能管理门面:统一安装管线(staging → 解析 name → 校验 → 拷贝 → manifest → lockfile),
136
137
  * 任何失败清理现场抛 INSTALL_FAILED。
138
+ * @stable
137
139
  */
138
140
  declare class SkillManager {
139
141
  #private;
@@ -154,6 +156,10 @@ declare class SkillManager {
154
156
  format: 'zip' | 'tar';
155
157
  outPath: string;
156
158
  }): Promise<string>;
159
+ /** 多技能包集导出(webskill.skill-pack.json + 各技能目录含 manifest),写 outPath 并返回 */
160
+ exportPack(names: string[], options: {
161
+ outPath: string;
162
+ }): Promise<string>;
157
163
  }
158
164
  //#endregion
159
165
  //#region src/skillManagement/export/archiveExporter.d.ts