@aipper/aiws 0.0.44 → 0.0.46

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.
Files changed (45) hide show
  1. package/dist/cli.js +162 -0
  2. package/dist/cli.js.map +1 -1
  3. package/dist/commands/goal-advance.d.ts +20 -0
  4. package/dist/commands/goal-advance.js +112 -0
  5. package/dist/commands/goal-advance.js.map +1 -0
  6. package/dist/commands/goal-help.d.ts +1 -0
  7. package/dist/commands/goal-help.js +28 -0
  8. package/dist/commands/goal-help.js.map +1 -0
  9. package/dist/commands/goal-validate-state.d.ts +92 -0
  10. package/dist/commands/goal-validate-state.js +371 -0
  11. package/dist/commands/goal-validate-state.js.map +1 -0
  12. package/dist/commands/goal-validate.d.ts +16 -0
  13. package/dist/commands/goal-validate.js +100 -0
  14. package/dist/commands/goal-validate.js.map +1 -0
  15. package/dist/commands/memory.d.ts +35 -0
  16. package/dist/commands/memory.js +239 -0
  17. package/dist/commands/memory.js.map +1 -0
  18. package/dist/memory-bank/disclosure.d.ts +24 -0
  19. package/dist/memory-bank/disclosure.js +143 -0
  20. package/dist/memory-bank/disclosure.js.map +1 -0
  21. package/dist/memory-bank/index.d.ts +24 -0
  22. package/dist/memory-bank/index.js +137 -0
  23. package/dist/memory-bank/index.js.map +1 -0
  24. package/dist/memory-bank/link.d.ts +21 -0
  25. package/dist/memory-bank/link.js +113 -0
  26. package/dist/memory-bank/link.js.map +1 -0
  27. package/dist/memory-bank/search.d.ts +6 -0
  28. package/dist/memory-bank/search.js +88 -0
  29. package/dist/memory-bank/search.js.map +1 -0
  30. package/dist/memory-bank/seed.d.ts +23 -0
  31. package/dist/memory-bank/seed.js +164 -0
  32. package/dist/memory-bank/seed.js.map +1 -0
  33. package/dist/memory-bank/store.d.ts +24 -0
  34. package/dist/memory-bank/store.js +193 -0
  35. package/dist/memory-bank/store.js.map +1 -0
  36. package/dist/memory-bank/types.d.ts +45 -0
  37. package/dist/memory-bank/types.js +2 -0
  38. package/dist/memory-bank/types.js.map +1 -0
  39. package/dist/memory-bank/uri.d.ts +16 -0
  40. package/dist/memory-bank/uri.js +52 -0
  41. package/dist/memory-bank/uri.js.map +1 -0
  42. package/dist/workspace.d.ts +1 -0
  43. package/dist/workspace.js +13 -0
  44. package/dist/workspace.js.map +1 -1
  45. package/package.json +4 -2
