@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 +70 -0
- package/dist/graph.d.ts +36 -0
- package/dist/graph.d.ts.map +1 -0
- package/dist/graph.js +116 -0
- package/dist/graph.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/inject.d.ts +2 -0
- package/dist/inject.d.ts.map +1 -0
- package/dist/inject.js +108 -0
- package/dist/inject.js.map +1 -0
- package/dist/read.d.ts +9 -0
- package/dist/read.d.ts.map +1 -0
- package/dist/read.js +48 -0
- package/dist/read.js.map +1 -0
- package/dist/schema.d.ts +61 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +34 -0
- package/dist/schema.js.map +1 -0
- package/dist/traverse.d.ts +13 -0
- package/dist/traverse.d.ts.map +1 -0
- package/dist/traverse.js +29 -0
- package/dist/traverse.js.map +1 -0
- package/dist/validate.d.ts +5 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +10 -0
- package/dist/validate.js.map +1 -0
- package/dist/write.d.ts +9 -0
- package/dist/write.d.ts.map +1 -0
- package/dist/write.js +90 -0
- package/dist/write.js.map +1 -0
- package/package.json +44 -0
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
|
package/dist/graph.d.ts
ADDED
|
@@ -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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"}
|
package/dist/index.d.ts
ADDED
|
@@ -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"}
|
package/dist/inject.d.ts
ADDED
|
@@ -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":"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"}
|
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
|
package/dist/read.js.map
ADDED
|
@@ -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"}
|
package/dist/schema.d.ts
ADDED
|
@@ -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"}
|
package/dist/traverse.js
ADDED
|
@@ -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 @@
|
|
|
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"}
|
package/dist/validate.js
ADDED
|
@@ -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"}
|
package/dist/write.d.ts
ADDED
|
@@ -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
|
+
}
|