heymark 1.1.2 → 1.2.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 +170 -170
- package/README.md +170 -170
- package/package.json +56 -57
- package/scripts/lib/config.js +110 -73
- package/scripts/lib/parser.js +125 -82
- package/scripts/lib/repo.js +52 -35
- package/scripts/sync.js +330 -239
- package/scripts/tools/antigravity.js +53 -41
- package/scripts/tools/claude.js +53 -42
- package/scripts/tools/codex.js +53 -41
- package/scripts/tools/copilot.js +65 -41
- package/scripts/tools/cursor.js +52 -41
package/README.md
CHANGED
|
@@ -1,170 +1,170 @@
|
|
|
1
|
-
# Heymark
|
|
2
|
-
|
|
3
|
-
Heymark is a tool that manages Skill documentation for AI coding tools in a single location and automatically converts it into each tool format.
|
|
4
|
-
A Markdown source written once can be reused across multiple agent tools.
|
|
5
|
-
|
|
6
|
-
1. [Overview](#overview)
|
|
7
|
-
2. [Features](#features)
|
|
8
|
-
3. [Supported Agent Tools](#supported-agent-tools)
|
|
9
|
-
4. [Tech Stack](#tech-stack)
|
|
10
|
-
5. [Heymark Usage](#heymark-usage)
|
|
11
|
-
6. [Heymark Development](#heymark-development)
|
|
12
|
-
|
|
13
|
-
## Overview
|
|
14
|
-
|
|
15
|
-
Managing Skill files separately for each AI tool leads to fragmented documentation and higher maintenance costs.
|
|
16
|
-
Heymark follows the Single Source of Truth principle and converts one Markdown source into multiple tool formats.
|
|
17
|
-
A Skill written once can be used immediately in Cursor, Claude Code, GitHub Copilot, OpenAI Codex, and Antigravity.
|
|
18
|
-
|
|
19
|
-
## Features
|
|
20
|
-
|
|
21
|
-
- Single source management: Manage Skills for multiple AI tools with one Markdown file
|
|
22
|
-
- Automatic format conversion: Convert into each tool's native format (YAML frontmatter, AGENTS.md, etc.)
|
|
23
|
-
- Selective conversion: Convert only the tools you need
|
|
24
|
-
- NPM package distribution: Run with `npx` without installation
|
|
25
|
-
- Plugin structure: Extend supported tools by adding conversion modules
|
|
26
|
-
|
|
27
|
-
## Supported Agent Tools
|
|
28
|
-
|
|
29
|
-
| Tool
|
|
30
|
-
|
|
|
31
|
-
| Cursor
|
|
32
|
-
| Claude Code
|
|
33
|
-
|
|
|
34
|
-
|
|
|
35
|
-
| Antigravity
|
|
36
|
-
|
|
37
|
-
## Tech Stack
|
|
38
|
-
|
|
39
|
-
- Runtime: Node.js
|
|
40
|
-
- Language: JavaScript
|
|
41
|
-
- Core: File system API, YAML frontmatter parsing
|
|
42
|
-
|
|
43
|
-
## Heymark Usage
|
|
44
|
-
|
|
45
|
-
### 1. Prepare the Skill Markdown Archive Repository
|
|
46
|
-
|
|
47
|
-
Create Markdown files in a Skill source directory (external or personal GitHub repository) and define metadata with YAML frontmatter.
|
|
48
|
-
|
|
49
|
-
```markdown
|
|
50
|
-
---
|
|
51
|
-
description: "AI assistant behavior guidelines"
|
|
52
|
-
globs: "**/*.ts,**/*.tsx"
|
|
53
|
-
alwaysApply: true
|
|
54
|
-
---
|
|
55
|
-
|
|
56
|
-
# Skill Title
|
|
57
|
-
|
|
58
|
-
Skill content...
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
You can keep the repository structure simple, as shown below.
|
|
62
|
-
|
|
63
|
-
```text
|
|
64
|
-
my-skills-repository/
|
|
65
|
-
ai-behavior.md
|
|
66
|
-
code-conventions.md
|
|
67
|
-
api-skills.md
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
Skill sources are read from a remote GitHub repository (Public/Private).
|
|
71
|
-
|
|
72
|
-
### 2. Initial Setup
|
|
73
|
-
|
|
74
|
-
For first-time use, configure the Skill source repository once.
|
|
75
|
-
|
|
76
|
-
```bash
|
|
77
|
-
# Configure Skill source (.heymark/config.json will be created)
|
|
78
|
-
npx heymark init <GitHub-Repository-URL>
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
```bash
|
|
82
|
-
# HTTPS (for private repositories, Git credentials/token setup is required)
|
|
83
|
-
npx heymark init https://github.com/org/my-rules.git
|
|
84
|
-
|
|
85
|
-
# SSH (recommended for private repositories)
|
|
86
|
-
npx heymark init git@github.com:org/my-rules.git
|
|
87
|
-
|
|
88
|
-
# When .md files are in a subdirectory of the repository
|
|
89
|
-
npx heymark init https://github.com/org/my-rules.git --dir rules --branch main
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
### 3. Run
|
|
93
|
-
|
|
94
|
-
You can run it directly with `npx` without installation.
|
|
95
|
-
Skills are fetched from an external GitHub repository, and Markdown files in that repository are converted into each AI tool format and generated in the current project.
|
|
96
|
-
|
|
97
|
-
```bash
|
|
98
|
-
# Fetch from the external Skill repository configured in .heymark/config.json and convert to all tool formats
|
|
99
|
-
# (delete previously generated files and recreate them)
|
|
100
|
-
npx heymark
|
|
101
|
-
|
|
102
|
-
# Use a different external repository for this run only (ignore .heymark/config.json)
|
|
103
|
-
npx heymark --source https://github.com/org/other-rules.git
|
|
104
|
-
|
|
105
|
-
# Convert only specific tools
|
|
106
|
-
npx heymark -t cursor,claude
|
|
107
|
-
|
|
108
|
-
# Preview (check conversion result without creating files)
|
|
109
|
-
npx heymark --preview
|
|
110
|
-
|
|
111
|
-
# Delete tool-specific files generated previously
|
|
112
|
-
npx heymark --clean
|
|
113
|
-
|
|
114
|
-
# CLI help
|
|
115
|
-
npx heymark --help
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
## Heymark Development
|
|
119
|
-
|
|
120
|
-
### 1. Local Execution
|
|
121
|
-
|
|
122
|
-
```bash
|
|
123
|
-
# Configure Skill source (first-time only, GitHub repository URL)
|
|
124
|
-
node scripts/sync.js init https://github.com/org/my-rules.git
|
|
125
|
-
|
|
126
|
-
# Convert to all tool formats
|
|
127
|
-
node scripts/sync.js
|
|
128
|
-
|
|
129
|
-
# Use a different repository for this run only
|
|
130
|
-
node scripts/sync.js --source https://github.com/org/other-rules.git
|
|
131
|
-
|
|
132
|
-
# Convert only specific tools
|
|
133
|
-
node scripts/sync.js -t cursor,claude
|
|
134
|
-
|
|
135
|
-
# Preview (check without creating files)
|
|
136
|
-
node scripts/sync.js --preview
|
|
137
|
-
|
|
138
|
-
# Delete generated files
|
|
139
|
-
node scripts/sync.js --clean
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
### 2. Release
|
|
143
|
-
|
|
144
|
-
```bash
|
|
145
|
-
# NPM login
|
|
146
|
-
npm login
|
|
147
|
-
# Username: your-npm-username
|
|
148
|
-
# Email: your-email@example.com
|
|
149
|
-
|
|
150
|
-
# 1. Test after updating Skills
|
|
151
|
-
node scripts/sync.js --preview
|
|
152
|
-
|
|
153
|
-
# 2. Update version (Git tag is created automatically)
|
|
154
|
-
npm version patch # or minor, major
|
|
155
|
-
|
|
156
|
-
# 3. Push to GitHub
|
|
157
|
-
git push --follow-tags # push commits and tags together
|
|
158
|
-
|
|
159
|
-
# 4. Publish to NPM
|
|
160
|
-
npm publish
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
### 3. Versioning
|
|
164
|
-
|
|
165
|
-
- `patch` (1.0.0 -> 1.0.1): Bug fixes, typo fixes
|
|
166
|
-
- `minor` (1.0.0 -> 1.1.0): New Skills, feature improvements
|
|
167
|
-
- `major` (1.0.0 -> 2.0.0): Breaking changes
|
|
168
|
-
- The `npm version` command automatically creates a Git tag.
|
|
169
|
-
- `git push --follow-tags` pushes normal commits and tags together. (Recommended)
|
|
170
|
-
- Alternatively, you can run `git push && git push --tags` to push commits first and then push all tags separately.
|
|
1
|
+
# Heymark
|
|
2
|
+
|
|
3
|
+
Heymark is a tool that manages Skill documentation for AI coding tools in a single location and automatically converts it into each tool format.
|
|
4
|
+
A Markdown source written once can be reused across multiple agent tools.
|
|
5
|
+
|
|
6
|
+
1. [Overview](#overview)
|
|
7
|
+
2. [Features](#features)
|
|
8
|
+
3. [Supported Agent Tools](#supported-agent-tools)
|
|
9
|
+
4. [Tech Stack](#tech-stack)
|
|
10
|
+
5. [Heymark Usage](#heymark-usage)
|
|
11
|
+
6. [Heymark Development](#heymark-development)
|
|
12
|
+
|
|
13
|
+
## Overview
|
|
14
|
+
|
|
15
|
+
Managing Skill files separately for each AI tool leads to fragmented documentation and higher maintenance costs.
|
|
16
|
+
Heymark follows the Single Source of Truth principle and converts one Markdown source into multiple tool formats.
|
|
17
|
+
A Skill written once can be used immediately in Cursor, Claude Code, GitHub Copilot, OpenAI Codex, and Antigravity.
|
|
18
|
+
|
|
19
|
+
## Features
|
|
20
|
+
|
|
21
|
+
- Single source management: Manage Skills for multiple AI tools with one Markdown file
|
|
22
|
+
- Automatic format conversion: Convert into each tool's native format (YAML frontmatter, AGENTS.md, etc.)
|
|
23
|
+
- Selective conversion: Convert only the tools you need
|
|
24
|
+
- NPM package distribution: Run with `npx` without installation
|
|
25
|
+
- Plugin structure: Extend supported tools by adding conversion modules
|
|
26
|
+
|
|
27
|
+
## Supported Agent Tools
|
|
28
|
+
|
|
29
|
+
| Tool | Output Format | Key Features |
|
|
30
|
+
| :---------- | :--------------------------------------- | :------------------------------------------------------- |
|
|
31
|
+
| Cursor | `.cursor/rules/*.mdc` | YAML frontmatter (`description`, `globs`, `alwaysApply`) |
|
|
32
|
+
| Claude Code | `.claude/skills/*/SKILL.md` | Skill directory structure + YAML frontmatter |
|
|
33
|
+
| Copilot | `.github/instructions/*.instructions.md` | Multi-pattern mapping via `applyTo` |
|
|
34
|
+
| Codex | `.agents/skills/*/SKILL.md` | Skill directory structure + YAML frontmatter |
|
|
35
|
+
| Antigravity | `.agent/skills/*/SKILL.md` | Skill directory structure + YAML frontmatter |
|
|
36
|
+
|
|
37
|
+
## Tech Stack
|
|
38
|
+
|
|
39
|
+
- Runtime: Node.js
|
|
40
|
+
- Language: JavaScript
|
|
41
|
+
- Core: File system API, YAML frontmatter parsing
|
|
42
|
+
|
|
43
|
+
## Heymark Usage
|
|
44
|
+
|
|
45
|
+
### 1. Prepare the Skill Markdown Archive Repository
|
|
46
|
+
|
|
47
|
+
Create Markdown files in a Skill source directory (external or personal GitHub repository) and define metadata with YAML frontmatter.
|
|
48
|
+
|
|
49
|
+
```markdown
|
|
50
|
+
---
|
|
51
|
+
description: "AI assistant behavior guidelines"
|
|
52
|
+
globs: "**/*.ts,**/*.tsx"
|
|
53
|
+
alwaysApply: true
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
# Skill Title
|
|
57
|
+
|
|
58
|
+
Skill content...
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
You can keep the repository structure simple, as shown below.
|
|
62
|
+
|
|
63
|
+
```text
|
|
64
|
+
my-skills-repository/
|
|
65
|
+
ai-behavior.md
|
|
66
|
+
code-conventions.md
|
|
67
|
+
api-skills.md
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Skill sources are read from a remote GitHub repository (Public/Private).
|
|
71
|
+
|
|
72
|
+
### 2. Initial Setup
|
|
73
|
+
|
|
74
|
+
For first-time use, configure the Skill source repository once.
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
# Configure Skill source (.heymark/config.json will be created)
|
|
78
|
+
npx heymark init <GitHub-Repository-URL>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
# HTTPS (for private repositories, Git credentials/token setup is required)
|
|
83
|
+
npx heymark init https://github.com/org/my-rules.git
|
|
84
|
+
|
|
85
|
+
# SSH (recommended for private repositories)
|
|
86
|
+
npx heymark init git@github.com:org/my-rules.git
|
|
87
|
+
|
|
88
|
+
# When .md files are in a subdirectory of the repository
|
|
89
|
+
npx heymark init https://github.com/org/my-rules.git --dir rules --branch main
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### 3. Run
|
|
93
|
+
|
|
94
|
+
You can run it directly with `npx` without installation.
|
|
95
|
+
Skills are fetched from an external GitHub repository, and Markdown files in that repository are converted into each AI tool format and generated in the current project.
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
# Fetch from the external Skill repository configured in .heymark/config.json and convert to all tool formats
|
|
99
|
+
# (delete previously generated files and recreate them)
|
|
100
|
+
npx heymark
|
|
101
|
+
|
|
102
|
+
# Use a different external repository for this run only (ignore .heymark/config.json)
|
|
103
|
+
npx heymark --source https://github.com/org/other-rules.git
|
|
104
|
+
|
|
105
|
+
# Convert only specific tools
|
|
106
|
+
npx heymark -t cursor,claude
|
|
107
|
+
|
|
108
|
+
# Preview (check conversion result without creating files)
|
|
109
|
+
npx heymark --preview
|
|
110
|
+
|
|
111
|
+
# Delete tool-specific files generated previously
|
|
112
|
+
npx heymark --clean
|
|
113
|
+
|
|
114
|
+
# CLI help
|
|
115
|
+
npx heymark --help
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Heymark Development
|
|
119
|
+
|
|
120
|
+
### 1. Local Execution
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
# Configure Skill source (first-time only, GitHub repository URL)
|
|
124
|
+
node scripts/sync.js init https://github.com/org/my-rules.git
|
|
125
|
+
|
|
126
|
+
# Convert to all tool formats
|
|
127
|
+
node scripts/sync.js
|
|
128
|
+
|
|
129
|
+
# Use a different repository for this run only
|
|
130
|
+
node scripts/sync.js --source https://github.com/org/other-rules.git
|
|
131
|
+
|
|
132
|
+
# Convert only specific tools
|
|
133
|
+
node scripts/sync.js -t cursor,claude
|
|
134
|
+
|
|
135
|
+
# Preview (check without creating files)
|
|
136
|
+
node scripts/sync.js --preview
|
|
137
|
+
|
|
138
|
+
# Delete generated files
|
|
139
|
+
node scripts/sync.js --clean
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### 2. Release
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
# NPM login
|
|
146
|
+
npm login
|
|
147
|
+
# Username: your-npm-username
|
|
148
|
+
# Email: your-email@example.com
|
|
149
|
+
|
|
150
|
+
# 1. Test after updating Skills
|
|
151
|
+
node scripts/sync.js --preview
|
|
152
|
+
|
|
153
|
+
# 2. Update version (Git tag is created automatically)
|
|
154
|
+
npm version patch # or minor, major
|
|
155
|
+
|
|
156
|
+
# 3. Push to GitHub
|
|
157
|
+
git push --follow-tags # push commits and tags together
|
|
158
|
+
|
|
159
|
+
# 4. Publish to NPM
|
|
160
|
+
npm publish
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### 3. Versioning
|
|
164
|
+
|
|
165
|
+
- `patch` (1.0.0 -> 1.0.1): Bug fixes, typo fixes
|
|
166
|
+
- `minor` (1.0.0 -> 1.1.0): New Skills, feature improvements
|
|
167
|
+
- `major` (1.0.0 -> 2.0.0): Breaking changes
|
|
168
|
+
- The `npm version` command automatically creates a Git tag.
|
|
169
|
+
- `git push --follow-tags` pushes normal commits and tags together. (Recommended)
|
|
170
|
+
- Alternatively, you can run `git push && git push --tags` to push commits first and then push all tags separately.
|
package/package.json
CHANGED
|
@@ -1,57 +1,56 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "heymark",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
"
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
"
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
"
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
"
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
"
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
"
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "heymark",
|
|
3
|
+
"version": "1.2.0",
|
|
4
|
+
"description": "Rules & Skills Hub for AI Coding Assistants",
|
|
5
|
+
"type": "commonjs",
|
|
6
|
+
"main": "scripts/sync.js",
|
|
7
|
+
"bin": "scripts/sync.js",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"ai-coding-assistant",
|
|
10
|
+
"ai-agent",
|
|
11
|
+
"ai-skill",
|
|
12
|
+
"ai-rule",
|
|
13
|
+
"skill-management",
|
|
14
|
+
"cursor",
|
|
15
|
+
"claude-code",
|
|
16
|
+
"copilot",
|
|
17
|
+
"codex",
|
|
18
|
+
"antigravity"
|
|
19
|
+
],
|
|
20
|
+
"homepage": "https://github.com/MosslandOpenDevs/heymark#readme",
|
|
21
|
+
"bugs": {
|
|
22
|
+
"url": "https://github.com/MosslandOpenDevs/heymark/issues",
|
|
23
|
+
"email": "yena@moss.land"
|
|
24
|
+
},
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"author": {
|
|
27
|
+
"name": "i-2na",
|
|
28
|
+
"email": "yena@moss.land",
|
|
29
|
+
"url": "https://github.com/i2na"
|
|
30
|
+
},
|
|
31
|
+
"contributors": [
|
|
32
|
+
{
|
|
33
|
+
"name": "i-2na",
|
|
34
|
+
"email": "yena@moss.land",
|
|
35
|
+
"url": "https://github.com/i2na"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"name": "yezzero",
|
|
39
|
+
"email": "yeyeonggim06@gmail.com",
|
|
40
|
+
"url": "https://github.com/yezzero"
|
|
41
|
+
}
|
|
42
|
+
],
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=14.0.0"
|
|
45
|
+
},
|
|
46
|
+
"files": [
|
|
47
|
+
"scripts/"
|
|
48
|
+
],
|
|
49
|
+
"repository": {
|
|
50
|
+
"type": "git",
|
|
51
|
+
"url": "git+https://github.com/MosslandOpenDevs/heymark.git"
|
|
52
|
+
},
|
|
53
|
+
"publishConfig": {
|
|
54
|
+
"access": "public"
|
|
55
|
+
}
|
|
56
|
+
}
|
package/scripts/lib/config.js
CHANGED
|
@@ -1,73 +1,110 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
const fs = require("fs");
|
|
4
|
-
const path = require("path");
|
|
5
|
-
|
|
6
|
-
const CONFIG_DIR = ".heymark";
|
|
7
|
-
const CONFIG_FILENAME = "config.json";
|
|
8
|
-
|
|
9
|
-
const CONFIG_RELATIVE = path.join(CONFIG_DIR, CONFIG_FILENAME);
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* rulesSource:
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
|
|
6
|
+
const CONFIG_DIR = ".heymark";
|
|
7
|
+
const CONFIG_FILENAME = "config.json";
|
|
8
|
+
const DEFAULT_BRANCH = "main";
|
|
9
|
+
const CONFIG_RELATIVE = path.join(CONFIG_DIR, CONFIG_FILENAME);
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @typedef {{ rulesSource: string, branch?: string, rulesSourceDir?: string }} RuleBookConfig
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Resolve config file path from project root.
|
|
17
|
+
* @param {string} projectRoot
|
|
18
|
+
* @returns {string}
|
|
19
|
+
*/
|
|
20
|
+
function getConfigPath(projectRoot) {
|
|
21
|
+
return path.join(projectRoot, CONFIG_DIR, CONFIG_FILENAME);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Normalize and validate config payload.
|
|
26
|
+
* @param {unknown} value
|
|
27
|
+
* @returns {RuleBookConfig | null}
|
|
28
|
+
*/
|
|
29
|
+
function normalizeConfig(value) {
|
|
30
|
+
if (!value || typeof value !== "object") {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const raw =
|
|
35
|
+
/** @type {{ rulesSource?: unknown, branch?: unknown, rulesSourceDir?: unknown }} */ (
|
|
36
|
+
value
|
|
37
|
+
);
|
|
38
|
+
if (typeof raw.rulesSource !== "string" || !raw.rulesSource.trim()) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
rulesSource: raw.rulesSource.trim(),
|
|
44
|
+
branch:
|
|
45
|
+
typeof raw.branch === "string" && raw.branch.trim()
|
|
46
|
+
? raw.branch.trim()
|
|
47
|
+
: DEFAULT_BRANCH,
|
|
48
|
+
rulesSourceDir: typeof raw.rulesSourceDir === "string" ? raw.rulesSourceDir.trim() : "",
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Read config from project root.
|
|
54
|
+
* @param {string} projectRoot
|
|
55
|
+
* @returns {RuleBookConfig | null}
|
|
56
|
+
*/
|
|
57
|
+
function loadConfig(projectRoot) {
|
|
58
|
+
const configPath = getConfigPath(projectRoot);
|
|
59
|
+
if (!fs.existsSync(configPath)) {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
const raw = fs.readFileSync(configPath, "utf8");
|
|
65
|
+
return normalizeConfig(JSON.parse(raw));
|
|
66
|
+
} catch {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Create initial config file in .heymark/config.json.
|
|
73
|
+
* @param {string} projectRoot
|
|
74
|
+
* @param {RuleBookConfig} config
|
|
75
|
+
* @returns {string}
|
|
76
|
+
*/
|
|
77
|
+
function writeConfig(projectRoot, config) {
|
|
78
|
+
const configDir = path.join(projectRoot, CONFIG_DIR);
|
|
79
|
+
if (!fs.existsSync(configDir)) {
|
|
80
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const normalized = normalizeConfig(config);
|
|
84
|
+
if (!normalized) {
|
|
85
|
+
throw new Error("Invalid config payload");
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const configPath = path.join(configDir, CONFIG_FILENAME);
|
|
89
|
+
const toWrite = {
|
|
90
|
+
rulesSource: normalized.rulesSource,
|
|
91
|
+
branch: normalized.branch || DEFAULT_BRANCH,
|
|
92
|
+
};
|
|
93
|
+
if (normalized.rulesSourceDir) {
|
|
94
|
+
toWrite.rulesSourceDir = normalized.rulesSourceDir;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
fs.writeFileSync(configPath, JSON.stringify(toWrite, null, 2), "utf8");
|
|
98
|
+
return configPath;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
module.exports = {
|
|
102
|
+
CONFIG_DIR,
|
|
103
|
+
CONFIG_FILENAME,
|
|
104
|
+
CONFIG_RELATIVE,
|
|
105
|
+
DEFAULT_BRANCH,
|
|
106
|
+
getConfigPath,
|
|
107
|
+
loadConfig,
|
|
108
|
+
normalizeConfig,
|
|
109
|
+
writeConfig,
|
|
110
|
+
};
|