clawpowers 2.2.6 → 2.2.7

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.
Files changed (136) hide show
  1. package/CHANGELOG.md +186 -175
  2. package/COMPATIBILITY.md +48 -13
  3. package/KNOWN_LIMITATIONS.md +20 -19
  4. package/LICENSE +44 -44
  5. package/LICENSING.md +10 -10
  6. package/README.md +486 -462
  7. package/SECURITY.md +52 -52
  8. package/dist/index.d.ts +17 -5
  9. package/dist/index.js +186 -91
  10. package/dist/index.js.map +1 -1
  11. package/native/Cargo.lock +4927 -4927
  12. package/native/Cargo.toml +73 -73
  13. package/native/crates/canonical/Cargo.toml +24 -24
  14. package/native/crates/canonical/src/lib.rs +677 -677
  15. package/native/crates/compression/Cargo.toml +20 -20
  16. package/native/crates/compression/benches/compression_bench.rs +42 -42
  17. package/native/crates/compression/src/lib.rs +393 -393
  18. package/native/crates/evm-eth/Cargo.toml +13 -13
  19. package/native/crates/evm-eth/src/lib.rs +105 -105
  20. package/native/crates/fee/Cargo.toml +15 -15
  21. package/native/crates/fee/src/lib.rs +281 -281
  22. package/native/crates/index/Cargo.toml +16 -16
  23. package/native/crates/index/src/lib.rs +277 -277
  24. package/native/crates/policy/Cargo.toml +17 -17
  25. package/native/crates/policy/src/lib.rs +614 -614
  26. package/native/crates/security/Cargo.toml +22 -22
  27. package/native/crates/security/src/lib.rs +478 -478
  28. package/native/crates/tokens/Cargo.toml +13 -13
  29. package/native/crates/tokens/src/lib.rs +534 -534
  30. package/native/crates/verification/Cargo.toml +23 -23
  31. package/native/crates/verification/src/lib.rs +333 -333
  32. package/native/crates/wallet/Cargo.toml +20 -20
  33. package/native/crates/wallet/src/lib.rs +261 -261
  34. package/native/crates/x402/Cargo.toml +30 -30
  35. package/native/crates/x402/src/lib.rs +423 -423
  36. package/native/ffi/Cargo.toml +34 -34
  37. package/native/ffi/build.rs +4 -4
  38. package/native/ffi/src/lib.rs +352 -352
  39. package/native/ffi/tests/integration.rs +354 -354
  40. package/native/pyo3/Cargo.toml +26 -26
  41. package/native/pyo3/pyproject.toml +16 -16
  42. package/native/pyo3/src/lib.rs +407 -407
  43. package/native/pyo3/tests/test_smoke.py +180 -180
  44. package/native/wasm/Cargo.toml +47 -47
  45. package/native/wasm/pkg/.gitignore +6 -6
  46. package/native/wasm/pkg/clawpowers_wasm.d.ts +208 -208
  47. package/native/wasm/pkg/clawpowers_wasm.js +872 -872
  48. package/native/wasm/pkg/clawpowers_wasm_bg.wasm.d.ts +40 -40
  49. package/native/wasm/pkg/package.json +16 -16
  50. package/native/wasm/pkg-node/clawpowers_wasm.d.ts +143 -143
  51. package/native/wasm/pkg-node/clawpowers_wasm.js +798 -798
  52. package/native/wasm/pkg-node/clawpowers_wasm_bg.wasm.d.ts +40 -40
  53. package/native/wasm/pkg-node/package.json +12 -12
  54. package/native/wasm/src/lib.rs +433 -433
  55. package/package.json +12 -8
  56. package/scripts/build-wasm.mjs +59 -0
  57. package/scripts/generate_hermes_wrappers.py +211 -0
  58. package/scripts/hermes_wrapper_overrides.json +184 -0
  59. package/scripts/run-python-script.mjs +48 -0
  60. package/scripts/verify-consumer-install.mjs +109 -0
  61. package/scripts/verify-wasm-artifacts.mjs +25 -2
  62. package/scripts/verify_hermes_wrappers.py +154 -0
  63. package/skill.json +1 -1
  64. package/skills/1password/SKILL.md +34 -0
  65. package/skills/README.md +44 -0
  66. package/skills/agent-nexus-2/SKILL.md +34 -0
  67. package/skills/apple-notes/SKILL.md +34 -0
  68. package/skills/apple-reminders/SKILL.md +34 -0
  69. package/skills/autoresearch/SKILL.md +43 -0
  70. package/skills/bear-notes/SKILL.md +34 -0
  71. package/skills/blogwatcher/SKILL.md +34 -0
  72. package/skills/blucli/SKILL.md +34 -0
  73. package/skills/bluebubbles/SKILL.md +34 -0
  74. package/skills/business-strategy/SKILL.md +41 -0
  75. package/skills/camsnap/SKILL.md +34 -0
  76. package/skills/canvas/SKILL.md +34 -0
  77. package/skills/clawhub/SKILL.md +34 -0
  78. package/skills/coding-agent/SKILL.md +34 -0
  79. package/skills/coding-discipline.skill/SKILL.md +34 -0
  80. package/skills/content-writer/SKILL.md +41 -0
  81. package/skills/discord/SKILL.md +34 -0
  82. package/skills/eightctl/SKILL.md +34 -0
  83. package/skills/execution-validation.skill/SKILL.md +34 -0
  84. package/skills/gemini/SKILL.md +34 -0
  85. package/skills/gh-issues/SKILL.md +34 -0
  86. package/skills/gifgrep/SKILL.md +34 -0
  87. package/skills/github/SKILL.md +41 -0
  88. package/skills/gog/SKILL.md +34 -0
  89. package/skills/goplaces/SKILL.md +34 -0
  90. package/skills/healthcheck/SKILL.md +34 -0
  91. package/skills/himalaya/SKILL.md +34 -0
  92. package/skills/humanize/SKILL.md +41 -0
  93. package/skills/imsg/SKILL.md +34 -0
  94. package/skills/itp/SKILL.md +112 -0
  95. package/skills/mcporter/SKILL.md +34 -0
  96. package/skills/model-usage/SKILL.md +34 -0
  97. package/skills/nano-pdf/SKILL.md +34 -0
  98. package/skills/node-connect/SKILL.md +34 -0
  99. package/skills/notion/SKILL.md +34 -0
  100. package/skills/obsidian/SKILL.md +34 -0
  101. package/skills/openai-whisper/SKILL.md +34 -0
  102. package/skills/openai-whisper-api/SKILL.md +34 -0
  103. package/skills/openhue/SKILL.md +34 -0
  104. package/skills/oracle/SKILL.md +34 -0
  105. package/skills/ordercli/SKILL.md +34 -0
  106. package/skills/peekaboo/SKILL.md +34 -0
  107. package/skills/polyclaw/SKILL.md +34 -0
  108. package/skills/prospector/SKILL.md +41 -0
  109. package/skills/rsi.skill/SKILL.md +34 -0
  110. package/skills/sag/SKILL.md +34 -0
  111. package/skills/security/SKILL.md +41 -0
  112. package/skills/session-logs/SKILL.md +34 -0
  113. package/skills/sherpa-onnx-tts/SKILL.md +34 -0
  114. package/skills/skill-creator/SKILL.md +34 -0
  115. package/skills/slack/SKILL.md +34 -0
  116. package/skills/songsee/SKILL.md +34 -0
  117. package/skills/sonoscli/SKILL.md +34 -0
  118. package/skills/spotify-player/SKILL.md +34 -0
  119. package/skills/strykr-prism/SKILL.md +41 -0
  120. package/skills/summarize/SKILL.md +34 -0
  121. package/skills/taskbridge/SKILL.md +34 -0
  122. package/skills/things-mac/SKILL.md +34 -0
  123. package/skills/tmux/SKILL.md +34 -0
  124. package/skills/trello/SKILL.md +34 -0
  125. package/skills/validator-agent/SKILL.md +41 -0
  126. package/skills/video-frames/SKILL.md +34 -0
  127. package/skills/voice-call/SKILL.md +34 -0
  128. package/skills/wacli/SKILL.md +34 -0
  129. package/skills/weather/SKILL.md +34 -0
  130. package/skills/webmcp-payments/SKILL.md +41 -0
  131. package/skills/xurl/SKILL.md +34 -0
  132. package/src/skills/catalog.ts +435 -435
  133. package/src/skills/executor.ts +56 -56
  134. package/src/skills/index.ts +3 -3
  135. package/src/skills/itp/SKILL.md +112 -112
  136. package/src/skills/loader.ts +262 -193
