mdkg 0.0.3 → 0.0.4
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.md +171 -169
- package/dist/cli.js +980 -624
- package/dist/commands/checkpoint.js +17 -6
- package/dist/commands/event.js +46 -0
- package/dist/commands/event_support.js +146 -0
- package/dist/commands/format.js +6 -7
- package/dist/commands/index.js +10 -4
- package/dist/commands/init.js +198 -16
- package/dist/commands/list.js +18 -1
- package/dist/commands/new.js +30 -5
- package/dist/commands/pack.js +194 -2
- package/dist/commands/query_output.js +84 -0
- package/dist/commands/search.js +22 -5
- package/dist/commands/show.js +26 -11
- package/dist/commands/skill.js +359 -0
- package/dist/commands/skill_support.js +121 -0
- package/dist/commands/task.js +270 -0
- package/dist/commands/validate.js +104 -7
- package/dist/graph/edges.js +2 -2
- package/dist/graph/frontmatter.js +1 -0
- package/dist/graph/indexer.js +21 -0
- package/dist/graph/node.js +20 -4
- package/dist/graph/skills_index_cache.js +94 -0
- package/dist/graph/skills_indexer.js +160 -0
- package/dist/init/core/rule-1-mdkg-conventions.md +9 -2
- package/dist/init/core/rule-3-cli-contract.md +73 -14
- package/dist/init/core/rule-4-repo-safety-and-ignores.md +9 -3
- package/dist/init/core/rule-6-templates-and-schemas.md +6 -2
- package/dist/init/skills/SKILL.md.example +41 -0
- package/dist/init/templates/default/bug.md +1 -0
- package/dist/init/templates/default/chk.md +1 -0
- package/dist/init/templates/default/epic.md +1 -0
- package/dist/init/templates/default/feat.md +1 -0
- package/dist/init/templates/default/task.md +1 -0
- package/dist/init/templates/default/test.md +1 -0
- package/dist/pack/export_md.js +6 -0
- package/dist/pack/export_xml.js +6 -0
- package/dist/pack/pack.js +35 -0
- package/dist/util/argparse.js +25 -0
- package/dist/util/filter.js +18 -0
- package/dist/util/id.js +23 -0
- package/package.json +5 -2
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.SKILL_SLUG_RE = exports.SKILLS_INDEX_RELATIVE_PATH = void 0;
|
|
7
|
+
exports.resolveSkillsRoot = resolveSkillsRoot;
|
|
8
|
+
exports.resolveSkillsIndexPath = resolveSkillsIndexPath;
|
|
9
|
+
exports.buildSkillIndexEntry = buildSkillIndexEntry;
|
|
10
|
+
exports.buildSkillsIndex = buildSkillsIndex;
|
|
11
|
+
const fs_1 = __importDefault(require("fs"));
|
|
12
|
+
const path_1 = __importDefault(require("path"));
|
|
13
|
+
const frontmatter_1 = require("./frontmatter");
|
|
14
|
+
exports.SKILLS_INDEX_RELATIVE_PATH = ".mdkg/index/skills.json";
|
|
15
|
+
exports.SKILL_SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
16
|
+
function listSkillMarkdownFiles(dir) {
|
|
17
|
+
if (!fs_1.default.existsSync(dir)) {
|
|
18
|
+
return [];
|
|
19
|
+
}
|
|
20
|
+
const entries = fs_1.default.readdirSync(dir, { withFileTypes: true });
|
|
21
|
+
const files = [];
|
|
22
|
+
for (const entry of entries) {
|
|
23
|
+
if (!entry.isDirectory()) {
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
const slug = entry.name.toLowerCase();
|
|
27
|
+
const skillDir = path_1.default.join(dir, entry.name);
|
|
28
|
+
const canonicalPath = path_1.default.join(skillDir, "SKILL.md");
|
|
29
|
+
const compatPath = path_1.default.join(skillDir, "SKILLS.md");
|
|
30
|
+
if (fs_1.default.existsSync(canonicalPath) && fs_1.default.existsSync(compatPath)) {
|
|
31
|
+
throw new Error(`${skillDir}: both SKILL.md and SKILLS.md exist`);
|
|
32
|
+
}
|
|
33
|
+
if (fs_1.default.existsSync(canonicalPath)) {
|
|
34
|
+
files.push({ slug, filePath: canonicalPath });
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
if (fs_1.default.existsSync(compatPath)) {
|
|
38
|
+
files.push({ slug, filePath: compatPath });
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
files.sort((a, b) => a.slug.localeCompare(b.slug));
|
|
42
|
+
return files;
|
|
43
|
+
}
|
|
44
|
+
function requireString(frontmatter, key, filePath) {
|
|
45
|
+
const value = frontmatter[key];
|
|
46
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
47
|
+
throw new Error(`${filePath}: ${key} is required and must be a non-empty string`);
|
|
48
|
+
}
|
|
49
|
+
return value;
|
|
50
|
+
}
|
|
51
|
+
function optionalString(frontmatter, key, filePath) {
|
|
52
|
+
const value = frontmatter[key];
|
|
53
|
+
if (value === undefined) {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
57
|
+
throw new Error(`${filePath}: ${key} must be a non-empty string when set`);
|
|
58
|
+
}
|
|
59
|
+
return value;
|
|
60
|
+
}
|
|
61
|
+
function optionalList(frontmatter, key, filePath) {
|
|
62
|
+
const value = frontmatter[key];
|
|
63
|
+
if (value === undefined) {
|
|
64
|
+
return [];
|
|
65
|
+
}
|
|
66
|
+
if (!Array.isArray(value)) {
|
|
67
|
+
throw new Error(`${filePath}: ${key} must be a list`);
|
|
68
|
+
}
|
|
69
|
+
return value;
|
|
70
|
+
}
|
|
71
|
+
function toLowercaseList(values) {
|
|
72
|
+
return values.map((value) => value.toLowerCase());
|
|
73
|
+
}
|
|
74
|
+
function extractOchatr(frontmatter) {
|
|
75
|
+
const keys = Object.keys(frontmatter)
|
|
76
|
+
.filter((key) => key.startsWith("ochatr_"))
|
|
77
|
+
.sort();
|
|
78
|
+
const extracted = {};
|
|
79
|
+
for (const key of keys) {
|
|
80
|
+
extracted[key] = frontmatter[key];
|
|
81
|
+
}
|
|
82
|
+
return extracted;
|
|
83
|
+
}
|
|
84
|
+
function hasDirectory(dirPath) {
|
|
85
|
+
if (!fs_1.default.existsSync(dirPath)) {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
return fs_1.default.statSync(dirPath).isDirectory();
|
|
89
|
+
}
|
|
90
|
+
function rootWorkspaceMdkgPath(root, config) {
|
|
91
|
+
const rootWs = config.workspaces.root;
|
|
92
|
+
if (rootWs && rootWs.enabled) {
|
|
93
|
+
return path_1.default.resolve(root, rootWs.path, rootWs.mdkg_dir);
|
|
94
|
+
}
|
|
95
|
+
return path_1.default.resolve(root, ".mdkg");
|
|
96
|
+
}
|
|
97
|
+
function resolveSkillsRoot(root, config) {
|
|
98
|
+
return path_1.default.join(rootWorkspaceMdkgPath(root, config), "skills");
|
|
99
|
+
}
|
|
100
|
+
function resolveSkillsIndexPath(root) {
|
|
101
|
+
return path_1.default.resolve(root, exports.SKILLS_INDEX_RELATIVE_PATH);
|
|
102
|
+
}
|
|
103
|
+
function buildSkillIndexEntry(root, slug, filePath) {
|
|
104
|
+
if (!exports.SKILL_SLUG_RE.test(slug)) {
|
|
105
|
+
throw new Error(`${filePath}: skill slug must be kebab-case`);
|
|
106
|
+
}
|
|
107
|
+
const content = fs_1.default.readFileSync(filePath, "utf8");
|
|
108
|
+
const { frontmatter } = (0, frontmatter_1.parseFrontmatter)(content, filePath);
|
|
109
|
+
const name = requireString(frontmatter, "name", filePath);
|
|
110
|
+
const description = requireString(frontmatter, "description", filePath);
|
|
111
|
+
const version = optionalString(frontmatter, "version", filePath);
|
|
112
|
+
const tags = toLowercaseList(optionalList(frontmatter, "tags", filePath));
|
|
113
|
+
const authors = toLowercaseList(optionalList(frontmatter, "authors", filePath));
|
|
114
|
+
const links = optionalList(frontmatter, "links", filePath);
|
|
115
|
+
const skillDir = path_1.default.dirname(filePath);
|
|
116
|
+
return {
|
|
117
|
+
slug,
|
|
118
|
+
id: `skill:${slug}`,
|
|
119
|
+
qid: `root:skill:${slug}`,
|
|
120
|
+
ws: "root",
|
|
121
|
+
type: "skill",
|
|
122
|
+
name,
|
|
123
|
+
description,
|
|
124
|
+
tags,
|
|
125
|
+
version,
|
|
126
|
+
authors,
|
|
127
|
+
links,
|
|
128
|
+
path: path_1.default.relative(root, filePath),
|
|
129
|
+
has_scripts: hasDirectory(path_1.default.join(skillDir, "scripts")),
|
|
130
|
+
has_references: hasDirectory(path_1.default.join(skillDir, "references")),
|
|
131
|
+
ochatr: extractOchatr(frontmatter),
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
function buildSkillsIndex(root, config) {
|
|
135
|
+
const skillsRoot = resolveSkillsRoot(root, config);
|
|
136
|
+
const files = listSkillMarkdownFiles(skillsRoot);
|
|
137
|
+
const skills = {};
|
|
138
|
+
for (const file of files) {
|
|
139
|
+
const { slug, filePath } = file;
|
|
140
|
+
if (skills[slug]) {
|
|
141
|
+
throw new Error(`${filePath}: duplicate skill slug ${slug}`);
|
|
142
|
+
}
|
|
143
|
+
skills[slug] = buildSkillIndexEntry(root, slug, filePath);
|
|
144
|
+
}
|
|
145
|
+
const sortedSkills = {};
|
|
146
|
+
for (const slug of Object.keys(skills).sort()) {
|
|
147
|
+
sortedSkills[slug] = skills[slug];
|
|
148
|
+
}
|
|
149
|
+
return {
|
|
150
|
+
meta: {
|
|
151
|
+
tool: config.tool,
|
|
152
|
+
schema_version: config.schema_version,
|
|
153
|
+
generated_at: new Date().toISOString(),
|
|
154
|
+
root,
|
|
155
|
+
skills_root: path_1.default.relative(root, skillsRoot),
|
|
156
|
+
skill_count: Object.keys(sortedSkills).length,
|
|
157
|
+
},
|
|
158
|
+
skills: sortedSkills,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
@@ -10,7 +10,7 @@ relates: []
|
|
|
10
10
|
refs: []
|
|
11
11
|
aliases: []
|
|
12
12
|
created: 2026-01-06
|
|
13
|
-
updated: 2026-
|
|
13
|
+
updated: 2026-03-05
|
|
14
14
|
---
|
|
15
15
|
|
|
16
16
|
# mdkg conventions
|
|
@@ -87,6 +87,11 @@ Canonical ID format:
|
|
|
87
87
|
|
|
88
88
|
`<prefix>-<number>`
|
|
89
89
|
|
|
90
|
+
Reserved rule IDs allowed by contract:
|
|
91
|
+
- `rule-guide`
|
|
92
|
+
- `rule-soul`
|
|
93
|
+
- `rule-human`
|
|
94
|
+
|
|
90
95
|
Examples:
|
|
91
96
|
- `task-183`
|
|
92
97
|
- `edd-14`
|
|
@@ -153,11 +158,12 @@ All nodes MUST include:
|
|
|
153
158
|
- `created` (YYYY-MM-DD)
|
|
154
159
|
- `updated` (YYYY-MM-DD)
|
|
155
160
|
|
|
156
|
-
Work items (`epic/feat/task/bug/
|
|
161
|
+
Work items (`epic/feat/task/bug/checkpoint/test`) MUST include:
|
|
157
162
|
- `status`
|
|
158
163
|
|
|
159
164
|
Work items MAY include:
|
|
160
165
|
- `priority`
|
|
166
|
+
- `skills: [slug, ...]` (kebab-case skill references)
|
|
161
167
|
|
|
162
168
|
Optional searchable metadata
|
|
163
169
|
|
|
@@ -222,6 +228,7 @@ They SHOULD include:
|
|
|
222
228
|
The cache is enabled by default.
|
|
223
229
|
|
|
224
230
|
- Root global index lives at `.mdkg/index/global.json`
|
|
231
|
+
- Root skills index lives at `.mdkg/index/skills.json`
|
|
225
232
|
- Index is rebuilt automatically when stale unless disabled by flag/config.
|
|
226
233
|
- `.mdkg/index/` is generated and MUST be gitignored.
|
|
227
234
|
|
|
@@ -10,7 +10,7 @@ relates: []
|
|
|
10
10
|
refs: []
|
|
11
11
|
aliases: []
|
|
12
12
|
created: 2026-01-06
|
|
13
|
-
updated: 2026-
|
|
13
|
+
updated: 2026-03-08
|
|
14
14
|
---
|
|
15
15
|
|
|
16
16
|
# mdkg CLI contract
|
|
@@ -88,7 +88,7 @@ If a user provides an unqualified ID and it is ambiguous globally:
|
|
|
88
88
|
- Commands should be script-friendly:
|
|
89
89
|
- concise outputs for single items
|
|
90
90
|
- predictable formatting
|
|
91
|
-
-
|
|
91
|
+
- `--json` output for supported discovery/show commands
|
|
92
92
|
- when printing node summaries (e.g., `show`/list results), outputs SHOULD surface key searchable frontmatter fields such as `links` and `artifacts`
|
|
93
93
|
|
|
94
94
|
## Command set (v1 target)
|
|
@@ -99,10 +99,17 @@ If a user provides an unqualified ID and it is ambiguous globally:
|
|
|
99
99
|
- creates `.mdkg/config.json` if missing
|
|
100
100
|
- creates core docs and templates if missing
|
|
101
101
|
- does NOT overwrite existing docs unless `--force`
|
|
102
|
-
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
- `--llm`
|
|
102
|
+
- updates `.gitignore` and `.npmignore` by default
|
|
103
|
+
- `--no-update-ignores` disables default ignore writes
|
|
104
|
+
- explicit flags (`--update-gitignore`, `--update-npmignore`, `--update-dockerignore`) force writes even with global opt-out
|
|
105
|
+
- `--llm` is the canonical documented path for creating `AGENTS.md` and `CLAUDE.md`
|
|
106
|
+
- `--agents` / `--claude` remain compatibility flags, but are not part of the primary onboarding story
|
|
107
|
+
- `--omni` adds strict-node bootstrap docs and scaffolding:
|
|
108
|
+
- `.mdkg/core/SOUL.md` (`id: rule-soul`)
|
|
109
|
+
- `.mdkg/core/HUMAN.md` (`id: rule-human`)
|
|
110
|
+
- `.mdkg/skills/registry.md`
|
|
111
|
+
- `.mdkg/work/events/events.jsonl`
|
|
112
|
+
- deterministic `core.md` pin insertion (`rule-soul`, then `rule-human`)
|
|
106
113
|
|
|
107
114
|
### Guide
|
|
108
115
|
- `mdkg guide`
|
|
@@ -116,6 +123,9 @@ If a user provides an unqualified ID and it is ambiguous globally:
|
|
|
116
123
|
### Indexing
|
|
117
124
|
- `mdkg index`
|
|
118
125
|
- rebuild global cache `.mdkg/index/global.json`
|
|
126
|
+
- rebuild skills cache `.mdkg/index/skills.json` from `.mdkg/skills/<slug>/SKILL.md`
|
|
127
|
+
- tolerate `.mdkg/skills/<slug>/SKILLS.md` on read with warning
|
|
128
|
+
- fail validation if both `SKILL.md` and `SKILLS.md` exist in one skill directory
|
|
119
129
|
- strict by default (fails on invalid frontmatter)
|
|
120
130
|
- optional `--tolerant` to skip invalid nodes (escape hatch)
|
|
121
131
|
|
|
@@ -140,24 +150,56 @@ Common flags:
|
|
|
140
150
|
- `--artifacts <ref,ref,...>`
|
|
141
151
|
- `--refs <id,id,...>`
|
|
142
152
|
- `--aliases <text,text,...>`
|
|
153
|
+
- `--skills <slug,slug,...>` (work items)
|
|
143
154
|
- `--template <set>` (default from config)
|
|
144
155
|
|
|
145
156
|
### Read/search
|
|
146
|
-
- `mdkg show <id-or-qid
|
|
147
|
-
-
|
|
157
|
+
- `mdkg show <id-or-qid> [--meta] [--json]`
|
|
158
|
+
- default behavior shows the full node body
|
|
159
|
+
- `--meta` is the compact card-only view
|
|
160
|
+
- `mdkg search "<query>" [--type <type>] [--status <status>] [--ws <alias>] [--tags <tag,tag,...>] [--tags-mode any|all] [--json]`
|
|
148
161
|
- search SHOULD match on IDs, titles, tags, path tokens, and searchable frontmatter lists (`links`, `artifacts`, `refs`, `aliases`)
|
|
149
|
-
- `mdkg list [--type <type>] [--status <status>] [--ws <alias>] [--epic <id>] [--blocked] [--priority <n>]`
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
- `mdkg
|
|
153
|
-
- `mdkg
|
|
162
|
+
- `mdkg list [--type <type>] [--status <status>] [--ws <alias>] [--epic <id>] [--blocked] [--priority <n>] [--tags <tag,tag,...>] [--tags-mode any|all] [--json]`
|
|
163
|
+
- skills are first-class under `mdkg skill ...` only:
|
|
164
|
+
- `mdkg skill list [--tags <tag,tag,...>] [--tags-mode any|all] [--json]`
|
|
165
|
+
- `mdkg skill show <slug> [--meta] [--json]`
|
|
166
|
+
- `mdkg skill search "<query>" [--tags <tag,tag,...>] [--tags-mode any|all] [--json]`
|
|
167
|
+
- `mdkg skill validate [<slug>]`
|
|
168
|
+
|
|
169
|
+
### Task lifecycle mutation
|
|
170
|
+
- `mdkg task start <id-or-qid> [--ws <alias>] [--run-id <id>] [--note "<text>"]`
|
|
171
|
+
- supports `task`, `bug`, and `test` nodes only
|
|
172
|
+
- sets `status: progress`
|
|
173
|
+
- `mdkg task update <id-or-qid> [...]`
|
|
174
|
+
- supports additive list mutation for `artifacts`, `links`, `refs`, `skills`, `tags`, and `blocked_by`
|
|
175
|
+
- supports scalar replacement for `status` and `priority`
|
|
176
|
+
- `--clear-blocked-by` resets blockers before optional re-add
|
|
177
|
+
- `mdkg task done <id-or-qid> [--checkpoint "<title>"] [...]`
|
|
178
|
+
- supports `task`, `bug`, and `test` nodes only
|
|
179
|
+
- sets `status: done`
|
|
180
|
+
- optional checkpoint creation is explicit only
|
|
154
181
|
|
|
155
182
|
### Packs (core feature)
|
|
156
|
-
- `mdkg pack <id-or-qid> [--
|
|
183
|
+
- `mdkg pack <id-or-qid> [--profile <name>] [--verbose] [--format md|json|toon|xml] [--out <path>] [--ws <alias>]`
|
|
184
|
+
- optional skill inclusion flags:
|
|
185
|
+
- `--skills none|auto|<slug,slug,...>`
|
|
186
|
+
- `--skills-depth meta|full`
|
|
187
|
+
- advanced shaping/debug flags remain supported but de-emphasized:
|
|
188
|
+
- `--depth <n>`
|
|
189
|
+
- `--edges <keys>`
|
|
190
|
+
- `--strip-code`
|
|
191
|
+
- `--max-code-lines <n>`
|
|
192
|
+
- `--max-chars <n>`
|
|
193
|
+
- `--max-lines <n>`
|
|
194
|
+
- `--max-tokens <n>`
|
|
195
|
+
- `--truncation-report <path>`
|
|
196
|
+
- `--stats-out <path>`
|
|
157
197
|
- `--edges` adds to the default edge set
|
|
158
198
|
- `--out` writes to a file (create parent dirs; overwrite if exists)
|
|
159
199
|
- if `--out` is omitted, write to `.mdkg/pack/pack_<kind>_<id>_<timestamp>.<ext>`
|
|
160
200
|
- short flags supported: `-o`, `-f`, `-v`, `-d`, `-e`, `-w`, `-r`
|
|
201
|
+
- `--profile` is the primary documented alias for `--pack-profile`
|
|
202
|
+
- pack selection includes latest checkpoint by pack-time resolver; index hint `latest_checkpoint_qid` is optimization-only
|
|
161
203
|
|
|
162
204
|
### Next priority
|
|
163
205
|
- `mdkg next [<id-or-qid>] [--ws <alias>]`
|
|
@@ -169,9 +211,26 @@ Common flags:
|
|
|
169
211
|
- creates a `chk-*` node from template
|
|
170
212
|
- designed as a phase summary / compression node
|
|
171
213
|
|
|
214
|
+
### Events
|
|
215
|
+
- `mdkg event enable [--ws <alias>] [--no-update-gitignore]`
|
|
216
|
+
- creates `.mdkg/work/events/events.jsonl` if missing
|
|
217
|
+
- updates `.gitignore` by default
|
|
218
|
+
- `mdkg event append --kind <kind> --status <ok|error|retry|skipped> --refs <id,...> [...]`
|
|
219
|
+
- appends one JSONL provenance record
|
|
220
|
+
- automatic command-level events append only when event logging is enabled for the target workspace
|
|
221
|
+
- current automatic mutation events:
|
|
222
|
+
- `NODE_CREATED`
|
|
223
|
+
- `SKILL_CREATED`
|
|
224
|
+
- `CHECKPOINT_CREATED`
|
|
225
|
+
- `TASK_STARTED`
|
|
226
|
+
- `TASK_UPDATED`
|
|
227
|
+
- `TASK_DONE`
|
|
228
|
+
|
|
172
229
|
### Validation and formatting
|
|
173
230
|
- `mdkg validate`
|
|
174
231
|
- strict frontmatter + graph integrity checks (exit code 2 on failure)
|
|
232
|
+
- validates optional node->skill references
|
|
233
|
+
- validates optional `.mdkg/work/events/events.jsonl` record shape when file exists
|
|
175
234
|
- `mdkg format`
|
|
176
235
|
- normalize frontmatter formatting and casing
|
|
177
236
|
- avoid destructive body edits
|
|
@@ -36,6 +36,7 @@ Recommended `.gitignore` entries:
|
|
|
36
36
|
- `.mdkg/index/`
|
|
37
37
|
- `.mdkg/index/**`
|
|
38
38
|
- `.mdkg/pack/`
|
|
39
|
+
- `.mdkg/work/events/*.jsonl` (when episodic logging is enabled)
|
|
39
40
|
|
|
40
41
|
## npm publish safety (required)
|
|
41
42
|
|
|
@@ -67,14 +68,18 @@ For application builds:
|
|
|
67
68
|
|
|
68
69
|
## mdkg init behavior
|
|
69
70
|
|
|
70
|
-
`mdkg init`
|
|
71
|
+
`mdkg init` updates ignore files by default for safety:
|
|
72
|
+
|
|
73
|
+
- `.gitignore` appends `.mdkg/index/`, `.mdkg/pack/`, `.mdkg/work/events/*.jsonl`
|
|
74
|
+
- `.npmignore` appends `.mdkg/`, `.mdkg/index/`, `.mdkg/pack/`
|
|
75
|
+
- `--no-update-ignores` disables these default writes
|
|
76
|
+
|
|
77
|
+
Explicit flags remain available and take precedence:
|
|
71
78
|
|
|
72
79
|
- `--update-gitignore`
|
|
73
80
|
- `--update-npmignore`
|
|
74
81
|
- `--update-dockerignore`
|
|
75
82
|
|
|
76
|
-
In v1, mdkg should default to **not** editing user files without an explicit flag.
|
|
77
|
-
|
|
78
83
|
## Index safety
|
|
79
84
|
|
|
80
85
|
- `.mdkg/index/` is generated.
|
|
@@ -92,6 +97,7 @@ Workspace-local `.mdkg/` directories (near code) should follow the same rules:
|
|
|
92
97
|
## Summary checklist
|
|
93
98
|
|
|
94
99
|
- ✅ `.mdkg/index/` ignored
|
|
100
|
+
- ✅ `.mdkg/work/events/*.jsonl` ignored when event logging is enabled
|
|
95
101
|
- ✅ npm publishes only `dist/`, `README.md`, `LICENSE`
|
|
96
102
|
- ✅ optional `.npmignore` excludes `.mdkg/`
|
|
97
103
|
- ✅ `.dockerignore` excludes `.mdkg/` when applicable
|
|
@@ -10,7 +10,7 @@ relates: []
|
|
|
10
10
|
refs: []
|
|
11
11
|
aliases: []
|
|
12
12
|
created: 2026-01-06
|
|
13
|
-
updated: 2026-
|
|
13
|
+
updated: 2026-03-05
|
|
14
14
|
---
|
|
15
15
|
|
|
16
16
|
# Templates and schemas
|
|
@@ -65,6 +65,7 @@ Optional tokens (nice-to-have, may be empty):
|
|
|
65
65
|
- `{{artifacts}}` (list)
|
|
66
66
|
- `{{refs}}` (list)
|
|
67
67
|
- `{{aliases}}` (list)
|
|
68
|
+
- `{{skills}}` (list; work items)
|
|
68
69
|
- `{{cases}}` (list)
|
|
69
70
|
|
|
70
71
|
## Frontmatter requirements by type
|
|
@@ -90,9 +91,10 @@ All nodes MAY include the following searchable frontmatter lists:
|
|
|
90
91
|
List fields SHOULD be written as `[]` when empty.
|
|
91
92
|
Optional scalar graph fields (like `epic`, `parent`, `prev`, `next`) should be omitted when empty.
|
|
92
93
|
|
|
93
|
-
Work items (`epic/feat/task/bug/
|
|
94
|
+
Work items (`epic/feat/task/bug/checkpoint/test`):
|
|
94
95
|
- `status` (enum)
|
|
95
96
|
- optional `priority` (0..9)
|
|
97
|
+
- optional `skills: [slug, ...]` (kebab-case skill slugs)
|
|
96
98
|
- optional graph edges: `epic`, `parent`, `relates`, `blocked_by`, `blocks`, `prev`, `next`
|
|
97
99
|
|
|
98
100
|
Decision records (`dec-*`):
|
|
@@ -182,5 +184,7 @@ Body headings are strongly recommended for agent usability but should not be har
|
|
|
182
184
|
|
|
183
185
|
- Frontmatter: strict, hard fail if invalid.
|
|
184
186
|
- Body headings: warn only (do not break indexing).
|
|
187
|
+
- Node -> skill references in `skills: [...]` are validated against `.mdkg/skills/<slug>/SKILL.md`.
|
|
188
|
+
- `.mdkg/work/events/events.jsonl` is optional; when present, records are schema-validated by `mdkg validate`.
|
|
185
189
|
- If a template is missing:
|
|
186
190
|
- `mdkg new` must fail with a helpful error (exit code 3).
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: {{name}}
|
|
3
|
+
description: {{description}}
|
|
4
|
+
{{tags_block}}{{authors_block}}{{links_block}}---
|
|
5
|
+
|
|
6
|
+
# Goal
|
|
7
|
+
|
|
8
|
+
Describe the deterministic outcome this skill should achieve.
|
|
9
|
+
|
|
10
|
+
## When To Use
|
|
11
|
+
|
|
12
|
+
- Use this skill when the workflow is triggered and the needed outcome is clear.
|
|
13
|
+
- Prefer this skill over ad-hoc instructions when the procedure should be repeatable.
|
|
14
|
+
|
|
15
|
+
## Inputs
|
|
16
|
+
|
|
17
|
+
- Repo root
|
|
18
|
+
- Current task, node, or user goal
|
|
19
|
+
- Any required references or artifacts
|
|
20
|
+
|
|
21
|
+
## Steps
|
|
22
|
+
|
|
23
|
+
1. Confirm the triggering task or need before acting.
|
|
24
|
+
2. Load only the references and artifacts required for this run.
|
|
25
|
+
3. Execute the smallest deterministic workflow that satisfies the request.
|
|
26
|
+
|
|
27
|
+
## Outputs
|
|
28
|
+
|
|
29
|
+
- Deterministic result, patch, or artifact
|
|
30
|
+
- Evidence needed for review or orchestration
|
|
31
|
+
|
|
32
|
+
## Safety
|
|
33
|
+
|
|
34
|
+
- Prefer repo truth over chat memory.
|
|
35
|
+
- Keep secrets out of skills, references, and generated artifacts.
|
|
36
|
+
- Stop and resolve ambiguity instead of guessing.
|
|
37
|
+
|
|
38
|
+
## Failure Handling
|
|
39
|
+
|
|
40
|
+
- If required context or policy is unclear, stop and ask before proceeding.
|
|
41
|
+
- If the procedure needs more detail, load the specific reference rather than broad context.
|
package/dist/pack/export_md.js
CHANGED
|
@@ -19,6 +19,12 @@ function renderHeader(meta, nodes) {
|
|
|
19
19
|
if (meta.body_mode) {
|
|
20
20
|
lines.push(`body_mode: ${meta.body_mode}`);
|
|
21
21
|
}
|
|
22
|
+
if (meta.latest_checkpoint_qid) {
|
|
23
|
+
lines.push(`latest_checkpoint_qid: ${meta.latest_checkpoint_qid}`);
|
|
24
|
+
}
|
|
25
|
+
if (meta.latest_checkpoint_qid_hint) {
|
|
26
|
+
lines.push(`latest_checkpoint_qid_hint: ${meta.latest_checkpoint_qid_hint}`);
|
|
27
|
+
}
|
|
22
28
|
lines.push(`nodes: ${nodes.length}`);
|
|
23
29
|
lines.push(`truncated: max_nodes=${meta.truncated.max_nodes} max_bytes=${meta.truncated.max_bytes} max_chars=${Boolean(meta.truncated.max_chars)} max_lines=${Boolean(meta.truncated.max_lines)} max_tokens=${Boolean(meta.truncated.max_tokens)}`);
|
|
24
30
|
if (meta.truncated.dropped.length > 0) {
|
package/dist/pack/export_xml.js
CHANGED
|
@@ -35,6 +35,12 @@ function exportXml(pack) {
|
|
|
35
35
|
if (pack.meta.body_mode) {
|
|
36
36
|
lines.push(` <body_mode>${escapeXml(pack.meta.body_mode)}</body_mode>`);
|
|
37
37
|
}
|
|
38
|
+
if (pack.meta.latest_checkpoint_qid) {
|
|
39
|
+
lines.push(` <latest_checkpoint_qid>${escapeXml(pack.meta.latest_checkpoint_qid)}</latest_checkpoint_qid>`);
|
|
40
|
+
}
|
|
41
|
+
if (pack.meta.latest_checkpoint_qid_hint) {
|
|
42
|
+
lines.push(` <latest_checkpoint_qid_hint>${escapeXml(pack.meta.latest_checkpoint_qid_hint)}</latest_checkpoint_qid_hint>`);
|
|
43
|
+
}
|
|
38
44
|
lines.push(` <generated_at>${escapeXml(pack.meta.generated_at)}</generated_at>`);
|
|
39
45
|
lines.push(` <node_count>${pack.meta.node_count}</node_count>`);
|
|
40
46
|
lines.push(" <truncated>");
|
package/dist/pack/pack.js
CHANGED
|
@@ -130,6 +130,24 @@ function buildPackNode(root, index, qid) {
|
|
|
130
130
|
function mergeWarnings(warnings, message) {
|
|
131
131
|
warnings.push(message);
|
|
132
132
|
}
|
|
133
|
+
function checkpointWorkspaceFromQid(qid) {
|
|
134
|
+
const [workspace] = qid.split(":");
|
|
135
|
+
return workspace ?? "root";
|
|
136
|
+
}
|
|
137
|
+
function resolveLatestCheckpointQid(index, workspace) {
|
|
138
|
+
const candidates = Object.values(index.nodes)
|
|
139
|
+
.filter((node) => node.ws === workspace && node.type === "checkpoint")
|
|
140
|
+
.sort((a, b) => {
|
|
141
|
+
if (a.updated !== b.updated) {
|
|
142
|
+
return b.updated.localeCompare(a.updated);
|
|
143
|
+
}
|
|
144
|
+
if (a.created !== b.created) {
|
|
145
|
+
return b.created.localeCompare(a.created);
|
|
146
|
+
}
|
|
147
|
+
return b.qid.localeCompare(a.qid);
|
|
148
|
+
});
|
|
149
|
+
return candidates[0]?.qid;
|
|
150
|
+
}
|
|
133
151
|
function applyMaxNodes(orderedQids, maxNodes, truncation) {
|
|
134
152
|
if (maxNodes <= 0 || orderedQids.length <= maxNodes) {
|
|
135
153
|
return { included: orderedQids, dropped: [] };
|
|
@@ -142,7 +160,22 @@ function applyMaxNodes(orderedQids, maxNodes, truncation) {
|
|
|
142
160
|
}
|
|
143
161
|
function buildPack(options) {
|
|
144
162
|
const warnings = [];
|
|
163
|
+
const includeLatestCheckpoint = options.includeLatestCheckpoint ?? true;
|
|
145
164
|
const { qids, depths } = collectNodes(options.index, options.rootQid, options.depth, options.edges);
|
|
165
|
+
const workspace = checkpointWorkspaceFromQid(options.rootQid);
|
|
166
|
+
const latestCheckpointHint = options.index.meta.latest_checkpoint_qid?.[workspace];
|
|
167
|
+
const latestCheckpointResolved = includeLatestCheckpoint
|
|
168
|
+
? resolveLatestCheckpointQid(options.index, workspace)
|
|
169
|
+
: undefined;
|
|
170
|
+
if (latestCheckpointResolved && latestCheckpointResolved !== options.rootQid) {
|
|
171
|
+
qids.add(latestCheckpointResolved);
|
|
172
|
+
}
|
|
173
|
+
if (includeLatestCheckpoint &&
|
|
174
|
+
latestCheckpointHint &&
|
|
175
|
+
latestCheckpointResolved &&
|
|
176
|
+
latestCheckpointHint !== latestCheckpointResolved) {
|
|
177
|
+
mergeWarnings(warnings, `latest_checkpoint_qid hint mismatch for ${workspace}: ${latestCheckpointHint} -> ${latestCheckpointResolved}`);
|
|
178
|
+
}
|
|
146
179
|
if (options.verbose) {
|
|
147
180
|
const coreIds = (0, verbose_core_1.readVerboseCoreList)(options.verboseCoreListPath);
|
|
148
181
|
for (const id of coreIds) {
|
|
@@ -173,6 +206,8 @@ function buildPack(options) {
|
|
|
173
206
|
verbose: options.verbose,
|
|
174
207
|
generated_at: new Date().toISOString(),
|
|
175
208
|
node_count: nodes.length,
|
|
209
|
+
latest_checkpoint_qid: latestCheckpointResolved,
|
|
210
|
+
latest_checkpoint_qid_hint: latestCheckpointHint,
|
|
176
211
|
truncated: truncation,
|
|
177
212
|
},
|
|
178
213
|
nodes,
|
package/dist/util/argparse.js
CHANGED
|
@@ -36,6 +36,24 @@ const VALUE_FLAGS = new Set([
|
|
|
36
36
|
"--max-tokens",
|
|
37
37
|
"--stats-out",
|
|
38
38
|
"--truncation-report",
|
|
39
|
+
"--description",
|
|
40
|
+
"--authors",
|
|
41
|
+
"--links",
|
|
42
|
+
"--tags-mode",
|
|
43
|
+
"--run-id",
|
|
44
|
+
"--note",
|
|
45
|
+
"--add-artifacts",
|
|
46
|
+
"--add-links",
|
|
47
|
+
"--add-refs",
|
|
48
|
+
"--add-skills",
|
|
49
|
+
"--add-tags",
|
|
50
|
+
"--add-blocked-by",
|
|
51
|
+
"--checkpoint",
|
|
52
|
+
"--kind",
|
|
53
|
+
"--notes",
|
|
54
|
+
"--agent",
|
|
55
|
+
"--skill",
|
|
56
|
+
"--tool",
|
|
39
57
|
]);
|
|
40
58
|
const BOOLEAN_FLAGS = new Set([
|
|
41
59
|
"--tolerant",
|
|
@@ -44,6 +62,7 @@ const BOOLEAN_FLAGS = new Set([
|
|
|
44
62
|
"--quiet",
|
|
45
63
|
"--no-cache",
|
|
46
64
|
"--no-reindex",
|
|
65
|
+
"--no-update-ignores",
|
|
47
66
|
"--force",
|
|
48
67
|
"--update-gitignore",
|
|
49
68
|
"--update-npmignore",
|
|
@@ -51,7 +70,9 @@ const BOOLEAN_FLAGS = new Set([
|
|
|
51
70
|
"--agents",
|
|
52
71
|
"--claude",
|
|
53
72
|
"--llm",
|
|
73
|
+
"--omni",
|
|
54
74
|
"--body",
|
|
75
|
+
"--meta",
|
|
55
76
|
"--strip-code",
|
|
56
77
|
"--stats",
|
|
57
78
|
"--concise",
|
|
@@ -59,10 +80,14 @@ const BOOLEAN_FLAGS = new Set([
|
|
|
59
80
|
"--dry-run",
|
|
60
81
|
"--json",
|
|
61
82
|
"--list-profiles",
|
|
83
|
+
"--with-scripts",
|
|
84
|
+
"--clear-blocked-by",
|
|
85
|
+
"--no-update-gitignore",
|
|
62
86
|
]);
|
|
63
87
|
const FLAG_ALIASES = {
|
|
64
88
|
"--o": "--out",
|
|
65
89
|
"-o": "--out",
|
|
90
|
+
"--profile": "--pack-profile",
|
|
66
91
|
"--f": "--format",
|
|
67
92
|
"-f": "--format",
|
|
68
93
|
"--v": "--verbose",
|