heymark 2.0.1 → 2.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 -21
- package/README.ko.md +121 -120
- package/README.md +123 -122
- package/package.json +57 -56
- package/src/alias.js +41 -41
- package/src/commands/clean/index.js +17 -17
- package/src/commands/cleaner.js +27 -27
- package/src/commands/constants.js +14 -14
- package/src/commands/help/index.js +34 -34
- package/src/commands/link/flags/branch.js +18 -18
- package/src/commands/link/flags/folder.js +18 -18
- package/src/commands/link/index.js +58 -58
- package/src/commands/select-tools.js +35 -35
- package/src/commands/sync/index.js +35 -35
- package/src/index.js +52 -52
- package/src/skill-repo/cache-folder.js +77 -77
- package/src/skill-repo/config-file.js +87 -87
- package/src/skill-repo/constants.js +14 -14
- package/src/skill-repo/skill-file-parser.js +79 -79
- package/src/tools/antigravity/index.js +33 -33
- package/src/tools/claude-code/index.js +33 -33
- package/src/tools/codex/index.js +33 -33
- package/src/tools/constants.js +52 -44
- package/src/tools/copilot/index.js +40 -40
- package/src/tools/cursor/index.js +39 -39
- package/src/tools/loader.js +17 -17
- package/src/tools/openclaw/index.js +72 -0
- package/src/tools/skill-per-file.js +29 -29
- package/src/tools/skill-per-folder.js +18 -18
package/src/index.js
CHANGED
|
@@ -1,52 +1,52 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
require("./alias.js");
|
|
4
|
-
|
|
5
|
-
const { COMMAND_LINK, COMMAND_SYNC, COMMAND_CLEAN, COMMAND_HELP } = require("@/commands/constants");
|
|
6
|
-
const { runLink } = require("@/commands/link");
|
|
7
|
-
const { runSync } = require("@/commands/sync");
|
|
8
|
-
const { runClean } = require("@/commands/clean");
|
|
9
|
-
const { runHelp } = require("@/commands/help");
|
|
10
|
-
const { loadTools } = require("@/tools/loader");
|
|
11
|
-
|
|
12
|
-
function main() {
|
|
13
|
-
const context = {
|
|
14
|
-
cwd: process.cwd(),
|
|
15
|
-
tools: loadTools(),
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
const args = process.argv.slice(2);
|
|
19
|
-
|
|
20
|
-
if (args.length === 0) {
|
|
21
|
-
runHelp([], context);
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const command = args[0];
|
|
26
|
-
const flags = args.slice(1);
|
|
27
|
-
|
|
28
|
-
if (command === COMMAND_LINK) {
|
|
29
|
-
runLink(flags, context);
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
if (command === COMMAND_SYNC) {
|
|
34
|
-
runSync(flags, context);
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
if (command === COMMAND_CLEAN) {
|
|
39
|
-
runClean(flags, context);
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
if (command === COMMAND_HELP) {
|
|
44
|
-
runHelp(flags, context);
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
console.error(`[Error] Unknown command: ${command}. Run: heymark help`);
|
|
49
|
-
process.exit(1);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
main();
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
require("./alias.js");
|
|
4
|
+
|
|
5
|
+
const { COMMAND_LINK, COMMAND_SYNC, COMMAND_CLEAN, COMMAND_HELP } = require("@/commands/constants");
|
|
6
|
+
const { runLink } = require("@/commands/link");
|
|
7
|
+
const { runSync } = require("@/commands/sync");
|
|
8
|
+
const { runClean } = require("@/commands/clean");
|
|
9
|
+
const { runHelp } = require("@/commands/help");
|
|
10
|
+
const { loadTools } = require("@/tools/loader");
|
|
11
|
+
|
|
12
|
+
function main() {
|
|
13
|
+
const context = {
|
|
14
|
+
cwd: process.cwd(),
|
|
15
|
+
tools: loadTools(),
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const args = process.argv.slice(2);
|
|
19
|
+
|
|
20
|
+
if (args.length === 0) {
|
|
21
|
+
runHelp([], context);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const command = args[0];
|
|
26
|
+
const flags = args.slice(1);
|
|
27
|
+
|
|
28
|
+
if (command === COMMAND_LINK) {
|
|
29
|
+
runLink(flags, context);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (command === COMMAND_SYNC) {
|
|
34
|
+
runSync(flags, context);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (command === COMMAND_CLEAN) {
|
|
39
|
+
runClean(flags, context);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (command === COMMAND_HELP) {
|
|
44
|
+
runHelp(flags, context);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
console.error(`[Error] Unknown command: ${command}. Run: heymark help`);
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
main();
|
|
@@ -1,77 +1,77 @@
|
|
|
1
|
-
const fs = require("fs");
|
|
2
|
-
const path = require("path");
|
|
3
|
-
const { execSync } = require("child_process");
|
|
4
|
-
const { HEYMARK, SKILL_REPO_DEFAULT_BRANCH } = require("@/skill-repo/constants");
|
|
5
|
-
const { readConfig } = require("@/skill-repo/config-file");
|
|
6
|
-
const { readSkillFiles } = require("@/skill-repo/skill-file-parser");
|
|
7
|
-
|
|
8
|
-
function getCloneFolderPath(cwd, repoUrl) {
|
|
9
|
-
const name = repoUrl.trim().split("/").pop() || "repo";
|
|
10
|
-
const dirName = name.endsWith(".git") ? name.slice(0, -4) : name;
|
|
11
|
-
return path.join(cwd, HEYMARK.DIR, HEYMARK.CACHE_DIR, dirName);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function gitClone(cwd, dir, branch, repoUrl) {
|
|
15
|
-
execSync(`git clone --depth 1 --branch "${branch}" "${repoUrl}" "${dir}"`, {
|
|
16
|
-
stdio: "inherit",
|
|
17
|
-
cwd,
|
|
18
|
-
});
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function gitPull(dir, branch) {
|
|
22
|
-
execSync(`git fetch origin && git checkout --quiet . && git pull --quiet origin "${branch}"`, {
|
|
23
|
-
stdio: "pipe",
|
|
24
|
-
cwd: dir,
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function writeCache(cwd) {
|
|
29
|
-
const config = readConfig(cwd);
|
|
30
|
-
if (!config) {
|
|
31
|
-
console.error(
|
|
32
|
-
`[Error] Not linked. Run: heymark link <repo-url> (config: ${HEYMARK.DIR}/${HEYMARK.CONFIG_FILE})`
|
|
33
|
-
);
|
|
34
|
-
process.exit(1);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const branch = config.branch || SKILL_REPO_DEFAULT_BRANCH;
|
|
38
|
-
const cacheBase = path.join(cwd, HEYMARK.DIR, HEYMARK.CACHE_DIR);
|
|
39
|
-
const cloneFolderPath = getCloneFolderPath(cwd, config.repoUrl);
|
|
40
|
-
|
|
41
|
-
if (!fs.existsSync(cloneFolderPath)) {
|
|
42
|
-
fs.mkdirSync(cacheBase, { recursive: true });
|
|
43
|
-
try {
|
|
44
|
-
gitClone(cwd, cloneFolderPath, branch, config.repoUrl);
|
|
45
|
-
} catch {
|
|
46
|
-
console.error("[Error] Clone failed. Check repo access (SSH or token).");
|
|
47
|
-
process.exit(1);
|
|
48
|
-
}
|
|
49
|
-
} else {
|
|
50
|
-
try {
|
|
51
|
-
gitPull(cloneFolderPath, branch);
|
|
52
|
-
} catch {
|
|
53
|
-
// Continue with cached clone when fetch/pull fails.
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return { config, cloneFolderPath };
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function readCache(cwd) {
|
|
61
|
-
const { config, cloneFolderPath } = writeCache(cwd);
|
|
62
|
-
|
|
63
|
-
const folder = config.folder || "";
|
|
64
|
-
const skillsFolderPath = folder ? path.join(cloneFolderPath, folder) : cloneFolderPath;
|
|
65
|
-
if (!fs.existsSync(skillsFolderPath) || !fs.statSync(skillsFolderPath).isDirectory()) {
|
|
66
|
-
console.error(`[Error] Folder not found in repo: ${folder || "(root)"}`);
|
|
67
|
-
process.exit(1);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const skills = readSkillFiles(skillsFolderPath);
|
|
71
|
-
|
|
72
|
-
return { config, skillsFolderPath, skills };
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
module.exports = {
|
|
76
|
-
readCache,
|
|
77
|
-
};
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const { execSync } = require("child_process");
|
|
4
|
+
const { HEYMARK, SKILL_REPO_DEFAULT_BRANCH } = require("@/skill-repo/constants");
|
|
5
|
+
const { readConfig } = require("@/skill-repo/config-file");
|
|
6
|
+
const { readSkillFiles } = require("@/skill-repo/skill-file-parser");
|
|
7
|
+
|
|
8
|
+
function getCloneFolderPath(cwd, repoUrl) {
|
|
9
|
+
const name = repoUrl.trim().split("/").pop() || "repo";
|
|
10
|
+
const dirName = name.endsWith(".git") ? name.slice(0, -4) : name;
|
|
11
|
+
return path.join(cwd, HEYMARK.DIR, HEYMARK.CACHE_DIR, dirName);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function gitClone(cwd, dir, branch, repoUrl) {
|
|
15
|
+
execSync(`git clone --depth 1 --branch "${branch}" "${repoUrl}" "${dir}"`, {
|
|
16
|
+
stdio: "inherit",
|
|
17
|
+
cwd,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function gitPull(dir, branch) {
|
|
22
|
+
execSync(`git fetch origin && git checkout --quiet . && git pull --quiet origin "${branch}"`, {
|
|
23
|
+
stdio: "pipe",
|
|
24
|
+
cwd: dir,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function writeCache(cwd) {
|
|
29
|
+
const config = readConfig(cwd);
|
|
30
|
+
if (!config) {
|
|
31
|
+
console.error(
|
|
32
|
+
`[Error] Not linked. Run: heymark link <repo-url> (config: ${HEYMARK.DIR}/${HEYMARK.CONFIG_FILE})`
|
|
33
|
+
);
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const branch = config.branch || SKILL_REPO_DEFAULT_BRANCH;
|
|
38
|
+
const cacheBase = path.join(cwd, HEYMARK.DIR, HEYMARK.CACHE_DIR);
|
|
39
|
+
const cloneFolderPath = getCloneFolderPath(cwd, config.repoUrl);
|
|
40
|
+
|
|
41
|
+
if (!fs.existsSync(cloneFolderPath)) {
|
|
42
|
+
fs.mkdirSync(cacheBase, { recursive: true });
|
|
43
|
+
try {
|
|
44
|
+
gitClone(cwd, cloneFolderPath, branch, config.repoUrl);
|
|
45
|
+
} catch {
|
|
46
|
+
console.error("[Error] Clone failed. Check repo access (SSH or token).");
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
} else {
|
|
50
|
+
try {
|
|
51
|
+
gitPull(cloneFolderPath, branch);
|
|
52
|
+
} catch {
|
|
53
|
+
// Continue with cached clone when fetch/pull fails.
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return { config, cloneFolderPath };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function readCache(cwd) {
|
|
61
|
+
const { config, cloneFolderPath } = writeCache(cwd);
|
|
62
|
+
|
|
63
|
+
const folder = config.folder || "";
|
|
64
|
+
const skillsFolderPath = folder ? path.join(cloneFolderPath, folder) : cloneFolderPath;
|
|
65
|
+
if (!fs.existsSync(skillsFolderPath) || !fs.statSync(skillsFolderPath).isDirectory()) {
|
|
66
|
+
console.error(`[Error] Folder not found in repo: ${folder || "(root)"}`);
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const skills = readSkillFiles(skillsFolderPath);
|
|
71
|
+
|
|
72
|
+
return { config, skillsFolderPath, skills };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
module.exports = {
|
|
76
|
+
readCache,
|
|
77
|
+
};
|
|
@@ -1,87 +1,87 @@
|
|
|
1
|
-
const fs = require("fs");
|
|
2
|
-
const path = require("path");
|
|
3
|
-
const { HEYMARK, SKILL_REPO_DEFAULT_BRANCH } = require("@/skill-repo/constants");
|
|
4
|
-
|
|
5
|
-
function getConfigFilePath(cwd) {
|
|
6
|
-
return path.join(cwd, HEYMARK.DIR, HEYMARK.CONFIG_FILE);
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
function parseRawConfig(rawConfig) {
|
|
10
|
-
if (!rawConfig || typeof rawConfig !== "object") {
|
|
11
|
-
return null;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const raw = rawConfig;
|
|
15
|
-
|
|
16
|
-
const repoUrl =
|
|
17
|
-
typeof raw.repoUrl === "string" && raw.repoUrl.trim()
|
|
18
|
-
? raw.repoUrl.trim()
|
|
19
|
-
: typeof raw.skillSource === "string" && raw.skillSource.trim()
|
|
20
|
-
? raw.skillSource.trim()
|
|
21
|
-
: typeof raw.rulesSource === "string" && raw.rulesSource.trim()
|
|
22
|
-
? raw.rulesSource.trim()
|
|
23
|
-
: "";
|
|
24
|
-
|
|
25
|
-
if (!repoUrl) {
|
|
26
|
-
return null;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const branch =
|
|
30
|
-
typeof raw.branch === "string" && raw.branch.trim()
|
|
31
|
-
? raw.branch.trim()
|
|
32
|
-
: SKILL_REPO_DEFAULT_BRANCH;
|
|
33
|
-
|
|
34
|
-
const folder =
|
|
35
|
-
typeof raw.folder === "string"
|
|
36
|
-
? raw.folder.trim()
|
|
37
|
-
: typeof raw.skillSourceDir === "string"
|
|
38
|
-
? raw.skillSourceDir.trim()
|
|
39
|
-
: typeof raw.rulesSourceDir === "string"
|
|
40
|
-
? raw.rulesSourceDir.trim()
|
|
41
|
-
: "";
|
|
42
|
-
|
|
43
|
-
return { repoUrl, branch, folder };
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function writeConfig(cwd, config) {
|
|
47
|
-
const dir = path.join(cwd, HEYMARK.DIR);
|
|
48
|
-
if (!fs.existsSync(dir)) {
|
|
49
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const data = parseRawConfig(config);
|
|
53
|
-
if (!data) {
|
|
54
|
-
throw new Error("Invalid config");
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const filePath = getConfigFilePath(cwd);
|
|
58
|
-
const payload = {
|
|
59
|
-
repoUrl: data.repoUrl,
|
|
60
|
-
branch: data.branch || SKILL_REPO_DEFAULT_BRANCH,
|
|
61
|
-
};
|
|
62
|
-
if (data.folder) {
|
|
63
|
-
payload.folder = data.folder;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
fs.writeFileSync(filePath, JSON.stringify(payload, null, 2), "utf8");
|
|
67
|
-
return filePath;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function readConfig(cwd) {
|
|
71
|
-
const filePath = getConfigFilePath(cwd);
|
|
72
|
-
if (!fs.existsSync(filePath)) {
|
|
73
|
-
return null;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
try {
|
|
77
|
-
const raw = fs.readFileSync(filePath, "utf8");
|
|
78
|
-
return parseRawConfig(JSON.parse(raw));
|
|
79
|
-
} catch {
|
|
80
|
-
return null;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
module.exports = {
|
|
85
|
-
writeConfig,
|
|
86
|
-
readConfig,
|
|
87
|
-
};
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const { HEYMARK, SKILL_REPO_DEFAULT_BRANCH } = require("@/skill-repo/constants");
|
|
4
|
+
|
|
5
|
+
function getConfigFilePath(cwd) {
|
|
6
|
+
return path.join(cwd, HEYMARK.DIR, HEYMARK.CONFIG_FILE);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function parseRawConfig(rawConfig) {
|
|
10
|
+
if (!rawConfig || typeof rawConfig !== "object") {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const raw = rawConfig;
|
|
15
|
+
|
|
16
|
+
const repoUrl =
|
|
17
|
+
typeof raw.repoUrl === "string" && raw.repoUrl.trim()
|
|
18
|
+
? raw.repoUrl.trim()
|
|
19
|
+
: typeof raw.skillSource === "string" && raw.skillSource.trim()
|
|
20
|
+
? raw.skillSource.trim()
|
|
21
|
+
: typeof raw.rulesSource === "string" && raw.rulesSource.trim()
|
|
22
|
+
? raw.rulesSource.trim()
|
|
23
|
+
: "";
|
|
24
|
+
|
|
25
|
+
if (!repoUrl) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const branch =
|
|
30
|
+
typeof raw.branch === "string" && raw.branch.trim()
|
|
31
|
+
? raw.branch.trim()
|
|
32
|
+
: SKILL_REPO_DEFAULT_BRANCH;
|
|
33
|
+
|
|
34
|
+
const folder =
|
|
35
|
+
typeof raw.folder === "string"
|
|
36
|
+
? raw.folder.trim()
|
|
37
|
+
: typeof raw.skillSourceDir === "string"
|
|
38
|
+
? raw.skillSourceDir.trim()
|
|
39
|
+
: typeof raw.rulesSourceDir === "string"
|
|
40
|
+
? raw.rulesSourceDir.trim()
|
|
41
|
+
: "";
|
|
42
|
+
|
|
43
|
+
return { repoUrl, branch, folder };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function writeConfig(cwd, config) {
|
|
47
|
+
const dir = path.join(cwd, HEYMARK.DIR);
|
|
48
|
+
if (!fs.existsSync(dir)) {
|
|
49
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const data = parseRawConfig(config);
|
|
53
|
+
if (!data) {
|
|
54
|
+
throw new Error("Invalid config");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const filePath = getConfigFilePath(cwd);
|
|
58
|
+
const payload = {
|
|
59
|
+
repoUrl: data.repoUrl,
|
|
60
|
+
branch: data.branch || SKILL_REPO_DEFAULT_BRANCH,
|
|
61
|
+
};
|
|
62
|
+
if (data.folder) {
|
|
63
|
+
payload.folder = data.folder;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
fs.writeFileSync(filePath, JSON.stringify(payload, null, 2), "utf8");
|
|
67
|
+
return filePath;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function readConfig(cwd) {
|
|
71
|
+
const filePath = getConfigFilePath(cwd);
|
|
72
|
+
if (!fs.existsSync(filePath)) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
const raw = fs.readFileSync(filePath, "utf8");
|
|
78
|
+
return parseRawConfig(JSON.parse(raw));
|
|
79
|
+
} catch {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
module.exports = {
|
|
85
|
+
writeConfig,
|
|
86
|
+
readConfig,
|
|
87
|
+
};
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
const HEYMARK = {
|
|
2
|
-
DIR: ".heymark",
|
|
3
|
-
CONFIG_FILE: "config.json",
|
|
4
|
-
CACHE_DIR: "cache",
|
|
5
|
-
};
|
|
6
|
-
|
|
7
|
-
const SKILL_FILE_EXTENSION = ".md";
|
|
8
|
-
const SKILL_REPO_DEFAULT_BRANCH = "main";
|
|
9
|
-
|
|
10
|
-
module.exports = {
|
|
11
|
-
HEYMARK,
|
|
12
|
-
SKILL_FILE_EXTENSION,
|
|
13
|
-
SKILL_REPO_DEFAULT_BRANCH,
|
|
14
|
-
};
|
|
1
|
+
const HEYMARK = {
|
|
2
|
+
DIR: ".heymark",
|
|
3
|
+
CONFIG_FILE: "config.json",
|
|
4
|
+
CACHE_DIR: "cache",
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
const SKILL_FILE_EXTENSION = ".md";
|
|
8
|
+
const SKILL_REPO_DEFAULT_BRANCH = "main";
|
|
9
|
+
|
|
10
|
+
module.exports = {
|
|
11
|
+
HEYMARK,
|
|
12
|
+
SKILL_FILE_EXTENSION,
|
|
13
|
+
SKILL_REPO_DEFAULT_BRANCH,
|
|
14
|
+
};
|
|
@@ -1,79 +1,79 @@
|
|
|
1
|
-
const fs = require("fs");
|
|
2
|
-
const path = require("path");
|
|
3
|
-
const { SKILL_FILE_EXTENSION } = require("@/skill-repo/constants");
|
|
4
|
-
|
|
5
|
-
const FRONTMATTER_REGEX = /^---\r?\n([\s\S]+?)\r?\n---\r?\n?([\s\S]*)$/;
|
|
6
|
-
|
|
7
|
-
function parseFrontmatter(content) {
|
|
8
|
-
const match = content.match(FRONTMATTER_REGEX);
|
|
9
|
-
if (!match) {
|
|
10
|
-
return { metadata: {}, body: content.trim() };
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const [, metadataBlock, body] = match;
|
|
14
|
-
|
|
15
|
-
const metadata = {};
|
|
16
|
-
metadataBlock.split(/\r?\n/).forEach((line) => {
|
|
17
|
-
const separatorIndex = line.indexOf(":");
|
|
18
|
-
if (separatorIndex === -1) return;
|
|
19
|
-
|
|
20
|
-
const key = line.slice(0, separatorIndex).trim();
|
|
21
|
-
let value = line.slice(separatorIndex + 1).trim();
|
|
22
|
-
|
|
23
|
-
if (
|
|
24
|
-
(value.startsWith('"') && value.endsWith('"')) ||
|
|
25
|
-
(value.startsWith("'") && value.endsWith("'"))
|
|
26
|
-
) {
|
|
27
|
-
value = value.slice(1, -1);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
if (value === "true") metadata[key] = true;
|
|
31
|
-
else if (value === "false") metadata[key] = false;
|
|
32
|
-
else metadata[key] = value;
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
return { metadata, body: body.trim() };
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function readSkillFile(skillsDir, fileName) {
|
|
39
|
-
const filePath = path.join(skillsDir, fileName);
|
|
40
|
-
const raw = fs.readFileSync(filePath, "utf8");
|
|
41
|
-
const { metadata, body } = parseFrontmatter(raw);
|
|
42
|
-
const baseName = path.basename(fileName, SKILL_FILE_EXTENSION);
|
|
43
|
-
|
|
44
|
-
return {
|
|
45
|
-
fileName,
|
|
46
|
-
name: typeof metadata.name === "string" && metadata.name ? metadata.name : baseName,
|
|
47
|
-
description:
|
|
48
|
-
typeof metadata.description === "string" && metadata.description
|
|
49
|
-
? metadata.description
|
|
50
|
-
: baseName,
|
|
51
|
-
globs: typeof metadata.globs === "string" ? metadata.globs : "",
|
|
52
|
-
alwaysApply: metadata.alwaysApply === true,
|
|
53
|
-
metadata,
|
|
54
|
-
body,
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function readSkillFiles(skillsDir) {
|
|
59
|
-
if (!fs.existsSync(skillsDir)) {
|
|
60
|
-
console.error(`[Error] Skills folder not found: ${skillsDir}`);
|
|
61
|
-
process.exit(1);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const files = fs
|
|
65
|
-
.readdirSync(skillsDir)
|
|
66
|
-
.filter((fileName) => fileName.endsWith(SKILL_FILE_EXTENSION))
|
|
67
|
-
.sort();
|
|
68
|
-
|
|
69
|
-
if (files.length === 0) {
|
|
70
|
-
console.error(`[Error] No .md files in: ${skillsDir}`);
|
|
71
|
-
process.exit(1);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
return files.map((fileName) => readSkillFile(skillsDir, fileName));
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
module.exports = {
|
|
78
|
-
readSkillFiles,
|
|
79
|
-
};
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const { SKILL_FILE_EXTENSION } = require("@/skill-repo/constants");
|
|
4
|
+
|
|
5
|
+
const FRONTMATTER_REGEX = /^---\r?\n([\s\S]+?)\r?\n---\r?\n?([\s\S]*)$/;
|
|
6
|
+
|
|
7
|
+
function parseFrontmatter(content) {
|
|
8
|
+
const match = content.match(FRONTMATTER_REGEX);
|
|
9
|
+
if (!match) {
|
|
10
|
+
return { metadata: {}, body: content.trim() };
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const [, metadataBlock, body] = match;
|
|
14
|
+
|
|
15
|
+
const metadata = {};
|
|
16
|
+
metadataBlock.split(/\r?\n/).forEach((line) => {
|
|
17
|
+
const separatorIndex = line.indexOf(":");
|
|
18
|
+
if (separatorIndex === -1) return;
|
|
19
|
+
|
|
20
|
+
const key = line.slice(0, separatorIndex).trim();
|
|
21
|
+
let value = line.slice(separatorIndex + 1).trim();
|
|
22
|
+
|
|
23
|
+
if (
|
|
24
|
+
(value.startsWith('"') && value.endsWith('"')) ||
|
|
25
|
+
(value.startsWith("'") && value.endsWith("'"))
|
|
26
|
+
) {
|
|
27
|
+
value = value.slice(1, -1);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (value === "true") metadata[key] = true;
|
|
31
|
+
else if (value === "false") metadata[key] = false;
|
|
32
|
+
else metadata[key] = value;
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
return { metadata, body: body.trim() };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function readSkillFile(skillsDir, fileName) {
|
|
39
|
+
const filePath = path.join(skillsDir, fileName);
|
|
40
|
+
const raw = fs.readFileSync(filePath, "utf8");
|
|
41
|
+
const { metadata, body } = parseFrontmatter(raw);
|
|
42
|
+
const baseName = path.basename(fileName, SKILL_FILE_EXTENSION);
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
fileName,
|
|
46
|
+
name: typeof metadata.name === "string" && metadata.name ? metadata.name : baseName,
|
|
47
|
+
description:
|
|
48
|
+
typeof metadata.description === "string" && metadata.description
|
|
49
|
+
? metadata.description
|
|
50
|
+
: baseName,
|
|
51
|
+
globs: typeof metadata.globs === "string" ? metadata.globs : "",
|
|
52
|
+
alwaysApply: metadata.alwaysApply === true,
|
|
53
|
+
metadata,
|
|
54
|
+
body,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function readSkillFiles(skillsDir) {
|
|
59
|
+
if (!fs.existsSync(skillsDir)) {
|
|
60
|
+
console.error(`[Error] Skills folder not found: ${skillsDir}`);
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const files = fs
|
|
65
|
+
.readdirSync(skillsDir)
|
|
66
|
+
.filter((fileName) => fileName.endsWith(SKILL_FILE_EXTENSION))
|
|
67
|
+
.sort();
|
|
68
|
+
|
|
69
|
+
if (files.length === 0) {
|
|
70
|
+
console.error(`[Error] No .md files in: ${skillsDir}`);
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return files.map((fileName) => readSkillFile(skillsDir, fileName));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
module.exports = {
|
|
78
|
+
readSkillFiles,
|
|
79
|
+
};
|