@staix/vault-mem 0.0.0-stage → 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/CHANGELOG.md +12 -0
- package/LICENSE +21 -0
- package/README.md +251 -2
- package/bin/vmem.js +12 -0
- package/package.json +39 -4
- package/src/amem/seam.ts +56 -0
- package/src/analysis-commands.ts +36 -0
- package/src/analysis-input.ts +82 -0
- package/src/analysis-reports.ts +69 -0
- package/src/analysis-types.ts +19 -0
- package/src/analysis-yaml.ts +178 -0
- package/src/cli.ts +101 -0
- package/src/commands-table.ts +88 -0
- package/src/config.ts +99 -0
- package/src/frontmatter.ts +154 -0
- package/src/home.ts +16 -0
- package/src/index.ts +44 -0
- package/src/links.ts +149 -0
- package/src/log-commands.ts +31 -0
- package/src/log-filter.ts +65 -0
- package/src/log-format.ts +57 -0
- package/src/log-types.ts +10 -0
- package/src/mcp-vault.ts +167 -0
- package/src/mcp.ts +110 -0
- package/src/org-commands.ts +31 -0
- package/src/org-promote.ts +259 -0
- package/src/platform.ts +1 -0
- package/src/promote-command.ts +77 -0
- package/src/promote.ts +167 -0
- package/src/read-commands.ts +43 -0
- package/src/registry.ts +170 -0
- package/src/setup.ts +214 -0
- package/src/source.ts +47 -0
- package/src/sync.ts +145 -0
- package/src/tidy.ts +386 -0
- package/src/vault-graph.ts +233 -0
- package/src/vault-index.ts +369 -0
- package/src/vault-lint.ts +135 -0
- package/src/vault-log.ts +229 -0
- package/src/write-commands.ts +93 -0
- package/src/write-operations.ts +181 -0
- package/src/write-types.ts +50 -0
- package/src/write-validation.ts +285 -0
- package/src/writer.ts +259 -0
- package/src/yaml-quoted.ts +141 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
|
|
3
|
+
const SHORT_ESCAPES: Record<string,string> = {
|
|
4
|
+
"0":"\0",a:"\x07",b:"\b",t:"\t","\t":"\t",n:"\n",v:"\v",f:"\f",r:"\r",e:"\x1b",
|
|
5
|
+
" ":" ",'"':'"',"/":"/","\\":"\\",N:"
",_:" ",L:"
",P:"
",
|
|
6
|
+
};
|
|
7
|
+
function lineBreak(source:string,offset:number):{value:string;end:number}|null {
|
|
8
|
+
const character=source[offset];
|
|
9
|
+
if(character === "\r")return {value:"\n",end:offset+(source[offset+1] === "\n" ? 2 : 1)};
|
|
10
|
+
if(character === "\n" || character === "
")return {value:"\n",end:offset+1};
|
|
11
|
+
if(character === "
" || character === "
")return {value:character,end:offset+1};
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
function continuation(source:string,offset:number):{breaks:string;end:number} {
|
|
15
|
+
let breaks="";
|
|
16
|
+
for(;;) {
|
|
17
|
+
while(source[offset] === " " || source[offset] === "\t")offset++;
|
|
18
|
+
const next=lineBreak(source,offset);
|
|
19
|
+
if(!next)return {breaks,end:offset};
|
|
20
|
+
breaks+=next.value;offset=next.end;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/** Decode one YAML double-quoted scalar, including YAML's line folding and escaped continuations. */
|
|
24
|
+
function doubleQuoted(source:string,start:number):{value:string;end:number} {
|
|
25
|
+
let value="",offset=start+1;
|
|
26
|
+
while(offset<source.length) {
|
|
27
|
+
const character=source[offset]!;
|
|
28
|
+
if(character === '"')return {value,end:offset+1};
|
|
29
|
+
if(character === "\\") {
|
|
30
|
+
const escape=source[++offset];
|
|
31
|
+
if(escape === undefined)throw new Error("YAML: incomplete quoted escape");
|
|
32
|
+
if(Object.hasOwn(SHORT_ESCAPES,escape)) {value+=SHORT_ESCAPES[escape]!;offset++;continue;}
|
|
33
|
+
const digits=escape === "x" ? 2 : escape === "u" ? 4 : escape === "U" ? 8 : 0;
|
|
34
|
+
if(digits) {
|
|
35
|
+
const hex=source.slice(offset+1,offset+digits+1);
|
|
36
|
+
if(hex.length!==digits || !/^[0-9a-fA-F]+$/.test(hex))throw new Error("YAML: invalid quoted Unicode escape");
|
|
37
|
+
const scalar=Number.parseInt(hex,16);
|
|
38
|
+
if(scalar>0x10ffff)throw new Error("YAML: quoted Unicode escape outside range");
|
|
39
|
+
value+=String.fromCodePoint(scalar);offset+=digits+1;continue;
|
|
40
|
+
}
|
|
41
|
+
const escapedBreak=lineBreak(source,offset);
|
|
42
|
+
if(escapedBreak) {const next=continuation(source,escapedBreak.end);value+=next.breaks;offset=next.end;continue;}
|
|
43
|
+
throw new Error("YAML: unknown quoted escape");
|
|
44
|
+
}
|
|
45
|
+
if(character === " " || character === "\t") {
|
|
46
|
+
const first=offset;
|
|
47
|
+
while(source[offset] === " " || source[offset] === "\t")offset++;
|
|
48
|
+
if(!lineBreak(source,offset))value+=source.slice(first,offset);
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
const nextBreak=lineBreak(source,offset);
|
|
52
|
+
if(nextBreak) {
|
|
53
|
+
const next=continuation(source,nextBreak.end);
|
|
54
|
+
value+=nextBreak.value!=="\n" ? nextBreak.value+next.breaks : next.breaks || " ";
|
|
55
|
+
offset=next.end;continue;
|
|
56
|
+
}
|
|
57
|
+
// These raw characters are not YAML-printable; explicitly escaped controls above remain valid.
|
|
58
|
+
const code=character.charCodeAt(0),next=source.charCodeAt(offset+1),previous=source.charCodeAt(offset-1);
|
|
59
|
+
if(code<32 || (code>=127 && code<=159) || code===65534 || code===65535
|
|
60
|
+
|| (code>=55296 && code<=56319 && !(next>=56320 && next<=57343))
|
|
61
|
+
|| (code>=56320 && code<=57343 && !(previous>=55296 && previous<=56319)))throw new Error("YAML: non-printable quoted character");
|
|
62
|
+
value+=character;offset++;
|
|
63
|
+
}
|
|
64
|
+
throw new Error("YAML: unterminated quoted scalar");
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Parse structural YAML with Bun, replacing only double-quoted scalar nodes in its semantic input.
|
|
69
|
+
* Original source and byte offsets remain the caller's property. Opaque scalars also avoid asking
|
|
70
|
+
* older Bun YAML versions to parse decoded control characters or unsupported Unicode escapes.
|
|
71
|
+
*/
|
|
72
|
+
export function parseYamlWithQuotedEscapes(source:string):unknown {
|
|
73
|
+
const prefix=`vmem-quoted-${randomUUID()}-`,values=new Map<string,string>();
|
|
74
|
+
const replacements:{start:number;end:number;token:string}[]=[];
|
|
75
|
+
let offset=0,lineStart=0,flow=0,nodeStart=true,blockIndent:number|null=null;
|
|
76
|
+
let effectiveIndent=0,mappingOnLine=false,plain=false,plainIndent=0;
|
|
77
|
+
while(offset<source.length) {
|
|
78
|
+
if(offset===lineStart) {
|
|
79
|
+
const end=source.indexOf("\n",offset),line=source.slice(offset,end===-1 ? undefined : end),indent=line.match(/^[ \t]*/)![0].length;
|
|
80
|
+
if(blockIndent!==null && (!line.trim() || indent>blockIndent)) {offset=end===-1 ? source.length : end+1;lineStart=offset;continue;}
|
|
81
|
+
blockIndent=null;effectiveIndent=indent;mappingOnLine=false;
|
|
82
|
+
if(!flow && line.trim() && indent<=plainIndent)plain=false;
|
|
83
|
+
nodeStart=!plain;
|
|
84
|
+
}
|
|
85
|
+
const character=source[offset]!;
|
|
86
|
+
if(character === "\n") {offset++;lineStart=offset;continue;}
|
|
87
|
+
if(/[ \t\r]/.test(character)) {offset++;continue;}
|
|
88
|
+
if(character === "#" && (offset===lineStart || /\s/.test(source[offset-1]!))) {
|
|
89
|
+
const end=source.indexOf("\n",offset);offset=end===-1 ? source.length : end;plain=false;continue;
|
|
90
|
+
}
|
|
91
|
+
if(nodeStart && character === '"') {
|
|
92
|
+
const decoded=doubleQuoted(source,offset),token=prefix+values.size;
|
|
93
|
+
values.set(token,decoded.value);replacements.push({start:offset,end:decoded.end,token:JSON.stringify(token)});
|
|
94
|
+
offset=decoded.end;lineStart=source.lastIndexOf("\n",offset-1)+1;nodeStart=false;plain=false;continue;
|
|
95
|
+
}
|
|
96
|
+
if(nodeStart && character === "'") {
|
|
97
|
+
offset++;
|
|
98
|
+
while(offset<source.length) {
|
|
99
|
+
if(source[offset++]!=="'")continue;
|
|
100
|
+
if(source[offset] === "'") {offset++;continue;}
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
lineStart=source.lastIndexOf("\n",offset-1)+1;nodeStart=false;plain=false;continue;
|
|
104
|
+
}
|
|
105
|
+
if(nodeStart && !flow && (character === "|" || character === ">") && /^[|>](?:[+-][1-9]?|[1-9][+-]?)?[ \t]*(?:#[^\r\n]*)?\r?(?:\n|$)/.test(source.slice(offset))) {
|
|
106
|
+
blockIndent=mappingOnLine ? effectiveIndent : lineStart===offset ? 0 : source.slice(lineStart).match(/^[ \t]*/)![0].length;
|
|
107
|
+
const end=source.indexOf("\n",offset);offset=end===-1 ? source.length : end;plain=false;continue;
|
|
108
|
+
}
|
|
109
|
+
if(nodeStart && (character === "&" || character === "!")) {
|
|
110
|
+
const prefix=/^[&!][^\s,[\]{}]*/.exec(source.slice(offset))![0];offset+=prefix.length;continue;
|
|
111
|
+
}
|
|
112
|
+
if(nodeStart && (character === "[" || character === "{")) {flow++;offset++;nodeStart=true;plain=false;continue;}
|
|
113
|
+
if(flow && (character === "]" || character === "}")) {flow--;offset++;nodeStart=false;plain=false;continue;}
|
|
114
|
+
if(flow && character === ",") {offset++;nodeStart=true;plain=false;continue;}
|
|
115
|
+
if(character === ":" && (!plain || /[\s,[\]{}]/.test(source[offset+1] ?? "\n"))) {
|
|
116
|
+
if(!flow)mappingOnLine=true;offset++;nodeStart=true;plain=false;continue;
|
|
117
|
+
}
|
|
118
|
+
if(nodeStart && character === "-" && /\s/.test(source[offset+1] ?? "\n")) {offset++;effectiveIndent=offset-lineStart+1;continue;}
|
|
119
|
+
if(nodeStart && character === "?" && /\s/.test(source[offset+1] ?? "\n")) {offset++;continue;}
|
|
120
|
+
if(!plain)plainIndent=effectiveIndent;
|
|
121
|
+
nodeStart=false;plain=true;offset++;
|
|
122
|
+
}
|
|
123
|
+
let normalized="",copied=0;
|
|
124
|
+
for(const replacement of replacements) {normalized+=source.slice(copied,replacement.start)+replacement.token;copied=replacement.end;}
|
|
125
|
+
normalized+=source.slice(copied);
|
|
126
|
+
const parsed:unknown=Bun.YAML.parse(normalized),seen=new WeakMap<object,unknown>();
|
|
127
|
+
function restore(value:unknown):unknown {
|
|
128
|
+
if(typeof value === "string")return values.get(value) ?? value;
|
|
129
|
+
if(value===null || typeof value!=="object")return value;
|
|
130
|
+
const previous=seen.get(value);if(previous!==undefined)return previous;
|
|
131
|
+
if(Array.isArray(value)) {const array:unknown[]=[];seen.set(value,array);for(const item of value)array.push(restore(item));return array;}
|
|
132
|
+
const result:Record<string,unknown>=Object.create(Object.getPrototypeOf(value)) as Record<string,unknown>;seen.set(value,result);
|
|
133
|
+
for(const [key,item] of Object.entries(value)) {
|
|
134
|
+
const decoded=values.get(key) ?? key;
|
|
135
|
+
if(Object.hasOwn(result,decoded))throw new Error("YAML: duplicate decoded mapping key");
|
|
136
|
+
Object.defineProperty(result,decoded,{value:restore(item),enumerable:true,writable:true,configurable:true});
|
|
137
|
+
}
|
|
138
|
+
return result;
|
|
139
|
+
}
|
|
140
|
+
return restore(parsed);
|
|
141
|
+
}
|