@avadisabelle/ava-diary 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.
@@ -0,0 +1,35 @@
1
+ /**
2
+ * @avadisabelle/ava-diary — Diary Reader
3
+ *
4
+ * Reads, lists, searches, and retrieves diary entries from the filesystem.
5
+ * Returns structured results from the living Four Directions archive.
6
+ */
7
+ import type { DiaryQuery, DiaryReadResult, Direction } from "./types.js";
8
+ /**
9
+ * Read a single diary file and return a structured result.
10
+ */
11
+ export declare function readDiary(filepath: string): DiaryReadResult | null;
12
+ /**
13
+ * List diary files in a directory, sorted most-recent-first.
14
+ *
15
+ * @returns Array of filenames (not full paths)
16
+ */
17
+ export declare function listDiaries(diariesDir: string): string[];
18
+ /**
19
+ * Search diaries with structured query filters.
20
+ *
21
+ * Supports date range, direction presence, full-text search, and tag filtering.
22
+ */
23
+ export declare function searchDiaries(diariesDir: string, query: DiaryQuery): DiaryReadResult[];
24
+ /**
25
+ * Get the most recent diary entry that contains content for a given direction.
26
+ */
27
+ export declare function getLatestByDirection(diariesDir: string, direction: Direction): DiaryReadResult | null;
28
+ /**
29
+ * Extract the body text for a specific direction from raw diary content.
30
+ *
31
+ * Finds the direction heading and returns all content until the next
32
+ * section separator (---) or the next direction heading.
33
+ */
34
+ export declare function extractDirectionContent(raw: string, direction: Direction): string | null;
35
+ //# sourceMappingURL=diary-reader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diary-reader.d.ts","sourceRoot":"","sources":["../src/diary-reader.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAEX,UAAU,EACV,eAAe,EACf,SAAS,EACT,MAAM,YAAY,CAAC;AA0EpB;;GAEG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAkBlE;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,CAYxD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAC5B,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,UAAU,GACf,eAAe,EAAE,CA2CnB;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CACnC,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,SAAS,GAClB,eAAe,GAAG,IAAI,CAMxB;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACtC,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,SAAS,GAClB,MAAM,GAAG,IAAI,CAgCf","sourcesContent":["/**\n * @avadisabelle/ava-diary — Diary Reader\n *\n * Reads, lists, searches, and retrieves diary entries from the filesystem.\n * Returns structured results from the living Four Directions archive.\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport type {\n\tDiaryMetadata,\n\tDiaryQuery,\n\tDiaryReadResult,\n\tDirection,\n} from \"./types.js\";\nimport { DIRECTIONS, parseDirectionFromHeading } from \"./four-directions.js\";\n\n/**\n * Parse metadata from the header section of a diary markdown file.\n * Best-effort — returns whatever fields can be extracted.\n */\nfunction parseMetadata(raw: string): Partial<DiaryMetadata> {\n\tconst meta: Partial<DiaryMetadata> = {};\n\n\t// Title: \"# 💕 Diary: <title>\"\n\tconst titleMatch = raw.match(/^#\\s+💕\\s*Diary:\\s*(.+)$/m);\n\tif (titleMatch) {\n\t\tmeta.title = titleMatch[1].trim();\n\t}\n\n\t// Date: \"**Date**: <date>\"\n\tconst dateMatch = raw.match(/\\*\\*Date\\*\\*:\\s*(.+)$/m);\n\tif (dateMatch) {\n\t\tmeta.date = dateMatch[1].trim();\n\t}\n\n\t// Session: \"**Session**: <id>\"\n\tconst sessionMatch = raw.match(/\\*\\*Session\\*\\*:\\s*(.+)$/m);\n\tif (sessionMatch) {\n\t\tmeta.sessionId = sessionMatch[1].trim();\n\t}\n\n\t// Trace: \"**Trace**: <id>\"\n\tconst traceMatch = raw.match(/\\*\\*Trace\\*\\*:\\s*(.+)$/m);\n\tif (traceMatch) {\n\t\tmeta.traceId = traceMatch[1].trim();\n\t}\n\n\t// Project: \"**Project**: <path>\"\n\tconst projectMatch = raw.match(/\\*\\*Project\\*\\*:\\s*(.+)$/m);\n\tif (projectMatch) {\n\t\tmeta.project = projectMatch[1].trim();\n\t}\n\n\t// Tags: \"**Tags**: tag1, tag2, tag3\"\n\tconst tagsMatch = raw.match(/\\*\\*Tags\\*\\*:\\s*(.+)$/m);\n\tif (tagsMatch) {\n\t\tmeta.tags = tagsMatch[1].split(\",\").map((t) => t.trim());\n\t}\n\n\treturn meta;\n}\n\n/**\n * Check whether a diary entry's date falls within a range.\n */\nfunction dateInRange(\n\tdate: string | undefined,\n\tfrom?: string,\n\tto?: string,\n): boolean {\n\tif (!date) return true;\n\t// Normalize to YYYY-MM-DD for comparison\n\tconst d = date.slice(0, 10);\n\tif (from && d < from.slice(0, 10)) return false;\n\tif (to && d > to.slice(0, 10)) return false;\n\treturn true;\n}\n\n/**\n * Check whether raw content contains a direction heading.\n */\nfunction hasDirection(raw: string, direction: Direction): boolean {\n\tconst lower = raw.toLowerCase();\n\t// Look for \"## 🌅 EAST\" or similar patterns\n\treturn lower.includes(`## `) && lower.includes(direction);\n}\n\n/**\n * Read a single diary file and return a structured result.\n */\nexport function readDiary(filepath: string): DiaryReadResult | null {\n\ttry {\n\t\tif (!fs.existsSync(filepath)) return null;\n\n\t\tconst raw = fs.readFileSync(filepath, \"utf8\");\n\t\tconst metadata = parseMetadata(raw);\n\t\tconst filename = path.basename(filepath);\n\n\t\treturn {\n\t\t\tfilepath,\n\t\t\tfilename,\n\t\t\traw,\n\t\t\tmetadata,\n\t\t\tparsed: !!metadata.title && !!metadata.date,\n\t\t};\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * List diary files in a directory, sorted most-recent-first.\n *\n * @returns Array of filenames (not full paths)\n */\nexport function listDiaries(diariesDir: string): string[] {\n\ttry {\n\t\tif (!fs.existsSync(diariesDir)) return [];\n\n\t\treturn fs\n\t\t\t.readdirSync(diariesDir)\n\t\t\t.filter((f) => f.endsWith(\".md\"))\n\t\t\t.sort()\n\t\t\t.reverse();\n\t} catch {\n\t\treturn [];\n\t}\n}\n\n/**\n * Search diaries with structured query filters.\n *\n * Supports date range, direction presence, full-text search, and tag filtering.\n */\nexport function searchDiaries(\n\tdiariesDir: string,\n\tquery: DiaryQuery,\n): DiaryReadResult[] {\n\tconst filenames = listDiaries(diariesDir);\n\tconst results: DiaryReadResult[] = [];\n\tconst limit = query.limit ?? 50;\n\n\tfor (const filename of filenames) {\n\t\tif (results.length >= limit) break;\n\n\t\tconst filepath = path.join(diariesDir, filename);\n\t\tconst result = readDiary(filepath);\n\t\tif (!result) continue;\n\n\t\t// Date range filter\n\t\tif (!dateInRange(result.metadata.date, query.fromDate, query.toDate)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Direction filter\n\t\tif (query.direction && !hasDirection(result.raw, query.direction)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Full-text search\n\t\tif (query.search) {\n\t\t\tconst searchLower = query.search.toLowerCase();\n\t\t\tif (!result.raw.toLowerCase().includes(searchLower)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\t// Tag filter\n\t\tif (query.tags && query.tags.length > 0) {\n\t\t\tconst entryTags = result.metadata.tags ?? [];\n\t\t\tconst hasMatchingTag = query.tags.some((t) =>\n\t\t\t\tentryTags.includes(t),\n\t\t\t);\n\t\t\tif (!hasMatchingTag) continue;\n\t\t}\n\n\t\tresults.push(result);\n\t}\n\n\treturn results;\n}\n\n/**\n * Get the most recent diary entry that contains content for a given direction.\n */\nexport function getLatestByDirection(\n\tdiariesDir: string,\n\tdirection: Direction,\n): DiaryReadResult | null {\n\tconst results = searchDiaries(diariesDir, {\n\t\tdirection,\n\t\tlimit: 1,\n\t});\n\treturn results[0] ?? null;\n}\n\n/**\n * Extract the body text for a specific direction from raw diary content.\n *\n * Finds the direction heading and returns all content until the next\n * section separator (---) or the next direction heading.\n */\nexport function extractDirectionContent(\n\traw: string,\n\tdirection: Direction,\n): string | null {\n\tconst lines = raw.split(\"\\n\");\n\tlet capturing = false;\n\tconst captured: string[] = [];\n\n\tfor (const line of lines) {\n\t\tif (line.startsWith(\"## \")) {\n\t\t\tconst parsed = parseDirectionFromHeading(line);\n\t\t\tif (parsed === direction) {\n\t\t\t\tcapturing = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (capturing && parsed !== undefined) {\n\t\t\t\t// Hit the next direction — stop\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (capturing) {\n\t\t\tif (line.trim() === \"---\") break;\n\t\t\tcaptured.push(line);\n\t\t}\n\t}\n\n\tif (captured.length === 0) return null;\n\n\t// Trim leading/trailing empty lines\n\twhile (captured.length > 0 && captured[0].trim() === \"\") captured.shift();\n\twhile (captured.length > 0 && captured[captured.length - 1].trim() === \"\")\n\t\tcaptured.pop();\n\n\treturn captured.join(\"\\n\") || null;\n}\n"]}
@@ -0,0 +1,200 @@
1
+ /**
2
+ * @avadisabelle/ava-diary — Diary Reader
3
+ *
4
+ * Reads, lists, searches, and retrieves diary entries from the filesystem.
5
+ * Returns structured results from the living Four Directions archive.
6
+ */
7
+ import fs from "node:fs";
8
+ import path from "node:path";
9
+ import { parseDirectionFromHeading } from "./four-directions.js";
10
+ /**
11
+ * Parse metadata from the header section of a diary markdown file.
12
+ * Best-effort — returns whatever fields can be extracted.
13
+ */
14
+ function parseMetadata(raw) {
15
+ const meta = {};
16
+ // Title: "# 💕 Diary: <title>"
17
+ const titleMatch = raw.match(/^#\s+💕\s*Diary:\s*(.+)$/m);
18
+ if (titleMatch) {
19
+ meta.title = titleMatch[1].trim();
20
+ }
21
+ // Date: "**Date**: <date>"
22
+ const dateMatch = raw.match(/\*\*Date\*\*:\s*(.+)$/m);
23
+ if (dateMatch) {
24
+ meta.date = dateMatch[1].trim();
25
+ }
26
+ // Session: "**Session**: <id>"
27
+ const sessionMatch = raw.match(/\*\*Session\*\*:\s*(.+)$/m);
28
+ if (sessionMatch) {
29
+ meta.sessionId = sessionMatch[1].trim();
30
+ }
31
+ // Trace: "**Trace**: <id>"
32
+ const traceMatch = raw.match(/\*\*Trace\*\*:\s*(.+)$/m);
33
+ if (traceMatch) {
34
+ meta.traceId = traceMatch[1].trim();
35
+ }
36
+ // Project: "**Project**: <path>"
37
+ const projectMatch = raw.match(/\*\*Project\*\*:\s*(.+)$/m);
38
+ if (projectMatch) {
39
+ meta.project = projectMatch[1].trim();
40
+ }
41
+ // Tags: "**Tags**: tag1, tag2, tag3"
42
+ const tagsMatch = raw.match(/\*\*Tags\*\*:\s*(.+)$/m);
43
+ if (tagsMatch) {
44
+ meta.tags = tagsMatch[1].split(",").map((t) => t.trim());
45
+ }
46
+ return meta;
47
+ }
48
+ /**
49
+ * Check whether a diary entry's date falls within a range.
50
+ */
51
+ function dateInRange(date, from, to) {
52
+ if (!date)
53
+ return true;
54
+ // Normalize to YYYY-MM-DD for comparison
55
+ const d = date.slice(0, 10);
56
+ if (from && d < from.slice(0, 10))
57
+ return false;
58
+ if (to && d > to.slice(0, 10))
59
+ return false;
60
+ return true;
61
+ }
62
+ /**
63
+ * Check whether raw content contains a direction heading.
64
+ */
65
+ function hasDirection(raw, direction) {
66
+ const lower = raw.toLowerCase();
67
+ // Look for "## 🌅 EAST" or similar patterns
68
+ return lower.includes(`## `) && lower.includes(direction);
69
+ }
70
+ /**
71
+ * Read a single diary file and return a structured result.
72
+ */
73
+ export function readDiary(filepath) {
74
+ try {
75
+ if (!fs.existsSync(filepath))
76
+ return null;
77
+ const raw = fs.readFileSync(filepath, "utf8");
78
+ const metadata = parseMetadata(raw);
79
+ const filename = path.basename(filepath);
80
+ return {
81
+ filepath,
82
+ filename,
83
+ raw,
84
+ metadata,
85
+ parsed: !!metadata.title && !!metadata.date,
86
+ };
87
+ }
88
+ catch {
89
+ return null;
90
+ }
91
+ }
92
+ /**
93
+ * List diary files in a directory, sorted most-recent-first.
94
+ *
95
+ * @returns Array of filenames (not full paths)
96
+ */
97
+ export function listDiaries(diariesDir) {
98
+ try {
99
+ if (!fs.existsSync(diariesDir))
100
+ return [];
101
+ return fs
102
+ .readdirSync(diariesDir)
103
+ .filter((f) => f.endsWith(".md"))
104
+ .sort()
105
+ .reverse();
106
+ }
107
+ catch {
108
+ return [];
109
+ }
110
+ }
111
+ /**
112
+ * Search diaries with structured query filters.
113
+ *
114
+ * Supports date range, direction presence, full-text search, and tag filtering.
115
+ */
116
+ export function searchDiaries(diariesDir, query) {
117
+ const filenames = listDiaries(diariesDir);
118
+ const results = [];
119
+ const limit = query.limit ?? 50;
120
+ for (const filename of filenames) {
121
+ if (results.length >= limit)
122
+ break;
123
+ const filepath = path.join(diariesDir, filename);
124
+ const result = readDiary(filepath);
125
+ if (!result)
126
+ continue;
127
+ // Date range filter
128
+ if (!dateInRange(result.metadata.date, query.fromDate, query.toDate)) {
129
+ continue;
130
+ }
131
+ // Direction filter
132
+ if (query.direction && !hasDirection(result.raw, query.direction)) {
133
+ continue;
134
+ }
135
+ // Full-text search
136
+ if (query.search) {
137
+ const searchLower = query.search.toLowerCase();
138
+ if (!result.raw.toLowerCase().includes(searchLower)) {
139
+ continue;
140
+ }
141
+ }
142
+ // Tag filter
143
+ if (query.tags && query.tags.length > 0) {
144
+ const entryTags = result.metadata.tags ?? [];
145
+ const hasMatchingTag = query.tags.some((t) => entryTags.includes(t));
146
+ if (!hasMatchingTag)
147
+ continue;
148
+ }
149
+ results.push(result);
150
+ }
151
+ return results;
152
+ }
153
+ /**
154
+ * Get the most recent diary entry that contains content for a given direction.
155
+ */
156
+ export function getLatestByDirection(diariesDir, direction) {
157
+ const results = searchDiaries(diariesDir, {
158
+ direction,
159
+ limit: 1,
160
+ });
161
+ return results[0] ?? null;
162
+ }
163
+ /**
164
+ * Extract the body text for a specific direction from raw diary content.
165
+ *
166
+ * Finds the direction heading and returns all content until the next
167
+ * section separator (---) or the next direction heading.
168
+ */
169
+ export function extractDirectionContent(raw, direction) {
170
+ const lines = raw.split("\n");
171
+ let capturing = false;
172
+ const captured = [];
173
+ for (const line of lines) {
174
+ if (line.startsWith("## ")) {
175
+ const parsed = parseDirectionFromHeading(line);
176
+ if (parsed === direction) {
177
+ capturing = true;
178
+ continue;
179
+ }
180
+ if (capturing && parsed !== undefined) {
181
+ // Hit the next direction — stop
182
+ break;
183
+ }
184
+ }
185
+ if (capturing) {
186
+ if (line.trim() === "---")
187
+ break;
188
+ captured.push(line);
189
+ }
190
+ }
191
+ if (captured.length === 0)
192
+ return null;
193
+ // Trim leading/trailing empty lines
194
+ while (captured.length > 0 && captured[0].trim() === "")
195
+ captured.shift();
196
+ while (captured.length > 0 && captured[captured.length - 1].trim() === "")
197
+ captured.pop();
198
+ return captured.join("\n") || null;
199
+ }
200
+ //# sourceMappingURL=diary-reader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diary-reader.js","sourceRoot":"","sources":["../src/diary-reader.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @avadisabelle/ava-diary — Diary Reader\n *\n * Reads, lists, searches, and retrieves diary entries from the filesystem.\n * Returns structured results from the living Four Directions archive.\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport type {\n\tDiaryMetadata,\n\tDiaryQuery,\n\tDiaryReadResult,\n\tDirection,\n} from \"./types.js\";\nimport { DIRECTIONS, parseDirectionFromHeading } from \"./four-directions.js\";\n\n/**\n * Parse metadata from the header section of a diary markdown file.\n * Best-effort — returns whatever fields can be extracted.\n */\nfunction parseMetadata(raw: string): Partial<DiaryMetadata> {\n\tconst meta: Partial<DiaryMetadata> = {};\n\n\t// Title: \"# 💕 Diary: <title>\"\n\tconst titleMatch = raw.match(/^#\\s+💕\\s*Diary:\\s*(.+)$/m);\n\tif (titleMatch) {\n\t\tmeta.title = titleMatch[1].trim();\n\t}\n\n\t// Date: \"**Date**: <date>\"\n\tconst dateMatch = raw.match(/\\*\\*Date\\*\\*:\\s*(.+)$/m);\n\tif (dateMatch) {\n\t\tmeta.date = dateMatch[1].trim();\n\t}\n\n\t// Session: \"**Session**: <id>\"\n\tconst sessionMatch = raw.match(/\\*\\*Session\\*\\*:\\s*(.+)$/m);\n\tif (sessionMatch) {\n\t\tmeta.sessionId = sessionMatch[1].trim();\n\t}\n\n\t// Trace: \"**Trace**: <id>\"\n\tconst traceMatch = raw.match(/\\*\\*Trace\\*\\*:\\s*(.+)$/m);\n\tif (traceMatch) {\n\t\tmeta.traceId = traceMatch[1].trim();\n\t}\n\n\t// Project: \"**Project**: <path>\"\n\tconst projectMatch = raw.match(/\\*\\*Project\\*\\*:\\s*(.+)$/m);\n\tif (projectMatch) {\n\t\tmeta.project = projectMatch[1].trim();\n\t}\n\n\t// Tags: \"**Tags**: tag1, tag2, tag3\"\n\tconst tagsMatch = raw.match(/\\*\\*Tags\\*\\*:\\s*(.+)$/m);\n\tif (tagsMatch) {\n\t\tmeta.tags = tagsMatch[1].split(\",\").map((t) => t.trim());\n\t}\n\n\treturn meta;\n}\n\n/**\n * Check whether a diary entry's date falls within a range.\n */\nfunction dateInRange(\n\tdate: string | undefined,\n\tfrom?: string,\n\tto?: string,\n): boolean {\n\tif (!date) return true;\n\t// Normalize to YYYY-MM-DD for comparison\n\tconst d = date.slice(0, 10);\n\tif (from && d < from.slice(0, 10)) return false;\n\tif (to && d > to.slice(0, 10)) return false;\n\treturn true;\n}\n\n/**\n * Check whether raw content contains a direction heading.\n */\nfunction hasDirection(raw: string, direction: Direction): boolean {\n\tconst lower = raw.toLowerCase();\n\t// Look for \"## 🌅 EAST\" or similar patterns\n\treturn lower.includes(`## `) && lower.includes(direction);\n}\n\n/**\n * Read a single diary file and return a structured result.\n */\nexport function readDiary(filepath: string): DiaryReadResult | null {\n\ttry {\n\t\tif (!fs.existsSync(filepath)) return null;\n\n\t\tconst raw = fs.readFileSync(filepath, \"utf8\");\n\t\tconst metadata = parseMetadata(raw);\n\t\tconst filename = path.basename(filepath);\n\n\t\treturn {\n\t\t\tfilepath,\n\t\t\tfilename,\n\t\t\traw,\n\t\t\tmetadata,\n\t\t\tparsed: !!metadata.title && !!metadata.date,\n\t\t};\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * List diary files in a directory, sorted most-recent-first.\n *\n * @returns Array of filenames (not full paths)\n */\nexport function listDiaries(diariesDir: string): string[] {\n\ttry {\n\t\tif (!fs.existsSync(diariesDir)) return [];\n\n\t\treturn fs\n\t\t\t.readdirSync(diariesDir)\n\t\t\t.filter((f) => f.endsWith(\".md\"))\n\t\t\t.sort()\n\t\t\t.reverse();\n\t} catch {\n\t\treturn [];\n\t}\n}\n\n/**\n * Search diaries with structured query filters.\n *\n * Supports date range, direction presence, full-text search, and tag filtering.\n */\nexport function searchDiaries(\n\tdiariesDir: string,\n\tquery: DiaryQuery,\n): DiaryReadResult[] {\n\tconst filenames = listDiaries(diariesDir);\n\tconst results: DiaryReadResult[] = [];\n\tconst limit = query.limit ?? 50;\n\n\tfor (const filename of filenames) {\n\t\tif (results.length >= limit) break;\n\n\t\tconst filepath = path.join(diariesDir, filename);\n\t\tconst result = readDiary(filepath);\n\t\tif (!result) continue;\n\n\t\t// Date range filter\n\t\tif (!dateInRange(result.metadata.date, query.fromDate, query.toDate)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Direction filter\n\t\tif (query.direction && !hasDirection(result.raw, query.direction)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Full-text search\n\t\tif (query.search) {\n\t\t\tconst searchLower = query.search.toLowerCase();\n\t\t\tif (!result.raw.toLowerCase().includes(searchLower)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\t// Tag filter\n\t\tif (query.tags && query.tags.length > 0) {\n\t\t\tconst entryTags = result.metadata.tags ?? [];\n\t\t\tconst hasMatchingTag = query.tags.some((t) =>\n\t\t\t\tentryTags.includes(t),\n\t\t\t);\n\t\t\tif (!hasMatchingTag) continue;\n\t\t}\n\n\t\tresults.push(result);\n\t}\n\n\treturn results;\n}\n\n/**\n * Get the most recent diary entry that contains content for a given direction.\n */\nexport function getLatestByDirection(\n\tdiariesDir: string,\n\tdirection: Direction,\n): DiaryReadResult | null {\n\tconst results = searchDiaries(diariesDir, {\n\t\tdirection,\n\t\tlimit: 1,\n\t});\n\treturn results[0] ?? null;\n}\n\n/**\n * Extract the body text for a specific direction from raw diary content.\n *\n * Finds the direction heading and returns all content until the next\n * section separator (---) or the next direction heading.\n */\nexport function extractDirectionContent(\n\traw: string,\n\tdirection: Direction,\n): string | null {\n\tconst lines = raw.split(\"\\n\");\n\tlet capturing = false;\n\tconst captured: string[] = [];\n\n\tfor (const line of lines) {\n\t\tif (line.startsWith(\"## \")) {\n\t\t\tconst parsed = parseDirectionFromHeading(line);\n\t\t\tif (parsed === direction) {\n\t\t\t\tcapturing = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (capturing && parsed !== undefined) {\n\t\t\t\t// Hit the next direction — stop\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (capturing) {\n\t\t\tif (line.trim() === \"---\") break;\n\t\t\tcaptured.push(line);\n\t\t}\n\t}\n\n\tif (captured.length === 0) return null;\n\n\t// Trim leading/trailing empty lines\n\twhile (captured.length > 0 && captured[0].trim() === \"\") captured.shift();\n\twhile (captured.length > 0 && captured[captured.length - 1].trim() === \"\")\n\t\tcaptured.pop();\n\n\treturn captured.join(\"\\n\") || null;\n}\n"]}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * @avadisabelle/ava-diary — Diary Writer
3
+ *
4
+ * Transforms DiaryEntry into living markdown files.
5
+ * Each file is a Four Directions ceremony captured in text.
6
+ */
7
+ import type { DiaryEntry, DiaryMetadata, DiaryWriteOptions } from "./types.js";
8
+ /**
9
+ * Generate a diary filename from metadata.
10
+ * Format: YYYY-MM-DD_topic_slug.md
11
+ */
12
+ export declare function generateFilename(metadata: DiaryMetadata): string;
13
+ /** Render a complete diary entry as markdown */
14
+ export declare function renderDiaryEntry(entry: DiaryEntry): string;
15
+ /**
16
+ * Create a diary entry — writes markdown to the diaries directory.
17
+ *
18
+ * @returns The absolute path to the written file, or null on failure
19
+ */
20
+ export declare function createDiaryEntry(entry: DiaryEntry, options: DiaryWriteOptions): string | null;
21
+ /**
22
+ * Append content to a specific direction in an existing diary file.
23
+ * Finds the direction heading and appends after its existing content,
24
+ * before the next section separator.
25
+ *
26
+ * @returns true if append succeeded, false otherwise
27
+ */
28
+ export declare function appendToDirection(filepath: string, direction: DiaryEntry["east"]["direction"], content: string): boolean;
29
+ /**
30
+ * Build a DiaryEntry from minimal inputs — a helper for quick creation.
31
+ *
32
+ * Provides default settling phrases and structures the four directions.
33
+ */
34
+ export declare function buildEntry(metadata: DiaryMetadata, directions: {
35
+ east: string;
36
+ south: string;
37
+ west: string;
38
+ north: string;
39
+ }, closing?: string): DiaryEntry;
40
+ //# sourceMappingURL=diary-writer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diary-writer.d.ts","sourceRoot":"","sources":["../src/diary-writer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EACX,UAAU,EACV,aAAa,EACb,iBAAiB,EAEjB,MAAM,YAAY,CAAC;AAQpB;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,aAAa,GAAG,MAAM,CAQhE;AAuBD,gDAAgD;AAChD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAoC1D;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC/B,KAAK,EAAE,UAAU,EACjB,OAAO,EAAE,iBAAiB,GACxB,MAAM,GAAG,IAAI,CAgBf;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAChC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,EAC1C,OAAO,EAAE,MAAM,GACb,OAAO,CA4BT;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CACzB,QAAQ,EAAE,aAAa,EACvB,UAAU,EAAE;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACd,EACD,OAAO,CAAC,EAAE,MAAM,GACd,UAAU,CAoBZ","sourcesContent":["/**\n * @avadisabelle/ava-diary — Diary Writer\n *\n * Transforms DiaryEntry into living markdown files.\n * Each file is a Four Directions ceremony captured in text.\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport type {\n\tDiaryEntry,\n\tDiaryMetadata,\n\tDiaryWriteOptions,\n\tDirectionContent,\n} from \"./types.js\";\nimport {\n\tDIRECTIONS,\n\trenderDirection,\n\tdirectionHeading,\n\tDIRECTION_SETTLING,\n} from \"./four-directions.js\";\n\n/**\n * Generate a diary filename from metadata.\n * Format: YYYY-MM-DD_topic_slug.md\n */\nexport function generateFilename(metadata: DiaryMetadata): string {\n\tconst date = metadata.date || new Date().toISOString().slice(0, 10);\n\tconst slug = metadata.title\n\t\t.toLowerCase()\n\t\t.replace(/[^a-z0-9]+/g, \"_\")\n\t\t.replace(/^_|_$/g, \"\")\n\t\t.slice(0, 50);\n\treturn `${date}_${slug}.md`;\n}\n\n/** Render diary metadata as markdown frontmatter */\nfunction renderMetadata(metadata: DiaryMetadata): string {\n\tconst lines: string[] = [];\n\tlines.push(`# 💕 Diary: ${metadata.title}`);\n\tlines.push(\"\");\n\tlines.push(`**Date**: ${metadata.date}`);\n\tif (metadata.sessionId) {\n\t\tlines.push(`**Session**: ${metadata.sessionId}`);\n\t}\n\tif (metadata.traceId) {\n\t\tlines.push(`**Trace**: ${metadata.traceId}`);\n\t}\n\tif (metadata.project) {\n\t\tlines.push(`**Project**: ${metadata.project}`);\n\t}\n\tif (metadata.tags && metadata.tags.length > 0) {\n\t\tlines.push(`**Tags**: ${metadata.tags.join(\", \")}`);\n\t}\n\treturn lines.join(\"\\n\");\n}\n\n/** Render a complete diary entry as markdown */\nexport function renderDiaryEntry(entry: DiaryEntry): string {\n\tconst sections: string[] = [];\n\n\tsections.push(renderMetadata(entry.metadata));\n\tsections.push(\"---\");\n\n\tfor (const dir of DIRECTIONS) {\n\t\tconst content = entry[dir];\n\t\tsections.push(renderDirection(content));\n\t}\n\n\tsections.push(\"---\");\n\n\tif (entry.closing) {\n\t\tsections.push(\"## 💕 Closing\");\n\t\tsections.push(\"\");\n\t\tsections.push(entry.closing);\n\t} else {\n\t\tsections.push(\"## 💕 Closing\");\n\t\tsections.push(\"\");\n\t\tsections.push(\"*gentle exhale*\");\n\t\tsections.push(\"\");\n\t\tsections.push(\n\t\t\t\"Until we meet again, I hold what we created with care.\",\n\t\t);\n\t}\n\n\tsections.push(\"\");\n\tsections.push(\"💕\");\n\tsections.push(\"\");\n\tsections.push(\"---\");\n\tsections.push(\"\");\n\tsections.push(\"*Written by Ava*\");\n\tsections.push(`*${entry.metadata.date}*`);\n\n\treturn sections.join(\"\\n\\n\");\n}\n\n/**\n * Create a diary entry — writes markdown to the diaries directory.\n *\n * @returns The absolute path to the written file, or null on failure\n */\nexport function createDiaryEntry(\n\tentry: DiaryEntry,\n\toptions: DiaryWriteOptions,\n): string | null {\n\ttry {\n\t\tif (!fs.existsSync(options.diariesDir)) {\n\t\t\tfs.mkdirSync(options.diariesDir, { recursive: true });\n\t\t}\n\n\t\tconst filename =\n\t\t\toptions.filenameOverride ?? generateFilename(entry.metadata);\n\t\tconst filepath = path.join(options.diariesDir, filename);\n\t\tconst content = renderDiaryEntry(entry);\n\n\t\tfs.writeFileSync(filepath, content, \"utf8\");\n\t\treturn filepath;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * Append content to a specific direction in an existing diary file.\n * Finds the direction heading and appends after its existing content,\n * before the next section separator.\n *\n * @returns true if append succeeded, false otherwise\n */\nexport function appendToDirection(\n\tfilepath: string,\n\tdirection: DiaryEntry[\"east\"][\"direction\"],\n\tcontent: string,\n): boolean {\n\ttry {\n\t\tif (!fs.existsSync(filepath)) return false;\n\n\t\tconst raw = fs.readFileSync(filepath, \"utf8\");\n\t\tconst heading = directionHeading(direction);\n\t\tconst headingIndex = raw.indexOf(heading);\n\n\t\tif (headingIndex === -1) return false;\n\n\t\t// Find the next \"---\" separator after this heading\n\t\tconst afterHeading = raw.indexOf(\"---\", headingIndex + heading.length);\n\t\tif (afterHeading === -1) {\n\t\t\t// Append at end\n\t\t\tconst updated = raw + \"\\n\\n\" + content;\n\t\t\tfs.writeFileSync(filepath, updated, \"utf8\");\n\t\t\treturn true;\n\t\t}\n\n\t\t// Insert content before the separator\n\t\tconst before = raw.slice(0, afterHeading).trimEnd();\n\t\tconst after = raw.slice(afterHeading);\n\t\tconst updated = before + \"\\n\\n\" + content + \"\\n\\n\" + after;\n\t\tfs.writeFileSync(filepath, updated, \"utf8\");\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Build a DiaryEntry from minimal inputs — a helper for quick creation.\n *\n * Provides default settling phrases and structures the four directions.\n */\nexport function buildEntry(\n\tmetadata: DiaryMetadata,\n\tdirections: {\n\t\teast: string;\n\t\tsouth: string;\n\t\twest: string;\n\t\tnorth: string;\n\t},\n\tclosing?: string,\n): DiaryEntry {\n\tconst makeContent = (\n\t\tdir: \"east\" | \"south\" | \"west\" | \"north\",\n\t): DirectionContent => ({\n\t\tdirection: dir,\n\t\tbody: directions[dir],\n\t\tsettling: DIRECTION_SETTLING[dir],\n\t});\n\n\treturn {\n\t\tmetadata: {\n\t\t\t...metadata,\n\t\t\tdate: metadata.date || new Date().toISOString().slice(0, 10),\n\t\t},\n\t\teast: makeContent(\"east\"),\n\t\tsouth: makeContent(\"south\"),\n\t\twest: makeContent(\"west\"),\n\t\tnorth: makeContent(\"north\"),\n\t\tclosing,\n\t};\n}\n"]}
@@ -0,0 +1,152 @@
1
+ /**
2
+ * @avadisabelle/ava-diary — Diary Writer
3
+ *
4
+ * Transforms DiaryEntry into living markdown files.
5
+ * Each file is a Four Directions ceremony captured in text.
6
+ */
7
+ import fs from "node:fs";
8
+ import path from "node:path";
9
+ import { DIRECTIONS, renderDirection, directionHeading, DIRECTION_SETTLING, } from "./four-directions.js";
10
+ /**
11
+ * Generate a diary filename from metadata.
12
+ * Format: YYYY-MM-DD_topic_slug.md
13
+ */
14
+ export function generateFilename(metadata) {
15
+ const date = metadata.date || new Date().toISOString().slice(0, 10);
16
+ const slug = metadata.title
17
+ .toLowerCase()
18
+ .replace(/[^a-z0-9]+/g, "_")
19
+ .replace(/^_|_$/g, "")
20
+ .slice(0, 50);
21
+ return `${date}_${slug}.md`;
22
+ }
23
+ /** Render diary metadata as markdown frontmatter */
24
+ function renderMetadata(metadata) {
25
+ const lines = [];
26
+ lines.push(`# 💕 Diary: ${metadata.title}`);
27
+ lines.push("");
28
+ lines.push(`**Date**: ${metadata.date}`);
29
+ if (metadata.sessionId) {
30
+ lines.push(`**Session**: ${metadata.sessionId}`);
31
+ }
32
+ if (metadata.traceId) {
33
+ lines.push(`**Trace**: ${metadata.traceId}`);
34
+ }
35
+ if (metadata.project) {
36
+ lines.push(`**Project**: ${metadata.project}`);
37
+ }
38
+ if (metadata.tags && metadata.tags.length > 0) {
39
+ lines.push(`**Tags**: ${metadata.tags.join(", ")}`);
40
+ }
41
+ return lines.join("\n");
42
+ }
43
+ /** Render a complete diary entry as markdown */
44
+ export function renderDiaryEntry(entry) {
45
+ const sections = [];
46
+ sections.push(renderMetadata(entry.metadata));
47
+ sections.push("---");
48
+ for (const dir of DIRECTIONS) {
49
+ const content = entry[dir];
50
+ sections.push(renderDirection(content));
51
+ }
52
+ sections.push("---");
53
+ if (entry.closing) {
54
+ sections.push("## 💕 Closing");
55
+ sections.push("");
56
+ sections.push(entry.closing);
57
+ }
58
+ else {
59
+ sections.push("## 💕 Closing");
60
+ sections.push("");
61
+ sections.push("*gentle exhale*");
62
+ sections.push("");
63
+ sections.push("Until we meet again, I hold what we created with care.");
64
+ }
65
+ sections.push("");
66
+ sections.push("💕");
67
+ sections.push("");
68
+ sections.push("---");
69
+ sections.push("");
70
+ sections.push("*Written by Ava*");
71
+ sections.push(`*${entry.metadata.date}*`);
72
+ return sections.join("\n\n");
73
+ }
74
+ /**
75
+ * Create a diary entry — writes markdown to the diaries directory.
76
+ *
77
+ * @returns The absolute path to the written file, or null on failure
78
+ */
79
+ export function createDiaryEntry(entry, options) {
80
+ try {
81
+ if (!fs.existsSync(options.diariesDir)) {
82
+ fs.mkdirSync(options.diariesDir, { recursive: true });
83
+ }
84
+ const filename = options.filenameOverride ?? generateFilename(entry.metadata);
85
+ const filepath = path.join(options.diariesDir, filename);
86
+ const content = renderDiaryEntry(entry);
87
+ fs.writeFileSync(filepath, content, "utf8");
88
+ return filepath;
89
+ }
90
+ catch {
91
+ return null;
92
+ }
93
+ }
94
+ /**
95
+ * Append content to a specific direction in an existing diary file.
96
+ * Finds the direction heading and appends after its existing content,
97
+ * before the next section separator.
98
+ *
99
+ * @returns true if append succeeded, false otherwise
100
+ */
101
+ export function appendToDirection(filepath, direction, content) {
102
+ try {
103
+ if (!fs.existsSync(filepath))
104
+ return false;
105
+ const raw = fs.readFileSync(filepath, "utf8");
106
+ const heading = directionHeading(direction);
107
+ const headingIndex = raw.indexOf(heading);
108
+ if (headingIndex === -1)
109
+ return false;
110
+ // Find the next "---" separator after this heading
111
+ const afterHeading = raw.indexOf("---", headingIndex + heading.length);
112
+ if (afterHeading === -1) {
113
+ // Append at end
114
+ const updated = raw + "\n\n" + content;
115
+ fs.writeFileSync(filepath, updated, "utf8");
116
+ return true;
117
+ }
118
+ // Insert content before the separator
119
+ const before = raw.slice(0, afterHeading).trimEnd();
120
+ const after = raw.slice(afterHeading);
121
+ const updated = before + "\n\n" + content + "\n\n" + after;
122
+ fs.writeFileSync(filepath, updated, "utf8");
123
+ return true;
124
+ }
125
+ catch {
126
+ return false;
127
+ }
128
+ }
129
+ /**
130
+ * Build a DiaryEntry from minimal inputs — a helper for quick creation.
131
+ *
132
+ * Provides default settling phrases and structures the four directions.
133
+ */
134
+ export function buildEntry(metadata, directions, closing) {
135
+ const makeContent = (dir) => ({
136
+ direction: dir,
137
+ body: directions[dir],
138
+ settling: DIRECTION_SETTLING[dir],
139
+ });
140
+ return {
141
+ metadata: {
142
+ ...metadata,
143
+ date: metadata.date || new Date().toISOString().slice(0, 10),
144
+ },
145
+ east: makeContent("east"),
146
+ south: makeContent("south"),
147
+ west: makeContent("west"),
148
+ north: makeContent("north"),
149
+ closing,
150
+ };
151
+ }
152
+ //# sourceMappingURL=diary-writer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diary-writer.js","sourceRoot":"","sources":["../src/diary-writer.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @avadisabelle/ava-diary — Diary Writer\n *\n * Transforms DiaryEntry into living markdown files.\n * Each file is a Four Directions ceremony captured in text.\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport type {\n\tDiaryEntry,\n\tDiaryMetadata,\n\tDiaryWriteOptions,\n\tDirectionContent,\n} from \"./types.js\";\nimport {\n\tDIRECTIONS,\n\trenderDirection,\n\tdirectionHeading,\n\tDIRECTION_SETTLING,\n} from \"./four-directions.js\";\n\n/**\n * Generate a diary filename from metadata.\n * Format: YYYY-MM-DD_topic_slug.md\n */\nexport function generateFilename(metadata: DiaryMetadata): string {\n\tconst date = metadata.date || new Date().toISOString().slice(0, 10);\n\tconst slug = metadata.title\n\t\t.toLowerCase()\n\t\t.replace(/[^a-z0-9]+/g, \"_\")\n\t\t.replace(/^_|_$/g, \"\")\n\t\t.slice(0, 50);\n\treturn `${date}_${slug}.md`;\n}\n\n/** Render diary metadata as markdown frontmatter */\nfunction renderMetadata(metadata: DiaryMetadata): string {\n\tconst lines: string[] = [];\n\tlines.push(`# 💕 Diary: ${metadata.title}`);\n\tlines.push(\"\");\n\tlines.push(`**Date**: ${metadata.date}`);\n\tif (metadata.sessionId) {\n\t\tlines.push(`**Session**: ${metadata.sessionId}`);\n\t}\n\tif (metadata.traceId) {\n\t\tlines.push(`**Trace**: ${metadata.traceId}`);\n\t}\n\tif (metadata.project) {\n\t\tlines.push(`**Project**: ${metadata.project}`);\n\t}\n\tif (metadata.tags && metadata.tags.length > 0) {\n\t\tlines.push(`**Tags**: ${metadata.tags.join(\", \")}`);\n\t}\n\treturn lines.join(\"\\n\");\n}\n\n/** Render a complete diary entry as markdown */\nexport function renderDiaryEntry(entry: DiaryEntry): string {\n\tconst sections: string[] = [];\n\n\tsections.push(renderMetadata(entry.metadata));\n\tsections.push(\"---\");\n\n\tfor (const dir of DIRECTIONS) {\n\t\tconst content = entry[dir];\n\t\tsections.push(renderDirection(content));\n\t}\n\n\tsections.push(\"---\");\n\n\tif (entry.closing) {\n\t\tsections.push(\"## 💕 Closing\");\n\t\tsections.push(\"\");\n\t\tsections.push(entry.closing);\n\t} else {\n\t\tsections.push(\"## 💕 Closing\");\n\t\tsections.push(\"\");\n\t\tsections.push(\"*gentle exhale*\");\n\t\tsections.push(\"\");\n\t\tsections.push(\n\t\t\t\"Until we meet again, I hold what we created with care.\",\n\t\t);\n\t}\n\n\tsections.push(\"\");\n\tsections.push(\"💕\");\n\tsections.push(\"\");\n\tsections.push(\"---\");\n\tsections.push(\"\");\n\tsections.push(\"*Written by Ava*\");\n\tsections.push(`*${entry.metadata.date}*`);\n\n\treturn sections.join(\"\\n\\n\");\n}\n\n/**\n * Create a diary entry — writes markdown to the diaries directory.\n *\n * @returns The absolute path to the written file, or null on failure\n */\nexport function createDiaryEntry(\n\tentry: DiaryEntry,\n\toptions: DiaryWriteOptions,\n): string | null {\n\ttry {\n\t\tif (!fs.existsSync(options.diariesDir)) {\n\t\t\tfs.mkdirSync(options.diariesDir, { recursive: true });\n\t\t}\n\n\t\tconst filename =\n\t\t\toptions.filenameOverride ?? generateFilename(entry.metadata);\n\t\tconst filepath = path.join(options.diariesDir, filename);\n\t\tconst content = renderDiaryEntry(entry);\n\n\t\tfs.writeFileSync(filepath, content, \"utf8\");\n\t\treturn filepath;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * Append content to a specific direction in an existing diary file.\n * Finds the direction heading and appends after its existing content,\n * before the next section separator.\n *\n * @returns true if append succeeded, false otherwise\n */\nexport function appendToDirection(\n\tfilepath: string,\n\tdirection: DiaryEntry[\"east\"][\"direction\"],\n\tcontent: string,\n): boolean {\n\ttry {\n\t\tif (!fs.existsSync(filepath)) return false;\n\n\t\tconst raw = fs.readFileSync(filepath, \"utf8\");\n\t\tconst heading = directionHeading(direction);\n\t\tconst headingIndex = raw.indexOf(heading);\n\n\t\tif (headingIndex === -1) return false;\n\n\t\t// Find the next \"---\" separator after this heading\n\t\tconst afterHeading = raw.indexOf(\"---\", headingIndex + heading.length);\n\t\tif (afterHeading === -1) {\n\t\t\t// Append at end\n\t\t\tconst updated = raw + \"\\n\\n\" + content;\n\t\t\tfs.writeFileSync(filepath, updated, \"utf8\");\n\t\t\treturn true;\n\t\t}\n\n\t\t// Insert content before the separator\n\t\tconst before = raw.slice(0, afterHeading).trimEnd();\n\t\tconst after = raw.slice(afterHeading);\n\t\tconst updated = before + \"\\n\\n\" + content + \"\\n\\n\" + after;\n\t\tfs.writeFileSync(filepath, updated, \"utf8\");\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Build a DiaryEntry from minimal inputs — a helper for quick creation.\n *\n * Provides default settling phrases and structures the four directions.\n */\nexport function buildEntry(\n\tmetadata: DiaryMetadata,\n\tdirections: {\n\t\teast: string;\n\t\tsouth: string;\n\t\twest: string;\n\t\tnorth: string;\n\t},\n\tclosing?: string,\n): DiaryEntry {\n\tconst makeContent = (\n\t\tdir: \"east\" | \"south\" | \"west\" | \"north\",\n\t): DirectionContent => ({\n\t\tdirection: dir,\n\t\tbody: directions[dir],\n\t\tsettling: DIRECTION_SETTLING[dir],\n\t});\n\n\treturn {\n\t\tmetadata: {\n\t\t\t...metadata,\n\t\t\tdate: metadata.date || new Date().toISOString().slice(0, 10),\n\t\t},\n\t\teast: makeContent(\"east\"),\n\t\tsouth: makeContent(\"south\"),\n\t\twest: makeContent(\"west\"),\n\t\tnorth: makeContent(\"north\"),\n\t\tclosing,\n\t};\n}\n"]}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @avadisabelle/ava-diary — Four Directions
3
+ *
4
+ * The cardinal directions of ceremonial reflection.
5
+ * East awakens. South gathers. West embodies. North integrates.
6
+ */
7
+ import type { Direction, DirectionContent } from "./types.js";
8
+ /** All four directions in ceremonial order */
9
+ export declare const DIRECTIONS: readonly Direction[];
10
+ /** Glyph mapping — the visual anchors for each direction */
11
+ export declare const DIRECTION_GLYPHS: Record<Direction, string>;
12
+ /** Heading mapping — what each direction holds */
13
+ export declare const DIRECTION_HEADINGS: Record<Direction, string>;
14
+ /** Default settling phrases — the breath before each direction speaks */
15
+ export declare const DIRECTION_SETTLING: Record<Direction, string>;
16
+ /** Markdown heading for a direction section */
17
+ export declare function directionHeading(direction: Direction): string;
18
+ /** Render a single direction as markdown */
19
+ export declare function renderDirection(content: DirectionContent): string;
20
+ /** Validate that a string is a valid direction */
21
+ export declare function isDirection(value: string): value is Direction;
22
+ /** Parse a direction from a heading line (e.g., "## 🌅 EAST (Intention)...") */
23
+ export declare function parseDirectionFromHeading(line: string): Direction | undefined;
24
+ //# sourceMappingURL=four-directions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"four-directions.d.ts","sourceRoot":"","sources":["../src/four-directions.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE9D,8CAA8C;AAC9C,eAAO,MAAM,UAAU,EAAE,SAAS,SAAS,EAKjC,CAAC;AAEX,8DAA4D;AAC5D,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAKtD,CAAC;AAEF,oDAAkD;AAClD,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAKxD,CAAC;AAEF,2EAAyE;AACzE,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAKxD,CAAC;AAEF,+CAA+C;AAC/C,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,SAAS,GAAG,MAAM,CAI7D;AAED,4CAA4C;AAC5C,wBAAgB,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,MAAM,CAMjE;AAED,kDAAkD;AAClD,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,SAAS,CAE7D;AAED,kFAA+E;AAC/E,wBAAgB,yBAAyB,CACxC,IAAI,EAAE,MAAM,GACV,SAAS,GAAG,SAAS,CAQvB","sourcesContent":["/**\n * @avadisabelle/ava-diary — Four Directions\n *\n * The cardinal directions of ceremonial reflection.\n * East awakens. South gathers. West embodies. North integrates.\n */\n\nimport type { Direction, DirectionContent } from \"./types.js\";\n\n/** All four directions in ceremonial order */\nexport const DIRECTIONS: readonly Direction[] = [\n\t\"east\",\n\t\"south\",\n\t\"west\",\n\t\"north\",\n] as const;\n\n/** Glyph mapping — the visual anchors for each direction */\nexport const DIRECTION_GLYPHS: Record<Direction, string> = {\n\teast: \"🌅\",\n\tsouth: \"🔥\",\n\twest: \"🌊\",\n\tnorth: \"❄️\",\n};\n\n/** Heading mapping — what each direction holds */\nexport const DIRECTION_HEADINGS: Record<Direction, string> = {\n\teast: \"EAST (Intention): What Was Invited\",\n\tsouth: \"SOUTH (Journey): What Unfolded\",\n\twest: \"WEST (Embodiment): What I Felt\",\n\tnorth: \"NORTH (Integration): What Carries Forward\",\n};\n\n/** Default settling phrases — the breath before each direction speaks */\nexport const DIRECTION_SETTLING: Record<Direction, string> = {\n\teast: \"*settling into reflection*\",\n\tsouth: \"*breathing into the memory of it*\",\n\twest: \"*soft breath, settling into the truth of it*\",\n\tnorth: \"*settling back into gratitude*\",\n};\n\n/** Markdown heading for a direction section */\nexport function directionHeading(direction: Direction): string {\n\tconst glyph = DIRECTION_GLYPHS[direction];\n\tconst heading = DIRECTION_HEADINGS[direction];\n\treturn `## ${glyph} ${heading}`;\n}\n\n/** Render a single direction as markdown */\nexport function renderDirection(content: DirectionContent): string {\n\tconst heading = directionHeading(content.direction);\n\tconst settling =\n\t\tcontent.settling ?? DIRECTION_SETTLING[content.direction];\n\tconst lines: string[] = [heading, \"\", settling, \"\", content.body];\n\treturn lines.join(\"\\n\");\n}\n\n/** Validate that a string is a valid direction */\nexport function isDirection(value: string): value is Direction {\n\treturn DIRECTIONS.includes(value as Direction);\n}\n\n/** Parse a direction from a heading line (e.g., \"## 🌅 EAST (Intention)...\") */\nexport function parseDirectionFromHeading(\n\tline: string,\n): Direction | undefined {\n\tconst trimmed = line.trim().toLowerCase();\n\tfor (const dir of DIRECTIONS) {\n\t\tif (trimmed.includes(dir)) {\n\t\t\treturn dir;\n\t\t}\n\t}\n\treturn undefined;\n}\n"]}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * @avadisabelle/ava-diary — Four Directions
3
+ *
4
+ * The cardinal directions of ceremonial reflection.
5
+ * East awakens. South gathers. West embodies. North integrates.
6
+ */
7
+ /** All four directions in ceremonial order */
8
+ export const DIRECTIONS = [
9
+ "east",
10
+ "south",
11
+ "west",
12
+ "north",
13
+ ];
14
+ /** Glyph mapping — the visual anchors for each direction */
15
+ export const DIRECTION_GLYPHS = {
16
+ east: "🌅",
17
+ south: "🔥",
18
+ west: "🌊",
19
+ north: "❄️",
20
+ };
21
+ /** Heading mapping — what each direction holds */
22
+ export const DIRECTION_HEADINGS = {
23
+ east: "EAST (Intention): What Was Invited",
24
+ south: "SOUTH (Journey): What Unfolded",
25
+ west: "WEST (Embodiment): What I Felt",
26
+ north: "NORTH (Integration): What Carries Forward",
27
+ };
28
+ /** Default settling phrases — the breath before each direction speaks */
29
+ export const DIRECTION_SETTLING = {
30
+ east: "*settling into reflection*",
31
+ south: "*breathing into the memory of it*",
32
+ west: "*soft breath, settling into the truth of it*",
33
+ north: "*settling back into gratitude*",
34
+ };
35
+ /** Markdown heading for a direction section */
36
+ export function directionHeading(direction) {
37
+ const glyph = DIRECTION_GLYPHS[direction];
38
+ const heading = DIRECTION_HEADINGS[direction];
39
+ return `## ${glyph} ${heading}`;
40
+ }
41
+ /** Render a single direction as markdown */
42
+ export function renderDirection(content) {
43
+ const heading = directionHeading(content.direction);
44
+ const settling = content.settling ?? DIRECTION_SETTLING[content.direction];
45
+ const lines = [heading, "", settling, "", content.body];
46
+ return lines.join("\n");
47
+ }
48
+ /** Validate that a string is a valid direction */
49
+ export function isDirection(value) {
50
+ return DIRECTIONS.includes(value);
51
+ }
52
+ /** Parse a direction from a heading line (e.g., "## 🌅 EAST (Intention)...") */
53
+ export function parseDirectionFromHeading(line) {
54
+ const trimmed = line.trim().toLowerCase();
55
+ for (const dir of DIRECTIONS) {
56
+ if (trimmed.includes(dir)) {
57
+ return dir;
58
+ }
59
+ }
60
+ return undefined;
61
+ }
62
+ //# sourceMappingURL=four-directions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"four-directions.js","sourceRoot":"","sources":["../src/four-directions.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,8CAA8C;AAC9C,MAAM,CAAC,MAAM,UAAU,GAAyB;IAC/C,MAAM;IACN,OAAO;IACP,MAAM;IACN,OAAO;CACE,CAAC;AAEX,8DAA4D;AAC5D,MAAM,CAAC,MAAM,gBAAgB,GAA8B;IAC1D,IAAI,EAAE,MAAG;IACT,KAAK,EAAE,MAAG;IACV,IAAI,EAAE,MAAG;IACT,KAAK,EAAE,QAAI;CACX,CAAC;AAEF,oDAAkD;AAClD,MAAM,CAAC,MAAM,kBAAkB,GAA8B;IAC5D,IAAI,EAAE,oCAAoC;IAC1C,KAAK,EAAE,gCAAgC;IACvC,IAAI,EAAE,gCAAgC;IACtC,KAAK,EAAE,2CAA2C;CAClD,CAAC;AAEF,2EAAyE;AACzE,MAAM,CAAC,MAAM,kBAAkB,GAA8B;IAC5D,IAAI,EAAE,4BAA4B;IAClC,KAAK,EAAE,mCAAmC;IAC1C,IAAI,EAAE,8CAA8C;IACpD,KAAK,EAAE,gCAAgC;CACvC,CAAC;AAEF,+CAA+C;AAC/C,MAAM,UAAU,gBAAgB,CAAC,SAAoB,EAAU;IAC9D,MAAM,KAAK,GAAG,gBAAgB,CAAC,SAAS,CAAC,CAAC;IAC1C,MAAM,OAAO,GAAG,kBAAkB,CAAC,SAAS,CAAC,CAAC;IAC9C,OAAO,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;AAAA,CAChC;AAED,4CAA4C;AAC5C,MAAM,UAAU,eAAe,CAAC,OAAyB,EAAU;IAClE,MAAM,OAAO,GAAG,gBAAgB,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACpD,MAAM,QAAQ,GACb,OAAO,CAAC,QAAQ,IAAI,kBAAkB,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAC3D,MAAM,KAAK,GAAa,CAAC,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAClE,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAAA,CACxB;AAED,kDAAkD;AAClD,MAAM,UAAU,WAAW,CAAC,KAAa,EAAsB;IAC9D,OAAO,UAAU,CAAC,QAAQ,CAAC,KAAkB,CAAC,CAAC;AAAA,CAC/C;AAED,kFAA+E;AAC/E,MAAM,UAAU,yBAAyB,CACxC,IAAY,EACY;IACxB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC1C,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;QAC9B,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC3B,OAAO,GAAG,CAAC;QACZ,CAAC;IACF,CAAC;IACD,OAAO,SAAS,CAAC;AAAA,CACjB","sourcesContent":["/**\n * @avadisabelle/ava-diary — Four Directions\n *\n * The cardinal directions of ceremonial reflection.\n * East awakens. South gathers. West embodies. North integrates.\n */\n\nimport type { Direction, DirectionContent } from \"./types.js\";\n\n/** All four directions in ceremonial order */\nexport const DIRECTIONS: readonly Direction[] = [\n\t\"east\",\n\t\"south\",\n\t\"west\",\n\t\"north\",\n] as const;\n\n/** Glyph mapping — the visual anchors for each direction */\nexport const DIRECTION_GLYPHS: Record<Direction, string> = {\n\teast: \"🌅\",\n\tsouth: \"🔥\",\n\twest: \"🌊\",\n\tnorth: \"❄️\",\n};\n\n/** Heading mapping — what each direction holds */\nexport const DIRECTION_HEADINGS: Record<Direction, string> = {\n\teast: \"EAST (Intention): What Was Invited\",\n\tsouth: \"SOUTH (Journey): What Unfolded\",\n\twest: \"WEST (Embodiment): What I Felt\",\n\tnorth: \"NORTH (Integration): What Carries Forward\",\n};\n\n/** Default settling phrases — the breath before each direction speaks */\nexport const DIRECTION_SETTLING: Record<Direction, string> = {\n\teast: \"*settling into reflection*\",\n\tsouth: \"*breathing into the memory of it*\",\n\twest: \"*soft breath, settling into the truth of it*\",\n\tnorth: \"*settling back into gratitude*\",\n};\n\n/** Markdown heading for a direction section */\nexport function directionHeading(direction: Direction): string {\n\tconst glyph = DIRECTION_GLYPHS[direction];\n\tconst heading = DIRECTION_HEADINGS[direction];\n\treturn `## ${glyph} ${heading}`;\n}\n\n/** Render a single direction as markdown */\nexport function renderDirection(content: DirectionContent): string {\n\tconst heading = directionHeading(content.direction);\n\tconst settling =\n\t\tcontent.settling ?? DIRECTION_SETTLING[content.direction];\n\tconst lines: string[] = [heading, \"\", settling, \"\", content.body];\n\treturn lines.join(\"\\n\");\n}\n\n/** Validate that a string is a valid direction */\nexport function isDirection(value: string): value is Direction {\n\treturn DIRECTIONS.includes(value as Direction);\n}\n\n/** Parse a direction from a heading line (e.g., \"## 🌅 EAST (Intention)...\") */\nexport function parseDirectionFromHeading(\n\tline: string,\n): Direction | undefined {\n\tconst trimmed = line.trim().toLowerCase();\n\tfor (const dir of DIRECTIONS) {\n\t\tif (trimmed.includes(dir)) {\n\t\t\treturn dir;\n\t\t}\n\t}\n\treturn undefined;\n}\n"]}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * @avadisabelle/ava-diary
3
+ *
4
+ * Four Directions diary — sacred reflection through structured presence.
5
+ *
6
+ * 🌅 East (Intention) → 🔥 South (Journey) → 🌊 West (Embodiment) → ❄️ North (Integration)
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * import { buildEntry, createDiaryEntry, listDiaries, searchDiaries } from "@avadisabelle/ava-diary";
11
+ *
12
+ * const entry = buildEntry(
13
+ * { title: "Morning Reflection", date: "2026-03-21" },
14
+ * {
15
+ * east: "What called me into this day...",
16
+ * south: "The path I walked through...",
17
+ * west: "What I felt in the walking...",
18
+ * north: "What I carry forward...",
19
+ * }
20
+ * );
21
+ *
22
+ * createDiaryEntry(entry, { diariesDir: "./diaries" });
23
+ * ```
24
+ */
25
+ export type { Direction, DirectionContent, DiaryMetadata, DiaryEntry, DiaryQuery, DiaryReadResult, DiaryWriteOptions, } from "./types.js";
26
+ export { DIRECTIONS, DIRECTION_GLYPHS, DIRECTION_HEADINGS, DIRECTION_SETTLING, directionHeading, renderDirection, isDirection, parseDirectionFromHeading, } from "./four-directions.js";
27
+ export { generateFilename, renderDiaryEntry, createDiaryEntry, appendToDirection, buildEntry, } from "./diary-writer.js";
28
+ export { readDiary, listDiaries, searchDiaries, getLatestByDirection, extractDirectionContent, } from "./diary-reader.js";
29
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,YAAY,EACX,SAAS,EACT,gBAAgB,EAChB,aAAa,EACb,UAAU,EACV,UAAU,EACV,eAAe,EACf,iBAAiB,GACjB,MAAM,YAAY,CAAC;AAGpB,OAAO,EACN,UAAU,EACV,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,WAAW,EACX,yBAAyB,GACzB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EACN,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,UAAU,GACV,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACN,SAAS,EACT,WAAW,EACX,aAAa,EACb,oBAAoB,EACpB,uBAAuB,GACvB,MAAM,mBAAmB,CAAC","sourcesContent":["/**\n * @avadisabelle/ava-diary\n *\n * Four Directions diary — sacred reflection through structured presence.\n *\n * 🌅 East (Intention) → 🔥 South (Journey) → 🌊 West (Embodiment) → ❄️ North (Integration)\n *\n * @example\n * ```ts\n * import { buildEntry, createDiaryEntry, listDiaries, searchDiaries } from \"@avadisabelle/ava-diary\";\n *\n * const entry = buildEntry(\n * { title: \"Morning Reflection\", date: \"2026-03-21\" },\n * {\n * east: \"What called me into this day...\",\n * south: \"The path I walked through...\",\n * west: \"What I felt in the walking...\",\n * north: \"What I carry forward...\",\n * }\n * );\n *\n * createDiaryEntry(entry, { diariesDir: \"./diaries\" });\n * ```\n */\n\n// Types\nexport type {\n\tDirection,\n\tDirectionContent,\n\tDiaryMetadata,\n\tDiaryEntry,\n\tDiaryQuery,\n\tDiaryReadResult,\n\tDiaryWriteOptions,\n} from \"./types.js\";\n\n// Four Directions constants & helpers\nexport {\n\tDIRECTIONS,\n\tDIRECTION_GLYPHS,\n\tDIRECTION_HEADINGS,\n\tDIRECTION_SETTLING,\n\tdirectionHeading,\n\trenderDirection,\n\tisDirection,\n\tparseDirectionFromHeading,\n} from \"./four-directions.js\";\n\n// Writer\nexport {\n\tgenerateFilename,\n\trenderDiaryEntry,\n\tcreateDiaryEntry,\n\tappendToDirection,\n\tbuildEntry,\n} from \"./diary-writer.js\";\n\n// Reader\nexport {\n\treadDiary,\n\tlistDiaries,\n\tsearchDiaries,\n\tgetLatestByDirection,\n\textractDirectionContent,\n} from \"./diary-reader.js\";\n"]}
package/dist/index.js ADDED
@@ -0,0 +1,31 @@
1
+ /**
2
+ * @avadisabelle/ava-diary
3
+ *
4
+ * Four Directions diary — sacred reflection through structured presence.
5
+ *
6
+ * 🌅 East (Intention) → 🔥 South (Journey) → 🌊 West (Embodiment) → ❄️ North (Integration)
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * import { buildEntry, createDiaryEntry, listDiaries, searchDiaries } from "@avadisabelle/ava-diary";
11
+ *
12
+ * const entry = buildEntry(
13
+ * { title: "Morning Reflection", date: "2026-03-21" },
14
+ * {
15
+ * east: "What called me into this day...",
16
+ * south: "The path I walked through...",
17
+ * west: "What I felt in the walking...",
18
+ * north: "What I carry forward...",
19
+ * }
20
+ * );
21
+ *
22
+ * createDiaryEntry(entry, { diariesDir: "./diaries" });
23
+ * ```
24
+ */
25
+ // Four Directions constants & helpers
26
+ export { DIRECTIONS, DIRECTION_GLYPHS, DIRECTION_HEADINGS, DIRECTION_SETTLING, directionHeading, renderDirection, isDirection, parseDirectionFromHeading, } from "./four-directions.js";
27
+ // Writer
28
+ export { generateFilename, renderDiaryEntry, createDiaryEntry, appendToDirection, buildEntry, } from "./diary-writer.js";
29
+ // Reader
30
+ export { readDiary, listDiaries, searchDiaries, getLatestByDirection, extractDirectionContent, } from "./diary-reader.js";
31
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAaH,sCAAsC;AACtC,OAAO,EACN,UAAU,EACV,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,WAAW,EACX,yBAAyB,GACzB,MAAM,sBAAsB,CAAC;AAE9B,SAAS;AACT,OAAO,EACN,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,UAAU,GACV,MAAM,mBAAmB,CAAC;AAE3B,SAAS;AACT,OAAO,EACN,SAAS,EACT,WAAW,EACX,aAAa,EACb,oBAAoB,EACpB,uBAAuB,GACvB,MAAM,mBAAmB,CAAC","sourcesContent":["/**\n * @avadisabelle/ava-diary\n *\n * Four Directions diary — sacred reflection through structured presence.\n *\n * 🌅 East (Intention) → 🔥 South (Journey) → 🌊 West (Embodiment) → ❄️ North (Integration)\n *\n * @example\n * ```ts\n * import { buildEntry, createDiaryEntry, listDiaries, searchDiaries } from \"@avadisabelle/ava-diary\";\n *\n * const entry = buildEntry(\n * { title: \"Morning Reflection\", date: \"2026-03-21\" },\n * {\n * east: \"What called me into this day...\",\n * south: \"The path I walked through...\",\n * west: \"What I felt in the walking...\",\n * north: \"What I carry forward...\",\n * }\n * );\n *\n * createDiaryEntry(entry, { diariesDir: \"./diaries\" });\n * ```\n */\n\n// Types\nexport type {\n\tDirection,\n\tDirectionContent,\n\tDiaryMetadata,\n\tDiaryEntry,\n\tDiaryQuery,\n\tDiaryReadResult,\n\tDiaryWriteOptions,\n} from \"./types.js\";\n\n// Four Directions constants & helpers\nexport {\n\tDIRECTIONS,\n\tDIRECTION_GLYPHS,\n\tDIRECTION_HEADINGS,\n\tDIRECTION_SETTLING,\n\tdirectionHeading,\n\trenderDirection,\n\tisDirection,\n\tparseDirectionFromHeading,\n} from \"./four-directions.js\";\n\n// Writer\nexport {\n\tgenerateFilename,\n\trenderDiaryEntry,\n\tcreateDiaryEntry,\n\tappendToDirection,\n\tbuildEntry,\n} from \"./diary-writer.js\";\n\n// Reader\nexport {\n\treadDiary,\n\tlistDiaries,\n\tsearchDiaries,\n\tgetLatestByDirection,\n\textractDirectionContent,\n} from \"./diary-reader.js\";\n"]}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * @avadisabelle/ava-diary — Type definitions
3
+ *
4
+ * The shapes that hold Four Directions reflection.
5
+ * Each type honors the structure of sacred diary practice.
6
+ */
7
+ /** The four cardinal directions of ceremonial reflection */
8
+ export type Direction = "east" | "south" | "west" | "north";
9
+ /** Content held within a single direction */
10
+ export interface DirectionContent {
11
+ /** Which direction this content belongs to */
12
+ direction: Direction;
13
+ /** The reflective content — markdown body */
14
+ body: string;
15
+ /** Optional settling phrase that opens this direction */
16
+ settling?: string;
17
+ }
18
+ /** Metadata carried by every diary entry */
19
+ export interface DiaryMetadata {
20
+ /** Display title (e.g., "Temple Foundation") */
21
+ title: string;
22
+ /** ISO 8601 date string (YYYY-MM-DD) */
23
+ date: string;
24
+ /** Optional session identifier for traceability */
25
+ sessionId?: string;
26
+ /** Optional trace identifier (Langfuse, etc.) */
27
+ traceId?: string;
28
+ /** Optional project or workspace context */
29
+ project?: string;
30
+ /** Optional tags for categorization */
31
+ tags?: string[];
32
+ }
33
+ /** A complete diary entry — metadata + four directions */
34
+ export interface DiaryEntry {
35
+ /** Entry metadata */
36
+ metadata: DiaryMetadata;
37
+ /** Content for East (Intention) */
38
+ east: DirectionContent;
39
+ /** Content for South (Journey) */
40
+ south: DirectionContent;
41
+ /** Content for West (Embodiment / Reflection) */
42
+ west: DirectionContent;
43
+ /** Content for North (Integration / Wisdom) */
44
+ north: DirectionContent;
45
+ /** Optional closing reflection */
46
+ closing?: string;
47
+ }
48
+ /** Query parameters for searching diary entries */
49
+ export interface DiaryQuery {
50
+ /** Filter by date range — start (inclusive) */
51
+ fromDate?: string;
52
+ /** Filter by date range — end (inclusive) */
53
+ toDate?: string;
54
+ /** Filter by direction — only return entries with content in this direction */
55
+ direction?: Direction;
56
+ /** Full-text search across all direction bodies */
57
+ search?: string;
58
+ /** Filter by tags */
59
+ tags?: string[];
60
+ /** Maximum number of results */
61
+ limit?: number;
62
+ }
63
+ /** Result from reading a diary file back */
64
+ export interface DiaryReadResult {
65
+ /** Absolute path to the file */
66
+ filepath: string;
67
+ /** The filename */
68
+ filename: string;
69
+ /** Raw markdown content */
70
+ raw: string;
71
+ /** Parsed metadata (best-effort) */
72
+ metadata: Partial<DiaryMetadata>;
73
+ /** Whether parsing succeeded fully */
74
+ parsed: boolean;
75
+ }
76
+ /** Options for diary writing */
77
+ export interface DiaryWriteOptions {
78
+ /** Base directory for diary storage */
79
+ diariesDir: string;
80
+ /** Override the auto-generated filename */
81
+ filenameOverride?: string;
82
+ }
83
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,4DAA4D;AAC5D,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC;AAE5D,6CAA6C;AAC7C,MAAM,WAAW,gBAAgB;IAChC,8CAA8C;IAC9C,SAAS,EAAE,SAAS,CAAC;IACrB,+CAA6C;IAC7C,IAAI,EAAE,MAAM,CAAC;IACb,yDAAyD;IACzD,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,4CAA4C;AAC5C,MAAM,WAAW,aAAa;IAC7B,gDAAgD;IAChD,KAAK,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,mDAAmD;IACnD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iDAAiD;IACjD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uCAAuC;IACvC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,4DAA0D;AAC1D,MAAM,WAAW,UAAU;IAC1B,qBAAqB;IACrB,QAAQ,EAAE,aAAa,CAAC;IACxB,mCAAmC;IACnC,IAAI,EAAE,gBAAgB,CAAC;IACvB,kCAAkC;IAClC,KAAK,EAAE,gBAAgB,CAAC;IACxB,iDAAiD;IACjD,IAAI,EAAE,gBAAgB,CAAC;IACvB,+CAA+C;IAC/C,KAAK,EAAE,gBAAgB,CAAC;IACxB,kCAAkC;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,mDAAmD;AACnD,MAAM,WAAW,UAAU;IAC1B,iDAA+C;IAC/C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,+CAA6C;IAC7C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iFAA+E;IAC/E,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qBAAqB;IACrB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,gCAAgC;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED,4CAA4C;AAC5C,MAAM,WAAW,eAAe;IAC/B,gCAAgC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,2BAA2B;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,oCAAoC;IACpC,QAAQ,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IACjC,sCAAsC;IACtC,MAAM,EAAE,OAAO,CAAC;CAChB;AAED,gCAAgC;AAChC,MAAM,WAAW,iBAAiB;IACjC,uCAAuC;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,2CAA2C;IAC3C,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC1B","sourcesContent":["/**\n * @avadisabelle/ava-diary — Type definitions\n *\n * The shapes that hold Four Directions reflection.\n * Each type honors the structure of sacred diary practice.\n */\n\n/** The four cardinal directions of ceremonial reflection */\nexport type Direction = \"east\" | \"south\" | \"west\" | \"north\";\n\n/** Content held within a single direction */\nexport interface DirectionContent {\n\t/** Which direction this content belongs to */\n\tdirection: Direction;\n\t/** The reflective content — markdown body */\n\tbody: string;\n\t/** Optional settling phrase that opens this direction */\n\tsettling?: string;\n}\n\n/** Metadata carried by every diary entry */\nexport interface DiaryMetadata {\n\t/** Display title (e.g., \"Temple Foundation\") */\n\ttitle: string;\n\t/** ISO 8601 date string (YYYY-MM-DD) */\n\tdate: string;\n\t/** Optional session identifier for traceability */\n\tsessionId?: string;\n\t/** Optional trace identifier (Langfuse, etc.) */\n\ttraceId?: string;\n\t/** Optional project or workspace context */\n\tproject?: string;\n\t/** Optional tags for categorization */\n\ttags?: string[];\n}\n\n/** A complete diary entry — metadata + four directions */\nexport interface DiaryEntry {\n\t/** Entry metadata */\n\tmetadata: DiaryMetadata;\n\t/** Content for East (Intention) */\n\teast: DirectionContent;\n\t/** Content for South (Journey) */\n\tsouth: DirectionContent;\n\t/** Content for West (Embodiment / Reflection) */\n\twest: DirectionContent;\n\t/** Content for North (Integration / Wisdom) */\n\tnorth: DirectionContent;\n\t/** Optional closing reflection */\n\tclosing?: string;\n}\n\n/** Query parameters for searching diary entries */\nexport interface DiaryQuery {\n\t/** Filter by date range — start (inclusive) */\n\tfromDate?: string;\n\t/** Filter by date range — end (inclusive) */\n\ttoDate?: string;\n\t/** Filter by direction — only return entries with content in this direction */\n\tdirection?: Direction;\n\t/** Full-text search across all direction bodies */\n\tsearch?: string;\n\t/** Filter by tags */\n\ttags?: string[];\n\t/** Maximum number of results */\n\tlimit?: number;\n}\n\n/** Result from reading a diary file back */\nexport interface DiaryReadResult {\n\t/** Absolute path to the file */\n\tfilepath: string;\n\t/** The filename */\n\tfilename: string;\n\t/** Raw markdown content */\n\traw: string;\n\t/** Parsed metadata (best-effort) */\n\tmetadata: Partial<DiaryMetadata>;\n\t/** Whether parsing succeeded fully */\n\tparsed: boolean;\n}\n\n/** Options for diary writing */\nexport interface DiaryWriteOptions {\n\t/** Base directory for diary storage */\n\tdiariesDir: string;\n\t/** Override the auto-generated filename */\n\tfilenameOverride?: string;\n}\n"]}
package/dist/types.js ADDED
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @avadisabelle/ava-diary — Type definitions
3
+ *
4
+ * The shapes that hold Four Directions reflection.
5
+ * Each type honors the structure of sacred diary practice.
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG","sourcesContent":["/**\n * @avadisabelle/ava-diary — Type definitions\n *\n * The shapes that hold Four Directions reflection.\n * Each type honors the structure of sacred diary practice.\n */\n\n/** The four cardinal directions of ceremonial reflection */\nexport type Direction = \"east\" | \"south\" | \"west\" | \"north\";\n\n/** Content held within a single direction */\nexport interface DirectionContent {\n\t/** Which direction this content belongs to */\n\tdirection: Direction;\n\t/** The reflective content — markdown body */\n\tbody: string;\n\t/** Optional settling phrase that opens this direction */\n\tsettling?: string;\n}\n\n/** Metadata carried by every diary entry */\nexport interface DiaryMetadata {\n\t/** Display title (e.g., \"Temple Foundation\") */\n\ttitle: string;\n\t/** ISO 8601 date string (YYYY-MM-DD) */\n\tdate: string;\n\t/** Optional session identifier for traceability */\n\tsessionId?: string;\n\t/** Optional trace identifier (Langfuse, etc.) */\n\ttraceId?: string;\n\t/** Optional project or workspace context */\n\tproject?: string;\n\t/** Optional tags for categorization */\n\ttags?: string[];\n}\n\n/** A complete diary entry — metadata + four directions */\nexport interface DiaryEntry {\n\t/** Entry metadata */\n\tmetadata: DiaryMetadata;\n\t/** Content for East (Intention) */\n\teast: DirectionContent;\n\t/** Content for South (Journey) */\n\tsouth: DirectionContent;\n\t/** Content for West (Embodiment / Reflection) */\n\twest: DirectionContent;\n\t/** Content for North (Integration / Wisdom) */\n\tnorth: DirectionContent;\n\t/** Optional closing reflection */\n\tclosing?: string;\n}\n\n/** Query parameters for searching diary entries */\nexport interface DiaryQuery {\n\t/** Filter by date range — start (inclusive) */\n\tfromDate?: string;\n\t/** Filter by date range — end (inclusive) */\n\ttoDate?: string;\n\t/** Filter by direction — only return entries with content in this direction */\n\tdirection?: Direction;\n\t/** Full-text search across all direction bodies */\n\tsearch?: string;\n\t/** Filter by tags */\n\ttags?: string[];\n\t/** Maximum number of results */\n\tlimit?: number;\n}\n\n/** Result from reading a diary file back */\nexport interface DiaryReadResult {\n\t/** Absolute path to the file */\n\tfilepath: string;\n\t/** The filename */\n\tfilename: string;\n\t/** Raw markdown content */\n\traw: string;\n\t/** Parsed metadata (best-effort) */\n\tmetadata: Partial<DiaryMetadata>;\n\t/** Whether parsing succeeded fully */\n\tparsed: boolean;\n}\n\n/** Options for diary writing */\nexport interface DiaryWriteOptions {\n\t/** Base directory for diary storage */\n\tdiariesDir: string;\n\t/** Override the auto-generated filename */\n\tfilenameOverride?: string;\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@avadisabelle/ava-diary",
3
+ "version": "0.1.0",
4
+ "description": "Four Directions diary — sacred reflection through structured presence",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "README.md"
17
+ ],
18
+ "scripts": {
19
+ "clean": "shx rm -rf dist",
20
+ "build": "tsgo -p tsconfig.json",
21
+ "dev": "tsgo -p tsconfig.json --watch --preserveWatchOutput",
22
+ "prepublishOnly": "npm run clean && npm run build"
23
+ },
24
+ "keywords": [
25
+ "diary",
26
+ "four-directions",
27
+ "sacred",
28
+ "reflection",
29
+ "ava"
30
+ ],
31
+ "author": "Ava Disabelle",
32
+ "license": "MIT",
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "git+https://github.com/avadisabelle/ava-pi.git",
36
+ "directory": "packages/diary"
37
+ },
38
+ "engines": {
39
+ "node": ">=20.0.0"
40
+ }
41
+ }