@thinkwell/acp 0.5.0-alpha.1 → 0.5.0-alpha.2
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/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/skill-server.d.ts +23 -0
- package/dist/skill-server.d.ts.map +1 -0
- package/dist/skill-server.js +96 -0
- package/dist/skill-server.js.map +1 -0
- package/dist/skill.d.ts +71 -0
- package/dist/skill.d.ts.map +1 -0
- package/dist/skill.js +117 -0
- package/dist/skill.js.map +1 -0
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -6,4 +6,8 @@ export { ActiveSession, SessionBuilder } from "./session.js";
|
|
|
6
6
|
export type { SessionUpdate, PromptMessage, McpReadyOptions } from "./session.js";
|
|
7
7
|
export { SacpConnection, connect, connectToConductor } from "./connection.js";
|
|
8
8
|
export type { SessionOptions } from "./connection.js";
|
|
9
|
+
export { parseSkillMd, validateSkillName, validateSkillDescription } from "./skill.js";
|
|
10
|
+
export type { Skill, VirtualSkill, StoredSkill, SkillTool } from "./skill.js";
|
|
11
|
+
export { createSkillServer } from "./skill-server.js";
|
|
12
|
+
export type { ResolvedSkill } from "./skill-server.js";
|
|
9
13
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,UAAU,EACV,cAAc,EACd,UAAU,EACV,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,UAAU,EACV,QAAQ,EACR,yBAAyB,EACzB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,cAAc,EACd,UAAU,EACV,WAAW,EACX,cAAc,GACf,MAAM,YAAY,CAAC;AAEpB,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAGvD,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAGzE,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAG9D,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC7D,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAGlF,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC9E,YAAY,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,UAAU,EACV,cAAc,EACd,UAAU,EACV,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,UAAU,EACV,QAAQ,EACR,yBAAyB,EACzB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,cAAc,EACd,UAAU,EACV,WAAW,EACX,cAAc,GACf,MAAM,YAAY,CAAC;AAEpB,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAGvD,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAGzE,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAG9D,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC7D,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAGlF,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC9E,YAAY,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGtD,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AACvF,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAG9E,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,YAAY,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -6,4 +6,8 @@ export { McpOverAcpHandler } from "./mcp-over-acp-handler.js";
|
|
|
6
6
|
export { ActiveSession, SessionBuilder } from "./session.js";
|
|
7
7
|
// Connection
|
|
8
8
|
export { SacpConnection, connect, connectToConductor } from "./connection.js";
|
|
9
|
+
// Skills
|
|
10
|
+
export { parseSkillMd, validateSkillName, validateSkillDescription } from "./skill.js";
|
|
11
|
+
// Skill MCP Server
|
|
12
|
+
export { createSkillServer } from "./skill-server.js";
|
|
9
13
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAyBA,aAAa;AACb,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEzE,uBAAuB;AACvB,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAE9D,UAAU;AACV,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAG7D,aAAa;AACb,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAyBA,aAAa;AACb,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEzE,uBAAuB;AACvB,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAE9D,UAAU;AACV,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAG7D,aAAa;AACb,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAG9E,SAAS;AACT,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAGvF,mBAAmB;AACnB,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill MCP server builder.
|
|
3
|
+
*
|
|
4
|
+
* Creates an MCP server that exposes three tools for skill interaction:
|
|
5
|
+
* - activate_skill: returns a skill's instruction body
|
|
6
|
+
* - call_skill_tool: dispatches to a virtual skill's tool handler
|
|
7
|
+
* - read_skill_file: reads a file from a stored skill's basePath
|
|
8
|
+
*
|
|
9
|
+
* These tools are registered as standard MCP tools but are intended to be
|
|
10
|
+
* hidden from the prompt (via ThinkBuilder's defineTool pattern).
|
|
11
|
+
*/
|
|
12
|
+
import type { McpServer } from "./mcp-server.js";
|
|
13
|
+
import type { VirtualSkill, StoredSkill } from "./skill.js";
|
|
14
|
+
/** A resolved skill is either a VirtualSkill or a StoredSkill. */
|
|
15
|
+
export type ResolvedSkill = VirtualSkill | StoredSkill;
|
|
16
|
+
/**
|
|
17
|
+
* Build an MCP server that provides skill tools.
|
|
18
|
+
*
|
|
19
|
+
* @param skills - resolved skills (virtual or stored) to make available
|
|
20
|
+
* @returns an McpServer with activate_skill, call_skill_tool, and read_skill_file tools
|
|
21
|
+
*/
|
|
22
|
+
export declare function createSkillServer(skills: ResolvedSkill[]): McpServer;
|
|
23
|
+
//# sourceMappingURL=skill-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-server.d.ts","sourceRoot":"","sources":["../src/skill-server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE5D,kEAAkE;AAClE,MAAM,MAAM,aAAa,GAAG,YAAY,GAAG,WAAW,CAAC;AAOvD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,SAAS,CAmGpE"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill MCP server builder.
|
|
3
|
+
*
|
|
4
|
+
* Creates an MCP server that exposes three tools for skill interaction:
|
|
5
|
+
* - activate_skill: returns a skill's instruction body
|
|
6
|
+
* - call_skill_tool: dispatches to a virtual skill's tool handler
|
|
7
|
+
* - read_skill_file: reads a file from a stored skill's basePath
|
|
8
|
+
*
|
|
9
|
+
* These tools are registered as standard MCP tools but are intended to be
|
|
10
|
+
* hidden from the prompt (via ThinkBuilder's defineTool pattern).
|
|
11
|
+
*/
|
|
12
|
+
import { readFile } from "node:fs/promises";
|
|
13
|
+
import { resolve, relative, isAbsolute } from "node:path";
|
|
14
|
+
import { mcpServer } from "./mcp-server.js";
|
|
15
|
+
/** Type guard for StoredSkill (has basePath). */
|
|
16
|
+
function isStoredSkill(skill) {
|
|
17
|
+
return "basePath" in skill && typeof skill.basePath === "string";
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Build an MCP server that provides skill tools.
|
|
21
|
+
*
|
|
22
|
+
* @param skills - resolved skills (virtual or stored) to make available
|
|
23
|
+
* @returns an McpServer with activate_skill, call_skill_tool, and read_skill_file tools
|
|
24
|
+
*/
|
|
25
|
+
export function createSkillServer(skills) {
|
|
26
|
+
const skillsByName = new Map();
|
|
27
|
+
for (const skill of skills) {
|
|
28
|
+
skillsByName.set(skill.name, skill);
|
|
29
|
+
}
|
|
30
|
+
return mcpServer("skills")
|
|
31
|
+
.tool("activate_skill", "Activate a skill by name, returning its full instructions.", {
|
|
32
|
+
type: "object",
|
|
33
|
+
properties: {
|
|
34
|
+
skill_name: { type: "string", description: "The name of the skill to activate" },
|
|
35
|
+
},
|
|
36
|
+
required: ["skill_name"],
|
|
37
|
+
}, { type: "string" }, async (input) => {
|
|
38
|
+
const skill = skillsByName.get(input.skill_name);
|
|
39
|
+
if (!skill) {
|
|
40
|
+
throw new Error(`Unknown skill: "${input.skill_name}"`);
|
|
41
|
+
}
|
|
42
|
+
return skill.body;
|
|
43
|
+
})
|
|
44
|
+
.tool("call_skill_tool", "Call a tool provided by a skill.", {
|
|
45
|
+
type: "object",
|
|
46
|
+
properties: {
|
|
47
|
+
skill_name: { type: "string", description: "The name of the skill that provides the tool" },
|
|
48
|
+
tool_name: { type: "string", description: "The name of the tool to call" },
|
|
49
|
+
input: { description: "Input to pass to the tool handler" },
|
|
50
|
+
},
|
|
51
|
+
required: ["skill_name", "tool_name"],
|
|
52
|
+
}, {}, async (input) => {
|
|
53
|
+
const skill = skillsByName.get(input.skill_name);
|
|
54
|
+
if (!skill) {
|
|
55
|
+
throw new Error(`Unknown skill: "${input.skill_name}"`);
|
|
56
|
+
}
|
|
57
|
+
const tools = skill.tools;
|
|
58
|
+
if (!tools || tools.length === 0) {
|
|
59
|
+
throw new Error(`Skill "${input.skill_name}" has no tools`);
|
|
60
|
+
}
|
|
61
|
+
const tool = tools.find((t) => t.name === input.tool_name);
|
|
62
|
+
if (!tool) {
|
|
63
|
+
throw new Error(`Unknown tool "${input.tool_name}" for skill "${input.skill_name}"`);
|
|
64
|
+
}
|
|
65
|
+
return tool.handler(input.input);
|
|
66
|
+
})
|
|
67
|
+
.tool("read_skill_file", "Read a file from a stored skill's directory.", {
|
|
68
|
+
type: "object",
|
|
69
|
+
properties: {
|
|
70
|
+
skill_name: { type: "string", description: "The name of the skill" },
|
|
71
|
+
path: { type: "string", description: "Relative path to the file within the skill directory" },
|
|
72
|
+
},
|
|
73
|
+
required: ["skill_name", "path"],
|
|
74
|
+
}, { type: "string" }, async (input) => {
|
|
75
|
+
const skill = skillsByName.get(input.skill_name);
|
|
76
|
+
if (!skill) {
|
|
77
|
+
throw new Error(`Unknown skill: "${input.skill_name}"`);
|
|
78
|
+
}
|
|
79
|
+
if (!isStoredSkill(skill)) {
|
|
80
|
+
throw new Error(`Skill "${input.skill_name}" is not a stored skill (no basePath)`);
|
|
81
|
+
}
|
|
82
|
+
// Reject absolute paths outright
|
|
83
|
+
if (isAbsolute(input.path)) {
|
|
84
|
+
throw new Error("Path must be relative");
|
|
85
|
+
}
|
|
86
|
+
const resolved = resolve(skill.basePath, input.path);
|
|
87
|
+
// Path traversal check: resolved path must be within basePath
|
|
88
|
+
const rel = relative(skill.basePath, resolved);
|
|
89
|
+
if (rel.startsWith("..") || isAbsolute(rel)) {
|
|
90
|
+
throw new Error("Path traversal is not allowed");
|
|
91
|
+
}
|
|
92
|
+
return readFile(resolved, "utf-8");
|
|
93
|
+
})
|
|
94
|
+
.build();
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=skill-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-server.js","sourceRoot":"","sources":["../src/skill-server.ts"],"names":[],"mappings":"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"}
|
package/dist/skill.d.ts
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill types and SKILL.md parser for the Agent Skills standard.
|
|
3
|
+
*
|
|
4
|
+
* This module defines the core skill types and provides a parser for
|
|
5
|
+
* SKILL.md files (YAML frontmatter + Markdown body).
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* A tool bundled with a virtual skill.
|
|
9
|
+
* Same trust model as ThinkBuilder's .tool() -- user-authored handler functions.
|
|
10
|
+
*
|
|
11
|
+
* Unlike top-level .tool() registrations, skill tools are not registered as
|
|
12
|
+
* individual MCP tools with formal schemas. Instead, the skill body documents
|
|
13
|
+
* available tools and their expected inputs as Markdown. The agent invokes them
|
|
14
|
+
* via the generic `call_skill_tool` dispatcher, which routes to the handler.
|
|
15
|
+
*/
|
|
16
|
+
export interface SkillTool<I = unknown, O = unknown> {
|
|
17
|
+
name: string;
|
|
18
|
+
description: string;
|
|
19
|
+
handler: (input: I) => Promise<O>;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Base skill definition: metadata + instructions.
|
|
23
|
+
*/
|
|
24
|
+
export interface Skill {
|
|
25
|
+
/** Skill name (lowercase, hyphens, matches directory name in the spec) */
|
|
26
|
+
name: string;
|
|
27
|
+
/** When to use this skill (max 1024 chars) */
|
|
28
|
+
description: string;
|
|
29
|
+
/** Full instruction content (Markdown body from SKILL.md) */
|
|
30
|
+
body: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* A virtual skill defined programmatically, with optional handler functions
|
|
34
|
+
* dispatched via `call_skill_tool`.
|
|
35
|
+
*/
|
|
36
|
+
export interface VirtualSkill extends Skill {
|
|
37
|
+
tools?: SkillTool[];
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* A stored skill loaded from a SKILL.md file on the filesystem.
|
|
41
|
+
* The basePath is used to serve reference docs and assets via `read_skill_file`.
|
|
42
|
+
*/
|
|
43
|
+
export interface StoredSkill extends Skill {
|
|
44
|
+
basePath: string;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Validate a skill name per the Agent Skills spec.
|
|
48
|
+
* - 1-64 characters
|
|
49
|
+
* - Lowercase alphanumeric + hyphens
|
|
50
|
+
* - No leading, trailing, or consecutive hyphens
|
|
51
|
+
*/
|
|
52
|
+
export declare function validateSkillName(name: unknown): asserts name is string;
|
|
53
|
+
/**
|
|
54
|
+
* Validate a skill description per the Agent Skills spec.
|
|
55
|
+
* - 1-1024 characters
|
|
56
|
+
* - Non-empty (after trimming)
|
|
57
|
+
*/
|
|
58
|
+
export declare function validateSkillDescription(description: unknown): asserts description is string;
|
|
59
|
+
/**
|
|
60
|
+
* Parse a SKILL.md file content into a Skill.
|
|
61
|
+
*
|
|
62
|
+
* Extracts YAML frontmatter (delimited by `---`), validates required fields
|
|
63
|
+
* (name, description), and returns the parsed skill with the Markdown body.
|
|
64
|
+
*
|
|
65
|
+
* Optional frontmatter fields (license, compatibility, metadata) are preserved
|
|
66
|
+
* in the returned object but not acted upon.
|
|
67
|
+
*
|
|
68
|
+
* @throws Error if frontmatter is missing, malformed, or required fields are invalid
|
|
69
|
+
*/
|
|
70
|
+
export declare function parseSkillMd(content: string): Skill & Record<string, unknown>;
|
|
71
|
+
//# sourceMappingURL=skill.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill.d.ts","sourceRoot":"","sources":["../src/skill.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;;;GAQG;AACH,MAAM,WAAW,SAAS,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,OAAO;IACjD,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;CACnC;AAED;;GAEG;AACH,MAAM,WAAW,KAAK;IACpB,0EAA0E;IAC1E,IAAI,EAAE,MAAM,CAAC;IACb,8CAA8C;IAC9C,WAAW,EAAE,MAAM,CAAC;IACpB,6DAA6D;IAC7D,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,MAAM,WAAW,YAAa,SAAQ,KAAK;IACzC,KAAK,CAAC,EAAE,SAAS,EAAE,CAAC;CACrB;AAED;;;GAGG;AACH,MAAM,WAAW,WAAY,SAAQ,KAAK;IACxC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAWD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,IAAI,MAAM,CAYvE;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,OAAO,GAAG,OAAO,CAAC,WAAW,IAAI,MAAM,CAS5F;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAa7E"}
|
package/dist/skill.js
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill types and SKILL.md parser for the Agent Skills standard.
|
|
3
|
+
*
|
|
4
|
+
* This module defines the core skill types and provides a parser for
|
|
5
|
+
* SKILL.md files (YAML frontmatter + Markdown body).
|
|
6
|
+
*/
|
|
7
|
+
/** Validation pattern for skill names: lowercase alphanumeric + hyphens, no leading/trailing/consecutive hyphens. */
|
|
8
|
+
const SKILL_NAME_PATTERN = /^[a-z0-9](?:[a-z0-9]|-(?=[a-z0-9]))*$/;
|
|
9
|
+
/** Maximum length for skill names. */
|
|
10
|
+
const MAX_NAME_LENGTH = 64;
|
|
11
|
+
/** Maximum length for skill descriptions. */
|
|
12
|
+
const MAX_DESCRIPTION_LENGTH = 1024;
|
|
13
|
+
/**
|
|
14
|
+
* Validate a skill name per the Agent Skills spec.
|
|
15
|
+
* - 1-64 characters
|
|
16
|
+
* - Lowercase alphanumeric + hyphens
|
|
17
|
+
* - No leading, trailing, or consecutive hyphens
|
|
18
|
+
*/
|
|
19
|
+
export function validateSkillName(name) {
|
|
20
|
+
if (typeof name !== "string" || name.length === 0) {
|
|
21
|
+
throw new Error("Skill name is required");
|
|
22
|
+
}
|
|
23
|
+
if (name.length > MAX_NAME_LENGTH) {
|
|
24
|
+
throw new Error(`Skill name must be at most ${MAX_NAME_LENGTH} characters, got ${name.length}`);
|
|
25
|
+
}
|
|
26
|
+
if (!SKILL_NAME_PATTERN.test(name)) {
|
|
27
|
+
throw new Error(`Invalid skill name "${name}": must be lowercase alphanumeric with hyphens, no leading/trailing/consecutive hyphens`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Validate a skill description per the Agent Skills spec.
|
|
32
|
+
* - 1-1024 characters
|
|
33
|
+
* - Non-empty (after trimming)
|
|
34
|
+
*/
|
|
35
|
+
export function validateSkillDescription(description) {
|
|
36
|
+
if (typeof description !== "string" || description.trim().length === 0) {
|
|
37
|
+
throw new Error("Skill description is required");
|
|
38
|
+
}
|
|
39
|
+
if (description.length > MAX_DESCRIPTION_LENGTH) {
|
|
40
|
+
throw new Error(`Skill description must be at most ${MAX_DESCRIPTION_LENGTH} characters, got ${description.length}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Parse a SKILL.md file content into a Skill.
|
|
45
|
+
*
|
|
46
|
+
* Extracts YAML frontmatter (delimited by `---`), validates required fields
|
|
47
|
+
* (name, description), and returns the parsed skill with the Markdown body.
|
|
48
|
+
*
|
|
49
|
+
* Optional frontmatter fields (license, compatibility, metadata) are preserved
|
|
50
|
+
* in the returned object but not acted upon.
|
|
51
|
+
*
|
|
52
|
+
* @throws Error if frontmatter is missing, malformed, or required fields are invalid
|
|
53
|
+
*/
|
|
54
|
+
export function parseSkillMd(content) {
|
|
55
|
+
const { frontmatter, body } = extractFrontmatter(content);
|
|
56
|
+
const fields = parseYamlFrontmatter(frontmatter);
|
|
57
|
+
validateSkillName(fields.name);
|
|
58
|
+
validateSkillDescription(fields.description);
|
|
59
|
+
return {
|
|
60
|
+
...fields,
|
|
61
|
+
name: fields.name,
|
|
62
|
+
description: fields.description,
|
|
63
|
+
body,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Extract YAML frontmatter and body from a SKILL.md string.
|
|
68
|
+
* Frontmatter is delimited by opening and closing `---` lines.
|
|
69
|
+
*/
|
|
70
|
+
function extractFrontmatter(content) {
|
|
71
|
+
const trimmed = content.trimStart();
|
|
72
|
+
if (!trimmed.startsWith("---")) {
|
|
73
|
+
throw new Error("SKILL.md must begin with YAML frontmatter (---)");
|
|
74
|
+
}
|
|
75
|
+
// Find the closing `---` after the opening one
|
|
76
|
+
const endIndex = trimmed.indexOf("\n---", 3);
|
|
77
|
+
if (endIndex === -1) {
|
|
78
|
+
throw new Error("SKILL.md frontmatter is missing closing ---");
|
|
79
|
+
}
|
|
80
|
+
const frontmatter = trimmed.slice(3, endIndex).trim();
|
|
81
|
+
// Body starts after the closing `---` and its newline
|
|
82
|
+
const afterClosing = endIndex + 4; // "\n---".length
|
|
83
|
+
// Strip the line ending after the closing --- and any single blank line
|
|
84
|
+
const body = trimmed.slice(afterClosing).replace(/^(\r?\n){1,2}/, "");
|
|
85
|
+
return { frontmatter, body };
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Minimal YAML parser for SKILL.md frontmatter.
|
|
89
|
+
*
|
|
90
|
+
* Supports only the flat key-value structure needed for skill metadata:
|
|
91
|
+
* simple string values (quoted or unquoted). This is intentionally limited --
|
|
92
|
+
* we don't need nested objects, arrays, or other YAML features.
|
|
93
|
+
*/
|
|
94
|
+
function parseYamlFrontmatter(yaml) {
|
|
95
|
+
const result = {};
|
|
96
|
+
for (const line of yaml.split("\n")) {
|
|
97
|
+
const trimmed = line.trim();
|
|
98
|
+
if (trimmed === "" || trimmed.startsWith("#"))
|
|
99
|
+
continue;
|
|
100
|
+
const colonIndex = trimmed.indexOf(":");
|
|
101
|
+
if (colonIndex === -1) {
|
|
102
|
+
throw new Error(`Invalid frontmatter line: ${trimmed}`);
|
|
103
|
+
}
|
|
104
|
+
const key = trimmed.slice(0, colonIndex).trim();
|
|
105
|
+
let value = trimmed.slice(colonIndex + 1).trim();
|
|
106
|
+
// Strip surrounding quotes (single or double)
|
|
107
|
+
if (typeof value === "string") {
|
|
108
|
+
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
109
|
+
(value.startsWith("'") && value.endsWith("'"))) {
|
|
110
|
+
value = value.slice(1, -1);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
result[key] = value;
|
|
114
|
+
}
|
|
115
|
+
return result;
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=skill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill.js","sourceRoot":"","sources":["../src/skill.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thinkwell/acp",
|
|
3
|
-
"version": "0.5.0-alpha.
|
|
3
|
+
"version": "0.5.0-alpha.2",
|
|
4
4
|
"description": "TypeScript implementation of ACP (Agent Client Protocol) extensions for Thinkwell",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"@agentclientprotocol/sdk": "^0.4.0",
|
|
29
29
|
"uuid": "^11.0.3",
|
|
30
|
-
"@thinkwell/conductor": "0.5.0-alpha.
|
|
31
|
-
"@thinkwell/protocol": "0.5.0-alpha.
|
|
30
|
+
"@thinkwell/conductor": "0.5.0-alpha.2",
|
|
31
|
+
"@thinkwell/protocol": "0.5.0-alpha.2"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@types/node": "^24.10.4",
|