@@ -0,0 +1,113 @@
1
+ import path from "node:path";
2
+ import fs from "node:fs/promises";
3
+ import yaml from "js-yaml";
4
+ import { getMemoryBankDir } from "./store.js";
5
+ import { validateUri } from "./uri.js";
6
+ import { loadIndex } from "./index.js";
7
+ import { pathExists, ensureDir } from "../fs.js";
8
+ const LINKS_FILENAME = ".links.yaml";
9
+ /**
10
+ * Get the absolute path to the links database file.
11
+ */
12
+ export function getLinksDbPath(wsRoot) {
13
+ return path.join(getMemoryBankDir(wsRoot), LINKS_FILENAME);
14
+ }
15
+ /**
16
+ * Load the links database.
17
+ */
18
+ async function loadLinksDb(wsRoot) {
19
+ const dbPath = getLinksDbPath(wsRoot);
20
+ if (!(await pathExists(dbPath))) {
21
+ return { links: [] };
22
+ }
23
+ try {
24
+ const raw = await fs.readFile(dbPath, "utf8");
25
+ const parsed = yaml.load(raw);
26
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
27
+ const data = parsed;
28
+ const links = data.links;
29
+ if (Array.isArray(links)) {
30
+ return {
31
+ links: links.map((l) => {
32
+ const entry = l;
33
+ return {
34
+ from: String(entry.from ?? ""),
35
+ to: String(entry.to ?? ""),
36
+ created: String(entry.created ?? ""),
37
+ };
38
+ }),
39
+ };
40
+ }
41
+ }
42
+ return { links: [] };
43
+ }
44
+ catch {
45
+ return { links: [] };
46
+ }
47
+ }
48
+ /**
49
+ * Save the links database.
50
+ */
51
+ async function saveLinksDb(wsRoot, db) {
52
+ const dbPath = getLinksDbPath(wsRoot);
53
+ await ensureDir(path.dirname(dbPath));
54
+ const yamlStr = yaml.dump(db, { lineWidth: 120, noRefs: true });
55
+ await fs.writeFile(dbPath, yamlStr, "utf8");
56
+ }
57
+ /**
58
+ * Add a directed link from `from` to `to`.
59
+ * Validates both URIs. Warns if either URI is not in the index.
60
+ */
61
+ export async function addLink(wsRoot, from, to) {
62
+ if (!validateUri(from)) {
63
+ throw new Error(`Invalid from URI: ${from}`);
64
+ }
65
+ if (!validateUri(to)) {
66
+ throw new Error(`Invalid to URI: ${to}`);
67
+ }
68
+ const index = await loadIndex(wsRoot);
69
+ if (!index.memories[from]) {
70
+ console.warn(`Warning: from-uri "${from}" not found in memory index`);
71
+ }
72
+ if (!index.memories[to]) {
73
+ console.warn(`Warning: to-uri "${to}" not found in memory index`);
74
+ }
75
+ const db = await loadLinksDb(wsRoot);
76
+ // Avoid duplicate entries
77
+ const exists = db.links.some((l) => l.from === from && l.to === to);
78
+ if (!exists) {
79
+ db.links.push({
80
+ from,
81
+ to,
82
+ created: new Date().toISOString(),
83
+ });
84
+ await saveLinksDb(wsRoot, db);
85
+ }
86
+ }
87
+ /**
88
+ * List outgoing and incoming links for a URI.
89
+ */
90
+ export async function listLinks(wsRoot, uri) {
91
+ if (!validateUri(uri)) {
92
+ throw new Error(`Invalid URI: ${uri}`);
93
+ }
94
+ const db = await loadLinksDb(wsRoot);
95
+ const outgoing = db.links.filter((l) => l.from === uri);
96
+ const incoming = db.links.filter((l) => l.to === uri);
97
+ return { outgoing, incoming };
98
+ }
99
+ /**
100
+ * Remove a specific link entry.
101
+ */
102
+ export async function removeLink(wsRoot, from, to) {
103
+ if (!validateUri(from)) {
104
+ throw new Error(`Invalid from URI: ${from}`);
105
+ }
106
+ if (!validateUri(to)) {
107
+ throw new Error(`Invalid to URI: ${to}`);
108
+ }
109
+ const db = await loadLinksDb(wsRoot);
110
+ db.links = db.links.filter((l) => !(l.from === from && l.to === to));
111
+ await saveLinksDb(wsRoot, db);
112
+ }
113
+ //# sourceMappingURL=link.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"link.js","sourceRoot":"","sources":["../../src/memory-bank/link.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import { SearchResult } from "./types.js";
2
+ /**
3
+ * Search memory entries by keyword.
4
+ * Searches index (title + tags) first, then body content.
5
+ */
6
+ export declare function searchMemories(wsRoot: string, query: string): Promise<SearchResult[]>;
@@ -0,0 +1,88 @@
1
+ import { loadIndex } from "./index.js";
2
+ import { readMemory } from "./store.js";
3
+ import { getMemoryBankDir } from "./store.js";
4
+ import { parseUri, uriToRelPath } from "./uri.js";
5
+ import { pathExists } from "../fs.js";
6
+ import path from "node:path";
7
+ import fs from "node:fs/promises";
8
+ const MAX_RESULTS = 20;
9
+ const SNIPPET_LENGTH = 120;
10
+ /**
11
+ * Search memory entries by keyword.
12
+ * Searches index (title + tags) first, then body content.
13
+ */
14
+ export async function searchMemories(wsRoot, query) {
15
+ const q = query.toLowerCase().trim();
16
+ if (!q)
17
+ return [];
18
+ const index = await loadIndex(wsRoot);
19
+ const results = [];
20
+ const seen = new Set();
21
+ // Phase 1: Search index for title/tag matches
22
+ const indexMatches = [];
23
+ for (const [uri, entry] of Object.entries(index.memories)) {
24
+ const titleMatch = entry.title.toLowerCase().includes(q);
25
+ const tagMatch = entry.tags.some((t) => t.toLowerCase().includes(q));
26
+ if (titleMatch || tagMatch) {
27
+ indexMatches.push(uri);
28
+ }
29
+ }
30
+ // Phase 2: If no index matches, search all memories; otherwise search matches + index
31
+ const urisToSearch = indexMatches.length > 0
32
+ ? indexMatches
33
+ : Object.keys(index.memories);
34
+ for (const uri of urisToSearch) {
35
+ if (results.length >= MAX_RESULTS)
36
+ break;
37
+ if (seen.has(uri))
38
+ continue;
39
+ seen.add(uri);
40
+ try {
41
+ const entry = index.memories[uri];
42
+ const title = entry?.title ?? uri;
43
+ // Read body from file for snippet
44
+ const memDir = getMemoryBankDir(wsRoot);
45
+ let bodyText = "";
46
+ try {
47
+ const mem = await readMemory(wsRoot, uri);
48
+ bodyText = mem.body;
49
+ }
50
+ catch {
51
+ // Try direct read
52
+ const { domain, path: uriPath } = parseUri(uri);
53
+ const relPath = uriToRelPath(domain, uriPath);
54
+ const absPath = path.join(memDir, relPath);
55
+ if (await pathExists(absPath)) {
56
+ bodyText = await fs.readFile(absPath, "utf8");
57
+ }
58
+ }
59
+ const bodyMatch = bodyText.toLowerCase().includes(q);
60
+ const isIndexMatch = indexMatches.includes(uri);
61
+ if (!bodyMatch && !isIndexMatch)
62
+ continue;
63
+ // Generate snippet
64
+ const lowerBody = bodyText.toLowerCase();
65
+ const matchIdx = lowerBody.indexOf(q);
66
+ let snippet;
67
+ if (matchIdx !== -1) {
68
+ const start = Math.max(0, matchIdx - 40);
69
+ snippet = bodyText.slice(start, start + SNIPPET_LENGTH).trim();
70
+ if (start > 0)
71
+ snippet = "..." + snippet;
72
+ if (start + SNIPPET_LENGTH < bodyText.length)
73
+ snippet = snippet + "...";
74
+ }
75
+ else {
76
+ snippet = bodyText.slice(0, SNIPPET_LENGTH).trim();
77
+ if (bodyText.length > SNIPPET_LENGTH)
78
+ snippet += "...";
79
+ }
80
+ results.push({ uri, title, snippet });
81
+ }
82
+ catch {
83
+ // Skip unreadable entries
84
+ }
85
+ }
86
+ return results.slice(0, MAX_RESULTS);
87
+ }
88
+ //# sourceMappingURL=search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/memory-bank/search.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Result of a seed operation.
3
+ */
4
+ export interface SeedResult {
5
+ written: number;
6
+ skipped: number;
7
+ uris: string[];
8
+ }
9
+ /**
10
+ * Seed project truth files and artifacts into the memory bank.
11
+ *
12
+ * Scans configured source files in the workspace, reads their content,
13
+ * and writes them as persistent memory entries under a predefined URI scheme.
14
+ *
15
+ * @param wsRoot - Absolute path to the workspace root (must contain .aiws/)
16
+ * @param options.dryRun - If true, only collect URIs without writing
17
+ * @param options.force - If true, overwrite existing memory entries
18
+ * @returns SeedResult with counts of written/skipped entries and list of URIs
19
+ */
20
+ export declare function seedMemories(wsRoot: string, options?: {
21
+ dryRun?: boolean;
22
+ force?: boolean;
23
+ }): Promise<SeedResult>;
@@ -0,0 +1,164 @@
1
+ import path from "node:path";
2
+ import fs from "node:fs/promises";
3
+ import { writeMemory, readMemory } from "./store.js";
4
+ import { loadIndex, updateIndex } from "./index.js";
5
+ import { pathExists } from "../fs.js";
6
+ /**
7
+ * Build the list of seedable sources from the workspace root.
8
+ */
9
+ function buildSources(_wsRoot) {
10
+ const sources = [
11
+ {
12
+ uri: "rule://ai-project",
13
+ title: "AI Project Rules",
14
+ tag: "seed:ai-project",
15
+ relPath: "AI_PROJECT.md",
16
+ },
17
+ {
18
+ uri: "project://requirement",
19
+ title: "Requirements",
20
+ tag: "seed:requirement",
21
+ relPath: "REQUIREMENTS.md",
22
+ },
23
+ {
24
+ uri: "project://ai-workspace",
25
+ title: "AI Workspace",
26
+ tag: "seed:ai-workspace",
27
+ relPath: "AI_WORKSPACE.md",
28
+ },
29
+ {
30
+ uri: "rule://agents",
31
+ title: "Agent Rules",
32
+ tag: "seed:agents",
33
+ relPath: "AGENTS.md",
34
+ },
35
+ ];
36
+ return sources;
37
+ }
38
+ /**
39
+ * Format file content as a clean Markdown body for memory storage.
40
+ */
41
+ function formatBody(title, sourcePath, content) {
42
+ return `# ${title}
43
+
44
+ _Source: \`${sourcePath}\`_
45
+
46
+ ${content.trim()}`;
47
+ }
48
+ /**
49
+ * Seed project truth files and artifacts into the memory bank.
50
+ *
51
+ * Scans configured source files in the workspace, reads their content,
52
+ * and writes them as persistent memory entries under a predefined URI scheme.
53
+ *
54
+ * @param wsRoot - Absolute path to the workspace root (must contain .aiws/)
55
+ * @param options.dryRun - If true, only collect URIs without writing
56
+ * @param options.force - If true, overwrite existing memory entries
57
+ * @returns SeedResult with counts of written/skipped entries and list of URIs
58
+ */
59
+ export async function seedMemories(wsRoot, options = {}) {
60
+ const { dryRun = false, force = false } = options;
61
+ const result = { written: 0, skipped: 0, uris: [] };
62
+ // Load existing index for idempotency checks
63
+ const index = await loadIndex(wsRoot);
64
+ // Build dynamic sources: scan .aiws/goals/ and .aiws/plan/
65
+ const sources = buildSources(wsRoot);
66
+ // Add dynamic goals
67
+ const goalsDir = path.join(wsRoot, ".aiws", "goals");
68
+ if (await pathExists(goalsDir)) {
69
+ const goalEntries = await fs.readdir(goalsDir, { withFileTypes: true });
70
+ for (const entry of goalEntries) {
71
+ if (!entry.name.endsWith(".md"))
72
+ continue;
73
+ if (entry.name.startsWith("."))
74
+ continue;
75
+ const baseName = entry.name.replace(/\.md$/, "");
76
+ sources.push({
77
+ uri: `decision://${toUriPath(baseName)}`,
78
+ title: baseName,
79
+ tag: "seed:goal",
80
+ relPath: path.join(".aiws", "goals", entry.name),
81
+ });
82
+ }
83
+ }
84
+ // Add dynamic plans
85
+ const planDir = path.join(wsRoot, ".aiws", "plan");
86
+ if (await pathExists(planDir)) {
87
+ const planEntries = await fs.readdir(planDir, { withFileTypes: true });
88
+ for (const entry of planEntries) {
89
+ if (!entry.name.endsWith(".md"))
90
+ continue;
91
+ if (entry.name.startsWith("."))
92
+ continue;
93
+ const baseName = entry.name.replace(/\.md$/, "");
94
+ sources.push({
95
+ uri: `change://${toUriPath(baseName)}`,
96
+ title: baseName,
97
+ tag: "seed:plan",
98
+ relPath: path.join(".aiws", "plan", entry.name),
99
+ });
100
+ }
101
+ }
102
+ for (const source of sources) {
103
+ const absPath = path.join(wsRoot, source.relPath);
104
+ // Skip if the source file doesn't exist
105
+ if (!(await pathExists(absPath)))
106
+ continue;
107
+ // Idempotency: skip if URI already exists and not force
108
+ if (!force && index.memories[source.uri]) {
109
+ result.skipped++;
110
+ result.uris.push(source.uri);
111
+ continue;
112
+ }
113
+ if (dryRun) {
114
+ result.uris.push(source.uri);
115
+ continue;
116
+ }
117
+ // Read file content and format body
118
+ const content = await fs.readFile(absPath, "utf8");
119
+ // For truth files, extract a meaningful title from the first heading
120
+ const title = extractTitle(content) ?? source.title;
121
+ const body = formatBody(title, source.relPath, content);
122
+ // Write memory entry
123
+ await writeMemory(wsRoot, source.uri, body, {
124
+ title,
125
+ tags: [source.tag],
126
+ });
127
+ // Update index so it reflects immediately
128
+ const entry = await readMemory(wsRoot, source.uri);
129
+ await updateIndex(wsRoot, source.uri, {
130
+ title: entry.title,
131
+ domain: entry.domain,
132
+ path: entry.path,
133
+ created: entry.created,
134
+ updated: entry.updated,
135
+ tags: entry.tags,
136
+ disclosure: entry.disclosure,
137
+ });
138
+ result.written++;
139
+ result.uris.push(source.uri);
140
+ }
141
+ return result;
142
+ }
143
+ /**
144
+ * Try to extract the first Markdown heading from content.
145
+ */
146
+ function extractTitle(content) {
147
+ const match = content.match(/^#\s+(.+)$/m);
148
+ return match?.[1]?.trim() ?? null;
149
+ }
150
+ /**
151
+ * Sanitize a filename to a valid URI path segment.
152
+ * URI path must match: [a-z0-9]+(-[a-z0-9]+)*
153
+ */
154
+ function toUriPath(name) {
155
+ const cleaned = name
156
+ .toLowerCase()
157
+ .replace(/_/g, "-")
158
+ .replace(/\./g, "-")
159
+ .replace(/[^a-z0-9-]/g, "")
160
+ .replace(/-+/g, "-")
161
+ .replace(/^-|-$/g, "");
162
+ return cleaned || "untitled";
163
+ }
164
+ //# sourceMappingURL=seed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seed.js","sourceRoot":"","sources":["../../src/memory-bank/seed.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { MemoryEntry, WriteOptions } from "./types.js";
2
+ /**
3
+ * Return the absolute path to the memory-bank directory.
4
+ */
5
+ export declare function getMemoryBankDir(wsRoot: string): string;
6
+ /**
7
+ * Read a memory entry from disk.
8
+ * Supports both new files with YAML frontmatter and legacy plain MD files.
9
+ * Tries the standard path (domain/path.md) first, then falls back to flat path (path.md)
10
+ * for backward compatibility with existing memory-bank files at the root level.
11
+ */
12
+ export declare function readMemory(wsRoot: string, uri: string): Promise<MemoryEntry>;
13
+ /**
14
+ * Write a memory entry to disk with YAML frontmatter.
15
+ */
16
+ export declare function writeMemory(wsRoot: string, uri: string, body: string, options?: WriteOptions): Promise<void>;
17
+ /**
18
+ * Delete a memory file from disk.
19
+ */
20
+ export declare function deleteMemory(wsRoot: string, uri: string): Promise<void>;
21
+ /**
22
+ * Collect all .md files under memory-bank/, returning relative paths from memory-bank/.
23
+ */
24
+ export declare function collectMemoryFiles(wsRoot: string): Promise<string[]>;
@@ -0,0 +1,193 @@
1
+ import path from "node:path";
2
+ import fs from "node:fs/promises";
3
+ import yaml from "js-yaml";
4
+ import { parseUri, uriToRelPath } from "./uri.js";
5
+ import { pathExists, ensureDir } from "../fs.js";
6
+ /**
7
+ * Return the absolute path to the memory-bank directory.
8
+ */
9
+ export function getMemoryBankDir(wsRoot) {
10
+ return path.join(wsRoot, ".aiws", "memory-bank");
11
+ }
12
+ /**
13
+ * Parse frontmatter (YAML between --- delimiters) from markdown content.
14
+ * Returns { frontmatter, body }. If no frontmatter found, frontmatter is {} and body is the full content.
15
+ */
16
+ function parseFrontmatter(content) {
17
+ const trimmed = content.trimStart();
18
+ if (trimmed.startsWith("---")) {
19
+ const endIdx = trimmed.indexOf("---", 3);
20
+ if (endIdx !== -1) {
21
+ const yamlBlock = trimmed.slice(3, endIdx).trim();
22
+ const body = trimmed.slice(endIdx + 3).trim();
23
+ try {
24
+ const parsed = yaml.load(yamlBlock);
25
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
26
+ return { frontmatter: parsed, body };
27
+ }
28
+ }
29
+ catch {
30
+ // If YAML parsing fails, treat as no frontmatter
31
+ }
32
+ }
33
+ }
34
+ return { frontmatter: {}, body: trimmed };
35
+ }
36
+ /**
37
+ * Format frontmatter + body into a markdown string.
38
+ */
39
+ function formatWithFrontmatter(frontmatter, body) {
40
+ const yamlStr = yaml.dump(frontmatter, { lineWidth: 120, noRefs: true });
41
+ return `---\n${yamlStr}---\n${body}\n`;
42
+ }
43
+ /**
44
+ * Extract a title from a memory file path or body.
45
+ */
46
+ function inferTitle(relPath, body) {
47
+ // Try first H1 heading
48
+ const h1Match = body.match(/^#\s+(.+)$/m);
49
+ if (h1Match?.[1])
50
+ return h1Match[1].trim();
51
+ // Fall back to filename without extension
52
+ const basename = path.basename(relPath, ".md");
53
+ // Convert kebab-case to Title Case
54
+ return basename
55
+ .split("-")
56
+ .map((w) => w.charAt(0).toUpperCase() + w.slice(1))
57
+ .join(" ");
58
+ }
59
+ /**
60
+ * Infer domain from a relative path under memory-bank/.
61
+ * Domain is the first path segment, fallback to "general".
62
+ */
63
+ function inferDomain(relPath) {
64
+ const parts = relPath.replaceAll(path.sep, "/").split("/");
65
+ return parts.length > 1 ? parts[0] ?? "general" : "general";
66
+ }
67
+ /**
68
+ * Read a memory entry from disk.
69
+ * Supports both new files with YAML frontmatter and legacy plain MD files.
70
+ * Tries the standard path (domain/path.md) first, then falls back to flat path (path.md)
71
+ * for backward compatibility with existing memory-bank files at the root level.
72
+ */
73
+ export async function readMemory(wsRoot, uri) {
74
+ const { domain, path: uriPath } = parseUri(uri);
75
+ const memDir = getMemoryBankDir(wsRoot);
76
+ const standardRelPath = uriToRelPath(domain, uriPath);
77
+ const standardAbsPath = path.join(memDir, standardRelPath);
78
+ // Try standard path first, fall back to flat file for legacy compatibility
79
+ let absPath;
80
+ let relPath;
81
+ if (await pathExists(standardAbsPath)) {
82
+ absPath = standardAbsPath;
83
+ relPath = standardRelPath;
84
+ }
85
+ else {
86
+ const flatRelPath = `${uriPath}.md`;
87
+ const flatAbsPath = path.join(memDir, flatRelPath);
88
+ if (await pathExists(flatAbsPath)) {
89
+ absPath = flatAbsPath;
90
+ relPath = flatRelPath;
91
+ }
92
+ else {
93
+ throw new Error(`Memory not found: ${uri} (tried ${standardAbsPath} and ${flatAbsPath})`);
94
+ }
95
+ }
96
+ const content = await fs.readFile(absPath, "utf8");
97
+ const { frontmatter, body } = parseFrontmatter(content);
98
+ // Support legacy files without frontmatter
99
+ const title = frontmatter.title ?? inferTitle(relPath, body);
100
+ const created = frontmatter.created ?? new Date().toISOString();
101
+ const updated = frontmatter.updated ?? new Date().toISOString();
102
+ const disclosure = frontmatter.disclosure;
103
+ const rawTags = frontmatter.tags;
104
+ const tags = Array.isArray(rawTags) ? rawTags.map(String) : [];
105
+ const inferredDomain = inferDomain(relPath);
106
+ return {
107
+ uri,
108
+ title,
109
+ domain: inferredDomain,
110
+ path: relPath,
111
+ created,
112
+ updated,
113
+ disclosure,
114
+ tags,
115
+ body,
116
+ frontmatter,
117
+ };
118
+ }
119
+ /**
120
+ * Write a memory entry to disk with YAML frontmatter.
121
+ */
122
+ export async function writeMemory(wsRoot, uri, body, options) {
123
+ const { domain, path: uriPath } = parseUri(uri);
124
+ const relPath = uriToRelPath(domain, uriPath);
125
+ const memDir = getMemoryBankDir(wsRoot);
126
+ const absPath = path.join(memDir, relPath);
127
+ let created = new Date().toISOString();
128
+ const existing = await pathExists(absPath);
129
+ if (existing) {
130
+ try {
131
+ const prev = await readMemory(wsRoot, uri);
132
+ created = prev.created;
133
+ }
134
+ catch {
135
+ // Use current time if we can't read existing
136
+ }
137
+ }
138
+ const frontmatter = {
139
+ title: options?.title ?? inferTitle(relPath, body),
140
+ created,
141
+ updated: new Date().toISOString(),
142
+ };
143
+ if (options?.disclosure) {
144
+ frontmatter.disclosure = options.disclosure;
145
+ }
146
+ if (options?.tags && options.tags.length > 0) {
147
+ frontmatter.tags = options.tags;
148
+ }
149
+ const content = formatWithFrontmatter(frontmatter, body.trim());
150
+ await ensureDir(path.dirname(absPath));
151
+ await fs.writeFile(absPath, content, "utf8");
152
+ }
153
+ /**
154
+ * Delete a memory file from disk.
155
+ */
156
+ export async function deleteMemory(wsRoot, uri) {
157
+ const { domain, path: uriPath } = parseUri(uri);
158
+ const relPath = uriToRelPath(domain, uriPath);
159
+ const absPath = path.join(getMemoryBankDir(wsRoot), relPath);
160
+ if (await pathExists(absPath)) {
161
+ await fs.unlink(absPath);
162
+ }
163
+ }
164
+ /**
165
+ * Collect all .md files under memory-bank/, returning relative paths from memory-bank/.
166
+ */
167
+ export async function collectMemoryFiles(wsRoot) {
168
+ const memDir = getMemoryBankDir(wsRoot);
169
+ if (!(await pathExists(memDir)))
170
+ return [];
171
+ const results = [];
172
+ const stack = [""];
173
+ while (stack.length > 0) {
174
+ const rel = stack.pop();
175
+ const abs = path.join(memDir, rel);
176
+ const entries = await fs.readdir(abs, { withFileTypes: true });
177
+ for (const entry of entries) {
178
+ if (entry.name.startsWith("."))
179
+ continue; // skip dotfiles like .index.yaml
180
+ const entryRel = rel ? `${rel}/${entry.name}` : entry.name;
181
+ const entryAbs = path.join(memDir, entryRel);
182
+ if (entry.isDirectory()) {
183
+ stack.push(entryRel);
184
+ }
185
+ else if (entry.isFile() && entry.name.endsWith(".md")) {
186
+ results.push(entryRel);
187
+ }
188
+ }
189
+ }
190
+ results.sort();
191
+ return results;
192
+ }
193
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/memory-bank/store.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,SAAS,CAAC;AAE3B,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAEjD;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAc;IAC7C,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC;AACnD,CAAC;AAED;;;GAGG;AACH,SAAS,gBAAgB,CAAC,OAAe;IACvC,MAAM,OAAO,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IACpC,IAAI,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9B,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QACzC,IAAI,MAAM,KAAK,CAAC,CAAC,EAAE,CAAC;YAClB,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;YAClD,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YAC9C,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBACpC,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;oBACnE,OAAO,EAAE,WAAW,EAAE,MAAiC,EAAE,IAAI,EAAE,CAAC;gBAClE,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,iDAAiD;YACnD,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAC5C,CAAC;AAED;;GAEG;AACH,SAAS,qBAAqB,CAAC,WAAoC,EAAE,IAAY;IAC/E,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IACzE,OAAO,QAAQ,OAAO,QAAQ,IAAI,IAAI,CAAC;AACzC,CAAC;AAED;;GAEG;AACH,SAAS,UAAU,CAAC,OAAe,EAAE,IAAY;IAC/C,uBAAuB;IACvB,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;IAC1C,IAAI,OAAO,EAAE,CAAC,CAAC,CAAC;QAAE,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC3C,0CAA0C;IAC1C,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAC/C,mCAAmC;IACnC,OAAO,QAAQ;SACZ,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;SAClD,IAAI,CAAC,GAAG,CAAC,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,SAAS,WAAW,CAAC,OAAe;IAClC,MAAM,KAAK,GAAG,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC3D,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;AAC9D,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,MAAc,EAAE,GAAW;IAC1D,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;IAChD,MAAM,MAAM,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACxC,MAAM,eAAe,GAAG,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtD,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAE3D,2EAA2E;IAC3E,IAAI,OAAe,CAAC;IACpB,IAAI,OAAe,CAAC;IACpB,IAAI,MAAM,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;QACtC,OAAO,GAAG,eAAe,CAAC;QAC1B,OAAO,GAAG,eAAe,CAAC;IAC5B,CAAC;SAAM,CAAC;QACN,MAAM,WAAW,GAAG,GAAG,OAAO,KAAK,CAAC;QACpC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;QACnD,IAAI,MAAM,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YAClC,OAAO,GAAG,WAAW,CAAC;YACtB,OAAO,GAAG,WAAW,CAAC;QACxB,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CAAC,qBAAqB,GAAG,WAAW,eAAe,QAAQ,WAAW,GAAG,CAAC,CAAC;QAC5F,CAAC;IACH,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACnD,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAExD,2CAA2C;IAC3C,MAAM,KAAK,GAAI,WAAW,CAAC,KAAgB,IAAI,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACzE,MAAM,OAAO,GAAI,WAAW,CAAC,OAAkB,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC5E,MAAM,OAAO,GAAI,WAAW,CAAC,OAAkB,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC5E,MAAM,UAAU,GAAG,WAAW,CAAC,UAAgC,CAAC;IAChE,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,CAAC;IACjC,MAAM,IAAI,GAAa,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACzE,MAAM,cAAc,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;IAE5C,OAAO;QACL,GAAG;QACH,KAAK;QACL,MAAM,EAAE,cAAc;QACtB,IAAI,EAAE,OAAO;QACb,OAAO;QACP,OAAO;QACP,UAAU;QACV,IAAI;QACJ,IAAI;QACJ,WAAW;KACZ,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,MAAc,EACd,GAAW,EACX,IAAY,EACZ,OAAsB;IAEtB,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;IAChD,MAAM,OAAO,GAAG,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9C,MAAM,MAAM,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACxC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAE3C,IAAI,OAAO,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACvC,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC,CAAC;IAC3C,IAAI,QAAQ,EAAE,CAAC;QACb,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;YAC3C,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QACzB,CAAC;QAAC,MAAM,CAAC;YACP,6CAA6C;QAC/C,CAAC;IACH,CAAC;IAED,MAAM,WAAW,GAA4B;QAC3C,KAAK,EAAE,OAAO,EAAE,KAAK,IAAI,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC;QAClD,OAAO;QACP,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KAClC,CAAC;IAEF,IAAI,OAAO,EAAE,UAAU,EAAE,CAAC;QACxB,WAAW,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IAC9C,CAAC;IACD,IAAI,OAAO,EAAE,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7C,WAAW,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAClC,CAAC;IAED,MAAM,OAAO,GAAG,qBAAqB,CAAC,WAAW,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IAChE,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;IACvC,MAAM,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;AAC/C,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,MAAc,EAAE,GAAW;IAC5D,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;IAChD,MAAM,OAAO,GAAG,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC;IAE7D,IAAI,MAAM,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAC9B,MAAM,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC3B,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,MAAc;IACrD,MAAM,MAAM,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACxC,IAAI,CAAC,CAAC,MAAM,UAAU,CAAC,MAAM,CAAC,CAAC;QAAE,OAAO,EAAE,CAAC;IAE3C,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,KAAK,GAAa,CAAC,EAAE,CAAC,CAAC;IAE7B,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,EAAG,CAAC;QACzB,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QACnC,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAE/D,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,IAAI,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;gBAAE,SAAS,CAAC,iCAAiC;YAC3E,MAAM,QAAQ,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;YAC3D,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;YAC7C,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;gBACxB,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACvB,CAAC;iBAAM,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;gBACxD,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,CAAC,IAAI,EAAE,CAAC;IACf,OAAO,OAAO,CAAC;AACjB,CAAC"}