mdkg 0.0.8 → 0.0.9

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.
Files changed (48) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/CONTRIBUTING.md +124 -0
  3. package/README.md +33 -14
  4. package/dist/cli.js +80 -32
  5. package/dist/commands/checkpoint.js +19 -2
  6. package/dist/commands/event.js +12 -0
  7. package/dist/commands/new.js +57 -21
  8. package/dist/commands/pack.js +14 -0
  9. package/dist/commands/query_output.js +2 -0
  10. package/dist/commands/search.js +8 -0
  11. package/dist/commands/show.js +7 -0
  12. package/dist/commands/skill.js +80 -12
  13. package/dist/commands/task.js +42 -12
  14. package/dist/commands/validate.js +31 -3
  15. package/dist/commands/workspace.js +105 -13
  16. package/dist/core/config.js +217 -22
  17. package/dist/core/migrate.js +39 -5
  18. package/dist/core/workspace_path.js +41 -0
  19. package/dist/graph/agent_file_types.js +392 -0
  20. package/dist/graph/edges.js +13 -10
  21. package/dist/graph/frontmatter.js +33 -0
  22. package/dist/graph/indexer.js +1 -0
  23. package/dist/graph/node.js +43 -16
  24. package/dist/graph/skills_indexer.js +14 -1
  25. package/dist/graph/template_schema.js +13 -126
  26. package/dist/graph/validate_graph.js +302 -2
  27. package/dist/init/AGENT_START.md +13 -2
  28. package/dist/init/CLI_COMMAND_MATRIX.md +43 -1
  29. package/dist/init/README.md +7 -0
  30. package/dist/init/core/rule-6-templates-and-schemas.md +1 -3
  31. package/dist/init/skills/default/verify-close-and-checkpoint/SKILL.md +1 -1
  32. package/dist/init/templates/default/dispute.md +31 -0
  33. package/dist/init/templates/default/feedback.md +27 -0
  34. package/dist/init/templates/default/proposal.md +35 -0
  35. package/dist/init/templates/default/receipt.md +31 -0
  36. package/dist/init/templates/default/spec.md +43 -0
  37. package/dist/init/templates/default/work.md +44 -0
  38. package/dist/init/templates/default/work_order.md +32 -0
  39. package/dist/pack/export_json.js +3 -0
  40. package/dist/pack/export_md.js +9 -0
  41. package/dist/pack/export_xml.js +9 -0
  42. package/dist/pack/order.js +7 -0
  43. package/dist/pack/pack.js +1 -0
  44. package/dist/templates/loader.js +2 -2
  45. package/dist/util/argparse.js +1 -0
  46. package/dist/util/id.js +19 -0
  47. package/package.json +9 -2
  48. package/scripts/postinstall.js +89 -0
