@yandy0725/pi-memory 1.4.0 → 2.0.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/src/topic-file.ts DELETED
@@ -1,119 +0,0 @@
1
- export interface TopicMeta {
2
- name: string;
3
- description: string;
4
- type: string;
5
- updated: string;
6
- }
7
-
8
- export const ALLOWED_TYPES = ["user", "feedback", "project", "reference"] as const;
9
-
10
- export function buildFrontmatter(meta: TopicMeta): string {
11
- return [
12
- "---",
13
- `name: ${meta.name}`,
14
- `description: ${meta.description}`,
15
- `type: ${meta.type}`,
16
- `updated: ${meta.updated}`,
17
- "---",
18
- "",
19
- "",
20
- ].join("\n");
21
- }
22
-
23
- export function parseFrontmatter(raw: string): TopicMeta | null {
24
- if (!raw.startsWith("---\n")) return null;
25
- const endIdx = raw.indexOf("\n---\n", 4);
26
- if (endIdx === -1) return null;
27
- const block = raw.slice(4, endIdx);
28
- const meta: Record<string, string> = {};
29
- for (const line of block.split("\n")) {
30
- const m = line.match(/^(\w+):\s*(.*)$/);
31
- if (m) meta[m[1]] = m[2].trim();
32
- }
33
- if (!meta.name || !meta.description || !meta.type || !meta.updated) return null;
34
- if (!(ALLOWED_TYPES as readonly string[]).includes(meta.type)) return null;
35
- return meta as unknown as TopicMeta;
36
- }
37
-
38
- export function appendContent(existing: string | null, entryTitle: string, content: string): string {
39
- const section = `## ${entryTitle}\n\n${content}`;
40
- if (!existing || existing.trim() === "") return section;
41
- return `${existing.trimEnd()}\n\n${section}\n`;
42
- }
43
-
44
- export function updateFrontmatterDate(raw: string, date: string): string {
45
- return raw.replace(/^(---\n(?:.*\n)*?)updated: .+(\n---)/m, `$1updated: ${date}$2`);
46
- }
47
-
48
- export function replaceFrontmatterField(raw: string, field: string, value: string): string {
49
- const regex = new RegExp(`^(---\n(?:.*\n)*?)${field}: .+(\n)`, "m");
50
- return raw.replace(regex, (_full: string, prefix: string, nl: string) => `${prefix}${field}: ${value}${nl}`);
51
- }
52
-
53
- export function removeEntrySection(raw: string, title: string): string {
54
- const marker = `## ${title}`;
55
- // find start of this entry block
56
- const startIdx = raw.indexOf(`\n${marker}\n`) !== -1 ? raw.indexOf(`\n${marker}\n`) : raw.indexOf(marker);
57
- if (startIdx === -1) throw new Error(`Entry "${title}" not found`);
58
-
59
- // find start of next ## or EOF
60
- const afterHeader = raw.indexOf("\n", startIdx + marker.length);
61
- const nextH2 = raw.indexOf("\n## ", afterHeader + 1);
62
- const endIdx = nextH2 === -1 ? raw.length : nextH2;
63
-
64
- // remove including preceding blank lines
65
- let cutStart = startIdx;
66
- while (cutStart > 0 && raw[cutStart - 1] === "\n") cutStart--;
67
- // also strip one more \n if present (the blank line separator)
68
- if (cutStart > 0 && raw[cutStart - 1] === "\n") cutStart--;
69
-
70
- let result = raw.slice(0, cutStart) + raw.slice(endIdx);
71
- // ensure exactly one trailing newline
72
- result = result.replace(/\n{3,}$/, "\n\n").replace(/\n{2,}$/, "\n");
73
- if (!result.endsWith("\n")) result += "\n";
74
- return result;
75
- }
76
-
77
- export function hasEntries(raw: string): boolean {
78
- return /^## /m.test(raw);
79
- }
80
-
81
- export interface ParsedEntry {
82
- title: string;
83
- content: string;
84
- }
85
-
86
- export function parseEntries(raw: string): ParsedEntry[] {
87
- const entries: ParsedEntry[] = [];
88
- const lines = raw.split("\n");
89
- let currentTitle = "";
90
- let currentContent: string[] = [];
91
- let inEntry = false;
92
- let inFrontmatter = false;
93
-
94
- for (const line of lines) {
95
- if (line === "---") {
96
- inFrontmatter = !inFrontmatter;
97
- continue;
98
- }
99
- if (inFrontmatter) continue;
100
-
101
- const h2 = line.match(/^## (.+)$/);
102
- if (h2) {
103
- if (inEntry) {
104
- entries.push({ title: currentTitle, content: currentContent.join("\n").trim() });
105
- }
106
- currentTitle = h2[1];
107
- currentContent = [];
108
- inEntry = true;
109
- continue;
110
- }
111
- if (inEntry) {
112
- currentContent.push(line);
113
- }
114
- }
115
- if (inEntry) {
116
- entries.push({ title: currentTitle, content: currentContent.join("\n").trim() });
117
- }
118
- return entries;
119
- }