@@ -1,193 +1,262 @@
1
- /**
2
- * ClawPowers Agent — Skill Loader
3
- * Discovers skills from skill directories, validates SKILL.md frontmatter.
4
- */
5
-
6
- import { readdirSync, readFileSync, existsSync, statSync } from 'node:fs';
7
- import { join } from 'node:path';
8
- import type { SkillManifest, SkillRequirements, Profile } from '../types.js';
9
-
10
- // ─── YAML Frontmatter Parser ──────────────────────────────────────────────────
11
-
12
- interface ParsedFrontmatter {
13
- name?: string;
14
- description?: string;
15
- metadata?: {
16
- openclaw?: {
17
- requires?: {
18
- bins?: string[];
19
- env?: string[];
20
- config?: string[];
21
- };
22
- };
23
- };
24
- }
25
-
26
- /**
27
- * Parse YAML frontmatter from a SKILL.md file content.
28
- * Expects format: ---\n<yaml>\n---\n<content>
29
- */
30
- export function parseFrontmatter(content: string): ParsedFrontmatter {
31
- const match = content.match(/^---\n([\s\S]*?)\n---/);
32
- if (!match?.[1]) {
33
- return {};
34
- }
35
-
36
- const yamlText = match[1];
37
- const result: ParsedFrontmatter = {};
38
-
39
- // Simple YAML parser for our known structure
40
- const lines = yamlText.split('\n');
41
- let currentKey = '';
42
- let inRequires = false;
43
- let requiresKey = '';
44
- const requires: { bins?: string[]; env?: string[]; config?: string[] } = {};
45
-
46
- for (const line of lines) {
47
- const trimmed = line.trim();
48
- if (trimmed === '' || trimmed.startsWith('#')) continue;
49
-
50
- // Top-level keys
51
- const topLevel = line.match(/^(\w+):\s*(.*)$/);
52
- if (topLevel?.[1]) {
53
- currentKey = topLevel[1];
54
- const val = topLevel[2]?.trim().replace(/^["']|["']$/g, '') ?? '';
55
- if (currentKey === 'name' && val) result.name = val;
56
- if (currentKey === 'description' && val) result.description = val;
57
- inRequires = false;
58
- continue;
59
- }
60
-
61
- // metadata.openclaw.requires detection
62
- if (trimmed === 'openclaw:') continue;
63
- if (trimmed === 'requires:') {
64
- inRequires = true;
65
- continue;
66
- }
67
-
68
- if (inRequires) {
69
- const reqKey = trimmed.match(/^(\w+):\s*(.*)$/);
70
- if (reqKey?.[1]) {
71
- requiresKey = reqKey[1];
72
- // Inline array: bins: ["node", "git"]
73
- const inlineArr = reqKey[2]?.match(/\[(.*)\]/);
74
- if (inlineArr?.[1]) {
75
- const items = inlineArr[1].split(',').map(s => s.trim().replace(/^["']|["']$/g, ''));
76
- if (requiresKey === 'bins') requires.bins = items;
77
- if (requiresKey === 'env') requires.env = items;
78
- if (requiresKey === 'config') requires.config = items;
79
- }
80
- continue;
81
- }
82
- // List item under requires key
83
- const listItem = trimmed.match(/^-\s*["']?(.+?)["']?$/);
84
- if (listItem?.[1] && requiresKey) {
85
- if (requiresKey === 'bins') {
86
- requires.bins = requires.bins ?? [];
87
- requires.bins.push(listItem[1]);
88
- }
89
- if (requiresKey === 'env') {
90
- requires.env = requires.env ?? [];
91
- requires.env.push(listItem[1]);
92
- }
93
- if (requiresKey === 'config') {
94
- requires.config = requires.config ?? [];
95
- requires.config.push(listItem[1]);
96
- }
97
- }
98
- }
99
- }
100
-
101
- if (Object.keys(requires).length > 0) {
102
- result.metadata = { openclaw: { requires } };
103
- }
104
-
105
- return result;
106
- }
107
-
108
- // ─── Skill Discovery ──────────────────────────────────────────────────────────
109
-
110
- /**
111
- * Load a single skill manifest from a directory containing SKILL.md
112
- */
113
- export function loadSkillManifest(skillDir: string): SkillManifest | null {
114
- const skillMdPath = join(skillDir, 'SKILL.md');
115
- if (!existsSync(skillMdPath)) {
116
- return null;
117
- }
118
-
119
- const content = readFileSync(skillMdPath, 'utf-8');
120
- const frontmatter = parseFrontmatter(content);
121
-
122
- if (!frontmatter.name || !frontmatter.description) {
123
- return null;
124
- }
125
-
126
- let requirements: SkillRequirements | null = null;
127
- const req = frontmatter.metadata?.openclaw?.requires;
128
- if (req) {
129
- requirements = {
130
- bins: req.bins ?? [],
131
- env: req.env ?? [],
132
- config: req.config ?? [],
133
- };
134
- }
135
-
136
- return {
137
- name: frontmatter.name,
138
- description: frontmatter.description,
139
- path: skillDir,
140
- requirements,
141
- };
142
- }
143
-
144
- /**
145
- * Discover all skills in a directory. Each subdirectory with a valid SKILL.md
146
- * becomes a skill manifest.
147
- */
148
- export function discoverSkills(skillsDir: string): SkillManifest[] {
149
- if (!existsSync(skillsDir)) {
150
- return [];
151
- }
152
-
153
- const entries = readdirSync(skillsDir);
154
- const manifests: SkillManifest[] = [];
155
-
156
- for (const entry of entries) {
157
- const fullPath = join(skillsDir, entry);
158
- if (!statSync(fullPath).isDirectory()) continue;
159
-
160
- const manifest = loadSkillManifest(fullPath);
161
- if (manifest) {
162
- manifests.push(manifest);
163
- }
164
- }
165
-
166
- return manifests.sort((a, b) => a.name.localeCompare(b.name));
167
- }
168
-
169
- /**
170
- * Filter skills based on active profile.
171
- * Returns only skills that are listed in the profile's skill list.
172
- */
173
- export function getActiveSkills(
174
- allSkills: SkillManifest[],
175
- profile: Profile
176
- ): SkillManifest[] {
177
- const profileSkillSet = new Set(profile.skills);
178
- return allSkills.filter(skill => profileSkillSet.has(skill.name));
179
- }
180
-
181
- /**
182
- * List skills with their active/inactive status for a given profile.
183
- */
184
- export function listSkillsWithStatus(
185
- allSkills: SkillManifest[],
186
- profile: Profile
187
- ): Array<{ skill: SkillManifest; active: boolean }> {
188
- const profileSkillSet = new Set(profile.skills);
189
- return allSkills.map(skill => ({
190
- skill,
191
- active: profileSkillSet.has(skill.name),
192
- }));
193
- }
1
+ /**
2
+ * ClawPowers Agent — Skill Loader
3
+ * Discovers skills from skill directories, validates SKILL.md frontmatter.
4
+ */
5
+
6
+ import { readdirSync, readFileSync, existsSync, statSync } from 'node:fs';
7
+ import { join } from 'node:path';
8
+ import type { SkillManifest, SkillRequirements, Profile } from '../types.js';
9
+
10
+ // ─── YAML Frontmatter Parser ──────────────────────────────────────────────────
11
+
12
+ interface ParsedFrontmatter {
13
+ name?: string;
14
+ description?: string;
15
+ metadata?: {
16
+ openclaw?: {
17
+ requires?: {
18
+ bins?: string[];
19
+ env?: string[];
20
+ config?: string[];
21
+ };
22
+ };
23
+ };
24
+ }
25
+
26
+ function stripQuotes(value: string): string {
27
+ if (value.length >= 2) {
28
+ const first = value[0];
29
+ const last = value[value.length - 1];
30
+ if ((first === '"' && last === '"') || (first === "'" && last === "'")) {
31
+ return value.slice(1, -1);
32
+ }
33
+ }
34
+ return value;
35
+ }
36
+
37
+ function splitYamlKeyValue(line: string): { key: string; value: string } | null {
38
+ const colonIndex = line.indexOf(':');
39
+ if (colonIndex <= 0) {
40
+ return null;
41
+ }
42
+
43
+ const key = line.slice(0, colonIndex).trim();
44
+ if (!key) {
45
+ return null;
46
+ }
47
+
48
+ for (const char of key) {
49
+ const isAlphaNum =
50
+ (char >= 'a' && char <= 'z')
51
+ || (char >= 'A' && char <= 'Z')
52
+ || (char >= '0' && char <= '9')
53
+ || char === '_';
54
+ if (!isAlphaNum) {
55
+ return null;
56
+ }
57
+ }
58
+
59
+ return {
60
+ key,
61
+ value: line.slice(colonIndex + 1).trim(),
62
+ };
63
+ }
64
+
65
+ function parseInlineArray(value: string): string[] | null {
66
+ if (!value.startsWith('[') || !value.endsWith(']')) {
67
+ return null;
68
+ }
69
+
70
+ const inner = value.slice(1, -1).trim();
71
+ if (!inner) {
72
+ return [];
73
+ }
74
+
75
+ return inner.split(',').map(item => stripQuotes(item.trim())).filter(Boolean);
76
+ }
77
+
78
+ function parseListItem(line: string): string | null {
79
+ if (!line.startsWith('-')) {
80
+ return null;
81
+ }
82
+
83
+ const value = line.slice(1).trim();
84
+ if (!value) {
85
+ return null;
86
+ }
87
+
88
+ return stripQuotes(value);
89
+ }
90
+
91
+ /**
92
+ * Parse YAML frontmatter from a SKILL.md file content.
93
+ * Expects format: ---\n<yaml>\n---\n<content>
94
+ */
95
+ export function parseFrontmatter(content: string): ParsedFrontmatter {
96
+ const normalized = content.replace(/\r\n/g, '\n');
97
+ if (!normalized.startsWith('---\n')) {
98
+ return {};
99
+ }
100
+
101
+ const endIndex = normalized.indexOf('\n---', 4);
102
+ if (endIndex === -1) {
103
+ return {};
104
+ }
105
+
106
+ const yamlText = normalized.slice(4, endIndex);
107
+ const result: ParsedFrontmatter = {};
108
+
109
+ // Simple YAML parser for our known structure
110
+ const lines = yamlText.split('\n');
111
+ let currentKey = '';
112
+ let inRequires = false;
113
+ let requiresKey = '';
114
+ const requires: { bins?: string[]; env?: string[]; config?: string[] } = {};
115
+
116
+ for (const line of lines) {
117
+ const trimmed = line.trim();
118
+ if (trimmed === '' || trimmed.startsWith('#')) continue;
119
+
120
+ // Top-level keys
121
+ const topLevel = line === trimmed ? splitYamlKeyValue(trimmed) : null;
122
+ if (topLevel) {
123
+ currentKey = topLevel.key;
124
+ const val = stripQuotes(topLevel.value);
125
+ if (currentKey === 'name' && val) result.name = val;
126
+ if (currentKey === 'description' && val) result.description = val;
127
+ inRequires = false;
128
+ continue;
129
+ }
130
+
131
+ // metadata.openclaw.requires detection
132
+ if (trimmed === 'openclaw:') continue;
133
+ if (trimmed === 'requires:') {
134
+ inRequires = true;
135
+ continue;
136
+ }
137
+
138
+ if (inRequires) {
139
+ const reqKey = splitYamlKeyValue(trimmed);
140
+ if (reqKey) {
141
+ requiresKey = reqKey.key;
142
+ // Inline array: bins: ["node", "git"]
143
+ const items = parseInlineArray(reqKey.value);
144
+ if (items) {
145
+ if (requiresKey === 'bins') requires.bins = items;
146
+ if (requiresKey === 'env') requires.env = items;
147
+ if (requiresKey === 'config') requires.config = items;
148
+ }
149
+ continue;
150
+ }
151
+ // List item under requires key
152
+ const listItem = parseListItem(trimmed);
153
+ if (listItem && requiresKey) {
154
+ if (requiresKey === 'bins') {
155
+ requires.bins = requires.bins ?? [];
156
+ requires.bins.push(listItem);
157
+ }
158
+ if (requiresKey === 'env') {
159
+ requires.env = requires.env ?? [];
160
+ requires.env.push(listItem);
161
+ }
162
+ if (requiresKey === 'config') {
163
+ requires.config = requires.config ?? [];
164
+ requires.config.push(listItem);
165
+ }
166
+ }
167
+ }
168
+ }
169
+
170
+ if (Object.keys(requires).length > 0) {
171
+ result.metadata = { openclaw: { requires } };
172
+ }
173
+
174
+ return result;
175
+ }
176
+
177
+ // ─── Skill Discovery ──────────────────────────────────────────────────────────
178
+
179
+ /**
180
+ * Load a single skill manifest from a directory containing SKILL.md
181
+ */
182
+ export function loadSkillManifest(skillDir: string): SkillManifest | null {
183
+ const skillMdPath = join(skillDir, 'SKILL.md');
184
+ if (!existsSync(skillMdPath)) {
185
+ return null;
186
+ }
187
+
188
+ const content = readFileSync(skillMdPath, 'utf-8');
189
+ const frontmatter = parseFrontmatter(content);
190
+
191
+ if (!frontmatter.name || !frontmatter.description) {
192
+ return null;
193
+ }
194
+
195
+ let requirements: SkillRequirements | null = null;
196
+ const req = frontmatter.metadata?.openclaw?.requires;
197
+ if (req) {
198
+ requirements = {
199
+ bins: req.bins ?? [],
200
+ env: req.env ?? [],
201
+ config: req.config ?? [],
202
+ };
203
+ }
204
+
205
+ return {
206
+ name: frontmatter.name,
207
+ description: frontmatter.description,
208
+ path: skillDir,
209
+ requirements,
210
+ };
211
+ }
212
+
213
+ /**
214
+ * Discover all skills in a directory. Each subdirectory with a valid SKILL.md
215
+ * becomes a skill manifest.
216
+ */
217
+ export function discoverSkills(skillsDir: string): SkillManifest[] {
218
+ if (!existsSync(skillsDir)) {
219
+ return [];
220
+ }
221
+
222
+ const entries = readdirSync(skillsDir);
223
+ const manifests: SkillManifest[] = [];
224
+
225
+ for (const entry of entries) {
226
+ const fullPath = join(skillsDir, entry);
227
+ if (!statSync(fullPath).isDirectory()) continue;
228
+
229
+ const manifest = loadSkillManifest(fullPath);
230
+ if (manifest) {
231
+ manifests.push(manifest);
232
+ }
233
+ }
234
+
235
+ return manifests.sort((a, b) => a.name.localeCompare(b.name));
236
+ }
237
+
238
+ /**
239
+ * Filter skills based on active profile.
240
+ * Returns only skills that are listed in the profile's skill list.
241
+ */
242
+ export function getActiveSkills(
243
+ allSkills: SkillManifest[],
244
+ profile: Profile
245
+ ): SkillManifest[] {
246
+ const profileSkillSet = new Set(profile.skills);
247
+ return allSkills.filter(skill => profileSkillSet.has(skill.name));
248
+ }
249
+
250
+ /**
251
+ * List skills with their active/inactive status for a given profile.
252
+ */
253
+ export function listSkillsWithStatus(
254
+ allSkills: SkillManifest[],
255
+ profile: Profile
256
+ ): Array<{ skill: SkillManifest; active: boolean }> {
257
+ const profileSkillSet = new Set(profile.skills);
258
+ return allSkills.map(skill => ({
259
+ skill,
260
+ active: profileSkillSet.has(skill.name),
261
+ }));
262
+ }