@@ -0,0 +1,27 @@
1
+ ---
2
+ id: {{id}}
3
+ type: feedback
4
+ title: {{title}}
5
+ version: 0.1.0
6
+ target_id: work.example
7
+ sentiment: neutral
8
+ feedback_status: new
9
+ source_ref: user.example
10
+ tags: []
11
+ owners: []
12
+ links: []
13
+ artifacts: []
14
+ relates: []
15
+ refs: []
16
+ aliases: []
17
+ created: {{created}}
18
+ updated: {{updated}}
19
+ ---
20
+
21
+ # Feedback
22
+
23
+ Capture high-signal feedback without raw secrets.
24
+
25
+ # Evidence
26
+
27
+ List supporting references and artifacts.
@@ -0,0 +1,35 @@
1
+ ---
2
+ id: {{id}}
3
+ type: proposal
4
+ title: {{title}}
5
+ version: 0.1.0
6
+ target_id: work.example
7
+ proposal_status: proposed
8
+ proposal_kind: work_update
9
+ evidence_refs: []
10
+ tags: []
11
+ owners: []
12
+ links: []
13
+ artifacts: []
14
+ relates: []
15
+ refs: []
16
+ aliases: []
17
+ created: {{created}}
18
+ updated: {{updated}}
19
+ ---
20
+
21
+ # Summary
22
+
23
+ Summarize the improvement proposal.
24
+
25
+ # Evidence
26
+
27
+ List feedback, receipts, disputes, or other evidence.
28
+
29
+ # Proposed Change
30
+
31
+ Describe the proposed update to a SPEC.md, WORK.md, or SKILL.md.
32
+
33
+ # Review
34
+
35
+ Capture review status and next decision points.
@@ -0,0 +1,31 @@
1
+ ---
2
+ id: {{id}}
3
+ type: receipt
4
+ title: {{title}}
5
+ version: 0.1.0
6
+ work_order_id: order.example
7
+ receipt_status: recorded
8
+ outcome: success
9
+ cost_ref: cost.redacted
10
+ tags: []
11
+ owners: []
12
+ links: []
13
+ artifacts: []
14
+ relates: []
15
+ refs: []
16
+ aliases: []
17
+ created: {{created}}
18
+ updated: {{updated}}
19
+ ---
20
+
21
+ # Outcome
22
+
23
+ Record the result and proof summary.
24
+
25
+ # Artifacts
26
+
27
+ List committed artifact references.
28
+
29
+ # Notes
30
+
31
+ Capture non-secret execution notes.
@@ -0,0 +1,43 @@
1
+ ---
2
+ id: {{id}}
3
+ type: spec
4
+ title: {{title}}
5
+ version: 0.1.0
6
+ role: subagent
7
+ runtime_mode: room_orchestrated
8
+ work_contracts: []
9
+ requested_capabilities: []
10
+ skill_refs: []
11
+ tool_refs: []
12
+ model_refs: []
13
+ wasm_component_refs: []
14
+ runtime_image_refs: []
15
+ subagent_refs: []
16
+ resource_profile: builder
17
+ update_policy: manual
18
+ tags: []
19
+ owners: []
20
+ links: []
21
+ artifacts: []
22
+ relates: []
23
+ refs: []
24
+ aliases: []
25
+ created: {{created}}
26
+ updated: {{updated}}
27
+ ---
28
+
29
+ # Purpose
30
+
31
+ Define the agent, package, or runtime specification.
32
+
33
+ # Runtime
34
+
35
+ Describe role, runtime mode, resource profile, and update policy.
36
+
37
+ # Work Contracts
38
+
39
+ List related WORK.md contracts.
40
+
41
+ # Capabilities
42
+
43
+ List requested capabilities and relevant constraints.
@@ -0,0 +1,44 @@
1
+ ---
2
+ id: {{id}}
3
+ type: work
4
+ title: {{title}}
5
+ version: 0.1.0
6
+ agent_id: agent.example
7
+ kind: generic
8
+ pricing_model: quoted
9
+ required_capabilities: []
10
+ skill_refs: []
11
+ tool_refs: []
12
+ model_refs: []
13
+ wasm_component_refs: []
14
+ runtime_image_refs: []
15
+ subagent_refs: []
16
+ inputs: [request:text:required]
17
+ outputs: [result:text:required]
18
+ receipt_required: true
19
+ tags: []
20
+ owners: []
21
+ links: []
22
+ artifacts: []
23
+ relates: []
24
+ refs: []
25
+ aliases: []
26
+ created: {{created}}
27
+ updated: {{updated}}
28
+ ---
29
+
30
+ # Capability
31
+
32
+ Describe the reusable capability contract.
33
+
34
+ # Inputs
35
+
36
+ Document input descriptors and validation expectations.
37
+
38
+ # Outputs
39
+
40
+ Document output descriptors and artifact expectations.
41
+
42
+ # Receipt
43
+
44
+ Describe required receipt evidence.
@@ -0,0 +1,32 @@
1
+ ---
2
+ id: {{id}}
3
+ type: work_order
4
+ title: {{title}}
5
+ version: 0.1.0
6
+ work_id: work.example
7
+ work_version: 0.1.0
8
+ requester: user.example
9
+ order_status: submitted
10
+ request_ref: request.example
11
+ tags: []
12
+ owners: []
13
+ links: []
14
+ artifacts: []
15
+ relates: []
16
+ refs: []
17
+ aliases: []
18
+ created: {{created}}
19
+ updated: {{updated}}
20
+ ---
21
+
22
+ # Request
23
+
24
+ Capture the concrete request against a WORK.md version.
25
+
26
+ # Inputs
27
+
28
+ Record committed input references without secrets.
29
+
30
+ # Constraints
31
+
32
+ Capture relevant policy, budget, and artifact constraints.
@@ -15,6 +15,9 @@ function buildFrontmatter(node) {
15
15
  if (node.aliases.length > 0) {
16
16
  frontmatter.aliases = node.aliases;
17
17
  }
18
+ for (const [key, value] of Object.entries(node.attributes ?? {})) {
19
+ frontmatter[key] = value;
20
+ }
18
21
  return frontmatter;
19
22
  }
