@actant/core 0.1.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 +1968 -0
- package/dist/index.js +5323 -0
- package/dist/index.js.map +1 -0
- package/dist/skill-md-parser-2HXC4AAW.js +115 -0
- package/dist/skill-md-parser-2HXC4AAW.js.map +1 -0
- package/package.json +47 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
// src/source/skill-md-parser.ts
|
|
2
|
+
import { readFile } from "fs/promises";
|
|
3
|
+
async function parseSkillMd(filePath) {
|
|
4
|
+
try {
|
|
5
|
+
const raw = await readFile(filePath, "utf-8");
|
|
6
|
+
return parseSkillMdContent(raw);
|
|
7
|
+
} catch {
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
function parseYamlFrontmatter(frontmatter) {
|
|
12
|
+
const meta = {};
|
|
13
|
+
const lines = frontmatter.split("\n");
|
|
14
|
+
let i = 0;
|
|
15
|
+
let inMetadata = false;
|
|
16
|
+
while (i < lines.length) {
|
|
17
|
+
const line = lines[i];
|
|
18
|
+
if (line === void 0) break;
|
|
19
|
+
const trimmed = line.trim();
|
|
20
|
+
if (trimmed === "metadata:") {
|
|
21
|
+
inMetadata = true;
|
|
22
|
+
i++;
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
const isNested = inMetadata && (line.startsWith(" ") || line.startsWith(" "));
|
|
26
|
+
const keyPrefix = isNested ? "metadata." : "";
|
|
27
|
+
const blockMatch = trimmed.match(/^(\w[\w-]*)\s*:\s*(\||>)\s*$/);
|
|
28
|
+
if (blockMatch) {
|
|
29
|
+
const key = keyPrefix + (blockMatch[1] ?? "");
|
|
30
|
+
if (!isNested) inMetadata = false;
|
|
31
|
+
const keyLineIndent = line.search(/\S/);
|
|
32
|
+
const blockIndent = keyLineIndent >= 0 ? keyLineIndent : line.length;
|
|
33
|
+
const blockLines = [];
|
|
34
|
+
i++;
|
|
35
|
+
while (i < lines.length) {
|
|
36
|
+
const nextLine = lines[i];
|
|
37
|
+
if (nextLine === void 0) break;
|
|
38
|
+
const nextIndent = nextLine.search(/\S/);
|
|
39
|
+
const isEmpty = nextLine.trim() === "";
|
|
40
|
+
if (isEmpty) {
|
|
41
|
+
blockLines.push(nextLine);
|
|
42
|
+
i++;
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (nextIndent !== -1 && nextIndent <= blockIndent) {
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
blockLines.push(nextLine);
|
|
49
|
+
i++;
|
|
50
|
+
}
|
|
51
|
+
const nonEmpty = blockLines.filter((l) => l.trim() !== "");
|
|
52
|
+
const minIndent = nonEmpty.length > 0 ? Math.min(...nonEmpty.map((l) => l.search(/\S/))) : 0;
|
|
53
|
+
meta[key] = blockMatch[2] === "|" ? blockLines.map((l) => l.trim() === "" ? "" : l.slice(minIndent)).join("\n").trimEnd() : blockLines.map((l) => l.trim()).join(" ").trim();
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
const quotedMatch = trimmed.match(/^(\w[\w-]*)\s*:\s*"((?:[^"\\]|\\.)*)"\s*$/);
|
|
57
|
+
if (quotedMatch) {
|
|
58
|
+
const key = keyPrefix + (quotedMatch[1] ?? "");
|
|
59
|
+
if (!isNested) inMetadata = false;
|
|
60
|
+
try {
|
|
61
|
+
meta[key] = JSON.parse(`"${(quotedMatch[2] ?? "").replace(/\\/g, "\\\\")}"`);
|
|
62
|
+
} catch {
|
|
63
|
+
meta[key] = (quotedMatch[2] ?? "").replace(/\\"/g, '"');
|
|
64
|
+
}
|
|
65
|
+
i++;
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
const match = trimmed.match(/^(\w[\w-]*)\s*:\s*(.*)$/);
|
|
69
|
+
if (match?.[1] !== void 0) {
|
|
70
|
+
const key = keyPrefix + match[1];
|
|
71
|
+
if (!isNested) inMetadata = false;
|
|
72
|
+
let value = (match[2] ?? "").trim();
|
|
73
|
+
if (value.startsWith('"') && value.endsWith('"')) {
|
|
74
|
+
try {
|
|
75
|
+
value = JSON.parse(value);
|
|
76
|
+
} catch {
|
|
77
|
+
value = value.slice(1, -1).replace(/\\"/g, '"');
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
meta[key] = value;
|
|
81
|
+
i++;
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
if (!isNested) inMetadata = false;
|
|
85
|
+
i++;
|
|
86
|
+
}
|
|
87
|
+
return meta;
|
|
88
|
+
}
|
|
89
|
+
function parseSkillMdContent(raw) {
|
|
90
|
+
if (!raw.startsWith("---")) return null;
|
|
91
|
+
const endIdx = raw.indexOf("---", 3);
|
|
92
|
+
if (endIdx === -1) return null;
|
|
93
|
+
const frontmatter = raw.substring(3, endIdx).trim();
|
|
94
|
+
const content = raw.substring(endIdx + 3).trim();
|
|
95
|
+
const meta = parseYamlFrontmatter(frontmatter);
|
|
96
|
+
const name = meta.name;
|
|
97
|
+
if (!name) return null;
|
|
98
|
+
const tags = [];
|
|
99
|
+
const actantTags = meta["metadata.actant-tags"];
|
|
100
|
+
if (actantTags) {
|
|
101
|
+
tags.push(...actantTags.split(",").map((t) => t.trim()).filter(Boolean));
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
name,
|
|
105
|
+
description: meta.description || void 0,
|
|
106
|
+
version: meta["metadata.version"] || meta.version || void 0,
|
|
107
|
+
content,
|
|
108
|
+
tags: tags.length > 0 ? tags : void 0
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
export {
|
|
112
|
+
parseSkillMd,
|
|
113
|
+
parseSkillMdContent
|
|
114
|
+
};
|
|
115
|
+
//# sourceMappingURL=skill-md-parser-2HXC4AAW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/source/skill-md-parser.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport type { SkillDefinition } from \"@actant/shared\";\n\n/**\n * Parses a SKILL.md file (Agent Skills / skill.sh format) into a SkillDefinition.\n * Format:\n * ---\n * name: skill-name\n * description: ...\n * license: MIT\n * metadata:\n * author: ...\n * version: \"1.0.0\"\n * actant-tags: \"tag1,tag2\"\n * ---\n *\n * # Skill content starts here...\n */\nexport async function parseSkillMd(filePath: string): Promise<SkillDefinition | null> {\n try {\n const raw = await readFile(filePath, \"utf-8\");\n return parseSkillMdContent(raw);\n } catch {\n return null;\n }\n}\n\n/**\n * Parses YAML frontmatter, handling single-line, quoted, and block scalar values.\n * Supports: key: value, key: \"quoted\", key: | (literal block), key: > (folded block).\n */\nfunction parseYamlFrontmatter(frontmatter: string): Record<string, string> {\n const meta: Record<string, string> = {};\n const lines = frontmatter.split(\"\\n\");\n let i = 0;\n let inMetadata = false;\n\n while (i < lines.length) {\n const line = lines[i];\n if (line === undefined) break;\n const trimmed = line.trim();\n\n if (trimmed === \"metadata:\") {\n inMetadata = true;\n i++;\n continue;\n }\n\n const isNested = inMetadata && (line.startsWith(\" \") || line.startsWith(\"\\t\"));\n const keyPrefix = isNested ? \"metadata.\" : \"\";\n\n const blockMatch = trimmed.match(/^(\\w[\\w-]*)\\s*:\\s*(\\||>)\\s*$/);\n if (blockMatch) {\n const key = keyPrefix + (blockMatch[1] ?? \"\");\n if (!isNested) inMetadata = false;\n\n const keyLineIndent = line.search(/\\S/);\n const blockIndent = keyLineIndent >= 0 ? keyLineIndent : line.length;\n const blockLines: string[] = [];\n i++;\n\n while (i < lines.length) {\n const nextLine = lines[i];\n if (nextLine === undefined) break;\n const nextIndent = nextLine.search(/\\S/);\n const isEmpty = nextLine.trim() === \"\";\n\n if (isEmpty) {\n blockLines.push(nextLine);\n i++;\n continue;\n }\n if (nextIndent !== -1 && nextIndent <= blockIndent) {\n break;\n }\n blockLines.push(nextLine);\n i++;\n }\n\n const nonEmpty = blockLines.filter((l) => l.trim() !== \"\");\n const minIndent =\n nonEmpty.length > 0 ? Math.min(...nonEmpty.map((l) => l.search(/\\S/))) : 0;\n meta[key] =\n blockMatch[2] === \"|\"\n ? blockLines\n .map((l) => (l.trim() === \"\" ? \"\" : l.slice(minIndent)))\n .join(\"\\n\")\n .trimEnd()\n : blockLines.map((l) => l.trim()).join(\" \").trim();\n continue;\n }\n\n const quotedMatch = trimmed.match(/^(\\w[\\w-]*)\\s*:\\s*\"((?:[^\"\\\\]|\\\\.)*)\"\\s*$/);\n if (quotedMatch) {\n const key = keyPrefix + (quotedMatch[1] ?? \"\");\n if (!isNested) inMetadata = false;\n try {\n meta[key] = JSON.parse(`\"${(quotedMatch[2] ?? \"\").replace(/\\\\/g, \"\\\\\\\\\")}\"`);\n } catch {\n meta[key] = (quotedMatch[2] ?? \"\").replace(/\\\\\"/g, '\"');\n }\n i++;\n continue;\n }\n\n const match = trimmed.match(/^(\\w[\\w-]*)\\s*:\\s*(.*)$/);\n if (match?.[1] !== undefined) {\n const key = keyPrefix + match[1];\n if (!isNested) inMetadata = false;\n let value = (match[2] ?? \"\").trim();\n if (value.startsWith('\"') && value.endsWith('\"')) {\n try {\n value = JSON.parse(value);\n } catch {\n value = value.slice(1, -1).replace(/\\\\\"/g, '\"');\n }\n }\n meta[key] = value;\n i++;\n continue;\n }\n\n if (!isNested) inMetadata = false;\n i++;\n }\n\n return meta;\n}\n\nexport function parseSkillMdContent(raw: string): SkillDefinition | null {\n // Check for YAML frontmatter\n if (!raw.startsWith(\"---\")) return null;\n\n const endIdx = raw.indexOf(\"---\", 3);\n if (endIdx === -1) return null;\n\n const frontmatter = raw.substring(3, endIdx).trim();\n const content = raw.substring(endIdx + 3).trim();\n\n // YAML parsing (handles single-line, quoted, and block scalars)\n const meta = parseYamlFrontmatter(frontmatter);\n\n const name = meta.name;\n if (!name) return null;\n\n const tags: string[] = [];\n const actantTags = meta[\"metadata.actant-tags\"];\n if (actantTags) {\n tags.push(...actantTags.split(\",\").map((t) => t.trim()).filter(Boolean));\n }\n\n return {\n name,\n description: meta.description || undefined,\n version: meta[\"metadata.version\"] || meta.version || undefined,\n content,\n tags: tags.length > 0 ? tags : undefined,\n };\n}\n"],"mappings":";AAAA,SAAS,gBAAgB;AAkBzB,eAAsB,aAAa,UAAmD;AACpF,MAAI;AACF,UAAM,MAAM,MAAM,SAAS,UAAU,OAAO;AAC5C,WAAO,oBAAoB,GAAG;AAAA,EAChC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAMA,SAAS,qBAAqB,aAA6C;AACzE,QAAM,OAA+B,CAAC;AACtC,QAAM,QAAQ,YAAY,MAAM,IAAI;AACpC,MAAI,IAAI;AACR,MAAI,aAAa;AAEjB,SAAO,IAAI,MAAM,QAAQ;AACvB,UAAM,OAAO,MAAM,CAAC;AACpB,QAAI,SAAS,OAAW;AACxB,UAAM,UAAU,KAAK,KAAK;AAE1B,QAAI,YAAY,aAAa;AAC3B,mBAAa;AACb;AACA;AAAA,IACF;AAEA,UAAM,WAAW,eAAe,KAAK,WAAW,IAAI,KAAK,KAAK,WAAW,GAAI;AAC7E,UAAM,YAAY,WAAW,cAAc;AAE3C,UAAM,aAAa,QAAQ,MAAM,8BAA8B;AAC/D,QAAI,YAAY;AACd,YAAM,MAAM,aAAa,WAAW,CAAC,KAAK;AAC1C,UAAI,CAAC,SAAU,cAAa;AAE5B,YAAM,gBAAgB,KAAK,OAAO,IAAI;AACtC,YAAM,cAAc,iBAAiB,IAAI,gBAAgB,KAAK;AAC9D,YAAM,aAAuB,CAAC;AAC9B;AAEA,aAAO,IAAI,MAAM,QAAQ;AACvB,cAAM,WAAW,MAAM,CAAC;AACxB,YAAI,aAAa,OAAW;AAC5B,cAAM,aAAa,SAAS,OAAO,IAAI;AACvC,cAAM,UAAU,SAAS,KAAK,MAAM;AAEpC,YAAI,SAAS;AACX,qBAAW,KAAK,QAAQ;AACxB;AACA;AAAA,QACF;AACA,YAAI,eAAe,MAAM,cAAc,aAAa;AAClD;AAAA,QACF;AACA,mBAAW,KAAK,QAAQ;AACxB;AAAA,MACF;AAEA,YAAM,WAAW,WAAW,OAAO,CAAC,MAAM,EAAE,KAAK,MAAM,EAAE;AACzD,YAAM,YACJ,SAAS,SAAS,IAAI,KAAK,IAAI,GAAG,SAAS,IAAI,CAAC,MAAM,EAAE,OAAO,IAAI,CAAC,CAAC,IAAI;AAC3E,WAAK,GAAG,IACN,WAAW,CAAC,MAAM,MACd,WACG,IAAI,CAAC,MAAO,EAAE,KAAK,MAAM,KAAK,KAAK,EAAE,MAAM,SAAS,CAAE,EACtD,KAAK,IAAI,EACT,QAAQ,IACX,WAAW,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK,GAAG,EAAE,KAAK;AACrD;AAAA,IACF;AAEA,UAAM,cAAc,QAAQ,MAAM,2CAA2C;AAC7E,QAAI,aAAa;AACf,YAAM,MAAM,aAAa,YAAY,CAAC,KAAK;AAC3C,UAAI,CAAC,SAAU,cAAa;AAC5B,UAAI;AACF,aAAK,GAAG,IAAI,KAAK,MAAM,KAAK,YAAY,CAAC,KAAK,IAAI,QAAQ,OAAO,MAAM,CAAC,GAAG;AAAA,MAC7E,QAAQ;AACN,aAAK,GAAG,KAAK,YAAY,CAAC,KAAK,IAAI,QAAQ,QAAQ,GAAG;AAAA,MACxD;AACA;AACA;AAAA,IACF;AAEA,UAAM,QAAQ,QAAQ,MAAM,yBAAyB;AACrD,QAAI,QAAQ,CAAC,MAAM,QAAW;AAC5B,YAAM,MAAM,YAAY,MAAM,CAAC;AAC/B,UAAI,CAAC,SAAU,cAAa;AAC5B,UAAI,SAAS,MAAM,CAAC,KAAK,IAAI,KAAK;AAClC,UAAI,MAAM,WAAW,GAAG,KAAK,MAAM,SAAS,GAAG,GAAG;AAChD,YAAI;AACF,kBAAQ,KAAK,MAAM,KAAK;AAAA,QAC1B,QAAQ;AACN,kBAAQ,MAAM,MAAM,GAAG,EAAE,EAAE,QAAQ,QAAQ,GAAG;AAAA,QAChD;AAAA,MACF;AACA,WAAK,GAAG,IAAI;AACZ;AACA;AAAA,IACF;AAEA,QAAI,CAAC,SAAU,cAAa;AAC5B;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,oBAAoB,KAAqC;AAEvE,MAAI,CAAC,IAAI,WAAW,KAAK,EAAG,QAAO;AAEnC,QAAM,SAAS,IAAI,QAAQ,OAAO,CAAC;AACnC,MAAI,WAAW,GAAI,QAAO;AAE1B,QAAM,cAAc,IAAI,UAAU,GAAG,MAAM,EAAE,KAAK;AAClD,QAAM,UAAU,IAAI,UAAU,SAAS,CAAC,EAAE,KAAK;AAG/C,QAAM,OAAO,qBAAqB,WAAW;AAE7C,QAAM,OAAO,KAAK;AAClB,MAAI,CAAC,KAAM,QAAO;AAElB,QAAM,OAAiB,CAAC;AACxB,QAAM,aAAa,KAAK,sBAAsB;AAC9C,MAAI,YAAY;AACd,SAAK,KAAK,GAAG,WAAW,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,OAAO,CAAC;AAAA,EACzE;AAEA,SAAO;AAAA,IACL;AAAA,IACA,aAAa,KAAK,eAAe;AAAA,IACjC,SAAS,KAAK,kBAAkB,KAAK,KAAK,WAAW;AAAA,IACrD;AAAA,IACA,MAAM,KAAK,SAAS,IAAI,OAAO;AAAA,EACjC;AACF;","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@actant/core",
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "Core runtime engine for the Actant AI agent platform",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "blackplume <blackplume233@gmail.com>",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/blackplume233/Actant.git",
|
|
11
|
+
"directory": "packages/core"
|
|
12
|
+
},
|
|
13
|
+
"homepage": "https://github.com/blackplume233/Actant#readme",
|
|
14
|
+
"bugs": "https://github.com/blackplume233/Actant/issues",
|
|
15
|
+
"keywords": [
|
|
16
|
+
"actant",
|
|
17
|
+
"ai-agent",
|
|
18
|
+
"core",
|
|
19
|
+
"runtime"
|
|
20
|
+
],
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"access": "public"
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"dist"
|
|
26
|
+
],
|
|
27
|
+
"main": "./dist/index.js",
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"exports": {
|
|
30
|
+
".": {
|
|
31
|
+
"import": "./dist/index.js",
|
|
32
|
+
"types": "./dist/index.d.ts"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"croner": "^9.0.0",
|
|
37
|
+
"zod": "^4.3.6",
|
|
38
|
+
"@actant/shared": "0.1.2"
|
|
39
|
+
},
|
|
40
|
+
"scripts": {
|
|
41
|
+
"build": "tsup",
|
|
42
|
+
"dev": "tsup --watch",
|
|
43
|
+
"type-check": "tsc --noEmit",
|
|
44
|
+
"test": "vitest run",
|
|
45
|
+
"clean": "rimraf dist"
|
|
46
|
+
}
|
|
47
|
+
}
|