@clawpify/skills 1.0.5 → 1.0.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.
- package/clawpify/SKILL.md +21 -118
- package/clawpify/references/docx.md +471 -0
- package/clawpify/references/pdf-forms.md +294 -0
- package/clawpify/references/pdf-reference.md +612 -0
- package/clawpify/references/pdf.md +308 -0
- package/clawpify/references/pptx-creating.md +420 -0
- package/clawpify/references/pptx-editing.md +205 -0
- package/clawpify/references/pptx.md +219 -0
- package/clawpify/references/xlsx.md +286 -0
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +76 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +79 -34
- package/dist/skills.d.ts +17 -0
- package/dist/skills.d.ts.map +1 -1
- package/dist/skills.js +20 -1
- package/package.json +1 -1
- package/src/agent.ts +33 -2
- package/src/index.ts +6 -1
- package/src/skills.ts +50 -0
package/dist/index.js
CHANGED
|
@@ -87,6 +87,54 @@ async function createAuthenticatedConfig() {
|
|
|
87
87
|
` + " - SHOPIFY_CLIENT_ID and SHOPIFY_CLIENT_SECRET (OAuth client credentials)");
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
+
// src/skills.ts
|
|
91
|
+
import { readdir, readFile } from "node:fs/promises";
|
|
92
|
+
import { join } from "node:path";
|
|
93
|
+
import { fileURLToPath } from "node:url";
|
|
94
|
+
async function loadSkills(customDir) {
|
|
95
|
+
const baseDir = customDir ?? join(fileURLToPath(import.meta.url), "..", "..", "clawpify");
|
|
96
|
+
const skillParts = [];
|
|
97
|
+
await collectMarkdown(baseDir, skillParts);
|
|
98
|
+
return skillParts.join(`
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
`);
|
|
103
|
+
}
|
|
104
|
+
async function loadSkillMetadata(customDir) {
|
|
105
|
+
const baseDir = customDir ?? join(fileURLToPath(import.meta.url), "..", "..", "clawpify");
|
|
106
|
+
const skillPath = join(baseDir, "SKILL.md");
|
|
107
|
+
return readFile(skillPath, "utf-8");
|
|
108
|
+
}
|
|
109
|
+
async function loadSkillReference(name, customDir) {
|
|
110
|
+
const baseDir = customDir ?? join(fileURLToPath(import.meta.url), "..", "..", "clawpify");
|
|
111
|
+
const refPath = join(baseDir, "references", name.endsWith(".md") ? name : `${name}.md`);
|
|
112
|
+
return readFile(refPath, "utf-8");
|
|
113
|
+
}
|
|
114
|
+
async function listSkillReferences(customDir) {
|
|
115
|
+
const baseDir = customDir ?? join(fileURLToPath(import.meta.url), "..", "..", "clawpify");
|
|
116
|
+
const refDir = join(baseDir, "references");
|
|
117
|
+
const entries = await readdir(refDir);
|
|
118
|
+
return entries.filter((e) => e.endsWith(".md")).map((e) => e.replace(".md", ""));
|
|
119
|
+
}
|
|
120
|
+
async function collectMarkdown(dir, parts) {
|
|
121
|
+
let entries;
|
|
122
|
+
try {
|
|
123
|
+
entries = await readdir(dir, { withFileTypes: true });
|
|
124
|
+
} catch {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
for (const entry of entries) {
|
|
128
|
+
const fullPath = join(dir, entry.name);
|
|
129
|
+
if (entry.isDirectory()) {
|
|
130
|
+
await collectMarkdown(fullPath, parts);
|
|
131
|
+
} else if (entry.name.endsWith(".md")) {
|
|
132
|
+
const content = await readFile(fullPath, "utf-8");
|
|
133
|
+
parts.push(content);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
90
138
|
// src/agent.ts
|
|
91
139
|
import Anthropic from "@anthropic-ai/sdk";
|
|
92
140
|
var DEFAULT_SYSTEM_INSTRUCTION = "You're Clawpify. You help run a Shopify store. The merchant texts you to get stuff done";
|
|
@@ -108,6 +156,20 @@ var SHOPIFY_GRAPHQL_TOOL = {
|
|
|
108
156
|
required: ["query"]
|
|
109
157
|
}
|
|
110
158
|
};
|
|
159
|
+
var LOAD_SKILL_REFERENCE_TOOL = {
|
|
160
|
+
name: "load_skill_reference",
|
|
161
|
+
description: "Load a reference document for a specific domain. Available Shopify references: products, orders, customers, inventory, discounts, collections, fulfillments, refunds, draft-orders, gift-cards, webhooks, locations, marketing, markets, menus, metafields, pages, blogs, files, shipping, shop, subscriptions, translations, segments, bulk-operations. Available document references: docx, pdf, pdf-forms, pdf-reference, pptx, pptx-editing, pptx-creating, xlsx. Use this BEFORE writing queries or processing documents to get the correct syntax and workflow.",
|
|
162
|
+
input_schema: {
|
|
163
|
+
type: "object",
|
|
164
|
+
properties: {
|
|
165
|
+
reference: {
|
|
166
|
+
type: "string",
|
|
167
|
+
description: "Name of the reference to load (e.g. 'orders', 'products', 'docx', 'pdf', 'xlsx')"
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
required: ["reference"]
|
|
171
|
+
}
|
|
172
|
+
};
|
|
111
173
|
var DEFAULT_PRICING = {
|
|
112
174
|
inputPerMillion: 3,
|
|
113
175
|
outputPerMillion: 15,
|
|
@@ -187,8 +249,8 @@ class ShopifyAgent {
|
|
|
187
249
|
}
|
|
188
250
|
registerPlugin(plugin) {
|
|
189
251
|
const name = plugin.tool.name;
|
|
190
|
-
if (name === "shopify_graphql") {
|
|
191
|
-
throw new Error(`Cannot register plugin with reserved tool name "
|
|
252
|
+
if (name === "shopify_graphql" || name === "load_skill_reference") {
|
|
253
|
+
throw new Error(`Cannot register plugin with reserved tool name "${name}"`);
|
|
192
254
|
}
|
|
193
255
|
if (this.plugins.has(name)) {
|
|
194
256
|
throw new Error(`Plugin with tool name "${name}" is already registered`);
|
|
@@ -208,6 +270,7 @@ class ShopifyAgent {
|
|
|
208
270
|
buildTools() {
|
|
209
271
|
const allTools = [
|
|
210
272
|
SHOPIFY_GRAPHQL_TOOL,
|
|
273
|
+
LOAD_SKILL_REFERENCE_TOOL,
|
|
211
274
|
...[...this.plugins.values()].map((p) => p.tool)
|
|
212
275
|
];
|
|
213
276
|
if (allTools.length > 0) {
|
|
@@ -245,6 +308,17 @@ class ShopifyAgent {
|
|
|
245
308
|
return { content: content2, isError: true };
|
|
246
309
|
}
|
|
247
310
|
}
|
|
311
|
+
if (name === "load_skill_reference") {
|
|
312
|
+
try {
|
|
313
|
+
const content2 = await loadSkillReference(input.reference);
|
|
314
|
+
await safeHook(this.hooks.onToolResult, name, content2, false);
|
|
315
|
+
return { content: content2, isError: false };
|
|
316
|
+
} catch (error) {
|
|
317
|
+
const content2 = `Error: ${error instanceof Error ? error.message : String(error)}`;
|
|
318
|
+
await safeHook(this.hooks.onToolResult, name, content2, true);
|
|
319
|
+
return { content: content2, isError: true };
|
|
320
|
+
}
|
|
321
|
+
}
|
|
248
322
|
if (this.plugins.has(name)) {
|
|
249
323
|
const plugin = this.plugins.get(name);
|
|
250
324
|
try {
|
|
@@ -488,40 +562,11 @@ class InMemoryStore {
|
|
|
488
562
|
this.store.delete(sessionId);
|
|
489
563
|
}
|
|
490
564
|
}
|
|
491
|
-
|
|
492
|
-
// src/skills.ts
|
|
493
|
-
import { readdir, readFile } from "node:fs/promises";
|
|
494
|
-
import { join } from "node:path";
|
|
495
|
-
import { fileURLToPath } from "node:url";
|
|
496
|
-
async function loadSkills(customDir) {
|
|
497
|
-
const baseDir = customDir ?? join(fileURLToPath(import.meta.url), "..", "..", "clawpify");
|
|
498
|
-
const skillParts = [];
|
|
499
|
-
await collectMarkdown(baseDir, skillParts);
|
|
500
|
-
return skillParts.join(`
|
|
501
|
-
|
|
502
|
-
---
|
|
503
|
-
|
|
504
|
-
`);
|
|
505
|
-
}
|
|
506
|
-
async function collectMarkdown(dir, parts) {
|
|
507
|
-
let entries;
|
|
508
|
-
try {
|
|
509
|
-
entries = await readdir(dir, { withFileTypes: true });
|
|
510
|
-
} catch {
|
|
511
|
-
return;
|
|
512
|
-
}
|
|
513
|
-
for (const entry of entries) {
|
|
514
|
-
const fullPath = join(dir, entry.name);
|
|
515
|
-
if (entry.isDirectory()) {
|
|
516
|
-
await collectMarkdown(fullPath, parts);
|
|
517
|
-
} else if (entry.name.endsWith(".md")) {
|
|
518
|
-
const content = await readFile(fullPath, "utf-8");
|
|
519
|
-
parts.push(content);
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
565
|
export {
|
|
524
566
|
loadSkills,
|
|
567
|
+
loadSkillReference,
|
|
568
|
+
loadSkillMetadata,
|
|
569
|
+
listSkillReferences,
|
|
525
570
|
getAccessToken,
|
|
526
571
|
createShopifyClient,
|
|
527
572
|
createAuthenticatedConfig,
|
package/dist/skills.d.ts
CHANGED
|
@@ -3,6 +3,23 @@
|
|
|
3
3
|
* Works both locally and when installed as an npm package.
|
|
4
4
|
*
|
|
5
5
|
* Optionally provide a custom directory path to load skills from.
|
|
6
|
+
*
|
|
7
|
+
* @deprecated Use `loadSkillMetadata()` for the system prompt and
|
|
8
|
+
* `loadSkillReference(name)` to load individual references on demand.
|
|
6
9
|
*/
|
|
7
10
|
export declare function loadSkills(customDir?: string): Promise<string>;
|
|
11
|
+
/**
|
|
12
|
+
* Load only the SKILL.md metadata file (Level 1+2).
|
|
13
|
+
* Use this for the system prompt instead of `loadSkills()` to keep context small.
|
|
14
|
+
*/
|
|
15
|
+
export declare function loadSkillMetadata(customDir?: string): Promise<string>;
|
|
16
|
+
/**
|
|
17
|
+
* Load a specific reference file on demand (Level 3).
|
|
18
|
+
* Returns the content of `clawpify/references/{name}.md`.
|
|
19
|
+
*/
|
|
20
|
+
export declare function loadSkillReference(name: string, customDir?: string): Promise<string>;
|
|
21
|
+
/**
|
|
22
|
+
* List available reference file names (without the `.md` extension).
|
|
23
|
+
*/
|
|
24
|
+
export declare function listSkillReferences(customDir?: string): Promise<string[]>;
|
|
8
25
|
//# sourceMappingURL=skills.d.ts.map
|
package/dist/skills.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../src/skills.ts"],"names":[],"mappings":"AAIA
|
|
1
|
+
{"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../src/skills.ts"],"names":[],"mappings":"AAIA;;;;;;;;GAQG;AACH,wBAAsB,UAAU,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CASpE;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,CAAC,CAMjB;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,EACZ,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,CAAC,CAUjB;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,EAAE,CAAC,CAOnB"}
|
package/dist/skills.js
CHANGED
|
@@ -12,6 +12,22 @@ async function loadSkills(customDir) {
|
|
|
12
12
|
|
|
13
13
|
`);
|
|
14
14
|
}
|
|
15
|
+
async function loadSkillMetadata(customDir) {
|
|
16
|
+
const baseDir = customDir ?? join(fileURLToPath(import.meta.url), "..", "..", "clawpify");
|
|
17
|
+
const skillPath = join(baseDir, "SKILL.md");
|
|
18
|
+
return readFile(skillPath, "utf-8");
|
|
19
|
+
}
|
|
20
|
+
async function loadSkillReference(name, customDir) {
|
|
21
|
+
const baseDir = customDir ?? join(fileURLToPath(import.meta.url), "..", "..", "clawpify");
|
|
22
|
+
const refPath = join(baseDir, "references", name.endsWith(".md") ? name : `${name}.md`);
|
|
23
|
+
return readFile(refPath, "utf-8");
|
|
24
|
+
}
|
|
25
|
+
async function listSkillReferences(customDir) {
|
|
26
|
+
const baseDir = customDir ?? join(fileURLToPath(import.meta.url), "..", "..", "clawpify");
|
|
27
|
+
const refDir = join(baseDir, "references");
|
|
28
|
+
const entries = await readdir(refDir);
|
|
29
|
+
return entries.filter((e) => e.endsWith(".md")).map((e) => e.replace(".md", ""));
|
|
30
|
+
}
|
|
15
31
|
async function collectMarkdown(dir, parts) {
|
|
16
32
|
let entries;
|
|
17
33
|
try {
|
|
@@ -30,5 +46,8 @@ async function collectMarkdown(dir, parts) {
|
|
|
30
46
|
}
|
|
31
47
|
}
|
|
32
48
|
export {
|
|
33
|
-
loadSkills
|
|
49
|
+
loadSkills,
|
|
50
|
+
loadSkillReference,
|
|
51
|
+
loadSkillMetadata,
|
|
52
|
+
listSkillReferences
|
|
34
53
|
};
|
package/package.json
CHANGED
package/src/agent.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import Anthropic from "@anthropic-ai/sdk";
|
|
2
2
|
import { ShopifyClient } from "./shopify";
|
|
3
3
|
import type { MemoryStore } from "./memory";
|
|
4
|
+
import { loadSkillReference } from "./skills";
|
|
4
5
|
|
|
5
6
|
// ---------------------------------------------------------------------------
|
|
6
7
|
// Types
|
|
@@ -148,6 +149,23 @@ const SHOPIFY_GRAPHQL_TOOL: Anthropic.Tool = {
|
|
|
148
149
|
},
|
|
149
150
|
};
|
|
150
151
|
|
|
152
|
+
const LOAD_SKILL_REFERENCE_TOOL: Anthropic.Tool = {
|
|
153
|
+
name: "load_skill_reference",
|
|
154
|
+
description:
|
|
155
|
+
"Load a reference document for a specific domain. Available Shopify references: products, orders, customers, inventory, discounts, collections, fulfillments, refunds, draft-orders, gift-cards, webhooks, locations, marketing, markets, menus, metafields, pages, blogs, files, shipping, shop, subscriptions, translations, segments, bulk-operations. Available document references: docx, pdf, pdf-forms, pdf-reference, pptx, pptx-editing, pptx-creating, xlsx. Use this BEFORE writing queries or processing documents to get the correct syntax and workflow.",
|
|
156
|
+
input_schema: {
|
|
157
|
+
type: "object" as const,
|
|
158
|
+
properties: {
|
|
159
|
+
reference: {
|
|
160
|
+
type: "string",
|
|
161
|
+
description:
|
|
162
|
+
"Name of the reference to load (e.g. 'orders', 'products', 'docx', 'pdf', 'xlsx')",
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
required: ["reference"],
|
|
166
|
+
},
|
|
167
|
+
};
|
|
168
|
+
|
|
151
169
|
/** Default pricing for claude-sonnet-4-5 (USD per million tokens). */
|
|
152
170
|
const DEFAULT_PRICING: ModelPricing = {
|
|
153
171
|
inputPerMillion: 3,
|
|
@@ -266,9 +284,9 @@ export class ShopifyAgent {
|
|
|
266
284
|
/** Register a plugin at runtime. Throws if a tool with the same name already exists. */
|
|
267
285
|
registerPlugin(plugin: AgentPlugin): void {
|
|
268
286
|
const name = plugin.tool.name;
|
|
269
|
-
if (name === "shopify_graphql") {
|
|
287
|
+
if (name === "shopify_graphql" || name === "load_skill_reference") {
|
|
270
288
|
throw new Error(
|
|
271
|
-
`Cannot register plugin with reserved tool name "
|
|
289
|
+
`Cannot register plugin with reserved tool name "${name}"`
|
|
272
290
|
);
|
|
273
291
|
}
|
|
274
292
|
if (this.plugins.has(name)) {
|
|
@@ -297,6 +315,7 @@ export class ShopifyAgent {
|
|
|
297
315
|
private buildTools(): Anthropic.Tool[] {
|
|
298
316
|
const allTools: Anthropic.Tool[] = [
|
|
299
317
|
SHOPIFY_GRAPHQL_TOOL,
|
|
318
|
+
LOAD_SKILL_REFERENCE_TOOL,
|
|
300
319
|
...[...this.plugins.values()].map((p) => p.tool),
|
|
301
320
|
];
|
|
302
321
|
if (allTools.length > 0) {
|
|
@@ -348,6 +367,18 @@ export class ShopifyAgent {
|
|
|
348
367
|
}
|
|
349
368
|
}
|
|
350
369
|
|
|
370
|
+
if (name === "load_skill_reference") {
|
|
371
|
+
try {
|
|
372
|
+
const content = await loadSkillReference(input.reference);
|
|
373
|
+
await safeHook(this.hooks.onToolResult, name, content, false);
|
|
374
|
+
return { content, isError: false };
|
|
375
|
+
} catch (error) {
|
|
376
|
+
const content = `Error: ${error instanceof Error ? error.message : String(error)}`;
|
|
377
|
+
await safeHook(this.hooks.onToolResult, name, content, true);
|
|
378
|
+
return { content, isError: true };
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
351
382
|
if (this.plugins.has(name)) {
|
|
352
383
|
const plugin = this.plugins.get(name)!;
|
|
353
384
|
try {
|
package/src/index.ts
CHANGED
|
@@ -63,7 +63,12 @@ export { InMemoryStore } from "./memory";
|
|
|
63
63
|
export type { MemoryStore } from "./memory";
|
|
64
64
|
|
|
65
65
|
// Skills loader
|
|
66
|
-
export {
|
|
66
|
+
export {
|
|
67
|
+
loadSkills,
|
|
68
|
+
loadSkillMetadata,
|
|
69
|
+
loadSkillReference,
|
|
70
|
+
listSkillReferences,
|
|
71
|
+
} from "./skills";
|
|
67
72
|
|
|
68
73
|
// Re-export types for convenience
|
|
69
74
|
export type { ShopifyClientConfig, GraphQLResponse } from "./shopify";
|
package/src/skills.ts
CHANGED
|
@@ -7,6 +7,9 @@ import { fileURLToPath } from "node:url";
|
|
|
7
7
|
* Works both locally and when installed as an npm package.
|
|
8
8
|
*
|
|
9
9
|
* Optionally provide a custom directory path to load skills from.
|
|
10
|
+
*
|
|
11
|
+
* @deprecated Use `loadSkillMetadata()` for the system prompt and
|
|
12
|
+
* `loadSkillReference(name)` to load individual references on demand.
|
|
10
13
|
*/
|
|
11
14
|
export async function loadSkills(customDir?: string): Promise<string> {
|
|
12
15
|
const baseDir =
|
|
@@ -19,6 +22,53 @@ export async function loadSkills(customDir?: string): Promise<string> {
|
|
|
19
22
|
return skillParts.join("\n\n---\n\n");
|
|
20
23
|
}
|
|
21
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Load only the SKILL.md metadata file (Level 1+2).
|
|
27
|
+
* Use this for the system prompt instead of `loadSkills()` to keep context small.
|
|
28
|
+
*/
|
|
29
|
+
export async function loadSkillMetadata(
|
|
30
|
+
customDir?: string
|
|
31
|
+
): Promise<string> {
|
|
32
|
+
const baseDir =
|
|
33
|
+
customDir ??
|
|
34
|
+
join(fileURLToPath(import.meta.url), "..", "..", "clawpify");
|
|
35
|
+
const skillPath = join(baseDir, "SKILL.md");
|
|
36
|
+
return readFile(skillPath, "utf-8");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Load a specific reference file on demand (Level 3).
|
|
41
|
+
* Returns the content of `clawpify/references/{name}.md`.
|
|
42
|
+
*/
|
|
43
|
+
export async function loadSkillReference(
|
|
44
|
+
name: string,
|
|
45
|
+
customDir?: string
|
|
46
|
+
): Promise<string> {
|
|
47
|
+
const baseDir =
|
|
48
|
+
customDir ??
|
|
49
|
+
join(fileURLToPath(import.meta.url), "..", "..", "clawpify");
|
|
50
|
+
const refPath = join(
|
|
51
|
+
baseDir,
|
|
52
|
+
"references",
|
|
53
|
+
name.endsWith(".md") ? name : `${name}.md`
|
|
54
|
+
);
|
|
55
|
+
return readFile(refPath, "utf-8");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* List available reference file names (without the `.md` extension).
|
|
60
|
+
*/
|
|
61
|
+
export async function listSkillReferences(
|
|
62
|
+
customDir?: string
|
|
63
|
+
): Promise<string[]> {
|
|
64
|
+
const baseDir =
|
|
65
|
+
customDir ??
|
|
66
|
+
join(fileURLToPath(import.meta.url), "..", "..", "clawpify");
|
|
67
|
+
const refDir = join(baseDir, "references");
|
|
68
|
+
const entries = await readdir(refDir);
|
|
69
|
+
return entries.filter((e) => e.endsWith(".md")).map((e) => e.replace(".md", ""));
|
|
70
|
+
}
|
|
71
|
+
|
|
22
72
|
async function collectMarkdown(
|
|
23
73
|
dir: string,
|
|
24
74
|
parts: string[]
|