heymark 2.0.0 → 2.0.1
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/README.ko.md +18 -21
- package/README.md +18 -21
- package/package.json +4 -4
- package/src/alias.js +41 -0
- package/src/commands/clean/index.js +17 -0
- package/src/commands/cleaner.js +27 -0
- package/src/commands/constants.js +14 -0
- package/src/commands/help/index.js +34 -0
- package/src/commands/link/flags/branch.js +18 -0
- package/src/commands/link/flags/folder.js +18 -0
- package/src/commands/link/index.js +58 -0
- package/src/commands/select-tools.js +35 -0
- package/src/commands/sync/index.js +35 -0
- package/src/index.js +52 -0
- package/src/skill-repo/cache-folder.js +77 -0
- package/src/skill-repo/config-file.js +87 -0
- package/src/skill-repo/constants.js +14 -0
- package/src/skill-repo/skill-file-parser.js +79 -0
- package/src/tools/antigravity/index.js +33 -0
- package/src/tools/claude-code/index.js +33 -0
- package/src/tools/codex/index.js +33 -0
- package/src/tools/constants.js +44 -0
- package/src/tools/copilot/index.js +40 -0
- package/src/tools/cursor/index.js +39 -0
- package/src/tools/loader.js +17 -0
- package/src/tools/skill-per-file.js +29 -0
- package/src/tools/skill-per-folder.js +18 -0
- package/scripts/cli.js +0 -375
- package/scripts/lib/config.js +0 -126
- package/scripts/lib/parser.js +0 -125
- package/scripts/lib/repo.js +0 -97
- package/scripts/tools/antigravity.js +0 -49
- package/scripts/tools/claude.js +0 -49
- package/scripts/tools/codex.js +0 -49
- package/scripts/tools/copilot.js +0 -61
- package/scripts/tools/cursor.js +0 -48
package/README.ko.md
CHANGED
|
@@ -26,17 +26,17 @@ _프롬프트 문맥에 맞는 Skill을 자동 로드하는 모습입니다._
|
|
|
26
26
|
- 단일 소스 관리: Markdown 기반 Skill을 한 곳에서 관리
|
|
27
27
|
- 자동 형식 변환: 도구별 형식으로 Skill 자동 생성
|
|
28
28
|
- 선택 동기화: 전체 또는 특정 도구만 동기화
|
|
29
|
-
- 샘플 Skill 즉시 사용:
|
|
29
|
+
- 샘플 Skill 즉시 사용: heymark 샘플 Skill 저장소로 바로 시작
|
|
30
30
|
|
|
31
31
|
## Supported Tools
|
|
32
32
|
|
|
33
|
-
| Tool
|
|
34
|
-
|
|
|
35
|
-
| Cursor
|
|
36
|
-
| Claude Code
|
|
37
|
-
|
|
|
38
|
-
|
|
|
39
|
-
| Antigravity
|
|
33
|
+
| Tool | CLI usage | Output Format |
|
|
34
|
+
| :---------- | :------------ | :--------------------------------------- |
|
|
35
|
+
| Cursor | `cursor` | `.cursor/rules/*.mdc` |
|
|
36
|
+
| Claude Code | `claude-code` | `.claude/skills/*/SKILL.md` |
|
|
37
|
+
| Copilot | `copilot` | `.github/instructions/*.instructions.md` |
|
|
38
|
+
| Codex | `codex` | `.agents/skills/*/SKILL.md` |
|
|
39
|
+
| Antigravity | `antigravity` | `.agent/skills/*/SKILL.md` |
|
|
40
40
|
|
|
41
41
|
## How to Use
|
|
42
42
|
|
|
@@ -68,7 +68,7 @@ Skill content...
|
|
|
68
68
|
### Quick Start
|
|
69
69
|
|
|
70
70
|
```bash
|
|
71
|
-
npx heymark link --samples
|
|
71
|
+
npx heymark link https://github.com/MosslandOpenDevs/heymark.git --folder skill-samples
|
|
72
72
|
npx heymark sync .
|
|
73
73
|
```
|
|
74
74
|
|
|
@@ -79,20 +79,17 @@ _`link`와 `sync` 실행 후, 각 도구가 요구하는 디렉터리에 Skill
|
|
|
79
79
|
### Commands
|
|
80
80
|
|
|
81
81
|
```bash
|
|
82
|
-
npx heymark link
|
|
82
|
+
npx heymark link <GitHub-저장소-URL>
|
|
83
|
+
npx heymark link <GitHub-저장소-URL> --folder <folder-name> # 하위 폴더 사용 시
|
|
84
|
+
npx heymark link <GitHub-저장소-URL> --branch <branch-name> # 다른 브랜치 사용 시
|
|
83
85
|
|
|
84
|
-
npx heymark
|
|
85
|
-
npx heymark
|
|
86
|
-
npx heymark link <GitHub-저장소-URL> --branch <branch-name> # 다른 브랜치 사용 시
|
|
86
|
+
npx heymark sync . # 전체 동기화
|
|
87
|
+
npx heymark sync cursor claude-code # 일부 도구만 동기화
|
|
87
88
|
|
|
88
|
-
npx heymark
|
|
89
|
-
npx heymark
|
|
89
|
+
npx heymark clean . # 전체 정리
|
|
90
|
+
npx heymark clean cursor claude-code # 일부 도구만 정리
|
|
90
91
|
|
|
91
|
-
npx heymark
|
|
92
|
-
npx heymark clean cursor claude # 일부 도구만 정리
|
|
93
|
-
|
|
94
|
-
npx heymark status # 상태 확인 (status 생략 가능)
|
|
95
|
-
npx heymark help # 명령어 확인
|
|
92
|
+
npx heymark help
|
|
96
93
|
```
|
|
97
94
|
|
|
98
95
|
## How to Dev
|
|
@@ -105,7 +102,7 @@ npx heymark help # 명령어 확인
|
|
|
105
102
|
|
|
106
103
|
### Local Development
|
|
107
104
|
|
|
108
|
-
`How to Use` 섹션의 `npx heymark`를 `node
|
|
105
|
+
`How to Use` 섹션의 `npx heymark`를 `node src/index.js`로 바꿔 실행하면 됩니다.
|
|
109
106
|
|
|
110
107
|
### Release
|
|
111
108
|
|
package/README.md
CHANGED
|
@@ -28,17 +28,17 @@ _This shows Skills being automatically loaded based on prompt context._
|
|
|
28
28
|
- Single source management: Manage Markdown-based Skills in one place
|
|
29
29
|
- Automatic format conversion: Generate Skill outputs in each tool's required format
|
|
30
30
|
- Selective sync: Sync all tools or only selected tools
|
|
31
|
-
-
|
|
31
|
+
- Sample skills: Try instantly with the heymark sample skill repo
|
|
32
32
|
|
|
33
33
|
## Supported Tools
|
|
34
34
|
|
|
35
|
-
| Tool
|
|
36
|
-
|
|
|
37
|
-
| Cursor
|
|
38
|
-
| Claude Code
|
|
39
|
-
|
|
|
40
|
-
|
|
|
41
|
-
| Antigravity
|
|
35
|
+
| Tool | CLI usage | Output Format |
|
|
36
|
+
| :---------- | :------------ | :--------------------------------------- |
|
|
37
|
+
| Cursor | `cursor` | `.cursor/rules/*.mdc` |
|
|
38
|
+
| Claude Code | `claude-code` | `.claude/skills/*/SKILL.md` |
|
|
39
|
+
| Copilot | `copilot` | `.github/instructions/*.instructions.md` |
|
|
40
|
+
| Codex | `codex` | `.agents/skills/*/SKILL.md` |
|
|
41
|
+
| Antigravity | `antigravity` | `.agent/skills/*/SKILL.md` |
|
|
42
42
|
|
|
43
43
|
## How to Use
|
|
44
44
|
|
|
@@ -70,7 +70,7 @@ Skill content...
|
|
|
70
70
|
### Quick Start
|
|
71
71
|
|
|
72
72
|
```bash
|
|
73
|
-
npx heymark link --samples
|
|
73
|
+
npx heymark link https://github.com/MosslandOpenDevs/heymark.git --folder skill-samples
|
|
74
74
|
npx heymark sync .
|
|
75
75
|
```
|
|
76
76
|
|
|
@@ -81,20 +81,17 @@ _After `link` and `sync`, Skill files are generated in each tool's expected dire
|
|
|
81
81
|
### Commands
|
|
82
82
|
|
|
83
83
|
```bash
|
|
84
|
-
npx heymark link
|
|
84
|
+
npx heymark link <GitHub-Repository-URL>
|
|
85
|
+
npx heymark link <GitHub-Repository-URL> --folder <folder-name>
|
|
86
|
+
npx heymark link <GitHub-Repository-URL> --branch <branch-name>
|
|
85
87
|
|
|
86
|
-
npx heymark
|
|
87
|
-
npx heymark
|
|
88
|
-
npx heymark link <GitHub-Repository-URL> --branch <branch-name> # when using another branch
|
|
88
|
+
npx heymark sync . # sync all tools
|
|
89
|
+
npx heymark sync cursor claude-code # sync selected tools
|
|
89
90
|
|
|
90
|
-
npx heymark
|
|
91
|
-
npx heymark
|
|
91
|
+
npx heymark clean . # clean all generated outputs
|
|
92
|
+
npx heymark clean cursor claude-code # clean selected tool outputs
|
|
92
93
|
|
|
93
|
-
npx heymark
|
|
94
|
-
npx heymark clean cursor claude # clean selected tool outputs
|
|
95
|
-
|
|
96
|
-
npx heymark status # check status (same as running npx heymark)
|
|
97
|
-
npx heymark help # show command help
|
|
94
|
+
npx heymark help
|
|
98
95
|
```
|
|
99
96
|
|
|
100
97
|
## How to Dev
|
|
@@ -107,7 +104,7 @@ npx heymark help # show command help
|
|
|
107
104
|
|
|
108
105
|
### Local Development
|
|
109
106
|
|
|
110
|
-
Replace `npx heymark` in the `How to Use` section with `node
|
|
107
|
+
Replace `npx heymark` in the `How to Use` section with `node src/index.js` for local runs.
|
|
111
108
|
|
|
112
109
|
### Release
|
|
113
110
|
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "heymark",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "Rules & Skills Hub for AI Coding Assistants",
|
|
5
5
|
"type": "commonjs",
|
|
6
|
-
"main": "
|
|
7
|
-
"bin": "
|
|
6
|
+
"main": "src/index.js",
|
|
7
|
+
"bin": "src/index.js",
|
|
8
8
|
"keywords": [
|
|
9
9
|
"ai-coding-assistant",
|
|
10
10
|
"ai-agent",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"node": ">=14.0.0"
|
|
45
45
|
},
|
|
46
46
|
"files": [
|
|
47
|
-
"
|
|
47
|
+
"src/"
|
|
48
48
|
],
|
|
49
49
|
"repository": {
|
|
50
50
|
"type": "git",
|
package/src/alias.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const Module = require("module");
|
|
4
|
+
|
|
5
|
+
const PREFIX = "@/";
|
|
6
|
+
const REGISTERED_KEY = "__heymark_alias_registered__";
|
|
7
|
+
const ROOT = __dirname;
|
|
8
|
+
|
|
9
|
+
function getPath(request) {
|
|
10
|
+
if (!request.startsWith(PREFIX)) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const rest = request.slice(PREFIX.length);
|
|
15
|
+
const base = path.join(ROOT, rest);
|
|
16
|
+
const candidates = [`${base}.js`, path.join(base, "index.js"), base];
|
|
17
|
+
|
|
18
|
+
const found = candidates.find((c) => fs.existsSync(c));
|
|
19
|
+
return found || base;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function registerPath() {
|
|
23
|
+
const g = /** @type {Record<string, unknown>} */ (globalThis);
|
|
24
|
+
if (g[REGISTERED_KEY] === true) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const original = Module._resolveFilename;
|
|
29
|
+
|
|
30
|
+
Module._resolveFilename = function (request, parent, isMain, options) {
|
|
31
|
+
const resolved = typeof request === "string" ? getPath(request) : null;
|
|
32
|
+
if (resolved) {
|
|
33
|
+
return original.call(this, resolved, parent, isMain, options);
|
|
34
|
+
}
|
|
35
|
+
return original.call(this, request, parent, isMain, options);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
g[REGISTERED_KEY] = true;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
registerPath();
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const { cleaner } = require("@/commands/cleaner");
|
|
2
|
+
const { selectTools } = require("@/commands/select-tools");
|
|
3
|
+
const { readCache } = require("@/skill-repo/cache-folder");
|
|
4
|
+
|
|
5
|
+
function runClean(flags, context) {
|
|
6
|
+
const selectedTools = selectTools(flags, context.tools);
|
|
7
|
+
const { skills } = readCache(context.cwd);
|
|
8
|
+
|
|
9
|
+
const skillNames = skills.map((s) => s.name);
|
|
10
|
+
const cleanedCount = cleaner(context.tools, selectedTools, skillNames, context.cwd);
|
|
11
|
+
|
|
12
|
+
console.log(`[Done] ${cleanedCount} tools cleaned.`);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
module.exports = {
|
|
16
|
+
runClean,
|
|
17
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
function cleaner(tools, selectedTools, skillNames, cwd) {
|
|
2
|
+
let headerPrinted = false;
|
|
3
|
+
let cleanedCount = 0;
|
|
4
|
+
|
|
5
|
+
for (const toolKey of selectedTools) {
|
|
6
|
+
const cleanedPaths = tools[toolKey].clean(skillNames, cwd);
|
|
7
|
+
if (cleanedPaths.length === 0) continue;
|
|
8
|
+
|
|
9
|
+
if (!headerPrinted) {
|
|
10
|
+
console.log("[Clean]");
|
|
11
|
+
headerPrinted = true;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
cleanedPaths.forEach((p) => console.log(` Removed: ${p}`));
|
|
15
|
+
cleanedCount++;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (headerPrinted) {
|
|
19
|
+
console.log("");
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return cleanedCount;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
module.exports = {
|
|
26
|
+
cleaner,
|
|
27
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const COMMAND_LINK = "link";
|
|
2
|
+
const COMMAND_SYNC = "sync";
|
|
3
|
+
const COMMAND_CLEAN = "clean";
|
|
4
|
+
const COMMAND_HELP = "help";
|
|
5
|
+
|
|
6
|
+
const LATEST_VERSION_COMMAND = "npx heymark@latest";
|
|
7
|
+
|
|
8
|
+
module.exports = {
|
|
9
|
+
COMMAND_LINK,
|
|
10
|
+
COMMAND_SYNC,
|
|
11
|
+
COMMAND_CLEAN,
|
|
12
|
+
COMMAND_HELP,
|
|
13
|
+
LATEST_VERSION_COMMAND,
|
|
14
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
const { LATEST_VERSION_COMMAND } = require("@/commands/constants");
|
|
2
|
+
|
|
3
|
+
function runHelp(flags, context) {
|
|
4
|
+
if (flags.length > 0) {
|
|
5
|
+
console.error(`[Error] Unknown: ${flags.join(", ")}. help takes no arguments.`);
|
|
6
|
+
process.exit(1);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const toolLines = Object.entries(context.tools)
|
|
10
|
+
.map(([key, tool]) => ` ${key.padEnd(14)} ${tool.output}`)
|
|
11
|
+
.join("\n");
|
|
12
|
+
|
|
13
|
+
console.log(`
|
|
14
|
+
Usage:
|
|
15
|
+
heymark link <repo-url>
|
|
16
|
+
heymark sync .
|
|
17
|
+
heymark sync <tool1> <tool2> ...
|
|
18
|
+
heymark clean .
|
|
19
|
+
heymark clean <tool1> <tool2> ...
|
|
20
|
+
|
|
21
|
+
Link flags:
|
|
22
|
+
--branch | -b
|
|
23
|
+
--folder | -f
|
|
24
|
+
|
|
25
|
+
Supported tools:
|
|
26
|
+
${toolLines}
|
|
27
|
+
|
|
28
|
+
Update: ${LATEST_VERSION_COMMAND}
|
|
29
|
+
`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
module.exports = {
|
|
33
|
+
runHelp,
|
|
34
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const key = "branch";
|
|
2
|
+
const FLAG = "--branch";
|
|
3
|
+
const SHORT_FLAG = "-b";
|
|
4
|
+
|
|
5
|
+
function is(flag) {
|
|
6
|
+
return flag === FLAG || flag === SHORT_FLAG;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function parse(flags, index) {
|
|
10
|
+
const value = flags[index + 1];
|
|
11
|
+
if (!value) {
|
|
12
|
+
console.error("[Error] --branch needs a value.");
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
return { value: value.trim(), advance: 1 };
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
module.exports = { key, is, parse };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const key = "folder";
|
|
2
|
+
const FLAG = "--folder";
|
|
3
|
+
const SHORT_FLAG = "-f";
|
|
4
|
+
|
|
5
|
+
function is(flag) {
|
|
6
|
+
return flag === FLAG || flag === SHORT_FLAG;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function parse(flags, index) {
|
|
10
|
+
const value = flags[index + 1];
|
|
11
|
+
if (!value) {
|
|
12
|
+
console.error("[Error] --folder needs a value.");
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
return { value: value.trim(), advance: 1 };
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
module.exports = { key, is, parse };
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
const path = require("path");
|
|
2
|
+
const { writeConfig } = require("@/skill-repo/config-file");
|
|
3
|
+
const { SKILL_REPO_DEFAULT_BRANCH } = require("@/skill-repo/constants");
|
|
4
|
+
const branch = require("@/commands/link/flags/branch");
|
|
5
|
+
const folder = require("@/commands/link/flags/folder");
|
|
6
|
+
|
|
7
|
+
function parseFlags(flags, handlers) {
|
|
8
|
+
const result = {};
|
|
9
|
+
for (let i = 0; i < flags.length; i++) {
|
|
10
|
+
const flag = flags[i];
|
|
11
|
+
const handler = handlers.find((h) => h.is(flag));
|
|
12
|
+
if (handler) {
|
|
13
|
+
const parsed = handler.parse(flags, i);
|
|
14
|
+
result[handler.key] = parsed.value;
|
|
15
|
+
i += parsed.advance;
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
console.error(`[Error] Unknown flag: ${flag}`);
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
return result;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function parseConfig(flags) {
|
|
25
|
+
const repoUrl = flags[0];
|
|
26
|
+
if (!repoUrl || repoUrl.startsWith("--")) {
|
|
27
|
+
console.error(
|
|
28
|
+
"[Error] Provide a repo URL. Example: heymark link https://github.com/org/repo.git"
|
|
29
|
+
);
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const parsed = parseFlags(flags.slice(1), [branch, folder]);
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
repoUrl: repoUrl.trim(),
|
|
37
|
+
branch: parsed.branch || SKILL_REPO_DEFAULT_BRANCH,
|
|
38
|
+
folder: parsed.folder || "",
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function runLink(flags, context) {
|
|
43
|
+
const config = parseConfig(flags);
|
|
44
|
+
const configPath = writeConfig(context.cwd, config);
|
|
45
|
+
|
|
46
|
+
console.log(`[Link] Saved to ${path.relative(context.cwd, configPath) || configPath}`);
|
|
47
|
+
console.log(` repo: ${config.repoUrl}`);
|
|
48
|
+
if (config.branch !== SKILL_REPO_DEFAULT_BRANCH) {
|
|
49
|
+
console.log(` branch: ${config.branch}`);
|
|
50
|
+
}
|
|
51
|
+
if (config.folder) {
|
|
52
|
+
console.log(` folder: ${config.folder}`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
module.exports = {
|
|
57
|
+
runLink,
|
|
58
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
const ALL_TOOLS_TOKEN = ".";
|
|
2
|
+
|
|
3
|
+
function selectTools(flags, availableTools) {
|
|
4
|
+
const availableToolKeys = Object.keys(availableTools);
|
|
5
|
+
if (flags.length === 0) {
|
|
6
|
+
return availableToolKeys;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
if (flags.some((tool) => tool.includes(","))) {
|
|
10
|
+
console.error("[Error] Use spaces between tools, not commas.");
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (flags.includes(ALL_TOOLS_TOKEN)) {
|
|
15
|
+
if (flags.length > 1) {
|
|
16
|
+
console.error("[Error] Use '.' alone for all tools.");
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
return availableToolKeys;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const invalid = flags.filter((tool) => !availableTools[tool]);
|
|
23
|
+
if (invalid.length > 0) {
|
|
24
|
+
console.error(
|
|
25
|
+
`[Error] Unknown: ${invalid.join(", ")}. Available: ${availableToolKeys.join(", ")}`
|
|
26
|
+
);
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return Array.from(new Set(flags));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
module.exports = {
|
|
34
|
+
selectTools,
|
|
35
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
const { cleaner } = require("@/commands/cleaner");
|
|
2
|
+
const { selectTools } = require("@/commands/select-tools");
|
|
3
|
+
const { readCache } = require("@/skill-repo/cache-folder");
|
|
4
|
+
const { readConfig } = require("@/skill-repo/config-file");
|
|
5
|
+
const { SKILL_REPO_DEFAULT_BRANCH } = require("@/skill-repo/constants");
|
|
6
|
+
|
|
7
|
+
function runSync(flags, context) {
|
|
8
|
+
const selectedTools = selectTools(flags, context.tools);
|
|
9
|
+
const { skills } = readCache(context.cwd);
|
|
10
|
+
const config = readConfig(context.cwd);
|
|
11
|
+
|
|
12
|
+
console.log("[Sync]");
|
|
13
|
+
if (config) {
|
|
14
|
+
console.log(` repo: ${config.repoUrl}`);
|
|
15
|
+
if (config.folder) console.log(` folder: ${config.folder}`);
|
|
16
|
+
if (config.branch !== SKILL_REPO_DEFAULT_BRANCH) console.log(` branch: ${config.branch}`);
|
|
17
|
+
}
|
|
18
|
+
console.log("");
|
|
19
|
+
|
|
20
|
+
const skillNames = skills.map((s) => s.name);
|
|
21
|
+
cleaner(context.tools, selectedTools, skillNames, context.cwd);
|
|
22
|
+
|
|
23
|
+
for (const toolKey of selectedTools) {
|
|
24
|
+
const tool = context.tools[toolKey];
|
|
25
|
+
const count = tool.generate(skills, context.cwd);
|
|
26
|
+
console.log(` ${tool.name.padEnd(16)} -> ${tool.output} (${count} skills)`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
console.log("");
|
|
30
|
+
console.log(`[Done] ${selectedTools.length} tools synced.`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
module.exports = {
|
|
34
|
+
runSync,
|
|
35
|
+
};
|
package/src/index.js
ADDED
|
@@ -0,0 +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();
|
|
@@ -0,0 +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
|
+
};
|