@webskill/sdk 0.7.0 → 0.9.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/agent.d.ts +1 -1
- package/dist/agent.js +1 -1
- package/dist/browser.d.ts +151 -4
- package/dist/browser.js +269 -30
- package/dist/{catalogComponents-Dr5dFMAb-DKH_7VPI.js → catalogComponents-DfxxfUvn-T7Ic8QFV.js} +4026 -997
- package/dist/{dist-DnYG2-eY.js → dist-BQe1uglQ.js} +498 -118
- package/dist/{dist-8oQRa8Xz.js → dist-Bev6i6Ip.js} +102 -7
- package/dist/{dist-D0qW6e40.js → dist-CFmkV45C.js} +234 -27
- package/dist/{eventTypes-DjIQpt8Y-Bj3vghj4.js → eventTypes-DbOpAECr-BjcjZVms.js} +15 -2
- package/dist/governance.d.ts +24 -3
- package/dist/governance.js +30 -11
- package/dist/{index-BwsK9lGk.d.ts → index-DXNTIa-6.d.ts} +163 -6
- package/dist/{index-Ba3xFtfz.d.ts → index-lLcCpHE-.d.ts} +2 -2
- package/dist/{index-DkbABR43.d.ts → index-znZjobkr.d.ts} +144 -76
- package/dist/index.d.ts +11 -3
- package/dist/index.js +13 -4
- package/dist/mcp.d.ts +13 -2
- package/dist/mcp.js +19 -5
- package/dist/{memoryArtifactStore-52Zn9npI-BMPYwvoy.js → memoryArtifactStore-52Zn9npI-LbCQaqyx.js} +1 -1
- package/dist/node.d.ts +3 -3
- package/dist/node.js +6 -6
- package/dist/{openUiLibrary-Bdrji9qK-D2LxmM-a.js → openUiLibrary-DURlAxjk-Do_yqg3u.js} +3 -3
- package/dist/{skillVersionStore-Bl-ElD45-CWPvGvoq.d.ts → skillVersionStore-Bl-ElD45-dMJ8Ybhb.d.ts} +1 -1
- package/dist/{testing-CYTFqkDm.js → testing-Csg5ljNm.js} +2 -2
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +2 -2
- package/dist/{types-CcxRLdJG-DCXyw1US.d.ts → types-B3n0cMZu-BDhheIhX.d.ts} +54 -6
- package/dist/ui-react.d.ts +19 -6
- package/dist/ui-react.js +156 -84
- package/dist/ui-vue.d.ts +1 -1
- package/dist/ui-vue.js +2 -2
- package/dist/ui.d.ts +4 -4
- package/dist/ui.js +3 -3
- package/dist/{webskillLitCatalog-_mugzRHx-B_54vxum.js → webskillLitCatalog-DwTwSBFt-BG7kL-Es.js} +22 -3
- package/package.json +2 -2
|
@@ -76,6 +76,14 @@ function verifyManifest(manifest, actualHashes, actualFiles = [...actualHashes.k
|
|
|
76
76
|
};
|
|
77
77
|
}
|
|
78
78
|
/**
|
|
79
|
+
* 原子写的临时文件名后缀模式;列举/打包侧据此排除中断残留(0.9.0 分册 11)。
|
|
80
|
+
* 单一来源:不要在别处手写正则(AC-G10),复制正则必然漂移。
|
|
81
|
+
* @stable
|
|
82
|
+
*/
|
|
83
|
+
const ATOMIC_TMP_SUFFIX_PATTERN = /\.tmp-\d+-[a-z0-9]+$/;
|
|
84
|
+
/** 该路径是否是 atomicWriteText 留下的临时文件 */
|
|
85
|
+
const isAtomicTempPath = (path) => ATOMIC_TMP_SUFFIX_PATTERN.test(path);
|
|
86
|
+
/**
|
|
79
87
|
* 原子写文本:先写临时文件再 rename(进程崩溃不留下半写文件;lockfile 等账本场景)。
|
|
80
88
|
* 原子性强弱取决于 provider 的 rename 实现:NodeFS/MemoryFS 为真 rename;
|
|
81
89
|
* OPFS 无原生 move,rename 是 copy+delete(非原子,崩溃可能残留双份),
|
|
@@ -656,7 +664,7 @@ async function listFilesRecursive(fs, root, prefix = "") {
|
|
|
656
664
|
for (const entry of await fs.list(root)) {
|
|
657
665
|
const rel = prefix === "" ? baseName$1(entry.path) : `${prefix}/${baseName$1(entry.path)}`;
|
|
658
666
|
if (entry.type === "directory") out.push(...await listFilesRecursive(fs, entry.path, rel));
|
|
659
|
-
else out.push(rel);
|
|
667
|
+
else if (!isAtomicTempPath(baseName$1(entry.path))) out.push(rel);
|
|
660
668
|
}
|
|
661
669
|
return out;
|
|
662
670
|
}
|
|
@@ -714,6 +722,87 @@ function parseSkillPackManifest(text) {
|
|
|
714
722
|
}
|
|
715
723
|
return raw;
|
|
716
724
|
}
|
|
725
|
+
const SKILL_FILE = "SKILL.md";
|
|
726
|
+
function normalize(path) {
|
|
727
|
+
return path.replace(/^\.?\//, "");
|
|
728
|
+
}
|
|
729
|
+
/**
|
|
730
|
+
* 按归档条目表判定包结构。
|
|
731
|
+
*
|
|
732
|
+
* 入参是条目表而不是文件系统:预览侧只有解压后的 entries,没有落盘的目录。
|
|
733
|
+
* 只看路径,不读内容——内容合法性由 checkSkillRules 负责,两者不重叠。
|
|
734
|
+
*/
|
|
735
|
+
function detectSkillArchiveShape(entries) {
|
|
736
|
+
const paths = [];
|
|
737
|
+
for (const raw of entries) {
|
|
738
|
+
const p = normalize(raw);
|
|
739
|
+
if (p !== "") paths.push(p);
|
|
740
|
+
}
|
|
741
|
+
if (paths.length === 0) return {
|
|
742
|
+
shape: "invalid",
|
|
743
|
+
reason: "Archive is empty."
|
|
744
|
+
};
|
|
745
|
+
if (paths.includes("webskill.skill-pack.json")) return { shape: "pack-set" };
|
|
746
|
+
if (paths.includes(SKILL_FILE)) return { shape: "flat" };
|
|
747
|
+
const topLevels = /* @__PURE__ */ new Set();
|
|
748
|
+
let hasLooseRootFile = false;
|
|
749
|
+
for (const p of paths) {
|
|
750
|
+
const slash = p.indexOf("/");
|
|
751
|
+
if (slash <= 0) hasLooseRootFile = true;
|
|
752
|
+
else topLevels.add(p.slice(0, slash));
|
|
753
|
+
}
|
|
754
|
+
if (!hasLooseRootFile && topLevels.size === 1) {
|
|
755
|
+
const [dir] = [...topLevels];
|
|
756
|
+
if (dir !== void 0) {
|
|
757
|
+
if (paths.includes(`${dir}/webskill.skill-pack.json`)) return {
|
|
758
|
+
shape: "pack-set",
|
|
759
|
+
rootDir: dir
|
|
760
|
+
};
|
|
761
|
+
if (paths.includes(`${dir}/${SKILL_FILE}`)) return {
|
|
762
|
+
shape: "nested-single",
|
|
763
|
+
rootDir: dir
|
|
764
|
+
};
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
return {
|
|
768
|
+
shape: "invalid",
|
|
769
|
+
reason: `Archive does not contain a ${SKILL_FILE} at its root or in a single top-level directory.`
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
/** nested-single 时剥掉顶层目录,其余形态原样返回 */
|
|
773
|
+
function stripArchiveRoot(entries, detection) {
|
|
774
|
+
if (detection.rootDir === void 0) return entries;
|
|
775
|
+
const prefix = `${detection.rootDir}/`;
|
|
776
|
+
const out = {};
|
|
777
|
+
for (const [path, value] of Object.entries(entries)) {
|
|
778
|
+
const p = normalize(path);
|
|
779
|
+
if (!p.startsWith(prefix)) continue;
|
|
780
|
+
const rel = p.slice(prefix.length);
|
|
781
|
+
if (rel !== "") out[rel] = value;
|
|
782
|
+
}
|
|
783
|
+
return out;
|
|
784
|
+
}
|
|
785
|
+
/**
|
|
786
|
+
* 文件系统入口:安装管线拿到的是解压后的目录,不是条目表。
|
|
787
|
+
*
|
|
788
|
+
* 只探测判定所需的少量路径(不递归全量列举),再交给上面的纯函数——
|
|
789
|
+
* 判定规则仍然只有一份,这正是 S7 的目的。
|
|
790
|
+
*/
|
|
791
|
+
async function detectSkillArchiveShapeFromFs(fs, contentDir) {
|
|
792
|
+
const sample = [];
|
|
793
|
+
const top = await fs.list(contentDir);
|
|
794
|
+
for (const entry of top) {
|
|
795
|
+
const name = entry.path.slice(contentDir.length + 1);
|
|
796
|
+
if (entry.type !== "directory") {
|
|
797
|
+
sample.push(name);
|
|
798
|
+
continue;
|
|
799
|
+
}
|
|
800
|
+
if (await fs.exists(`${entry.path}/${SKILL_FILE}`)) sample.push(`${name}/${SKILL_FILE}`);
|
|
801
|
+
else if (await fs.exists(`${entry.path}/webskill.skill-pack.json`)) sample.push(`${name}/${SKILL_PACK_FILE}`);
|
|
802
|
+
else sample.push(`${name}/`);
|
|
803
|
+
}
|
|
804
|
+
return detectSkillArchiveShape(sample);
|
|
805
|
+
}
|
|
717
806
|
const DEFAULT_ARCHIVE_LIMITS = {
|
|
718
807
|
maxDownloadBytes: 64 * 1024 * 1024,
|
|
719
808
|
maxEntryBytes: 64 * 1024 * 1024,
|
|
@@ -854,12 +943,15 @@ const baseName = (path) => path.split("/").pop() ?? path;
|
|
|
854
943
|
var SkillDiscovery = class {
|
|
855
944
|
#fs;
|
|
856
945
|
#roots;
|
|
946
|
+
/** 扫描范围之外已知存在的技能名:只影响 dependencies 存在性判定,不产生目录项 */
|
|
947
|
+
#extraKnownSkillNames;
|
|
857
948
|
/** name → skillRoot,与 SkillReader 共享同一 Map 引用 */
|
|
858
949
|
#index = /* @__PURE__ */ new Map();
|
|
859
950
|
#reader;
|
|
860
|
-
constructor(fs, roots) {
|
|
951
|
+
constructor(fs, roots, options) {
|
|
861
952
|
this.#fs = fs;
|
|
862
953
|
this.#roots = roots;
|
|
954
|
+
this.#extraKnownSkillNames = options?.extraKnownSkillNames ?? [];
|
|
863
955
|
this.#reader = new SkillReader(fs, this.#index);
|
|
864
956
|
}
|
|
865
957
|
async discover() {
|
|
@@ -867,7 +959,7 @@ var SkillDiscovery = class {
|
|
|
867
959
|
const entries = [];
|
|
868
960
|
const issues = [];
|
|
869
961
|
const candidates = [];
|
|
870
|
-
const knownSkillNames =
|
|
962
|
+
const knownSkillNames = new Set(this.#extraKnownSkillNames);
|
|
871
963
|
const adjacency = /* @__PURE__ */ new Map();
|
|
872
964
|
for (const [rootIndex, root] of this.#roots.entries()) {
|
|
873
965
|
if (!await this.#fs.exists(root)) {
|
|
@@ -940,7 +1032,7 @@ var SkillDiscovery = class {
|
|
|
940
1032
|
});
|
|
941
1033
|
}
|
|
942
1034
|
issues.push(...cycles.issues);
|
|
943
|
-
const admitted = new Set(entries.map((e) => e.name));
|
|
1035
|
+
const admitted = /* @__PURE__ */ new Set([...entries.map((e) => e.name), ...this.#extraKnownSkillNames]);
|
|
944
1036
|
let changed = true;
|
|
945
1037
|
while (changed) {
|
|
946
1038
|
changed = false;
|
|
@@ -996,9 +1088,12 @@ var SkillDiscovery = class {
|
|
|
996
1088
|
/**
|
|
997
1089
|
* 合规校验。内部直接复用 SkillDiscovery 的扫描逻辑,
|
|
998
1090
|
* 规则判定同样落在 checkSkillRules 单一来源上。
|
|
1091
|
+
*
|
|
1092
|
+
* `extraKnownSkillNames`:扫描范围之外已存在的技能名。安装时只扫刚解出来的那一个目录,
|
|
1093
|
+
* 不告诉它库里还有谁,任何指向包外的 dependencies 都会被判成不存在。
|
|
999
1094
|
*/
|
|
1000
|
-
async function validateSkills(fs, roots) {
|
|
1001
|
-
const { issues } = await new SkillDiscovery(fs, roots).discover();
|
|
1095
|
+
async function validateSkills(fs, roots, options) {
|
|
1096
|
+
const { issues } = await new SkillDiscovery(fs, roots, options).discover();
|
|
1002
1097
|
return {
|
|
1003
1098
|
ok: !issues.some((i) => i.severity === "error"),
|
|
1004
1099
|
issues
|
|
@@ -1035,4 +1130,4 @@ const xmlRenderer = {
|
|
|
1035
1130
|
};
|
|
1036
1131
|
|
|
1037
1132
|
//#endregion
|
|
1038
|
-
export {
|
|
1133
|
+
export { jsonRenderer as A, resolveArchiveLimits as B, computeDigest as C, exportSkills as D, escapeXml as E, parseSkillPackManifest as F, unzipWithLimits as G, signSkill as H, readResponseWithLimit as I, verifySkillSignature as J, validateSkills as K, readSkillSignature as L, messageOf as M, normalizePath as N, isAtomicTempPath as O, parseSkillMarkdown as P, renderAvailableSkillsXml as R, checkSkillRules as S, detectSkillArchiveShapeFromFs as T, signaturePayloadBytes as U, resolveInsideRoot as V, stripArchiveRoot as W, xmlRenderer as Y, assertSafePathSegment as _, MemoryFS as a, buildManifest as b, SKILL_MANIFEST_FILE as c, SKILL_PACK_FILE as d, SKILL_SIGNATURE_FILE as f, assertRemoteUrlAllowed as g, WebSkillError as h, MANIFEST_EXCLUDED_FILES as i, keyIdOf as j, isValidSkillName as k, SKILL_NAME_MAX_LENGTH as l, SkillReader as m, DEFAULT_ARCHIVE_LIMITS as n, SIGNATURE_SCHEMA_VERSION as o, SkillDiscovery as p, verifyManifest as q, FsTrustedKeyStore as r, SKILLS_LOCKFILE as s, ATOMIC_TMP_SUFFIX_PATTERN as t, SKILL_NAME_PATTERN as u, atomicWriteText as v, detectSkillArchiveShape as w, checkDependencyCycles as x, buildCatalog as y, renderCatalogJson as z };
|