@batonfx/skills 0.7.1 → 0.8.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/hosted-catalog.js +2 -26
- package/dist/skill-document.js +2 -16
- package/package.json +2 -2
package/dist/hosted-catalog.js
CHANGED
|
@@ -3,18 +3,9 @@ import { HttpClient, HttpClientRequest, HttpClientResponse, Url } from "effect/u
|
|
|
3
3
|
import { SkillSource } from "@batonfx/core";
|
|
4
4
|
import { parseDocument, validateName } from "./skill-document.js";
|
|
5
5
|
const ManifestSkill = Schema.Struct({
|
|
6
|
-
|
|
7
|
-
description: Schema.String,
|
|
6
|
+
...SkillSource.Frontmatter.fields,
|
|
8
7
|
skillPath: Schema.String,
|
|
9
8
|
sha256: Schema.String,
|
|
10
|
-
whenToUse: Schema.optionalKey(Schema.String),
|
|
11
|
-
allowedTools: Schema.optionalKey(Schema.Array(Schema.String)),
|
|
12
|
-
disableModelInvocation: Schema.optionalKey(Schema.Boolean),
|
|
13
|
-
userInvocable: Schema.optionalKey(Schema.Boolean),
|
|
14
|
-
contextFork: Schema.optionalKey(Schema.Boolean),
|
|
15
|
-
agent: Schema.optionalKey(Schema.String),
|
|
16
|
-
model: Schema.optionalKey(Schema.String),
|
|
17
|
-
paths: Schema.optionalKey(Schema.Array(Schema.String)),
|
|
18
9
|
});
|
|
19
10
|
const Manifest = Schema.Struct({
|
|
20
11
|
version: Schema.Literal(1),
|
|
@@ -51,18 +42,6 @@ const decodeText = (source, bytes) => Effect.try({
|
|
|
51
42
|
try: () => decoder.decode(bytes),
|
|
52
43
|
catch: (cause) => sourceError(source, "Hosted skill response is not valid UTF-8", cause),
|
|
53
44
|
});
|
|
54
|
-
const frontmatter = (entry) => ({
|
|
55
|
-
name: entry.name,
|
|
56
|
-
description: entry.description,
|
|
57
|
-
...(entry.whenToUse === undefined ? {} : { whenToUse: entry.whenToUse }),
|
|
58
|
-
...(entry.allowedTools === undefined ? {} : { allowedTools: entry.allowedTools }),
|
|
59
|
-
...(entry.disableModelInvocation === undefined ? {} : { disableModelInvocation: entry.disableModelInvocation }),
|
|
60
|
-
...(entry.userInvocable === undefined ? {} : { userInvocable: entry.userInvocable }),
|
|
61
|
-
...(entry.contextFork === undefined ? {} : { contextFork: entry.contextFork }),
|
|
62
|
-
...(entry.agent === undefined ? {} : { agent: entry.agent }),
|
|
63
|
-
...(entry.model === undefined ? {} : { model: entry.model }),
|
|
64
|
-
...(entry.paths === undefined ? {} : { paths: entry.paths }),
|
|
65
|
-
});
|
|
66
45
|
const sameFrontmatter = (left, right) => JSON.stringify(left) === JSON.stringify(right);
|
|
67
46
|
/** @experimental Validate one safe relative SKILL.md path. */
|
|
68
47
|
export const validateSkillPath = Function.dual(2, (source, skillPath) => {
|
|
@@ -105,9 +84,6 @@ export const make = (options) => Effect.gen(function* () {
|
|
|
105
84
|
const byName = new Map();
|
|
106
85
|
for (const entry of manifest.skills) {
|
|
107
86
|
yield* validateName(options.source, entry.name);
|
|
108
|
-
if (entry.description.length === 0 || entry.description.length > 1_024) {
|
|
109
|
-
return yield* sourceError(options.source, "Hosted skill description must contain 1-1024 characters");
|
|
110
|
-
}
|
|
111
87
|
if (!/^[0-9a-f]{64}$/.test(entry.sha256)) {
|
|
112
88
|
return yield* sourceError(options.source, `Invalid SHA-256 for hosted skill ${entry.name}`);
|
|
113
89
|
}
|
|
@@ -119,7 +95,7 @@ export const make = (options) => Effect.gen(function* () {
|
|
|
119
95
|
return yield* sourceError(options.source, `Hosted skill path directory must match skill name: ${entry.name}`);
|
|
120
96
|
}
|
|
121
97
|
const skillUrl = yield* options.resolveSkillUrl(entry.skillPath);
|
|
122
|
-
const metadata =
|
|
98
|
+
const { sha256: _, skillPath: __, ...metadata } = entry;
|
|
123
99
|
const body = fetchBytes(client, options.source, skillUrl, options.bodyHeaders, bodyMaxBytes).pipe(Effect.flatMap((bytes) => crypto.digest("SHA-256", bytes).pipe(Effect.mapError((error) => sourceError(options.source, `Unable to hash hosted skill ${entry.name}`, error)), Effect.flatMap((actual) => Encoding.encodeHex(actual) === entry.sha256
|
|
124
100
|
? decodeText(options.source, bytes)
|
|
125
101
|
: Effect.fail(sourceError(options.source, `SHA-256 mismatch for hosted skill ${entry.name}`))))), Effect.flatMap((content) => parseDocument(options.source, content, entry.name).pipe(Effect.flatMap((document) => sameFrontmatter(document.frontmatter, metadata)
|
package/dist/skill-document.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Effect, Function } from "effect";
|
|
1
|
+
import { Effect, Function, Schema } from "effect";
|
|
2
2
|
import { SkillSource } from "@batonfx/core";
|
|
3
3
|
const sourceError = (source, message, cause) => SkillSource.SkillSourceError.make({ source, message, ...(cause === undefined ? {} : { cause }) });
|
|
4
4
|
const normalizeKey = (key) => key.replace(/[-_]/g, "").toLowerCase();
|
|
@@ -122,21 +122,7 @@ export const parseFrontmatter = Function.dual(3, (source, block, directoryName)
|
|
|
122
122
|
if (parsed.name !== directoryName) {
|
|
123
123
|
return yield* sourceError(source, `SKILL.md name must match directory ${directoryName}`);
|
|
124
124
|
}
|
|
125
|
-
|
|
126
|
-
return yield* sourceError(source, "SKILL.md description must contain 1-1024 characters");
|
|
127
|
-
}
|
|
128
|
-
return {
|
|
129
|
-
name: parsed.name,
|
|
130
|
-
description: parsed.description,
|
|
131
|
-
...(parsed.whenToUse === undefined ? {} : { whenToUse: parsed.whenToUse }),
|
|
132
|
-
...(parsed.allowedTools === undefined ? {} : { allowedTools: parsed.allowedTools }),
|
|
133
|
-
...(parsed.disableModelInvocation === undefined ? {} : { disableModelInvocation: parsed.disableModelInvocation }),
|
|
134
|
-
...(parsed.userInvocable === undefined ? {} : { userInvocable: parsed.userInvocable }),
|
|
135
|
-
...(parsed.contextFork === undefined ? {} : { contextFork: parsed.contextFork }),
|
|
136
|
-
...(parsed.agent === undefined ? {} : { agent: parsed.agent }),
|
|
137
|
-
...(parsed.model === undefined ? {} : { model: parsed.model }),
|
|
138
|
-
...(parsed.paths === undefined ? {} : { paths: parsed.paths }),
|
|
139
|
-
};
|
|
125
|
+
return yield* Schema.decodeUnknownEffect(SkillSource.Frontmatter)(parsed).pipe(Effect.mapError((cause) => sourceError(source, `SKILL.md description must contain 1-${SkillSource.DESCRIPTION_CAP} characters`, cause)));
|
|
140
126
|
}));
|
|
141
127
|
export const parseDocument = Function.dual(3, (source, content, directoryName) => Effect.gen(function* () {
|
|
142
128
|
const [header, body] = yield* splitDocument(source, content);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "@batonfx/skills",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.8.0",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
7
7
|
"exports": {
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"typecheck": "bun tsc --noEmit"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@batonfx/core": "0.
|
|
20
|
+
"@batonfx/core": "0.8.0",
|
|
21
21
|
"effect": "4.0.0-beta.98"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|