@mastishk/core 0.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/README.md ADDED
@@ -0,0 +1,70 @@
1
+ # @mastishk/core
2
+
3
+ Core library for the [Mastishk protocol](https://mastishk.dev) — schema, validation, read, write, graph, traversal, and context injection for persistent AI agent memory.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @mastishk/core
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```typescript
14
+ import { readNode, writeNode, inject, readMemoryMap } from '@mastishk/core';
15
+
16
+ // Read a memory node
17
+ const node = await readNode('.mastishk/intent/goal-launch-v1.msk.md');
18
+
19
+ // Write a new node
20
+ await writeNode('.mastishk/state/task-build-auth.msk.md', {
21
+ id: 'task-build-auth',
22
+ type: 'task',
23
+ layer: 'state',
24
+ status: 'active',
25
+ confidence: 1.0,
26
+ created_by: 'claude-code',
27
+ created_at: new Date().toISOString(),
28
+ last_updated_by: 'claude-code',
29
+ last_updated_at: new Date().toISOString(),
30
+ dependencies: ['goal-launch-v1'],
31
+ contradictions: [],
32
+ body: 'Implement JWT authentication.',
33
+ });
34
+
35
+ // Get inject context for a task
36
+ const context = await inject('build authentication', '.mastishk');
37
+ // Returns formatted context string ready for an agent system prompt
38
+ ```
39
+
40
+ ## API
41
+
42
+ ### `readNode(filePath): Promise<MskNode>`
43
+ Parse a `.msk.md` file into a validated `MskNode`. Throws `MskReadError` if invalid.
44
+
45
+ ### `writeNode(filePath, node): Promise<void>`
46
+ Write a node to disk. State-layer writes are append-only with timestamp headers. Throws `MskWriteError` if validation fails.
47
+
48
+ ### `inject(task, mastishkDir): Promise<string>`
49
+ Tokenise the task, match against node IDs and tags, traverse the DAG at depth 2, and return a formatted context string per spec section 6.3.
50
+
51
+ ### `validate(node): { valid: boolean; errors: string[] }`
52
+ Validate any object against the `MskNodeSchema`.
53
+
54
+ ### `readMemoryMap(filePath) / writeMemoryMap(filePath, map)`
55
+ Read/write the `memory-map.json` DAG index.
56
+
57
+ ### `upsertNode(map, id, entry): MemoryMap`
58
+ Add or update a node in the memory map and rebuild edges.
59
+
60
+ ### `traverse(map, seedIds, options): TraversalResult[]`
61
+ DFS traversal from seed nodes following dependency edges.
62
+
63
+ ### `validateGraph(map) / assertValidGraph(map)`
64
+ Check for cycles, dangling references, and duplicate IDs.
65
+
66
+ ## Protocol
67
+
68
+ - Spec: [MASTISHK-SPEC.md](https://github.com/mastishk-ai/mastishk/blob/main/MASTISHK-SPEC.md)
69
+ - Website: [mastishk.dev](https://mastishk.dev)
70
+ - License: Apache 2.0
@@ -0,0 +1,36 @@
1
+ import type { MskLayer, MskType, MskStatus } from './schema.js';
2
+ export interface MemoryMapNode {
3
+ file: string;
4
+ layer: MskLayer;
5
+ type: MskType;
6
+ status: MskStatus;
7
+ confidence: number;
8
+ dependencies: string[];
9
+ tags?: string[];
10
+ }
11
+ export interface MemoryMapEdge {
12
+ from: string;
13
+ to: string;
14
+ relation: string;
15
+ }
16
+ export interface MemoryMap {
17
+ version: string;
18
+ updated_at: string;
19
+ nodes: Record<string, MemoryMapNode>;
20
+ edges: MemoryMapEdge[];
21
+ }
22
+ export declare class MskGraphError extends Error {
23
+ readonly violation: 'cycle' | 'dangling' | 'duplicate';
24
+ constructor(message: string, violation: 'cycle' | 'dangling' | 'duplicate');
25
+ }
26
+ export declare function createEmptyMemoryMap(): MemoryMap;
27
+ export declare function readMemoryMap(filePath: string): Promise<MemoryMap>;
28
+ export declare function writeMemoryMap(filePath: string, map: MemoryMap): Promise<void>;
29
+ export declare function validateGraph(map: MemoryMap): {
30
+ valid: boolean;
31
+ errors: string[];
32
+ };
33
+ export declare function assertValidGraph(map: MemoryMap): void;
34
+ export declare function upsertNode(map: MemoryMap, id: string, entry: MemoryMapNode): MemoryMap;
35
+ export declare function removeNode(map: MemoryMap, id: string): MemoryMap;
36
+ //# sourceMappingURL=graph.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../src/graph.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAIhE,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,QAAQ,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,SAAS,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACrC,KAAK,EAAE,aAAa,EAAE,CAAC;CACxB;AAGD,qBAAa,aAAc,SAAQ,KAAK;IACtC,QAAQ,CAAC,SAAS,EAAE,OAAO,GAAG,UAAU,GAAG,WAAW,CAAC;gBAE3C,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,UAAU,GAAG,WAAW;CAK3E;AAED,wBAAgB,oBAAoB,IAAI,SAAS,CAOhD;AAED,wBAAsB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAQxE;AAED,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAIpF;AAkCD,wBAAgB,aAAa,CAAC,GAAG,EAAE,SAAS,GAAG;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAkBlF;AAGD,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,SAAS,GAAG,IAAI,CAQrD;AAeD,wBAAgB,UAAU,CAAC,GAAG,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,SAAS,CAGtF;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,GAAG,SAAS,CAGhE"}
package/dist/graph.js ADDED
@@ -0,0 +1,116 @@
1
+ import { readFile, writeFile, mkdir } from 'node:fs/promises';
2
+ import { dirname } from 'node:path';
3
+ // Spec section 5.2 — typed error for DAG constraint violations
4
+ export class MskGraphError extends Error {
5
+ violation;
6
+ constructor(message, violation) {
7
+ super(message);
8
+ this.name = 'MskGraphError';
9
+ this.violation = violation;
10
+ }
11
+ }
12
+ export function createEmptyMemoryMap() {
13
+ return {
14
+ version: '0.1',
15
+ updated_at: new Date().toISOString(),
16
+ nodes: {},
17
+ edges: [],
18
+ };
19
+ }
20
+ export async function readMemoryMap(filePath) {
21
+ let raw;
22
+ try {
23
+ raw = await readFile(filePath, 'utf-8');
24
+ }
25
+ catch (cause) {
26
+ throw new Error(`Cannot read memory-map.json at "${filePath}"`, { cause });
27
+ }
28
+ return JSON.parse(raw);
29
+ }
30
+ export async function writeMemoryMap(filePath, map) {
31
+ await mkdir(dirname(filePath), { recursive: true });
32
+ const updated = { ...map, updated_at: new Date().toISOString() };
33
+ await writeFile(filePath, JSON.stringify(updated, null, 2) + '\n', 'utf-8');
34
+ }
35
+ // Spec section 5.2 — cycle detection via DFS coloring (white/gray/black)
36
+ function findCycle(nodes) {
37
+ const WHITE = 0, GRAY = 1, BLACK = 2;
38
+ const color = {};
39
+ for (const id of Object.keys(nodes))
40
+ color[id] = WHITE;
41
+ function dfs(id, path) {
42
+ color[id] = GRAY;
43
+ for (const dep of nodes[id]?.dependencies ?? []) {
44
+ if (!(dep in color))
45
+ continue; // dangling — caught separately
46
+ if (color[dep] === GRAY)
47
+ return [...path, id, dep].join(' → ');
48
+ if (color[dep] === WHITE) {
49
+ const cycle = dfs(dep, [...path, id]);
50
+ if (cycle)
51
+ return cycle;
52
+ }
53
+ }
54
+ color[id] = BLACK;
55
+ return null;
56
+ }
57
+ for (const id of Object.keys(nodes)) {
58
+ if (color[id] === WHITE) {
59
+ const cycle = dfs(id, []);
60
+ if (cycle)
61
+ return cycle;
62
+ }
63
+ }
64
+ return null;
65
+ }
66
+ // Spec section 5.2 — validates no cycles, no dangling refs, unique IDs.
67
+ // Returns { valid, errors } rather than throwing so callers can choose.
68
+ // Use assertValidGraph() to get the typed throw behaviour.
69
+ export function validateGraph(map) {
70
+ const errors = [];
71
+ const ids = new Set(Object.keys(map.nodes));
72
+ // No dangling references in dependencies
73
+ for (const [id, node] of Object.entries(map.nodes)) {
74
+ for (const dep of node.dependencies) {
75
+ if (!ids.has(dep)) {
76
+ errors.push(`Node "${id}" has dangling dependency: "${dep}"`);
77
+ }
78
+ }
79
+ }
80
+ // No cycles
81
+ const cycle = findCycle(map.nodes);
82
+ if (cycle)
83
+ errors.push(`Cycle detected: ${cycle}`);
84
+ return { valid: errors.length === 0, errors };
85
+ }
86
+ // Throws MskGraphError if any constraint is violated. Spec section 5.2.
87
+ export function assertValidGraph(map) {
88
+ const { valid, errors } = validateGraph(map);
89
+ if (!valid) {
90
+ const hasCycle = errors.some((e) => e.startsWith('Cycle'));
91
+ const hasDangling = errors.some((e) => e.includes('dangling'));
92
+ const violation = hasCycle ? 'cycle' : hasDangling ? 'dangling' : 'duplicate';
93
+ throw new MskGraphError(errors.join('; '), violation);
94
+ }
95
+ }
96
+ // Rebuild edges array from dependencies — keeps edges consistent with node data.
97
+ // SPEC-GAP: spec shows edges with semantic relation types (e.g. "serves") but does
98
+ // not define how they are assigned. We use "depends-on" as the default relation.
99
+ function rebuildEdges(nodes) {
100
+ const edges = [];
101
+ for (const [id, node] of Object.entries(nodes)) {
102
+ for (const dep of node.dependencies) {
103
+ edges.push({ from: id, to: dep, relation: 'depends-on' });
104
+ }
105
+ }
106
+ return edges;
107
+ }
108
+ export function upsertNode(map, id, entry) {
109
+ const nodes = { ...map.nodes, [id]: entry };
110
+ return { ...map, nodes, edges: rebuildEdges(nodes), updated_at: new Date().toISOString() };
111
+ }
112
+ export function removeNode(map, id) {
113
+ const { [id]: _removed, ...rest } = map.nodes;
114
+ return { ...map, nodes: rest, edges: rebuildEdges(rest), updated_at: new Date().toISOString() };
115
+ }
116
+ //# sourceMappingURL=graph.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph.js","sourceRoot":"","sources":["../src/graph.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ export { MskLayerSchema, MskTypeSchema, MskStatusSchema, MskNodeSchema, } from './schema.js';
2
+ export type { MskLayer, MskType, MskStatus, MskNode } from './schema.js';
3
+ export { validate } from './validate.js';
4
+ export { readNode, MskReadError } from './read.js';
5
+ export { writeNode, updateNodeMeta, MskWriteError } from './write.js';
6
+ export { createEmptyMemoryMap, readMemoryMap, writeMemoryMap, validateGraph, assertValidGraph, upsertNode, removeNode, MskGraphError, } from './graph.js';
7
+ export type { MemoryMap, MemoryMapNode, MemoryMapEdge } from './graph.js';
8
+ export { traverse } from './traverse.js';
9
+ export type { TraverseOptions, TraversalResult } from './traverse.js';
10
+ export { inject } from './inject.js';
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,aAAa,EACb,eAAe,EACf,aAAa,GACd,MAAM,aAAa,CAAC;AAErB,YAAY,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAEzE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEnD,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEtE,OAAO,EACL,oBAAoB,EACpB,aAAa,EACb,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,UAAU,EACV,UAAU,EACV,aAAa,GACd,MAAM,YAAY,CAAC;AAEpB,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE1E,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEtE,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+ export { MskLayerSchema, MskTypeSchema, MskStatusSchema, MskNodeSchema, } from './schema.js';
2
+ export { validate } from './validate.js';
3
+ export { readNode, MskReadError } from './read.js';
4
+ export { writeNode, updateNodeMeta, MskWriteError } from './write.js';
5
+ export { createEmptyMemoryMap, readMemoryMap, writeMemoryMap, validateGraph, assertValidGraph, upsertNode, removeNode, MskGraphError, } from './graph.js';
6
+ export { traverse } from './traverse.js';
7
+ export { inject } from './inject.js';
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,aAAa,EACb,eAAe,EACf,aAAa,GACd,MAAM,aAAa,CAAC;AAIrB,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEnD,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEtE,OAAO,EACL,oBAAoB,EACpB,aAAa,EACb,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,UAAU,EACV,UAAU,EACV,aAAa,GACd,MAAM,YAAY,CAAC;AAIpB,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAIzC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function inject(task: string, mastishkDir: string): Promise<string>;
2
+ //# sourceMappingURL=inject.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inject.d.ts","sourceRoot":"","sources":["../src/inject.ts"],"names":[],"mappings":"AAoDA,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA0E/E"}
package/dist/inject.js ADDED
@@ -0,0 +1,108 @@
1
+ import { join } from 'node:path';
2
+ import { readMemoryMap } from './graph.js';
3
+ import { traverse } from './traverse.js';
4
+ import { readNode } from './read.js';
5
+ const LAYER_ORDER = { intent: 0, state: 1, knowledge: 2, issues: 3 };
6
+ // SPEC-GAP: "token" is not defined by the spec (it is model-specific).
7
+ // We approximate: 1 token ≈ 4 characters.
8
+ const CHARS_PER_TOKEN = 4;
9
+ const TOKEN_BUDGET = 2000;
10
+ const CHAR_BUDGET = TOKEN_BUDGET * CHARS_PER_TOKEN;
11
+ function tokenize(str) {
12
+ return str.toLowerCase().split(/\W+/).filter(Boolean);
13
+ }
14
+ // Score how well a node's id and tags match the task tokens.
15
+ // SPEC-GAP: spec says match against id, tags, AND body content. Reading all node files
16
+ // for body-content matching is expensive; we match id and tags from memory-map.json only.
17
+ function matchScore(id, node, tokens) {
18
+ let score = 0;
19
+ const idParts = id.split('-');
20
+ for (const token of tokens) {
21
+ if (idParts.includes(token))
22
+ score += 2;
23
+ if (node.tags?.some((t) => t.toLowerCase() === token))
24
+ score += 1;
25
+ }
26
+ return score;
27
+ }
28
+ function firstSentence(text) {
29
+ const match = text.match(/^[^.!?]+[.!?]?/);
30
+ return (match?.[0] ?? text).trim();
31
+ }
32
+ async function readBodySafe(mastishkDir, file) {
33
+ try {
34
+ const node = await readNode(join(mastishkDir, file));
35
+ return node.body;
36
+ }
37
+ catch {
38
+ return '';
39
+ }
40
+ }
41
+ // Spec section 6.3 — render one node line
42
+ function renderNodeLine(id, confidence, body, fullBody) {
43
+ const content = fullBody ? body : firstSentence(body);
44
+ return `**${id}** [${confidence.toFixed(1)}] — ${content}`;
45
+ }
46
+ // Spec section 6.2 — inject algorithm
47
+ export async function inject(task, mastishkDir) {
48
+ const memoryMapPath = join(mastishkDir, 'memory-map.json');
49
+ const map = await readMemoryMap(memoryMapPath);
50
+ // Step 1-2: tokenize task, score and rank nodes by match
51
+ const tokens = tokenize(task);
52
+ const scored = Object.entries(map.nodes)
53
+ .map(([id, node]) => ({ id, node, score: matchScore(id, node, tokens) }))
54
+ .filter((x) => x.score > 0)
55
+ .sort((a, b) => b.node.confidence - a.node.confidence || b.score - a.score);
56
+ const seedIds = scored.map((x) => x.id);
57
+ // Step 3-4: traverse at depth 2, filter active + confidence >= 0.5
58
+ const traversed = traverse(map, seedIds, { depth: 2, statusFilter: ['active'], minConfidence: 0.5 });
59
+ // Step 5: sort by layer then confidence
60
+ traversed.sort((a, b) => {
61
+ const lo = (LAYER_ORDER[a.node.layer] ?? 99) - (LAYER_ORDER[b.node.layer] ?? 99);
62
+ return lo !== 0 ? lo : b.node.confidence - a.node.confidence;
63
+ });
64
+ // Read bodies for all traversed nodes
65
+ const bodies = await Promise.all(traversed.map((r) => readBodySafe(mastishkDir, r.node.file)));
66
+ const nodeData = traversed.map((r, i) => ({ ...r, body: bodies[i] }));
67
+ // Step 7: enforce 2000-token budget — drop lowest-confidence first
68
+ const header = `## Mastishk context — ${task}\nGenerated: ${new Date().toISOString()}\n`;
69
+ let charBudget = CHAR_BUDGET - header.length;
70
+ // Sort a copy by confidence asc for budget truncation, but keep display order
71
+ const budgetOrder = [...nodeData].sort((a, b) => a.node.confidence - b.node.confidence);
72
+ const excluded = new Set();
73
+ for (const item of budgetOrder) {
74
+ const line = renderNodeLine(item.id, item.node.confidence, item.body, item.node.confidence >= 0.9);
75
+ if (charBudget - line.length < 0) {
76
+ excluded.add(item.id);
77
+ }
78
+ else {
79
+ charBudget -= line.length + 1; // +1 for newline
80
+ }
81
+ }
82
+ const included = nodeData.filter((r) => !excluded.has(r.id));
83
+ // Step 6: format output per spec section 6.3
84
+ const byLayer = {
85
+ intent: included.filter((r) => r.node.layer === 'intent'),
86
+ state: included.filter((r) => r.node.layer === 'state'),
87
+ knowledge: included.filter((r) => r.node.layer === 'knowledge'),
88
+ issues: included.filter((r) => r.node.layer === 'issues'),
89
+ };
90
+ function renderSection(title, items) {
91
+ if (items.length === 0)
92
+ return '';
93
+ const lines = items
94
+ .map((r) => renderNodeLine(r.id, r.node.confidence, r.body, r.node.confidence >= 0.9))
95
+ .join('\n');
96
+ return `### ${title}\n${lines}\n`;
97
+ }
98
+ const sections = [
99
+ renderSection('Goals', byLayer.intent),
100
+ renderSection('Current state', byLayer.state),
101
+ renderSection('Knowledge', byLayer.knowledge),
102
+ renderSection('Open issues', byLayer.issues),
103
+ ]
104
+ .filter(Boolean)
105
+ .join('\n');
106
+ return `${header}\n${sections}`.trimEnd();
107
+ }
108
+ //# sourceMappingURL=inject.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inject.js","sourceRoot":"","sources":["../src/inject.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAGrC,MAAM,WAAW,GAA2B,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;AAE7F,uEAAuE;AACvE,0CAA0C;AAC1C,MAAM,eAAe,GAAG,CAAC,CAAC;AAC1B,MAAM,YAAY,GAAG,IAAI,CAAC;AAC1B,MAAM,WAAW,GAAG,YAAY,GAAG,eAAe,CAAC;AAEnD,SAAS,QAAQ,CAAC,GAAW;IAC3B,OAAO,GAAG,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;AACxD,CAAC;AAED,6DAA6D;AAC7D,uFAAuF;AACvF,0FAA0F;AAC1F,SAAS,UAAU,CAAC,EAAU,EAAE,IAAyB,EAAE,MAAgB;IACzE,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,MAAM,OAAO,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC9B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,KAAK,IAAI,CAAC,CAAC;QACxC,IAAI,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,KAAK,KAAK,CAAC;YAAE,KAAK,IAAI,CAAC,CAAC;IACpE,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,aAAa,CAAC,IAAY;IACjC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;IAC3C,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;AACrC,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,WAAmB,EAAE,IAAY;IAC3D,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC;QACrD,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,0CAA0C;AAC1C,SAAS,cAAc,CAAC,EAAU,EAAE,UAAkB,EAAE,IAAY,EAAE,QAAiB;IACrF,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IACtD,OAAO,KAAK,EAAE,OAAO,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,OAAO,EAAE,CAAC;AAC7D,CAAC;AAED,sCAAsC;AACtC,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,IAAY,EAAE,WAAmB;IAC5D,MAAM,aAAa,GAAG,IAAI,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAC;IAC3D,MAAM,GAAG,GAAG,MAAM,aAAa,CAAC,aAAa,CAAC,CAAC;IAE/C,yDAAyD;IACzD,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC9B,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;SACrC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,UAAU,CAAC,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;SACxE,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC;SAC1B,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;IAE9E,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAExC,mEAAmE;IACnE,MAAM,SAAS,GAAG,QAAQ,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,QAAQ,CAAC,EAAE,aAAa,EAAE,GAAG,EAAE,CAAC,CAAC;IAErG,wCAAwC;IACxC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACtB,MAAM,EAAE,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;QACjF,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,sCAAsC;IACtC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAC9B,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAC7D,CAAC;IAEF,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAEtE,mEAAmE;IACnE,MAAM,MAAM,GAAG,yBAAyB,IAAI,gBAAgB,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,IAAI,CAAC;IACzF,IAAI,UAAU,GAAG,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC;IAE7C,8EAA8E;IAC9E,MAAM,WAAW,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACxF,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IAEnC,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,cAAc,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,GAAG,CAAC,CAAC;QACnG,IAAI,UAAU,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACjC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACxB,CAAC;aAAM,CAAC;YACN,UAAU,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,iBAAiB;QAClD,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAE7D,6CAA6C;IAC7C,MAAM,OAAO,GAAoC;QAC/C,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,KAAK,QAAQ,CAAC;QACzD,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,KAAK,OAAO,CAAC;QACvD,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,KAAK,WAAW,CAAC;QAC/D,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,KAAK,QAAQ,CAAC;KAC1D,CAAC;IAEF,SAAS,aAAa,CAAC,KAAa,EAAE,KAAsB;QAC1D,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QAClC,MAAM,KAAK,GAAG,KAAK;aAChB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU,IAAI,GAAG,CAAC,CAAC;aACrF,IAAI,CAAC,IAAI,CAAC,CAAC;QACd,OAAO,OAAO,KAAK,KAAK,KAAK,IAAI,CAAC;IACpC,CAAC;IAED,MAAM,QAAQ,GAAG;QACf,aAAa,CAAC,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC;QACtC,aAAa,CAAC,eAAe,EAAE,OAAO,CAAC,KAAK,CAAC;QAC7C,aAAa,CAAC,WAAW,EAAE,OAAO,CAAC,SAAS,CAAC;QAC7C,aAAa,CAAC,aAAa,EAAE,OAAO,CAAC,MAAM,CAAC;KAC7C;SACE,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,OAAO,GAAG,MAAM,KAAK,QAAQ,EAAE,CAAC,OAAO,EAAE,CAAC;AAC5C,CAAC"}
package/dist/read.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ import type { MskNode } from './schema.js';
2
+ export declare class MskReadError extends Error {
3
+ readonly filePath: string;
4
+ readonly validationErrors: string[];
5
+ readonly rawContent: string;
6
+ constructor(filePath: string, validationErrors: string[], rawContent: string);
7
+ }
8
+ export declare function readNode(filePath: string): Promise<MskNode>;
9
+ //# sourceMappingURL=read.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../src/read.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C,qBAAa,YAAa,SAAQ,KAAK;IACrC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;gBAEhB,QAAQ,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,MAAM;CAO7E;AAeD,wBAAsB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAsBjE"}
package/dist/read.js ADDED
@@ -0,0 +1,48 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import matter from 'gray-matter';
3
+ import { validate } from './validate.js';
4
+ export class MskReadError extends Error {
5
+ filePath;
6
+ validationErrors;
7
+ rawContent;
8
+ constructor(filePath, validationErrors, rawContent) {
9
+ super(`Invalid .msk.md at "${filePath}": ${validationErrors[0] ?? 'unknown error'}`);
10
+ this.name = 'MskReadError';
11
+ this.filePath = filePath;
12
+ this.validationErrors = validationErrors;
13
+ this.rawContent = rawContent;
14
+ }
15
+ }
16
+ // gray-matter uses js-yaml which auto-parses ISO 8601 strings to Date objects.
17
+ // We normalize the known datetime fields back to ISO strings so Zod validation passes.
18
+ function normalizeDateFields(data) {
19
+ const dateFields = ['created_at', 'last_updated_at', 'expires_at'];
20
+ const result = { ...data };
21
+ for (const field of dateFields) {
22
+ if (result[field] instanceof Date) {
23
+ result[field] = result[field].toISOString();
24
+ }
25
+ }
26
+ return result;
27
+ }
28
+ export async function readNode(filePath) {
29
+ let rawContent;
30
+ try {
31
+ rawContent = await readFile(filePath, 'utf-8');
32
+ }
33
+ catch (cause) {
34
+ throw new Error(`Cannot read file at "${filePath}"`, { cause });
35
+ }
36
+ const { data, content } = matter(rawContent);
37
+ const normalized = normalizeDateFields(data);
38
+ const candidate = {
39
+ ...normalized,
40
+ body: content.trim(),
41
+ };
42
+ const result = validate(candidate);
43
+ if (!result.valid) {
44
+ throw new MskReadError(filePath, result.errors, rawContent);
45
+ }
46
+ return candidate;
47
+ }
48
+ //# sourceMappingURL=read.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read.js","sourceRoot":"","sources":["../src/read.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAGzC,MAAM,OAAO,YAAa,SAAQ,KAAK;IAC5B,QAAQ,CAAS;IACjB,gBAAgB,CAAW;IAC3B,UAAU,CAAS;IAE5B,YAAY,QAAgB,EAAE,gBAA0B,EAAE,UAAkB;QAC1E,KAAK,CAAC,uBAAuB,QAAQ,MAAM,gBAAgB,CAAC,CAAC,CAAC,IAAI,eAAe,EAAE,CAAC,CAAC;QACrF,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;QAC3B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,gBAAgB,GAAG,gBAAgB,CAAC;QACzC,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;CACF;AAED,+EAA+E;AAC/E,uFAAuF;AACvF,SAAS,mBAAmB,CAAC,IAA6B;IACxD,MAAM,UAAU,GAAG,CAAC,YAAY,EAAE,iBAAiB,EAAE,YAAY,CAAU,CAAC;IAC5E,MAAM,MAAM,GAA4B,EAAE,GAAG,IAAI,EAAE,CAAC;IACpD,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;QAC/B,IAAI,MAAM,CAAC,KAAK,CAAC,YAAY,IAAI,EAAE,CAAC;YAClC,MAAM,CAAC,KAAK,CAAC,GAAI,MAAM,CAAC,KAAK,CAAU,CAAC,WAAW,EAAE,CAAC;QACxD,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,QAAgB;IAC7C,IAAI,UAAkB,CAAC;IACvB,IAAI,CAAC;QACH,UAAU,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACjD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,wBAAwB,QAAQ,GAAG,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;IAClE,CAAC;IAED,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;IAC7C,MAAM,UAAU,GAAG,mBAAmB,CAAC,IAA+B,CAAC,CAAC;IAExE,MAAM,SAAS,GAAG;QAChB,GAAG,UAAU;QACb,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE;KACrB,CAAC;IAEF,MAAM,MAAM,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;IACnC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAClB,MAAM,IAAI,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC9D,CAAC;IAED,OAAO,SAAoB,CAAC;AAC9B,CAAC"}
@@ -0,0 +1,61 @@
1
+ import { z } from 'zod';
2
+ export declare const MskLayerSchema: z.ZodEnum<["intent", "state", "knowledge", "issues"]>;
3
+ export declare const MskTypeSchema: z.ZodEnum<["goal", "task", "decision", "constraint", "issue", "fact"]>;
4
+ export declare const MskStatusSchema: z.ZodEnum<["active", "resolved", "deprecated", "draft"]>;
5
+ export declare const MskNodeSchema: z.ZodObject<{
6
+ id: z.ZodString;
7
+ type: z.ZodEnum<["goal", "task", "decision", "constraint", "issue", "fact"]>;
8
+ layer: z.ZodEnum<["intent", "state", "knowledge", "issues"]>;
9
+ status: z.ZodEnum<["active", "resolved", "deprecated", "draft"]>;
10
+ confidence: z.ZodNumber;
11
+ created_by: z.ZodString;
12
+ created_at: z.ZodString;
13
+ last_updated_by: z.ZodString;
14
+ last_updated_at: z.ZodString;
15
+ dependencies: z.ZodArray<z.ZodString, "many">;
16
+ contradictions: z.ZodArray<z.ZodString, "many">;
17
+ tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
18
+ scanned: z.ZodOptional<z.ZodBoolean>;
19
+ verified: z.ZodOptional<z.ZodBoolean>;
20
+ expires_at: z.ZodOptional<z.ZodString>;
21
+ body: z.ZodString;
22
+ }, "strip", z.ZodTypeAny, {
23
+ id: string;
24
+ type: "goal" | "task" | "decision" | "constraint" | "issue" | "fact";
25
+ layer: "intent" | "state" | "knowledge" | "issues";
26
+ status: "active" | "resolved" | "deprecated" | "draft";
27
+ confidence: number;
28
+ created_by: string;
29
+ created_at: string;
30
+ last_updated_by: string;
31
+ last_updated_at: string;
32
+ dependencies: string[];
33
+ contradictions: string[];
34
+ body: string;
35
+ tags?: string[] | undefined;
36
+ scanned?: boolean | undefined;
37
+ verified?: boolean | undefined;
38
+ expires_at?: string | undefined;
39
+ }, {
40
+ id: string;
41
+ type: "goal" | "task" | "decision" | "constraint" | "issue" | "fact";
42
+ layer: "intent" | "state" | "knowledge" | "issues";
43
+ status: "active" | "resolved" | "deprecated" | "draft";
44
+ confidence: number;
45
+ created_by: string;
46
+ created_at: string;
47
+ last_updated_by: string;
48
+ last_updated_at: string;
49
+ dependencies: string[];
50
+ contradictions: string[];
51
+ body: string;
52
+ tags?: string[] | undefined;
53
+ scanned?: boolean | undefined;
54
+ verified?: boolean | undefined;
55
+ expires_at?: string | undefined;
56
+ }>;
57
+ export type MskLayer = z.infer<typeof MskLayerSchema>;
58
+ export type MskType = z.infer<typeof MskTypeSchema>;
59
+ export type MskStatus = z.infer<typeof MskStatusSchema>;
60
+ export type MskNode = z.infer<typeof MskNodeSchema>;
61
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,eAAO,MAAM,cAAc,uDAAqD,CAAC;AAEjF,eAAO,MAAM,aAAa,wEAAsE,CAAC;AAEjG,eAAO,MAAM,eAAe,0DAAwD,CAAC;AAcrF,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyBxB,CAAC;AAEH,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AACtD,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AACpD,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AACxD,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC"}
package/dist/schema.js ADDED
@@ -0,0 +1,34 @@
1
+ import { z } from 'zod';
2
+ // Spec section 3.2 — YAML frontmatter enums
3
+ export const MskLayerSchema = z.enum(['intent', 'state', 'knowledge', 'issues']);
4
+ export const MskTypeSchema = z.enum(['goal', 'task', 'decision', 'constraint', 'issue', 'fact']);
5
+ export const MskStatusSchema = z.enum(['active', 'resolved', 'deprecated', 'draft']);
6
+ // ISO 8601 datetime — spec requires timestamps in created_at, last_updated_at, expires_at
7
+ const iso8601 = z.string().regex(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})$/, 'Must be an ISO 8601 datetime (e.g. 2026-05-12T00:00:00Z)');
8
+ // Spec section 3.1 — id must be kebab-case and unique within the project
9
+ const kebabCase = z.string().regex(/^[a-z0-9]+(-[a-z0-9]+)*$/, 'Must be kebab-case (lowercase letters, numbers, and hyphens only)');
10
+ export const MskNodeSchema = z.object({
11
+ // --- Required fields (spec section 3.2) ---
12
+ id: kebabCase,
13
+ type: MskTypeSchema,
14
+ layer: MskLayerSchema,
15
+ status: MskStatusSchema,
16
+ confidence: z.number().min(0, 'confidence must be >= 0.0').max(1, 'confidence must be <= 1.0'),
17
+ created_by: z.string().min(1, 'created_by must not be empty'),
18
+ created_at: iso8601,
19
+ last_updated_by: z.string().min(1, 'last_updated_by must not be empty'),
20
+ last_updated_at: iso8601,
21
+ dependencies: z.array(z.string()),
22
+ contradictions: z.array(z.string()),
23
+ // --- Optional fields (spec section 3.2) ---
24
+ tags: z.array(z.string()).optional(),
25
+ scanned: z.boolean().optional(),
26
+ verified: z.boolean().optional(),
27
+ expires_at: iso8601.optional(),
28
+ // --- Body content (spec section 3.3) ---
29
+ // The markdown body following the YAML frontmatter block.
30
+ // SPEC-GAP: spec says body MUST be valid markdown but does not define it as a named field.
31
+ // We model it as `body: string` on the node for uniform access after gray-matter parsing.
32
+ body: z.string(),
33
+ });
34
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,4CAA4C;AAE5C,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC;AAEjF,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;AAEjG,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,UAAU,EAAE,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC;AAErF,0FAA0F;AAC1F,MAAM,OAAO,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAC9B,kEAAkE,EAClE,0DAA0D,CAC3D,CAAC;AAEF,yEAAyE;AACzE,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAChC,0BAA0B,EAC1B,mEAAmE,CACpE,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC;IACpC,6CAA6C;IAC7C,EAAE,EAAE,SAAS;IACb,IAAI,EAAE,aAAa;IACnB,KAAK,EAAE,cAAc;IACrB,MAAM,EAAE,eAAe;IACvB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,2BAA2B,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,2BAA2B,CAAC;IAC9F,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,8BAA8B,CAAC;IAC7D,UAAU,EAAE,OAAO;IACnB,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,mCAAmC,CAAC;IACvE,eAAe,EAAE,OAAO;IACxB,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IACjC,cAAc,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAEnC,6CAA6C;IAC7C,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;IACpC,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAC/B,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAChC,UAAU,EAAE,OAAO,CAAC,QAAQ,EAAE;IAE9B,0CAA0C;IAC1C,0DAA0D;IAC1D,2FAA2F;IAC3F,0FAA0F;IAC1F,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;CACjB,CAAC,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type { MemoryMap, MemoryMapNode } from './graph.js';
2
+ export interface TraverseOptions {
3
+ depth?: number;
4
+ statusFilter?: string[];
5
+ minConfidence?: number;
6
+ }
7
+ export interface TraversalResult {
8
+ id: string;
9
+ node: MemoryMapNode;
10
+ depth: number;
11
+ }
12
+ export declare function traverse(map: MemoryMap, seedIds: string[], options?: TraverseOptions): TraversalResult[];
13
+ //# sourceMappingURL=traverse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"traverse.d.ts","sourceRoot":"","sources":["../src/traverse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAG3D,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,aAAa,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;CACf;AAGD,wBAAgB,QAAQ,CACtB,GAAG,EAAE,SAAS,EACd,OAAO,EAAE,MAAM,EAAE,EACjB,OAAO,GAAE,eAAoB,GAC5B,eAAe,EAAE,CAgCnB"}
@@ -0,0 +1,29 @@
1
+ // Spec section 5.3 — traverse the DAG from seedIds following dependency edges outward.
2
+ export function traverse(map, seedIds, options = {}) {
3
+ const { depth = 2, statusFilter = ['active'], minConfidence = 0.5, } = options;
4
+ const visited = new Set();
5
+ const results = [];
6
+ function visit(id, currentDepth) {
7
+ if (visited.has(id))
8
+ return;
9
+ if (currentDepth > depth)
10
+ return;
11
+ const node = map.nodes[id];
12
+ if (!node)
13
+ return;
14
+ if (!statusFilter.includes(node.status))
15
+ return;
16
+ if (node.confidence < minConfidence)
17
+ return;
18
+ visited.add(id);
19
+ results.push({ id, node, depth: currentDepth });
20
+ for (const depId of node.dependencies) {
21
+ visit(depId, currentDepth + 1);
22
+ }
23
+ }
24
+ for (const seedId of seedIds) {
25
+ visit(seedId, 0);
26
+ }
27
+ return results;
28
+ }
29
+ //# sourceMappingURL=traverse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"traverse.js","sourceRoot":"","sources":["../src/traverse.ts"],"names":[],"mappings":"AAeA,uFAAuF;AACvF,MAAM,UAAU,QAAQ,CACtB,GAAc,EACd,OAAiB,EACjB,UAA2B,EAAE;IAE7B,MAAM,EACJ,KAAK,GAAG,CAAC,EACT,YAAY,GAAG,CAAC,QAAQ,CAAC,EACzB,aAAa,GAAG,GAAG,GACpB,GAAG,OAAO,CAAC;IAEZ,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,MAAM,OAAO,GAAsB,EAAE,CAAC;IAEtC,SAAS,KAAK,CAAC,EAAU,EAAE,YAAoB;QAC7C,IAAI,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,OAAO;QAC5B,IAAI,YAAY,GAAG,KAAK;YAAE,OAAO;QAEjC,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC3B,IAAI,CAAC,IAAI;YAAE,OAAO;QAClB,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC;YAAE,OAAO;QAChD,IAAI,IAAI,CAAC,UAAU,GAAG,aAAa;YAAE,OAAO;QAE5C,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC,CAAC;QAEhD,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACtC,KAAK,CAAC,KAAK,EAAE,YAAY,GAAG,CAAC,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;IAED,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IACnB,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,5 @@
1
+ export declare function validate(node: unknown): {
2
+ valid: boolean;
3
+ errors: string[];
4
+ };
5
+ //# sourceMappingURL=validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AAEA,wBAAgB,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAS5E"}
@@ -0,0 +1,10 @@
1
+ import { MskNodeSchema } from './schema.js';
2
+ export function validate(node) {
3
+ const result = MskNodeSchema.safeParse(node);
4
+ if (result.success) {
5
+ return { valid: true, errors: [] };
6
+ }
7
+ const errors = result.error.errors.map((e) => `${e.path.join('.') || '(root)'}: ${e.message}`);
8
+ return { valid: false, errors };
9
+ }
10
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,UAAU,QAAQ,CAAC,IAAa;IACpC,MAAM,MAAM,GAAG,aAAa,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAC7C,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IACrC,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CACpC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,QAAQ,KAAK,CAAC,CAAC,OAAO,EAAE,CACvD,CAAC;IACF,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;AAClC,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { MskNode } from './schema.js';
2
+ export declare class MskWriteError extends Error {
3
+ readonly filePath: string;
4
+ readonly validationErrors: string[];
5
+ constructor(filePath: string, validationErrors: string[]);
6
+ }
7
+ export declare function writeNode(filePath: string, node: MskNode): Promise<void>;
8
+ export declare function updateNodeMeta(filePath: string, updates: Partial<Omit<MskNode, 'id' | 'body'>>): Promise<void>;
9
+ //# sourceMappingURL=write.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../src/write.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C,qBAAa,aAAc,SAAQ,KAAK;IACtC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,EAAE,CAAC;gBAExB,QAAQ,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE;CAMzD;AAuBD,wBAAsB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAwC9E;AAKD,wBAAsB,cAAc,CAClC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,GAAG,MAAM,CAAC,CAAC,GAC7C,OAAO,CAAC,IAAI,CAAC,CAcf"}
package/dist/write.js ADDED
@@ -0,0 +1,90 @@
1
+ import { writeFile, mkdir, readFile, access } from 'node:fs/promises';
2
+ import { dirname } from 'node:path';
3
+ import matter from 'gray-matter';
4
+ import { validate } from './validate.js';
5
+ import { readNode } from './read.js';
6
+ export class MskWriteError extends Error {
7
+ filePath;
8
+ validationErrors;
9
+ constructor(filePath, validationErrors) {
10
+ super(`Cannot write invalid node to "${filePath}": ${validationErrors.join('; ')}`);
11
+ this.name = 'MskWriteError';
12
+ this.filePath = filePath;
13
+ this.validationErrors = validationErrors;
14
+ }
15
+ }
16
+ async function fileExists(filePath) {
17
+ try {
18
+ await access(filePath);
19
+ return true;
20
+ }
21
+ catch {
22
+ return false;
23
+ }
24
+ }
25
+ // Remove undefined-valued keys so they don't appear as `null` in YAML output.
26
+ // SPEC-GAP: spec does not define how optional fields with no value should be serialized.
27
+ function stripUndefined(obj) {
28
+ return Object.fromEntries(Object.entries(obj).filter(([, v]) => v !== undefined));
29
+ }
30
+ function serialize(node) {
31
+ const { body, ...rest } = node;
32
+ const frontmatter = stripUndefined(rest);
33
+ return matter.stringify(body, frontmatter);
34
+ }
35
+ export async function writeNode(filePath, node) {
36
+ const result = validate(node);
37
+ if (!result.valid) {
38
+ throw new MskWriteError(filePath, result.errors);
39
+ }
40
+ // Spec section 7.1: always update last_updated_at before writing.
41
+ const updatedNode = {
42
+ ...node,
43
+ last_updated_at: new Date().toISOString(),
44
+ };
45
+ await mkdir(dirname(filePath), { recursive: true });
46
+ let content;
47
+ if (node.layer === 'state') {
48
+ // Spec section 7.2: state layer writes MUST be append-only.
49
+ const appendHeader = `### ${updatedNode.last_updated_at} — ${updatedNode.last_updated_by}`;
50
+ if (await fileExists(filePath)) {
51
+ const raw = await readFile(filePath, 'utf-8');
52
+ const existingBody = matter(raw).content.trim();
53
+ const newBody = `${existingBody}\n\n${appendHeader}\n\n${updatedNode.body.trim()}`;
54
+ content = serialize({ ...updatedNode, body: newBody });
55
+ }
56
+ else {
57
+ // First write to a state node: still wrap in the append header format.
58
+ const newBody = `${appendHeader}\n\n${updatedNode.body.trim()}`;
59
+ content = serialize({ ...updatedNode, body: newBody });
60
+ }
61
+ }
62
+ else {
63
+ // intent, knowledge: replace body content.
64
+ // SPEC-GAP: spec section 4.3 says knowledge writes MUST "preserve the full frontmatter history"
65
+ // but does not define the file format for this. We replace body and update frontmatter fields only.
66
+ // SPEC-GAP: spec section 4.4 says issue nodes must be append-only (never deleted) but does not
67
+ // explicitly require append-only body content the way section 7.2 does for state. Treating as replace.
68
+ content = serialize(updatedNode);
69
+ }
70
+ await writeFile(filePath, content, 'utf-8');
71
+ }
72
+ // SPEC-GAP: spec does not define a metadata-only update path. This is needed by the
73
+ // CLI `update` command to change status/confidence without triggering state-layer append.
74
+ // Reads the existing file, applies frontmatter-only updates, preserves body exactly.
75
+ export async function updateNodeMeta(filePath, updates) {
76
+ const existing = await readNode(filePath);
77
+ const updated = {
78
+ ...existing,
79
+ ...updates,
80
+ id: existing.id,
81
+ body: existing.body,
82
+ last_updated_at: new Date().toISOString(),
83
+ };
84
+ const result = validate(updated);
85
+ if (!result.valid) {
86
+ throw new MskWriteError(filePath, result.errors);
87
+ }
88
+ await writeFile(filePath, serialize(updated), 'utf-8');
89
+ }
90
+ //# sourceMappingURL=write.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write.js","sourceRoot":"","sources":["../src/write.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@mastishk/core",
3
+ "version": "0.1.0",
4
+ "description": "Core schema, validation, read, write, graph, and inject for the Mastishk protocol.",
5
+ "license": "Apache-2.0",
6
+ "author": "Mastishk Protocol Contributors",
7
+ "homepage": "https://mastishk.dev",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/mastishk-ai/mastishk.git",
11
+ "directory": "src/packages/core"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/mastishk-ai/mastishk/issues"
15
+ },
16
+ "keywords": [
17
+ "ai", "agent", "memory", "mcp", "claude", "cursor", "llm",
18
+ "markdown", "dag", "protocol", "mastishk"
19
+ ],
20
+ "type": "module",
21
+ "main": "./dist/index.js",
22
+ "types": "./dist/index.d.ts",
23
+ "exports": {
24
+ ".": {
25
+ "import": "./dist/index.js",
26
+ "types": "./dist/index.d.ts"
27
+ }
28
+ },
29
+ "files": [
30
+ "dist",
31
+ "README.md"
32
+ ],
33
+ "scripts": {
34
+ "build": "tsc",
35
+ "typecheck": "tsc --noEmit"
36
+ },
37
+ "dependencies": {
38
+ "gray-matter": "^4.0.3",
39
+ "zod": "^3.23.8"
40
+ },
41
+ "engines": {
42
+ "node": ">=18.0.0"
43
+ }
44
+ }