20
23
  function exportJson(pack) {
@@ -7,6 +7,12 @@ function formatList(label, values) {
7
7
  }
8
8
  return `${label}: ${values.join(", ")}`;
9
9
  }
10
+ function formatAttribute(label, value) {
11
+ if (Array.isArray(value)) {
12
+ return formatList(label, value);
13
+ }
14
+ return `${label}: ${String(value)}`;
15
+ }
10
16
  function renderHeader(meta, nodes) {
11
17
  const lines = [];
12
18
  lines.push("# mdkg pack");
@@ -56,6 +62,9 @@ function renderNode(node) {
56
62
  if (node.refs.length > 0) {
57
63
  lines.push(formatList("refs", node.refs));
58
64
  }
65
+ for (const [key, value] of Object.entries(node.attributes ?? {})) {
66
+ lines.push(formatAttribute(key, value));
67
+ }
59
68
  if (node.body.trim().length > 0) {
60
69
  lines.push("");
61
70
  lines.push(node.body);
@@ -21,6 +21,12 @@ function listItems(tag, itemTag, items, indent) {
21
21
  lines.push(`${indent}</${tag}>`);
22
22
  return lines;
23
23
  }
24
+ function attributeLines(key, value, indent) {
25
+ if (Array.isArray(value)) {
26
+ return listItems(key, "item", value, indent);
27
+ }
28
+ return [`${indent}<${key}>${escapeXml(String(value))}</${key}>`];
29
+ }
24
30
  function exportXml(pack) {
25
31
  const lines = [];
26
32
  lines.push("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
@@ -78,6 +84,9 @@ function exportXml(pack) {
78
84
  lines.push(...listItems("artifacts", "artifact", node.artifacts, " "));
79
85
  lines.push(...listItems("refs", "ref", node.refs, " "));
80
86
  lines.push(...listItems("aliases", "alias", node.aliases, " "));
87
+ for (const [key, value] of Object.entries(node.attributes ?? {})) {
88
+ lines.push(...attributeLines(key, value, " "));
89
+ }
81
90
  lines.push(" </frontmatter>");
82
91
  lines.push(` <body>${escapeXml(node.body)}</body>`);
83
92
  lines.push(" </node>");
@@ -8,6 +8,13 @@ const FALLBACK_TYPES = [
8
8
  "rule",
9
9
  "prd",
10
10
  "prop",
11
+ "spec",
12
+ "work",
13
+ "work_order",
14
+ "receipt",
15
+ "feedback",
16
+ "dispute",
17
+ "proposal",
11
18
  "epic",
12
19
  "feat",
13
20
  "task",
package/dist/pack/pack.js CHANGED
@@ -124,6 +124,7 @@ function buildPackNode(root, index, qid) {
124
124
  artifacts: node.artifacts,
125
125
  refs: node.refs,
126
126
  aliases: node.aliases,
127
+ attributes: node.attributes ?? {},
127
128
  body,
128
129
  };
129
130
  }
@@ -48,8 +48,8 @@ function renderTokenValue(value) {
48
48
  }
49
49
  return value;
50
50
  }
51
- function renderTemplate(template, context, allowedKeysInput) {
52
- const allowedKeys = new Set(allowedKeysInput ?? Object.keys(template.frontmatter));
51
+ function renderTemplate(template, context) {
52
+ const allowedKeys = new Set(Object.keys(template.frontmatter));
53
53
  const rendered = {};
54
54
  for (const [key, value] of Object.entries(template.frontmatter)) {
55
55
  if (isTokenPlaceholder(value)) {
@@ -4,6 +4,7 @@ exports.parseArgs = parseArgs;
4
4
  const NORMALIZE_VALUE_FLAGS = new Set(["--ws", "--type", "--status", "--template", "--epic"]);
5
5
  const VALUE_FLAGS = new Set([
6
6
  "--root",
7
+ "--id",
7
8
  "--ws",
8
9
  "--type",
9
10
  "--status",
package/dist/util/id.js CHANGED
@@ -1,13 +1,19 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.isCanonicalId = isCanonicalId;
4
+ exports.isPortableId = isPortableId;
4
5
  exports.isCanonicalIdRef = isCanonicalIdRef;
6
+ exports.isPortableIdRef = isPortableIdRef;
5
7
  const NUMERIC_ID_RE = /^[a-z]+-[0-9]+$/;
6
8
  const WORKSPACE_RE = /^[a-z][a-z0-9_]*$/;
9
+ const PORTABLE_ID_RE = /^[a-z][a-z0-9_]*(?:[._-][a-z0-9_]+)*$/;
7
10
  const SPECIAL_IDS = new Set(["rule-guide", "rule-soul", "rule-human"]);
8
11
  function isCanonicalId(value) {
9
12
  return NUMERIC_ID_RE.test(value) || SPECIAL_IDS.has(value);
10
13
  }
14
+ function isPortableId(value) {
15
+ return isCanonicalId(value) || PORTABLE_ID_RE.test(value);
16
+ }
11
17
  function isCanonicalIdRef(value) {
12
18
  const normalized = value.toLowerCase();
13
19
  const parts = normalized.split(":");
@@ -21,3 +27,16 @@ function isCanonicalIdRef(value) {
21
27
  const id = parts[1] ?? "";
22
28
  return WORKSPACE_RE.test(workspace) && isCanonicalId(id);
23
29
  }
30
+ function isPortableIdRef(value) {
31
+ const normalized = value.toLowerCase();
32
+ const parts = normalized.split(":");
33
+ if (parts.length === 1) {
34
+ return isPortableId(parts[0] ?? "");
35
+ }
36
+ if (parts.length !== 2) {
37
+ return false;
38
+ }
39
+ const workspace = parts[0] ?? "";
40
+ const id = parts[1] ?? "";
41
+ return WORKSPACE_RE.test(workspace) && isPortableId(id);
42
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mdkg",
3
- "version": "0.0.8",
3
+ "version": "0.0.9",
4
4
  "description": "Markdown Knowledge Graph",
5
5
  "license": "MIT",
6
6
  "bin": {
@@ -12,8 +12,12 @@
12
12
  "test": "npm run build && npm run build:test && node --test dist/tests/**/*.test.js",
13
13
  "test:coverage": "npm run build && npm run build:test && node --test --experimental-test-coverage dist/tests/**/*.test.js",
14
14
  "smoke:consumer": "npm run build && node scripts/smoke-consumer.js",
15
+ "smoke:matrix": "npm run build && node scripts/smoke-command-matrix.js",
15
16
  "cli:snapshot": "npm run build && node scripts/cli_help_snapshot.js",
16
- "cli:check": "npm run build && node scripts/cli_help_snapshot.js --check"
17
+ "cli:check": "npm run build && node scripts/cli_help_snapshot.js --check",
18
+ "prepack": "npm run build && node scripts/assert-publish-ready.js",
19
+ "prepublishOnly": "npm run test && npm run cli:check && node dist/cli.js validate && npm run smoke:consumer && npm run smoke:matrix && node scripts/assert-publish-ready.js",
20
+ "postinstall": "node scripts/postinstall.js"
17
21
  },
18
22
  "devDependencies": {
19
23
  "@types/node": "^18.19.0",
@@ -28,7 +32,10 @@
28
32
  "dist/pack/",
29
33
  "dist/templates/",
30
34
  "dist/util/",
35
+ "scripts/postinstall.js",
31
36
  "README.md",
37
+ "CHANGELOG.md",
38
+ "CONTRIBUTING.md",
32
39
  "LICENSE"
33
40
  ],
34
41
  "engines": {
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require("node:fs");
4
+ const path = require("node:path");
5
+ const { spawnSync } = require("node:child_process");
6
+
7
+ function readPackageVersion() {
8
+ try {
9
+ const pkgPath = path.resolve(__dirname, "..", "package.json");
10
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
11
+ return typeof pkg.version === "string" ? pkg.version : "unknown";
12
+ } catch {
13
+ return "unknown";
14
+ }
15
+ }
16
+
17
+ function npmCommand(platform = process.platform) {
18
+ return platform === "win32" ? "npm.cmd" : "npm";
19
+ }
20
+
21
+ function npmPrefixGlobal(env = process.env, platform = process.platform, spawn = spawnSync) {
22
+ if (env.npm_config_prefix) {
23
+ return env.npm_config_prefix;
24
+ }
25
+ const result = spawn(npmCommand(platform), ["prefix", "-g"], {
26
+ encoding: "utf8",
27
+ stdio: "pipe",
28
+ });
29
+ if (result.status !== 0) {
30
+ return undefined;
31
+ }
32
+ const prefix = String(result.stdout || "").trim();
33
+ return prefix || undefined;
34
+ }
35
+
36
+ function globalBinFromPrefix(prefix, platform = process.platform) {
37
+ if (!prefix) {
38
+ return undefined;
39
+ }
40
+ return platform === "win32" ? prefix : path.join(prefix, "bin");
41
+ }
42
+
43
+ function pathIncludesDir(dir, env = process.env, platform = process.platform) {
44
+ if (!dir) {
45
+ return false;
46
+ }
47
+ const currentPath = env.PATH || "";
48
+ return currentPath
49
+ .split(path.delimiter)
50
+ .filter(Boolean)
51
+ .some((entry) => path.resolve(entry) === path.resolve(dir));
52
+ }
53
+
54
+ function buildPostinstallMessage(env = process.env, platform = process.platform, spawn = spawnSync) {
55
+ const version = readPackageVersion();
56
+ const lines = [
57
+ `mdkg ${version} installed.`,
58
+ "",
59
+ "Start here:",
60
+ " mdkg --help",
61
+ ];
62
+
63
+ const prefix = npmPrefixGlobal(env, platform, spawn);
64
+ const globalBin = globalBinFromPrefix(prefix, platform);
65
+ if (platform !== "win32" && globalBin && !pathIncludesDir(globalBin, env, platform)) {
66
+ lines.push(
67
+ "",
68
+ "If your shell cannot find mdkg, add npm's global bin directory to PATH:",
69
+ "",
70
+ "# zsh",
71
+ `echo 'export PATH="${globalBin}:$PATH"' >> ~/.zshrc`,
72
+ "",
73
+ "# bash",
74
+ `echo 'export PATH="${globalBin}:$PATH"' >> ~/.bashrc`
75
+ );
76
+ }
77
+
78
+ return lines.join("\n");
79
+ }
80
+
81
+ if (require.main === module) {
82
+ console.log(buildPostinstallMessage());
83
+ }
84
+
85
+ module.exports = {
86
+ buildPostinstallMessage,
87
+ globalBinFromPrefix,
88
+ pathIncludesDir,
89
+ };