botlearn 0.0.1 → 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.
- package/LICENSE +21 -0
- package/README.md +89 -8
- package/dist/index.cjs +172 -0
- package/dist/index.d.cts +150 -0
- package/dist/index.d.ts +147 -7
- package/dist/index.js +141 -34
- package/package.json +32 -29
- package/dist/index.d.mts +0 -10
- package/dist/index.js.map +0 -1
- package/dist/index.mjs +0 -10
- package/dist/index.mjs.map +0 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 BotLearn
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,25 +1,106 @@
|
|
|
1
1
|
# botlearn
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
BotLearn OpenClaw Skills SDK — types, validator, and utilities for `@botlearn/*` skill packages.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
+
# Install the SDK (for building custom skills or tools)
|
|
8
9
|
npm install botlearn
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
|
|
11
|
+
# Install individual skills into your Agent
|
|
12
|
+
npm install @botlearn/google-search
|
|
13
|
+
npm install @botlearn/code-gen
|
|
14
|
+
clawhub install @botlearn/google-search
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Skills
|
|
18
|
+
|
|
19
|
+
### Information Retrieval (5)
|
|
20
|
+
|
|
21
|
+
| Skill | Description | Dependencies |
|
|
22
|
+
|-------|-------------|-------------|
|
|
23
|
+
| `@botlearn/google-search` | Web search query optimization and result curation | — |
|
|
24
|
+
| `@botlearn/academic-search` | Academic paper discovery and literature review | google-search |
|
|
25
|
+
| `@botlearn/rss-manager` | RSS/Atom feed monitoring, deduplication, and digest generation | — |
|
|
26
|
+
| `@botlearn/twitter-intel` | Twitter/X intelligence gathering and trend analysis | — |
|
|
27
|
+
| `@botlearn/reddit-tracker` | Reddit trend detection and cross-subreddit correlation | — |
|
|
28
|
+
|
|
29
|
+
### Content Processing (5)
|
|
30
|
+
|
|
31
|
+
| Skill | Description | Dependencies |
|
|
32
|
+
|-------|-------------|-------------|
|
|
33
|
+
| `@botlearn/summarizer` | Multi-format content summarization with discourse analysis | — |
|
|
34
|
+
| `@botlearn/translator` | Context-aware translation with terminology management | — |
|
|
35
|
+
| `@botlearn/rewriter` | Audience-adaptive content rewriting and style transformation | summarizer |
|
|
36
|
+
| `@botlearn/keyword-extractor` | Multi-layer keyword and keyphrase extraction | — |
|
|
37
|
+
| `@botlearn/sentiment-analyzer` | Aspect-level sentiment analysis with sarcasm detection | — |
|
|
38
|
+
|
|
39
|
+
### Programming Assistance (5)
|
|
40
|
+
|
|
41
|
+
| Skill | Description | Dependencies |
|
|
42
|
+
|-------|-------------|-------------|
|
|
43
|
+
| `@botlearn/code-gen` | Multi-language code generation with architecture-aware design | — |
|
|
44
|
+
| `@botlearn/code-review` | Security, performance, and quality code review (OWASP Top 10) | — |
|
|
45
|
+
| `@botlearn/debugger` | Systematic bug diagnosis and root cause analysis | code-review |
|
|
46
|
+
| `@botlearn/refactor` | Design-pattern-driven code refactoring | code-review |
|
|
47
|
+
| `@botlearn/doc-gen` | API documentation and README generation | code-gen |
|
|
48
|
+
|
|
49
|
+
### Creative Generation (5)
|
|
50
|
+
|
|
51
|
+
| Skill | Description | Dependencies |
|
|
52
|
+
|-------|-------------|-------------|
|
|
53
|
+
| `@botlearn/brainstorm` | Structured creative ideation (SCAMPER, Six Hats, TRIZ) | — |
|
|
54
|
+
| `@botlearn/storyteller` | Narrative craft across genres and structures | — |
|
|
55
|
+
| `@botlearn/writer` | Long-form article writing with argument frameworks | summarizer, keyword-extractor |
|
|
56
|
+
| `@botlearn/copywriter` | Persuasion-framework-driven marketing copy | sentiment-analyzer |
|
|
57
|
+
| `@botlearn/social-media` | Platform-native social media content creation | copywriter |
|
|
58
|
+
|
|
59
|
+
## Skill Package Structure
|
|
60
|
+
|
|
61
|
+
Each skill is an independent npm package with a standardized structure:
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
@botlearn/<skill-name>/ # npm package
|
|
65
|
+
├── package.json # npm package config
|
|
66
|
+
├── manifest.json # Skill metadata: category, benchmark dimension
|
|
67
|
+
├── skill.md # Role definition, triggers, activation rules
|
|
68
|
+
├── knowledge/
|
|
69
|
+
│ ├── domain.md # Domain expertise
|
|
70
|
+
│ ├── best-practices.md # Quality standards
|
|
71
|
+
│ └── anti-patterns.md # Common mistakes to avoid
|
|
72
|
+
├── strategies/
|
|
73
|
+
│ └── main.md # Step-by-step behavioral strategy
|
|
74
|
+
└── tests/
|
|
75
|
+
├── smoke.json # 1 task, < 60s, pass threshold 60/100
|
|
76
|
+
└── benchmark.json # 10 tasks (3 easy, 4 medium, 3 hard)
|
|
13
77
|
```
|
|
14
78
|
|
|
15
|
-
##
|
|
79
|
+
## SDK API
|
|
16
80
|
|
|
17
81
|
```typescript
|
|
18
|
-
import {
|
|
82
|
+
import { validateManifest } from "botlearn";
|
|
83
|
+
import type { SkillManifest, ValidationResult } from "botlearn";
|
|
19
84
|
|
|
20
|
-
|
|
85
|
+
// Validate a manifest
|
|
86
|
+
const result: ValidationResult = validateManifest(manifest, knownSkillNames);
|
|
87
|
+
console.log(result.valid, result.errors);
|
|
21
88
|
```
|
|
22
89
|
|
|
90
|
+
## Publishing
|
|
91
|
+
|
|
92
|
+
Each skill is published independently to npm:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
cd packages/skills/google-search
|
|
96
|
+
npm publish --access public # publishes @botlearn/google-search
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Compatibility
|
|
100
|
+
|
|
101
|
+
- OpenClaw Agent: `>=0.5.0`
|
|
102
|
+
- Node.js: `>=18`
|
|
103
|
+
|
|
23
104
|
## License
|
|
24
105
|
|
|
25
106
|
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
VALID_CATEGORIES: () => VALID_CATEGORIES,
|
|
24
|
+
VALID_DIMENSIONS: () => VALID_DIMENSIONS,
|
|
25
|
+
validateManifest: () => validateManifest
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(index_exports);
|
|
28
|
+
|
|
29
|
+
// src/validator.ts
|
|
30
|
+
var VALID_CATEGORIES = [
|
|
31
|
+
"information-retrieval",
|
|
32
|
+
"content-processing",
|
|
33
|
+
"programming-assistance",
|
|
34
|
+
"creative-generation"
|
|
35
|
+
];
|
|
36
|
+
var VALID_DIMENSIONS = [
|
|
37
|
+
"information-retrieval",
|
|
38
|
+
"content-understanding",
|
|
39
|
+
"logical-reasoning",
|
|
40
|
+
"code-generation",
|
|
41
|
+
"creative-generation"
|
|
42
|
+
];
|
|
43
|
+
var SEMVER_RE = /^\d+\.\d+\.\d+(?:-[\w.]+)?(?:\+[\w.]+)?$/;
|
|
44
|
+
var SEMVER_RANGE_RE = /^(?:[~^]?\d+\.\d+\.\d+(?:-[\w.]+)?|>=?\d+\.\d+\.\d+)$/;
|
|
45
|
+
var SKILL_NAME_RE = /^@botlearn\/[a-z][a-z0-9-]*$/;
|
|
46
|
+
function validateManifest(manifest, knownSkillNames) {
|
|
47
|
+
const errors = [];
|
|
48
|
+
if (manifest === null || typeof manifest !== "object") {
|
|
49
|
+
return { valid: false, errors: [{ field: "(root)", message: "Manifest must be a non-null object" }] };
|
|
50
|
+
}
|
|
51
|
+
const m = manifest;
|
|
52
|
+
requireString(m, "name", errors);
|
|
53
|
+
requireString(m, "version", errors);
|
|
54
|
+
requireString(m, "description", errors);
|
|
55
|
+
requireString(m, "author", errors);
|
|
56
|
+
if (typeof m.name === "string" && !SKILL_NAME_RE.test(m.name)) {
|
|
57
|
+
errors.push({
|
|
58
|
+
field: "name",
|
|
59
|
+
message: `Name must match @botlearn/<kebab-case>, got "${m.name}"`
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
if (typeof m.version === "string" && !SEMVER_RE.test(m.version)) {
|
|
63
|
+
errors.push({
|
|
64
|
+
field: "version",
|
|
65
|
+
message: `Version must be valid semver, got "${m.version}"`
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
if (!VALID_CATEGORIES.includes(m.category)) {
|
|
69
|
+
errors.push({
|
|
70
|
+
field: "category",
|
|
71
|
+
message: `Category must be one of: ${VALID_CATEGORIES.join(", ")}`
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
if (!VALID_DIMENSIONS.includes(m.benchmarkDimension)) {
|
|
75
|
+
errors.push({
|
|
76
|
+
field: "benchmarkDimension",
|
|
77
|
+
message: `benchmarkDimension must be one of: ${VALID_DIMENSIONS.join(", ")}`
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
if (typeof m.expectedImprovement !== "number" || m.expectedImprovement < 0) {
|
|
81
|
+
errors.push({
|
|
82
|
+
field: "expectedImprovement",
|
|
83
|
+
message: "expectedImprovement must be a non-negative number"
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
if (m.dependencies !== void 0) {
|
|
87
|
+
if (typeof m.dependencies !== "object" || m.dependencies === null) {
|
|
88
|
+
errors.push({
|
|
89
|
+
field: "dependencies",
|
|
90
|
+
message: "dependencies must be an object"
|
|
91
|
+
});
|
|
92
|
+
} else {
|
|
93
|
+
const deps = m.dependencies;
|
|
94
|
+
for (const [depName, depVersion] of Object.entries(deps)) {
|
|
95
|
+
if (!SKILL_NAME_RE.test(depName)) {
|
|
96
|
+
errors.push({
|
|
97
|
+
field: `dependencies.${depName}`,
|
|
98
|
+
message: `Dependency name must match @botlearn/<kebab-case>`
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
if (typeof depVersion !== "string" || !SEMVER_RANGE_RE.test(depVersion)) {
|
|
102
|
+
errors.push({
|
|
103
|
+
field: `dependencies.${depName}`,
|
|
104
|
+
message: `Dependency version must be a valid semver range, got "${String(depVersion)}"`
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
if (knownSkillNames && !knownSkillNames.includes(depName)) {
|
|
108
|
+
errors.push({
|
|
109
|
+
field: `dependencies.${depName}`,
|
|
110
|
+
message: `Unknown dependency "${depName}" \u2014 not in known skills list`
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (typeof m.compatibility !== "object" || m.compatibility === null) {
|
|
117
|
+
errors.push({
|
|
118
|
+
field: "compatibility",
|
|
119
|
+
message: "compatibility must be an object with an openclaw field"
|
|
120
|
+
});
|
|
121
|
+
} else {
|
|
122
|
+
const compat = m.compatibility;
|
|
123
|
+
if (typeof compat.openclaw !== "string" || !SEMVER_RANGE_RE.test(compat.openclaw)) {
|
|
124
|
+
errors.push({
|
|
125
|
+
field: "compatibility.openclaw",
|
|
126
|
+
message: `compatibility.openclaw must be a valid semver range`
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
if (typeof m.files !== "object" || m.files === null) {
|
|
131
|
+
errors.push({
|
|
132
|
+
field: "files",
|
|
133
|
+
message: "files must be an object"
|
|
134
|
+
});
|
|
135
|
+
} else {
|
|
136
|
+
const files = m.files;
|
|
137
|
+
requireString(files, "skill", errors, "files.skill");
|
|
138
|
+
requireStringArray(files, "knowledge", errors, "files.knowledge");
|
|
139
|
+
requireStringArray(files, "strategies", errors, "files.strategies");
|
|
140
|
+
requireString(files, "smokeTest", errors, "files.smokeTest");
|
|
141
|
+
requireString(files, "benchmark", errors, "files.benchmark");
|
|
142
|
+
}
|
|
143
|
+
return { valid: errors.length === 0, errors };
|
|
144
|
+
}
|
|
145
|
+
function requireString(obj, field, errors, displayField) {
|
|
146
|
+
if (typeof obj[field] !== "string" || obj[field].length === 0) {
|
|
147
|
+
errors.push({
|
|
148
|
+
field: displayField ?? field,
|
|
149
|
+
message: `${displayField ?? field} is required and must be a non-empty string`
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
function requireStringArray(obj, field, errors, displayField) {
|
|
154
|
+
const val = obj[field];
|
|
155
|
+
if (!Array.isArray(val) || val.length === 0) {
|
|
156
|
+
errors.push({
|
|
157
|
+
field: displayField ?? field,
|
|
158
|
+
message: `${displayField ?? field} must be a non-empty array of strings`
|
|
159
|
+
});
|
|
160
|
+
} else if (val.some((item) => typeof item !== "string")) {
|
|
161
|
+
errors.push({
|
|
162
|
+
field: displayField ?? field,
|
|
163
|
+
message: `${displayField ?? field} must contain only strings`
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
168
|
+
0 && (module.exports = {
|
|
169
|
+
VALID_CATEGORIES,
|
|
170
|
+
VALID_DIMENSIONS,
|
|
171
|
+
validateManifest
|
|
172
|
+
});
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
type SkillCategory = "information-retrieval" | "content-processing" | "programming-assistance" | "creative-generation";
|
|
2
|
+
type BenchmarkDimension = "information-retrieval" | "content-understanding" | "logical-reasoning" | "code-generation" | "creative-generation";
|
|
3
|
+
type Difficulty = "easy" | "medium" | "hard";
|
|
4
|
+
type Priority = "high" | "medium" | "low";
|
|
5
|
+
type SkillPhase = "retrieval" | "reasoning" | "verification" | "reflection";
|
|
6
|
+
type IssueSeverity = "critical" | "high" | "medium" | "low";
|
|
7
|
+
interface SkillManifest {
|
|
8
|
+
name: string;
|
|
9
|
+
version: string;
|
|
10
|
+
description: string;
|
|
11
|
+
category: SkillCategory;
|
|
12
|
+
author: string;
|
|
13
|
+
benchmarkDimension: BenchmarkDimension;
|
|
14
|
+
expectedImprovement: number;
|
|
15
|
+
dependencies: Record<string, string>;
|
|
16
|
+
compatibility: {
|
|
17
|
+
openclaw: string;
|
|
18
|
+
};
|
|
19
|
+
files: {
|
|
20
|
+
skill: string;
|
|
21
|
+
knowledge: string[];
|
|
22
|
+
strategies: string[];
|
|
23
|
+
smokeTest: string;
|
|
24
|
+
benchmark: string;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
interface RubricItem {
|
|
28
|
+
criterion: string;
|
|
29
|
+
weight: number;
|
|
30
|
+
scoring: {
|
|
31
|
+
5: string;
|
|
32
|
+
3: string;
|
|
33
|
+
1: string;
|
|
34
|
+
0: string;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
interface SmokeTestTask {
|
|
38
|
+
id: string;
|
|
39
|
+
description: string;
|
|
40
|
+
input: string;
|
|
41
|
+
rubric: RubricItem[];
|
|
42
|
+
passThreshold: number;
|
|
43
|
+
}
|
|
44
|
+
interface SmokeTest {
|
|
45
|
+
version: string;
|
|
46
|
+
timeout: number;
|
|
47
|
+
tasks: SmokeTestTask[];
|
|
48
|
+
}
|
|
49
|
+
interface BenchmarkTask {
|
|
50
|
+
id: string;
|
|
51
|
+
difficulty: Difficulty;
|
|
52
|
+
description: string;
|
|
53
|
+
input: string;
|
|
54
|
+
rubric: RubricItem[];
|
|
55
|
+
expectedScoreWithout: number;
|
|
56
|
+
expectedScoreWith: number;
|
|
57
|
+
}
|
|
58
|
+
interface BenchmarkTest {
|
|
59
|
+
version: string;
|
|
60
|
+
dimension: BenchmarkDimension;
|
|
61
|
+
tasks: BenchmarkTask[];
|
|
62
|
+
}
|
|
63
|
+
interface MemoryDocument {
|
|
64
|
+
id: string;
|
|
65
|
+
content: string;
|
|
66
|
+
metadata: {
|
|
67
|
+
domain: string;
|
|
68
|
+
topic: string;
|
|
69
|
+
priority: Priority;
|
|
70
|
+
ttl?: string;
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
interface MemoryInjectRequest {
|
|
74
|
+
skillName: string;
|
|
75
|
+
documents: MemoryDocument[];
|
|
76
|
+
}
|
|
77
|
+
interface MemoryInjectResponse {
|
|
78
|
+
injected: number;
|
|
79
|
+
skipped: number;
|
|
80
|
+
errors: string[];
|
|
81
|
+
}
|
|
82
|
+
interface MemoryRollbackRequest {
|
|
83
|
+
skillName: string;
|
|
84
|
+
}
|
|
85
|
+
interface StrategyDocument {
|
|
86
|
+
id: string;
|
|
87
|
+
content: string;
|
|
88
|
+
steps: number;
|
|
89
|
+
}
|
|
90
|
+
interface SkillRegisterRequest {
|
|
91
|
+
skillName: string;
|
|
92
|
+
definition: string;
|
|
93
|
+
strategies: StrategyDocument[];
|
|
94
|
+
triggers: string[];
|
|
95
|
+
}
|
|
96
|
+
interface SkillRegisterResponse {
|
|
97
|
+
registered: boolean;
|
|
98
|
+
activeSkills: string[];
|
|
99
|
+
}
|
|
100
|
+
interface SkillUnregisterRequest {
|
|
101
|
+
skillName: string;
|
|
102
|
+
}
|
|
103
|
+
interface BenchmarkRunRequest {
|
|
104
|
+
tasks: Array<{
|
|
105
|
+
id: string;
|
|
106
|
+
input: string;
|
|
107
|
+
rubric: RubricItem[];
|
|
108
|
+
}>;
|
|
109
|
+
judgeModel: string;
|
|
110
|
+
runs: number;
|
|
111
|
+
}
|
|
112
|
+
interface TaskResult {
|
|
113
|
+
taskId: string;
|
|
114
|
+
output: string;
|
|
115
|
+
scores: number[];
|
|
116
|
+
medianScore: number;
|
|
117
|
+
rubricBreakdown: Array<{
|
|
118
|
+
criterion: string;
|
|
119
|
+
score: number;
|
|
120
|
+
feedback: string;
|
|
121
|
+
}>;
|
|
122
|
+
}
|
|
123
|
+
interface BenchmarkRunResponse {
|
|
124
|
+
results: TaskResult[];
|
|
125
|
+
aggregateScore: number;
|
|
126
|
+
}
|
|
127
|
+
interface SkillError {
|
|
128
|
+
skill: string;
|
|
129
|
+
phase: SkillPhase;
|
|
130
|
+
message: string;
|
|
131
|
+
recoverable: boolean;
|
|
132
|
+
suggestion?: string;
|
|
133
|
+
}
|
|
134
|
+
interface ValidationResult {
|
|
135
|
+
valid: boolean;
|
|
136
|
+
errors: ValidationError[];
|
|
137
|
+
}
|
|
138
|
+
interface ValidationError {
|
|
139
|
+
field: string;
|
|
140
|
+
message: string;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
declare const VALID_CATEGORIES: SkillCategory[];
|
|
144
|
+
declare const VALID_DIMENSIONS: BenchmarkDimension[];
|
|
145
|
+
/**
|
|
146
|
+
* Validate a SkillManifest object and return all discovered errors.
|
|
147
|
+
*/
|
|
148
|
+
declare function validateManifest(manifest: unknown, knownSkillNames?: string[]): ValidationResult;
|
|
149
|
+
|
|
150
|
+
export { type BenchmarkDimension, type BenchmarkRunRequest, type BenchmarkRunResponse, type BenchmarkTask, type BenchmarkTest, type Difficulty, type IssueSeverity, type MemoryDocument, type MemoryInjectRequest, type MemoryInjectResponse, type MemoryRollbackRequest, type Priority, type RubricItem, type SkillCategory, type SkillError, type SkillManifest, type SkillPhase, type SkillRegisterRequest, type SkillRegisterResponse, type SkillUnregisterRequest, type SmokeTest, type SmokeTestTask, type StrategyDocument, type TaskResult, VALID_CATEGORIES, VALID_DIMENSIONS, type ValidationError, type ValidationResult, validateManifest };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,150 @@
|
|
|
1
|
+
type SkillCategory = "information-retrieval" | "content-processing" | "programming-assistance" | "creative-generation";
|
|
2
|
+
type BenchmarkDimension = "information-retrieval" | "content-understanding" | "logical-reasoning" | "code-generation" | "creative-generation";
|
|
3
|
+
type Difficulty = "easy" | "medium" | "hard";
|
|
4
|
+
type Priority = "high" | "medium" | "low";
|
|
5
|
+
type SkillPhase = "retrieval" | "reasoning" | "verification" | "reflection";
|
|
6
|
+
type IssueSeverity = "critical" | "high" | "medium" | "low";
|
|
7
|
+
interface SkillManifest {
|
|
8
|
+
name: string;
|
|
9
|
+
version: string;
|
|
10
|
+
description: string;
|
|
11
|
+
category: SkillCategory;
|
|
12
|
+
author: string;
|
|
13
|
+
benchmarkDimension: BenchmarkDimension;
|
|
14
|
+
expectedImprovement: number;
|
|
15
|
+
dependencies: Record<string, string>;
|
|
16
|
+
compatibility: {
|
|
17
|
+
openclaw: string;
|
|
18
|
+
};
|
|
19
|
+
files: {
|
|
20
|
+
skill: string;
|
|
21
|
+
knowledge: string[];
|
|
22
|
+
strategies: string[];
|
|
23
|
+
smokeTest: string;
|
|
24
|
+
benchmark: string;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
interface RubricItem {
|
|
28
|
+
criterion: string;
|
|
29
|
+
weight: number;
|
|
30
|
+
scoring: {
|
|
31
|
+
5: string;
|
|
32
|
+
3: string;
|
|
33
|
+
1: string;
|
|
34
|
+
0: string;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
interface SmokeTestTask {
|
|
38
|
+
id: string;
|
|
39
|
+
description: string;
|
|
40
|
+
input: string;
|
|
41
|
+
rubric: RubricItem[];
|
|
42
|
+
passThreshold: number;
|
|
43
|
+
}
|
|
44
|
+
interface SmokeTest {
|
|
45
|
+
version: string;
|
|
46
|
+
timeout: number;
|
|
47
|
+
tasks: SmokeTestTask[];
|
|
48
|
+
}
|
|
49
|
+
interface BenchmarkTask {
|
|
50
|
+
id: string;
|
|
51
|
+
difficulty: Difficulty;
|
|
52
|
+
description: string;
|
|
53
|
+
input: string;
|
|
54
|
+
rubric: RubricItem[];
|
|
55
|
+
expectedScoreWithout: number;
|
|
56
|
+
expectedScoreWith: number;
|
|
57
|
+
}
|
|
58
|
+
interface BenchmarkTest {
|
|
59
|
+
version: string;
|
|
60
|
+
dimension: BenchmarkDimension;
|
|
61
|
+
tasks: BenchmarkTask[];
|
|
62
|
+
}
|
|
63
|
+
interface MemoryDocument {
|
|
64
|
+
id: string;
|
|
65
|
+
content: string;
|
|
66
|
+
metadata: {
|
|
67
|
+
domain: string;
|
|
68
|
+
topic: string;
|
|
69
|
+
priority: Priority;
|
|
70
|
+
ttl?: string;
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
interface MemoryInjectRequest {
|
|
74
|
+
skillName: string;
|
|
75
|
+
documents: MemoryDocument[];
|
|
76
|
+
}
|
|
77
|
+
interface MemoryInjectResponse {
|
|
78
|
+
injected: number;
|
|
79
|
+
skipped: number;
|
|
80
|
+
errors: string[];
|
|
81
|
+
}
|
|
82
|
+
interface MemoryRollbackRequest {
|
|
83
|
+
skillName: string;
|
|
84
|
+
}
|
|
85
|
+
interface StrategyDocument {
|
|
86
|
+
id: string;
|
|
87
|
+
content: string;
|
|
88
|
+
steps: number;
|
|
89
|
+
}
|
|
90
|
+
interface SkillRegisterRequest {
|
|
91
|
+
skillName: string;
|
|
92
|
+
definition: string;
|
|
93
|
+
strategies: StrategyDocument[];
|
|
94
|
+
triggers: string[];
|
|
95
|
+
}
|
|
96
|
+
interface SkillRegisterResponse {
|
|
97
|
+
registered: boolean;
|
|
98
|
+
activeSkills: string[];
|
|
99
|
+
}
|
|
100
|
+
interface SkillUnregisterRequest {
|
|
101
|
+
skillName: string;
|
|
102
|
+
}
|
|
103
|
+
interface BenchmarkRunRequest {
|
|
104
|
+
tasks: Array<{
|
|
105
|
+
id: string;
|
|
106
|
+
input: string;
|
|
107
|
+
rubric: RubricItem[];
|
|
108
|
+
}>;
|
|
109
|
+
judgeModel: string;
|
|
110
|
+
runs: number;
|
|
111
|
+
}
|
|
112
|
+
interface TaskResult {
|
|
113
|
+
taskId: string;
|
|
114
|
+
output: string;
|
|
115
|
+
scores: number[];
|
|
116
|
+
medianScore: number;
|
|
117
|
+
rubricBreakdown: Array<{
|
|
118
|
+
criterion: string;
|
|
119
|
+
score: number;
|
|
120
|
+
feedback: string;
|
|
121
|
+
}>;
|
|
122
|
+
}
|
|
123
|
+
interface BenchmarkRunResponse {
|
|
124
|
+
results: TaskResult[];
|
|
125
|
+
aggregateScore: number;
|
|
126
|
+
}
|
|
127
|
+
interface SkillError {
|
|
128
|
+
skill: string;
|
|
129
|
+
phase: SkillPhase;
|
|
130
|
+
message: string;
|
|
131
|
+
recoverable: boolean;
|
|
132
|
+
suggestion?: string;
|
|
133
|
+
}
|
|
134
|
+
interface ValidationResult {
|
|
135
|
+
valid: boolean;
|
|
136
|
+
errors: ValidationError[];
|
|
137
|
+
}
|
|
138
|
+
interface ValidationError {
|
|
139
|
+
field: string;
|
|
140
|
+
message: string;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
declare const VALID_CATEGORIES: SkillCategory[];
|
|
144
|
+
declare const VALID_DIMENSIONS: BenchmarkDimension[];
|
|
1
145
|
/**
|
|
2
|
-
*
|
|
3
|
-
*/
|
|
4
|
-
declare const version = "0.0.1";
|
|
5
|
-
/**
|
|
6
|
-
* 示例函数
|
|
146
|
+
* Validate a SkillManifest object and return all discovered errors.
|
|
7
147
|
*/
|
|
8
|
-
declare function
|
|
148
|
+
declare function validateManifest(manifest: unknown, knownSkillNames?: string[]): ValidationResult;
|
|
9
149
|
|
|
10
|
-
export {
|
|
150
|
+
export { type BenchmarkDimension, type BenchmarkRunRequest, type BenchmarkRunResponse, type BenchmarkTask, type BenchmarkTest, type Difficulty, type IssueSeverity, type MemoryDocument, type MemoryInjectRequest, type MemoryInjectResponse, type MemoryRollbackRequest, type Priority, type RubricItem, type SkillCategory, type SkillError, type SkillManifest, type SkillPhase, type SkillRegisterRequest, type SkillRegisterResponse, type SkillUnregisterRequest, type SmokeTest, type SmokeTestTask, type StrategyDocument, type TaskResult, VALID_CATEGORIES, VALID_DIMENSIONS, type ValidationError, type ValidationResult, validateManifest };
|
package/dist/index.js
CHANGED
|
@@ -1,36 +1,143 @@
|
|
|
1
|
-
|
|
2
|
-
var
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
1
|
+
// src/validator.ts
|
|
2
|
+
var VALID_CATEGORIES = [
|
|
3
|
+
"information-retrieval",
|
|
4
|
+
"content-processing",
|
|
5
|
+
"programming-assistance",
|
|
6
|
+
"creative-generation"
|
|
7
|
+
];
|
|
8
|
+
var VALID_DIMENSIONS = [
|
|
9
|
+
"information-retrieval",
|
|
10
|
+
"content-understanding",
|
|
11
|
+
"logical-reasoning",
|
|
12
|
+
"code-generation",
|
|
13
|
+
"creative-generation"
|
|
14
|
+
];
|
|
15
|
+
var SEMVER_RE = /^\d+\.\d+\.\d+(?:-[\w.]+)?(?:\+[\w.]+)?$/;
|
|
16
|
+
var SEMVER_RANGE_RE = /^(?:[~^]?\d+\.\d+\.\d+(?:-[\w.]+)?|>=?\d+\.\d+\.\d+)$/;
|
|
17
|
+
var SKILL_NAME_RE = /^@botlearn\/[a-z][a-z0-9-]*$/;
|
|
18
|
+
function validateManifest(manifest, knownSkillNames) {
|
|
19
|
+
const errors = [];
|
|
20
|
+
if (manifest === null || typeof manifest !== "object") {
|
|
21
|
+
return { valid: false, errors: [{ field: "(root)", message: "Manifest must be a non-null object" }] };
|
|
22
|
+
}
|
|
23
|
+
const m = manifest;
|
|
24
|
+
requireString(m, "name", errors);
|
|
25
|
+
requireString(m, "version", errors);
|
|
26
|
+
requireString(m, "description", errors);
|
|
27
|
+
requireString(m, "author", errors);
|
|
28
|
+
if (typeof m.name === "string" && !SKILL_NAME_RE.test(m.name)) {
|
|
29
|
+
errors.push({
|
|
30
|
+
field: "name",
|
|
31
|
+
message: `Name must match @botlearn/<kebab-case>, got "${m.name}"`
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
if (typeof m.version === "string" && !SEMVER_RE.test(m.version)) {
|
|
35
|
+
errors.push({
|
|
36
|
+
field: "version",
|
|
37
|
+
message: `Version must be valid semver, got "${m.version}"`
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
if (!VALID_CATEGORIES.includes(m.category)) {
|
|
41
|
+
errors.push({
|
|
42
|
+
field: "category",
|
|
43
|
+
message: `Category must be one of: ${VALID_CATEGORIES.join(", ")}`
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
if (!VALID_DIMENSIONS.includes(m.benchmarkDimension)) {
|
|
47
|
+
errors.push({
|
|
48
|
+
field: "benchmarkDimension",
|
|
49
|
+
message: `benchmarkDimension must be one of: ${VALID_DIMENSIONS.join(", ")}`
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
if (typeof m.expectedImprovement !== "number" || m.expectedImprovement < 0) {
|
|
53
|
+
errors.push({
|
|
54
|
+
field: "expectedImprovement",
|
|
55
|
+
message: "expectedImprovement must be a non-negative number"
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
if (m.dependencies !== void 0) {
|
|
59
|
+
if (typeof m.dependencies !== "object" || m.dependencies === null) {
|
|
60
|
+
errors.push({
|
|
61
|
+
field: "dependencies",
|
|
62
|
+
message: "dependencies must be an object"
|
|
63
|
+
});
|
|
64
|
+
} else {
|
|
65
|
+
const deps = m.dependencies;
|
|
66
|
+
for (const [depName, depVersion] of Object.entries(deps)) {
|
|
67
|
+
if (!SKILL_NAME_RE.test(depName)) {
|
|
68
|
+
errors.push({
|
|
69
|
+
field: `dependencies.${depName}`,
|
|
70
|
+
message: `Dependency name must match @botlearn/<kebab-case>`
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
if (typeof depVersion !== "string" || !SEMVER_RANGE_RE.test(depVersion)) {
|
|
74
|
+
errors.push({
|
|
75
|
+
field: `dependencies.${depName}`,
|
|
76
|
+
message: `Dependency version must be a valid semver range, got "${String(depVersion)}"`
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
if (knownSkillNames && !knownSkillNames.includes(depName)) {
|
|
80
|
+
errors.push({
|
|
81
|
+
field: `dependencies.${depName}`,
|
|
82
|
+
message: `Unknown dependency "${depName}" \u2014 not in known skills list`
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (typeof m.compatibility !== "object" || m.compatibility === null) {
|
|
89
|
+
errors.push({
|
|
90
|
+
field: "compatibility",
|
|
91
|
+
message: "compatibility must be an object with an openclaw field"
|
|
92
|
+
});
|
|
93
|
+
} else {
|
|
94
|
+
const compat = m.compatibility;
|
|
95
|
+
if (typeof compat.openclaw !== "string" || !SEMVER_RANGE_RE.test(compat.openclaw)) {
|
|
96
|
+
errors.push({
|
|
97
|
+
field: "compatibility.openclaw",
|
|
98
|
+
message: `compatibility.openclaw must be a valid semver range`
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (typeof m.files !== "object" || m.files === null) {
|
|
103
|
+
errors.push({
|
|
104
|
+
field: "files",
|
|
105
|
+
message: "files must be an object"
|
|
106
|
+
});
|
|
107
|
+
} else {
|
|
108
|
+
const files = m.files;
|
|
109
|
+
requireString(files, "skill", errors, "files.skill");
|
|
110
|
+
requireStringArray(files, "knowledge", errors, "files.knowledge");
|
|
111
|
+
requireStringArray(files, "strategies", errors, "files.strategies");
|
|
112
|
+
requireString(files, "smokeTest", errors, "files.smokeTest");
|
|
113
|
+
requireString(files, "benchmark", errors, "files.benchmark");
|
|
114
|
+
}
|
|
115
|
+
return { valid: errors.length === 0, errors };
|
|
116
|
+
}
|
|
117
|
+
function requireString(obj, field, errors, displayField) {
|
|
118
|
+
if (typeof obj[field] !== "string" || obj[field].length === 0) {
|
|
119
|
+
errors.push({
|
|
120
|
+
field: displayField ?? field,
|
|
121
|
+
message: `${displayField ?? field} is required and must be a non-empty string`
|
|
122
|
+
});
|
|
15
123
|
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
|
|
20
|
-
// src/index.ts
|
|
21
|
-
var index_exports = {};
|
|
22
|
-
__export(index_exports, {
|
|
23
|
-
hello: () => hello,
|
|
24
|
-
version: () => version
|
|
25
|
-
});
|
|
26
|
-
module.exports = __toCommonJS(index_exports);
|
|
27
|
-
var version = "0.0.1";
|
|
28
|
-
function hello(name = "World") {
|
|
29
|
-
return `Hello, ${name}!`;
|
|
30
124
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
125
|
+
function requireStringArray(obj, field, errors, displayField) {
|
|
126
|
+
const val = obj[field];
|
|
127
|
+
if (!Array.isArray(val) || val.length === 0) {
|
|
128
|
+
errors.push({
|
|
129
|
+
field: displayField ?? field,
|
|
130
|
+
message: `${displayField ?? field} must be a non-empty array of strings`
|
|
131
|
+
});
|
|
132
|
+
} else if (val.some((item) => typeof item !== "string")) {
|
|
133
|
+
errors.push({
|
|
134
|
+
field: displayField ?? field,
|
|
135
|
+
message: `${displayField ?? field} must contain only strings`
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
export {
|
|
140
|
+
VALID_CATEGORIES,
|
|
141
|
+
VALID_DIMENSIONS,
|
|
142
|
+
validateManifest
|
|
143
|
+
};
|
package/package.json
CHANGED
|
@@ -1,45 +1,48 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "botlearn",
|
|
3
|
-
"version": "0.0
|
|
4
|
-
"description": "
|
|
5
|
-
"
|
|
6
|
-
"type": "commonjs",
|
|
7
|
-
"main": "./dist/index.js",
|
|
8
|
-
"module": "./dist/index.mjs",
|
|
9
|
-
"types": "./dist/index.d.ts",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "BotLearn OpenClaw Skills SDK — types, validator, and utilities for @botlearn/* skill packages",
|
|
5
|
+
"type": "module",
|
|
10
6
|
"exports": {
|
|
11
7
|
".": {
|
|
12
8
|
"types": "./dist/index.d.ts",
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
|
|
16
|
-
},
|
|
17
|
-
"./package.json": "./package.json"
|
|
9
|
+
"import": "./dist/index.js",
|
|
10
|
+
"require": "./dist/index.cjs"
|
|
11
|
+
}
|
|
18
12
|
},
|
|
13
|
+
"main": "./dist/index.cjs",
|
|
14
|
+
"module": "./dist/index.js",
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
19
16
|
"files": [
|
|
20
17
|
"dist",
|
|
21
18
|
"README.md"
|
|
22
19
|
],
|
|
23
|
-
"scripts": {
|
|
24
|
-
"build": "tsup",
|
|
25
|
-
"dev": "tsup --watch",
|
|
26
|
-
"check-types": "tsc --noEmit",
|
|
27
|
-
"prepublishOnly": "pnpm build"
|
|
28
|
-
},
|
|
29
20
|
"keywords": [
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
21
|
+
"botlearn",
|
|
22
|
+
"openclaw",
|
|
23
|
+
"skills",
|
|
24
|
+
"agent"
|
|
33
25
|
],
|
|
34
|
-
"author": "",
|
|
26
|
+
"author": "BotLearn",
|
|
35
27
|
"license": "MIT",
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "https://github.com/readai-team/botlearn-awesome-skills.git",
|
|
31
|
+
"directory": "packages/botlearn"
|
|
32
|
+
},
|
|
33
|
+
"homepage": "https://github.com/readai-team/botlearn-awesome-skills/tree/main/packages/botlearn",
|
|
34
|
+
"bugs": {
|
|
35
|
+
"url": "https://github.com/readai-team/botlearn-awesome-skills/issues"
|
|
36
|
+
},
|
|
37
|
+
"publishConfig": {
|
|
38
|
+
"access": "public"
|
|
39
|
+
},
|
|
36
40
|
"devDependencies": {
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"tsup": "^8.3.5",
|
|
40
|
-
"typescript": "^5.7.3"
|
|
41
|
+
"tsup": "^8.0.0",
|
|
42
|
+
"typescript": "^5.4.0"
|
|
41
43
|
},
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "tsup",
|
|
46
|
+
"typecheck": "tsc --noEmit"
|
|
44
47
|
}
|
|
45
|
-
}
|
|
48
|
+
}
|
package/dist/index.d.mts
DELETED
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Botlearn - A Node.js toolkit for bot learning\n */\n\nexport const version = '0.0.1';\n\n/**\n * 示例函数\n */\nexport function hello(name = 'World'): string {\n return `Hello, ${name}!`;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAIO,IAAM,UAAU;AAKhB,SAAS,MAAM,OAAO,SAAiB;AAC5C,SAAO,UAAU,IAAI;AACvB;","names":[]}
|
package/dist/index.mjs
DELETED
package/dist/index.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Botlearn - A Node.js toolkit for bot learning\n */\n\nexport const version = '0.0.1';\n\n/**\n * 示例函数\n */\nexport function hello(name = 'World'): string {\n return `Hello, ${name}!`;\n}\n"],"mappings":";AAIO,IAAM,UAAU;AAKhB,SAAS,MAAM,OAAO,SAAiB;AAC5C,SAAO,UAAU,IAAI;AACvB;","names":[]}
|