@fractary/codex 0.12.17 → 0.12.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as path3 from 'path';
2
- import path3__default from 'path';
2
+ import path3__default, { join, dirname } from 'path';
3
3
  import { execFile, execSync } from 'child_process';
4
4
  import micromatch3 from 'micromatch';
5
5
  import { z } from 'zod';
@@ -8,9 +8,16 @@ import fs4__default from 'fs/promises';
8
8
  import { promisify } from 'util';
9
9
  import * as yaml2 from 'js-yaml';
10
10
  import yaml2__default from 'js-yaml';
11
+ import { existsSync, readFileSync, statSync, mkdirSync, writeFileSync, readdirSync } from 'fs';
11
12
 
12
13
  var __defProp = Object.defineProperty;
13
14
  var __getOwnPropNames = Object.getOwnPropertyNames;
15
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
16
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
17
+ }) : x)(function(x) {
18
+ if (typeof require !== "undefined") return require.apply(this, arguments);
19
+ throw Error('Dynamic require of "' + x + '" is not supported');
20
+ });
14
21
  var __esm = (fn, res) => function __init() {
15
22
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
16
23
  };
@@ -516,6 +523,22 @@ var init_built_in = __esm({
516
523
  defaultTtl: TTL.TWO_WEEKS,
517
524
  archiveAfterDays: null,
518
525
  archiveStorage: null
526
+ },
527
+ memory: {
528
+ name: "memory",
529
+ description: "Institutional memory entries (troubleshooting, decisions, patterns)",
530
+ patterns: [
531
+ "memory/**",
532
+ ".fractary/codex/memory/**",
533
+ "**/knowledge-base/**"
534
+ ],
535
+ defaultTtl: TTL.ONE_MONTH,
536
+ archiveAfterDays: 365,
537
+ archiveStorage: "cloud",
538
+ syncPatterns: [
539
+ "memory/**",
540
+ ".fractary/codex/memory/**"
541
+ ]
519
542
  }
520
543
  };
521
544
  DEFAULT_TYPE = {
@@ -4780,7 +4803,7 @@ function createSyncPlan(sourceFiles, targetFiles, options, config) {
4780
4803
  hash: sourceFile.hash
4781
4804
  });
4782
4805
  } else {
4783
- const isDifferent = sourceFile.hash !== targetFile.hash;
4806
+ const isDifferent = sourceFile.hash !== void 0 && targetFile.hash !== void 0 ? sourceFile.hash !== targetFile.hash : sourceFile.size !== targetFile.size;
4784
4807
  if (isDifferent) {
4785
4808
  if (options.force) {
4786
4809
  files.push({
@@ -6701,6 +6724,583 @@ function createHealthChecker(options = {}) {
6701
6724
  return new HealthChecker(options);
6702
6725
  }
6703
6726
 
6727
+ // src/memory/types.ts
6728
+ var MEMORY_TYPE_PREFIXES = {
6729
+ "troubleshooting": "TS",
6730
+ "architectural-decision": "AD",
6731
+ "performance": "PF",
6732
+ "pattern": "PT",
6733
+ "integration": "IN",
6734
+ "convention": "CV"
6735
+ };
6736
+ var DEFAULT_MEMORY_CONFIG = {
6737
+ memoryDir: ".fractary/codex/memory",
6738
+ cacheDir: ".fractary/codex/cache",
6739
+ syncedMemoryPatterns: [
6740
+ ".fractary/codex/cache/projects/*/*/.fractary/codex/memory/**/*.md"
6741
+ ]
6742
+ };
6743
+ function parseFrontmatter(content) {
6744
+ const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
6745
+ if (!match) return null;
6746
+ const yaml3 = match[1];
6747
+ const frontmatter = {};
6748
+ let currentKey = "";
6749
+ let inArray = false;
6750
+ let arrayValues = [];
6751
+ for (const line of yaml3.split("\n")) {
6752
+ const trimmed = line.trim();
6753
+ if (!trimmed || trimmed.startsWith("#")) continue;
6754
+ if (trimmed.startsWith("- ") && inArray) {
6755
+ let value = trimmed.slice(2).trim();
6756
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
6757
+ value = value.slice(1, -1);
6758
+ }
6759
+ arrayValues.push(value);
6760
+ continue;
6761
+ }
6762
+ if (inArray && currentKey) {
6763
+ frontmatter[currentKey] = arrayValues;
6764
+ inArray = false;
6765
+ arrayValues = [];
6766
+ currentKey = "";
6767
+ }
6768
+ const kvMatch = trimmed.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*:\s*(.*)$/);
6769
+ if (kvMatch) {
6770
+ const key = kvMatch[1];
6771
+ let value = kvMatch[2].trim();
6772
+ if (value === "" || value === "[]") {
6773
+ currentKey = key;
6774
+ inArray = true;
6775
+ arrayValues = [];
6776
+ if (value === "[]") {
6777
+ frontmatter[key] = [];
6778
+ inArray = false;
6779
+ currentKey = "";
6780
+ }
6781
+ continue;
6782
+ }
6783
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
6784
+ value = value.slice(1, -1);
6785
+ }
6786
+ if (value === "true") frontmatter[key] = true;
6787
+ else if (value === "false") frontmatter[key] = false;
6788
+ else if (value === "null") frontmatter[key] = null;
6789
+ else if (/^-?\d+$/.test(value)) frontmatter[key] = parseInt(value, 10);
6790
+ else if (/^-?\d+\.\d+$/.test(value)) frontmatter[key] = parseFloat(value);
6791
+ else frontmatter[key] = value;
6792
+ }
6793
+ }
6794
+ if (inArray && currentKey) {
6795
+ frontmatter[currentKey] = arrayValues;
6796
+ }
6797
+ if (!frontmatter.title && !frontmatter.memory_id && !frontmatter.id) {
6798
+ return null;
6799
+ }
6800
+ return frontmatter;
6801
+ }
6802
+ function findMarkdownFiles(dir) {
6803
+ const results = [];
6804
+ if (!existsSync(dir)) return results;
6805
+ try {
6806
+ const entries = readdirSync(dir, { withFileTypes: true });
6807
+ for (const entry of entries) {
6808
+ const fullPath = join(dir, entry.name);
6809
+ if (entry.isDirectory()) {
6810
+ results.push(...findMarkdownFiles(fullPath));
6811
+ } else if (entry.isFile() && entry.name.endsWith(".md")) {
6812
+ results.push(fullPath);
6813
+ }
6814
+ }
6815
+ } catch {
6816
+ }
6817
+ return results;
6818
+ }
6819
+ function findSyncedMemoryFiles(cacheDir) {
6820
+ const results = [];
6821
+ const projectsDir = join(cacheDir, "projects");
6822
+ if (!existsSync(projectsDir)) return results;
6823
+ try {
6824
+ const orgs = readdirSync(projectsDir, { withFileTypes: true });
6825
+ for (const org of orgs) {
6826
+ if (!org.isDirectory()) continue;
6827
+ const orgDir = join(projectsDir, org.name);
6828
+ const projects = readdirSync(orgDir, { withFileTypes: true });
6829
+ for (const project of projects) {
6830
+ if (!project.isDirectory()) continue;
6831
+ const memoryDir = join(orgDir, project.name, ".fractary", "codex", "memory");
6832
+ if (!existsSync(memoryDir)) continue;
6833
+ const files = findMarkdownFiles(memoryDir);
6834
+ const source = `${org.name}/${project.name}`;
6835
+ for (const file of files) {
6836
+ results.push({ path: file, source });
6837
+ }
6838
+ }
6839
+ }
6840
+ } catch {
6841
+ }
6842
+ return results;
6843
+ }
6844
+ var MemorySearcher = class {
6845
+ config;
6846
+ projectRoot;
6847
+ constructor(projectRoot, config) {
6848
+ this.projectRoot = projectRoot;
6849
+ this.config = { ...DEFAULT_MEMORY_CONFIG, ...config };
6850
+ }
6851
+ /**
6852
+ * Search memories with cascading scope
6853
+ *
6854
+ * 1. Project memories (highest priority)
6855
+ * 2. Synced memories from other projects
6856
+ */
6857
+ search(query) {
6858
+ const index = this.loadOrRebuildIndex();
6859
+ let candidates = index.entries.filter((entry) => {
6860
+ const fm = entry.frontmatter;
6861
+ if (query.memory_type && fm.memory_type !== query.memory_type) return false;
6862
+ if (query.category && fm.category !== query.category) return false;
6863
+ if (query.phase) {
6864
+ const phases = fm.phases || (fm.phase ? [fm.phase] : []);
6865
+ if (!phases.includes(query.phase)) return false;
6866
+ }
6867
+ if (query.agent) {
6868
+ const agents = fm.agents || (fm.agent ? [fm.agent] : []);
6869
+ if (!agents.includes(query.agent)) return false;
6870
+ }
6871
+ if (query.tags && query.tags.length > 0) {
6872
+ if (!fm.tags || !query.tags.some((t) => fm.tags.includes(t))) return false;
6873
+ }
6874
+ if (query.status && fm.status !== query.status) return false;
6875
+ return true;
6876
+ });
6877
+ const scored = candidates.map((entry) => ({
6878
+ entry,
6879
+ score: this.calculateRelevanceScore(entry, query),
6880
+ source: entry.source,
6881
+ filePath: entry.file_path
6882
+ }));
6883
+ scored.sort((a, b) => b.score - a.score);
6884
+ const limit = query.limit || 20;
6885
+ return scored.slice(0, limit);
6886
+ }
6887
+ /**
6888
+ * Calculate relevance score for a memory entry
6889
+ */
6890
+ calculateRelevanceScore(entry, query) {
6891
+ const fm = entry.frontmatter;
6892
+ let score = 0;
6893
+ score += Math.min((fm.success_count || 0) * 2, 40);
6894
+ if (fm.status === "verified" || fm.verified === true) {
6895
+ score += 10;
6896
+ }
6897
+ if (query.agent) {
6898
+ const agents = fm.agents || (fm.agent ? [fm.agent] : []);
6899
+ if (agents.includes(query.agent)) {
6900
+ score += 20;
6901
+ }
6902
+ }
6903
+ if (query.phase) {
6904
+ const phases = fm.phases || (fm.phase ? [fm.phase] : []);
6905
+ if (phases.includes(query.phase)) {
6906
+ score += 10;
6907
+ }
6908
+ }
6909
+ score += entry.source === "local" ? 10 : 5;
6910
+ if (query.text) {
6911
+ const queryLower = query.text.toLowerCase();
6912
+ if (fm.symptoms && fm.symptoms.some((s) => s.toLowerCase().includes(queryLower) || queryLower.includes(s.toLowerCase()))) {
6913
+ score += 15;
6914
+ }
6915
+ if (fm.keywords && fm.keywords.some((k) => queryLower.includes(k.toLowerCase()))) {
6916
+ score += 5;
6917
+ }
6918
+ if (fm.description && fm.description.toLowerCase().includes(queryLower)) {
6919
+ score += 8;
6920
+ }
6921
+ if (fm.title && fm.title.toLowerCase().includes(queryLower)) {
6922
+ score += 5;
6923
+ }
6924
+ }
6925
+ return score;
6926
+ }
6927
+ /**
6928
+ * Load the frontmatter index from cache, or rebuild if stale
6929
+ */
6930
+ loadOrRebuildIndex() {
6931
+ const indexPath = join(this.projectRoot, this.config.cacheDir, "memory-index.json");
6932
+ let existingIndex = null;
6933
+ if (existsSync(indexPath)) {
6934
+ try {
6935
+ const raw = readFileSync(indexPath, "utf-8");
6936
+ existingIndex = JSON.parse(raw);
6937
+ } catch {
6938
+ existingIndex = null;
6939
+ }
6940
+ }
6941
+ const memoryDir = join(this.projectRoot, this.config.memoryDir);
6942
+ const localFiles = findMarkdownFiles(memoryDir);
6943
+ const syncedFiles = findSyncedMemoryFiles(join(this.projectRoot, this.config.cacheDir));
6944
+ const needsRebuild = !existingIndex || this.isIndexStale(existingIndex, localFiles, syncedFiles.map((f) => f.path));
6945
+ if (!needsRebuild && existingIndex) {
6946
+ return existingIndex;
6947
+ }
6948
+ return this.rebuildIndex(localFiles, syncedFiles, indexPath);
6949
+ }
6950
+ /**
6951
+ * Check if the index is stale (any source file newer than index)
6952
+ */
6953
+ isIndexStale(index, localFiles, syncedFilePaths) {
6954
+ const indexTime = new Date(index.built_at).getTime();
6955
+ const allFiles = [...localFiles, ...syncedFilePaths];
6956
+ for (const file of allFiles) {
6957
+ try {
6958
+ const stat = statSync(file);
6959
+ if (stat.mtimeMs > indexTime) return true;
6960
+ } catch {
6961
+ }
6962
+ }
6963
+ const indexedPaths = new Set(index.entries.map((e) => e.file_path));
6964
+ for (const file of allFiles) {
6965
+ if (!indexedPaths.has(file)) return true;
6966
+ }
6967
+ return false;
6968
+ }
6969
+ /**
6970
+ * Rebuild the frontmatter index from all memory sources
6971
+ */
6972
+ rebuildIndex(localFiles, syncedFiles, indexPath) {
6973
+ const entries = [];
6974
+ for (const file of localFiles) {
6975
+ const entry = this.indexFile(file, "local");
6976
+ if (entry) entries.push(entry);
6977
+ }
6978
+ for (const { path: path9, source } of syncedFiles) {
6979
+ const entry = this.indexFile(path9, source);
6980
+ if (entry) entries.push(entry);
6981
+ }
6982
+ const index = {
6983
+ version: 1,
6984
+ built_at: (/* @__PURE__ */ new Date()).toISOString(),
6985
+ entries
6986
+ };
6987
+ try {
6988
+ const dir = dirname(indexPath);
6989
+ if (!existsSync(dir)) {
6990
+ mkdirSync(dir, { recursive: true });
6991
+ }
6992
+ writeFileSync(indexPath, JSON.stringify(index, null, 2), "utf-8");
6993
+ } catch {
6994
+ }
6995
+ return index;
6996
+ }
6997
+ /**
6998
+ * Index a single memory file by parsing its frontmatter
6999
+ */
7000
+ indexFile(filePath, source) {
7001
+ try {
7002
+ const content = readFileSync(filePath, "utf-8");
7003
+ const frontmatter = parseFrontmatter(content);
7004
+ if (!frontmatter) return null;
7005
+ const stat = statSync(filePath);
7006
+ return {
7007
+ file_path: filePath,
7008
+ mtime: stat.mtime.toISOString(),
7009
+ source,
7010
+ frontmatter
7011
+ };
7012
+ } catch {
7013
+ return null;
7014
+ }
7015
+ }
7016
+ /**
7017
+ * Invalidate the index cache (call after writing memories)
7018
+ */
7019
+ invalidateIndex() {
7020
+ const indexPath = join(this.projectRoot, this.config.cacheDir, "memory-index.json");
7021
+ try {
7022
+ if (existsSync(indexPath)) {
7023
+ const { unlinkSync } = __require("fs");
7024
+ unlinkSync(indexPath);
7025
+ }
7026
+ } catch {
7027
+ }
7028
+ }
7029
+ };
7030
+ function sanitizeSlug(text, maxLength = 50) {
7031
+ return text.toLowerCase().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, maxLength);
7032
+ }
7033
+ function serializeFrontmatter(fm) {
7034
+ const lines = ["---"];
7035
+ for (const [key, value] of Object.entries(fm)) {
7036
+ if (value === void 0 || value === null) continue;
7037
+ if (Array.isArray(value)) {
7038
+ if (value.length === 0) {
7039
+ lines.push(`${key}: []`);
7040
+ } else {
7041
+ lines.push(`${key}:`);
7042
+ for (const item of value) {
7043
+ const itemStr = typeof item === "string" && (item.includes(":") || item.includes('"') || item.includes("'")) ? `"${item.replace(/"/g, '\\"')}"` : String(item);
7044
+ lines.push(` - ${itemStr}`);
7045
+ }
7046
+ }
7047
+ } else if (typeof value === "string") {
7048
+ if (value.includes(":") || value.includes('"') || value.includes("'") || value.includes("\n")) {
7049
+ lines.push(`${key}: "${value.replace(/"/g, '\\"')}"`);
7050
+ } else {
7051
+ lines.push(`${key}: ${value}`);
7052
+ }
7053
+ } else {
7054
+ lines.push(`${key}: ${value}`);
7055
+ }
7056
+ }
7057
+ lines.push("---");
7058
+ return lines.join("\n");
7059
+ }
7060
+ function getNextSequence(typeDir, prefix) {
7061
+ if (!existsSync(typeDir)) return 1;
7062
+ let maxSeq = 0;
7063
+ try {
7064
+ const files = readdirSync(typeDir);
7065
+ const pattern = new RegExp(`^MEM-${prefix}-(\\d+)-`);
7066
+ for (const file of files) {
7067
+ const match = file.match(pattern);
7068
+ if (match) {
7069
+ const seq = parseInt(match[1], 10);
7070
+ if (seq > maxSeq) maxSeq = seq;
7071
+ }
7072
+ }
7073
+ } catch {
7074
+ }
7075
+ return maxSeq + 1;
7076
+ }
7077
+ function calculateSimilarity(existing, newEntry) {
7078
+ let score = 0;
7079
+ let factors = 0;
7080
+ if (existing.title && newEntry.title) {
7081
+ const existingWords = new Set(existing.title.toLowerCase().split(/\s+/));
7082
+ const newWords = new Set(newEntry.title.toLowerCase().split(/\s+/));
7083
+ const intersection = [...existingWords].filter((w) => newWords.has(w)).length;
7084
+ const union = (/* @__PURE__ */ new Set([...existingWords, ...newWords])).size;
7085
+ score += union > 0 ? intersection / union : 0;
7086
+ factors++;
7087
+ }
7088
+ if (existing.symptoms && newEntry.symptoms) {
7089
+ const existingSymptoms = new Set(existing.symptoms.map((s) => s.toLowerCase()));
7090
+ const newSymptoms = new Set(newEntry.symptoms.map((s) => s.toLowerCase()));
7091
+ const intersection = [...existingSymptoms].filter((s) => newSymptoms.has(s)).length;
7092
+ const union = (/* @__PURE__ */ new Set([...existingSymptoms, ...newSymptoms])).size;
7093
+ score += union > 0 ? intersection / union : 0;
7094
+ factors++;
7095
+ }
7096
+ if (existing.category && newEntry.category) {
7097
+ score += existing.category === newEntry.category ? 1 : 0;
7098
+ factors++;
7099
+ }
7100
+ if (existing.memory_type && newEntry.memory_type) {
7101
+ score += existing.memory_type === newEntry.memory_type ? 1 : 0;
7102
+ factors++;
7103
+ }
7104
+ return factors > 0 ? score / factors : 0;
7105
+ }
7106
+ var MemoryWriter = class {
7107
+ config;
7108
+ projectRoot;
7109
+ searcher;
7110
+ constructor(projectRoot, config) {
7111
+ this.projectRoot = projectRoot;
7112
+ this.config = { ...DEFAULT_MEMORY_CONFIG, ...config };
7113
+ this.searcher = new MemorySearcher(projectRoot, config);
7114
+ }
7115
+ /**
7116
+ * Write a new memory entry
7117
+ *
7118
+ * Handles ID generation, deduplication check, file creation,
7119
+ * and index invalidation.
7120
+ */
7121
+ write(options) {
7122
+ const { memory_type, title, description, body, frontmatter } = options;
7123
+ const dupResult = this.checkDuplicate(frontmatter, memory_type);
7124
+ if (dupResult) {
7125
+ return {
7126
+ memory_id: dupResult.memory_id,
7127
+ file_path: dupResult.file_path,
7128
+ deduplicated: true,
7129
+ existing_id: dupResult.memory_id
7130
+ };
7131
+ }
7132
+ const prefix = MEMORY_TYPE_PREFIXES[memory_type];
7133
+ const typeDir = join(this.projectRoot, this.config.memoryDir, memory_type);
7134
+ const seq = getNextSequence(typeDir, prefix);
7135
+ const slug = sanitizeSlug(title);
7136
+ const memoryId = `MEM-${prefix}-${String(seq).padStart(3, "0")}-${slug}`;
7137
+ const fullFrontmatter = {
7138
+ title,
7139
+ description,
7140
+ memory_type,
7141
+ memory_id: memoryId,
7142
+ status: "draft",
7143
+ created: (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
7144
+ verified: false,
7145
+ success_count: 0,
7146
+ ...frontmatter
7147
+ };
7148
+ fullFrontmatter.memory_type = memory_type;
7149
+ fullFrontmatter.memory_id = memoryId;
7150
+ const fileContent = `${serializeFrontmatter(fullFrontmatter)}
7151
+
7152
+ ${body}
7153
+ `;
7154
+ const fileName = `${memoryId}.md`;
7155
+ const filePath = join(typeDir, fileName);
7156
+ if (!existsSync(typeDir)) {
7157
+ mkdirSync(typeDir, { recursive: true });
7158
+ }
7159
+ writeFileSync(filePath, fileContent, "utf-8");
7160
+ this.searcher.invalidateIndex();
7161
+ return {
7162
+ memory_id: memoryId,
7163
+ file_path: filePath,
7164
+ deduplicated: false
7165
+ };
7166
+ }
7167
+ /**
7168
+ * Update an existing memory's frontmatter
7169
+ */
7170
+ update(memoryId, changes) {
7171
+ const filePath = this.findMemoryFile(memoryId);
7172
+ if (!filePath) {
7173
+ throw new Error(`Memory not found: ${memoryId}`);
7174
+ }
7175
+ const content = readFileSync(filePath, "utf-8");
7176
+ const fmMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/);
7177
+ if (!fmMatch) {
7178
+ throw new Error(`Invalid memory file format: ${filePath}`);
7179
+ }
7180
+ const existingContent = fmMatch[1];
7181
+ const bodyContent = fmMatch[2];
7182
+ const lines = existingContent.split("\n");
7183
+ const updatedFm = {};
7184
+ let currentKey = "";
7185
+ let inArray = false;
7186
+ let arrayValues = [];
7187
+ for (const line of lines) {
7188
+ const trimmed = line.trim();
7189
+ if (!trimmed || trimmed.startsWith("#")) continue;
7190
+ if (trimmed.startsWith("- ") && inArray) {
7191
+ let value = trimmed.slice(2).trim();
7192
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
7193
+ value = value.slice(1, -1);
7194
+ }
7195
+ arrayValues.push(value);
7196
+ continue;
7197
+ }
7198
+ if (inArray && currentKey) {
7199
+ updatedFm[currentKey] = arrayValues;
7200
+ inArray = false;
7201
+ arrayValues = [];
7202
+ currentKey = "";
7203
+ }
7204
+ const kvMatch = trimmed.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*:\s*(.*)$/);
7205
+ if (kvMatch) {
7206
+ const key = kvMatch[1];
7207
+ let value = kvMatch[2].trim();
7208
+ if (value === "" || value === "[]") {
7209
+ currentKey = key;
7210
+ inArray = true;
7211
+ arrayValues = [];
7212
+ if (value === "[]") {
7213
+ updatedFm[key] = [];
7214
+ inArray = false;
7215
+ currentKey = "";
7216
+ }
7217
+ continue;
7218
+ }
7219
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
7220
+ value = value.slice(1, -1);
7221
+ }
7222
+ if (value === "true") updatedFm[key] = true;
7223
+ else if (value === "false") updatedFm[key] = false;
7224
+ else if (value === "null") updatedFm[key] = null;
7225
+ else if (/^-?\d+$/.test(value)) updatedFm[key] = parseInt(value, 10);
7226
+ else if (/^-?\d+\.\d+$/.test(value)) updatedFm[key] = parseFloat(value);
7227
+ else updatedFm[key] = value;
7228
+ }
7229
+ }
7230
+ if (inArray && currentKey) {
7231
+ updatedFm[currentKey] = arrayValues;
7232
+ }
7233
+ const merged = { ...updatedFm, ...changes, updated: (/* @__PURE__ */ new Date()).toISOString().split("T")[0] };
7234
+ const newContent = `${serializeFrontmatter(merged)}
7235
+
7236
+ ${bodyContent}`;
7237
+ writeFileSync(filePath, newContent, "utf-8");
7238
+ this.searcher.invalidateIndex();
7239
+ }
7240
+ /**
7241
+ * Deprecate a memory
7242
+ */
7243
+ deprecate(memoryId, reason, supersededBy) {
7244
+ const changes = {
7245
+ status: "deprecated",
7246
+ deprecated_reason: reason
7247
+ };
7248
+ if (supersededBy) {
7249
+ changes.superseded_by = supersededBy;
7250
+ }
7251
+ this.update(memoryId, changes);
7252
+ }
7253
+ /**
7254
+ * Check for duplicate memories (>0.95 similarity)
7255
+ */
7256
+ checkDuplicate(frontmatter, memoryType) {
7257
+ const results = this.searcher.search({
7258
+ memory_type: memoryType,
7259
+ category: frontmatter.category,
7260
+ limit: 10
7261
+ });
7262
+ for (const result of results) {
7263
+ const similarity = calculateSimilarity(result.entry.frontmatter, frontmatter);
7264
+ if (similarity > 0.95) {
7265
+ return {
7266
+ memory_id: result.entry.frontmatter.memory_id,
7267
+ file_path: result.filePath
7268
+ };
7269
+ }
7270
+ }
7271
+ return null;
7272
+ }
7273
+ /**
7274
+ * Find a memory file by its ID
7275
+ */
7276
+ findMemoryFile(memoryId) {
7277
+ const memoryDir = join(this.projectRoot, this.config.memoryDir);
7278
+ if (!existsSync(memoryDir)) return null;
7279
+ const files = findMarkdownFilesRecursive(memoryDir);
7280
+ for (const file of files) {
7281
+ if (file.includes(memoryId)) return file;
7282
+ }
7283
+ return null;
7284
+ }
7285
+ };
7286
+ function findMarkdownFilesRecursive(dir) {
7287
+ const results = [];
7288
+ if (!existsSync(dir)) return results;
7289
+ try {
7290
+ const entries = readdirSync(dir, { withFileTypes: true });
7291
+ for (const entry of entries) {
7292
+ const fullPath = join(dir, entry.name);
7293
+ if (entry.isDirectory()) {
7294
+ results.push(...findMarkdownFilesRecursive(fullPath));
7295
+ } else if (entry.isFile() && entry.name.endsWith(".md")) {
7296
+ results.push(fullPath);
7297
+ }
7298
+ }
7299
+ } catch {
7300
+ }
7301
+ return results;
7302
+ }
7303
+
6704
7304
  // src/client/codex-client.ts
6705
7305
  var CodexClient = class _CodexClient {
6706
7306
  cache;
@@ -7011,6 +7611,6 @@ async function createCodexClient(options) {
7011
7611
  return CodexClient.create(options);
7012
7612
  }
7013
7613
 
7014
- export { AutoSyncPatternSchema, BUILT_IN_TYPES, CODEX_DIRECTORIES, CODEX_URI_PREFIX, CONFIG_SCHEMA_VERSION, CacheManager, CachePersistence, CodexClient, CodexConfigSchema, CodexError, CommonRules, ConfigManager, ConfigurationError, CustomTypeSchema, DEFAULT_CACHE_DIR, DEFAULT_FETCH_OPTIONS, DEFAULT_FRACTARY_GITIGNORE, DEFAULT_GLOBAL_EXCLUDES, DEFAULT_MIGRATION_OPTIONS, DEFAULT_PERMISSION_CONFIG, DEFAULT_SYNC_CONFIG, DEFAULT_TYPE, FilePluginFileNotFoundError, FilePluginStorage, GitHubStorage, HealthChecker, HttpStorage, LEGACY_PATTERNS, LEGACY_REF_PREFIX, LocalStorage, MetadataSchema, PERMISSION_LEVEL_ORDER, PermissionDeniedError, PermissionManager, STANDARD_DIRECTORIES, SYNC_PATTERN_PRESETS, StorageManager, SyncManager, SyncRulesSchema, TTL, TypeRegistry, TypesConfigSchema, ValidationError, buildUri, calculateCachePath, calculateContentHash, convertLegacyReference, convertLegacyReferences, convertToUri, createCacheEntry, createCacheManager, createCachePersistence, createCodexClient, createConfigManager, createDefaultRegistry, createEmptyModernConfig, createEmptySyncPlan, createGitHubStorage, createHealthChecker, createHttpStorage, createLocalStorage, createPermissionManager, createRule, createRulesFromPatterns, createStorageManager, createSyncManager, createSyncPlan, deserializeCacheEntry, detectContentType, detectCurrentProject, detectOrganizationFromGit, detectProjectName, detectVersion, discoverCodexRepo, ensureCachePathIgnored, ensureDirectoryStructure, estimateSyncTime, evaluatePath, evaluatePaths, evaluatePatterns, evaluatePermission, evaluatePermissions, expandEnvVars, expandEnvVarsInConfig, extendType, extractEnvVarNames, extractOrgFromRepoName, extractRawFrontmatter, filterByPatterns, filterByPermission, filterPlanOperations, filterSyncablePaths, findLegacyReferences, formatBytes2 as formatBytes, formatDuration, formatPlanSummary, formatSeconds, generateCodexSection, generateMigrationReport, generateReferenceMigrationSummary, generateSyncConfigFromPreset, generateUnifiedConfig, getBuiltInType, getBuiltInTypeNames, getCacheEntryAge, getCacheEntryStatus, getCurrentContext, getCustomSyncDestinations, getDefaultCacheManager, getDefaultConfig, getDefaultDirectories, getDefaultPermissionManager, getDefaultRules, getDefaultStorageManager, getDirectory, getExtension, getFilename, getMigrationRequirements, getPlanStats, getRelativeCachePath, getRemainingTtl, getSyncPreset, getSyncPresetNames, getTargetRepos, hasContentChanged, hasEnvVars, hasFrontmatter, hasLegacyReferences, hasPermission as hasPermissionLevel, installMcpServer, isBuiltInType, isCacheEntryFresh, isCacheEntryValid, isCurrentProjectUri, isLegacyConfig, isLegacyReference, isModernConfig, isAllowed as isPermissionAllowed, isUnifiedConfig, isValidDuration, isValidSize, isValidUri, levelGrants, loadConfig, loadCustomTypes, matchAnyPattern, matchPattern, maxLevel, mergeFetchOptions, mergeRules, mergeTypes, mergeUnifiedConfigs, migrateConfig, migrateFileReferences, minLevel, needsMigration, normalizeCachePath, parseCustomDestination, parseDuration, parseMetadata, parseReference, parseSize, parseTtl, readCodexConfig, readUnifiedConfig, readUnifiedConfig2 as readYamlUnifiedConfig, resolveOrganization, resolveReference, resolveReferences, ruleMatchesAction, ruleMatchesContext, ruleMatchesPath, sanitizeForS3BucketName, sanitizePath, serializeCacheEntry, setDefaultCacheManager, setDefaultPermissionManager, setDefaultStorageManager, shouldSyncToRepo, substitutePatternPlaceholders, summarizeEvaluations, touchCacheEntry, validateCustomTypes, validateMetadata, validateMigratedConfig, validateNameFormat, validateOrg, validateOrganizationName, validatePath, validateRules2 as validatePermissionRules, validateProject, validateRepositoryName, validateRules, validateUri, writeUnifiedConfig };
7614
+ export { AutoSyncPatternSchema, BUILT_IN_TYPES, CODEX_DIRECTORIES, CODEX_URI_PREFIX, CONFIG_SCHEMA_VERSION, CacheManager, CachePersistence, CodexClient, CodexConfigSchema, CodexError, CommonRules, ConfigManager, ConfigurationError, CustomTypeSchema, DEFAULT_CACHE_DIR, DEFAULT_FETCH_OPTIONS, DEFAULT_FRACTARY_GITIGNORE, DEFAULT_GLOBAL_EXCLUDES, DEFAULT_MEMORY_CONFIG, DEFAULT_MIGRATION_OPTIONS, DEFAULT_PERMISSION_CONFIG, DEFAULT_SYNC_CONFIG, DEFAULT_TYPE, FilePluginFileNotFoundError, FilePluginStorage, GitHubStorage, HealthChecker, HttpStorage, LEGACY_PATTERNS, LEGACY_REF_PREFIX, LocalStorage, MEMORY_TYPE_PREFIXES, MemorySearcher, MemoryWriter, MetadataSchema, PERMISSION_LEVEL_ORDER, PermissionDeniedError, PermissionManager, STANDARD_DIRECTORIES, SYNC_PATTERN_PRESETS, StorageManager, SyncManager, SyncRulesSchema, TTL, TypeRegistry, TypesConfigSchema, ValidationError, buildUri, calculateCachePath, calculateContentHash, convertLegacyReference, convertLegacyReferences, convertToUri, createCacheEntry, createCacheManager, createCachePersistence, createCodexClient, createConfigManager, createDefaultRegistry, createEmptyModernConfig, createEmptySyncPlan, createGitHubStorage, createHealthChecker, createHttpStorage, createLocalStorage, createPermissionManager, createRule, createRulesFromPatterns, createStorageManager, createSyncManager, createSyncPlan, deserializeCacheEntry, detectContentType, detectCurrentProject, detectOrganizationFromGit, detectProjectName, detectVersion, discoverCodexRepo, ensureCachePathIgnored, ensureDirectoryStructure, estimateSyncTime, evaluatePath, evaluatePaths, evaluatePatterns, evaluatePermission, evaluatePermissions, expandEnvVars, expandEnvVarsInConfig, extendType, extractEnvVarNames, extractOrgFromRepoName, extractRawFrontmatter, filterByPatterns, filterByPermission, filterPlanOperations, filterSyncablePaths, findLegacyReferences, formatBytes2 as formatBytes, formatDuration, formatPlanSummary, formatSeconds, generateCodexSection, generateMigrationReport, generateReferenceMigrationSummary, generateSyncConfigFromPreset, generateUnifiedConfig, getBuiltInType, getBuiltInTypeNames, getCacheEntryAge, getCacheEntryStatus, getCurrentContext, getCustomSyncDestinations, getDefaultCacheManager, getDefaultConfig, getDefaultDirectories, getDefaultPermissionManager, getDefaultRules, getDefaultStorageManager, getDirectory, getExtension, getFilename, getMigrationRequirements, getPlanStats, getRelativeCachePath, getRemainingTtl, getSyncPreset, getSyncPresetNames, getTargetRepos, hasContentChanged, hasEnvVars, hasFrontmatter, hasLegacyReferences, hasPermission as hasPermissionLevel, installMcpServer, isBuiltInType, isCacheEntryFresh, isCacheEntryValid, isCurrentProjectUri, isLegacyConfig, isLegacyReference, isModernConfig, isAllowed as isPermissionAllowed, isUnifiedConfig, isValidDuration, isValidSize, isValidUri, levelGrants, loadConfig, loadCustomTypes, matchAnyPattern, matchPattern, maxLevel, mergeFetchOptions, mergeRules, mergeTypes, mergeUnifiedConfigs, migrateConfig, migrateFileReferences, minLevel, needsMigration, normalizeCachePath, parseCustomDestination, parseDuration, parseMetadata, parseReference, parseSize, parseTtl, readCodexConfig, readUnifiedConfig, readUnifiedConfig2 as readYamlUnifiedConfig, resolveOrganization, resolveReference, resolveReferences, ruleMatchesAction, ruleMatchesContext, ruleMatchesPath, sanitizeForS3BucketName, sanitizePath, serializeCacheEntry, setDefaultCacheManager, setDefaultPermissionManager, setDefaultStorageManager, shouldSyncToRepo, substitutePatternPlaceholders, summarizeEvaluations, touchCacheEntry, validateCustomTypes, validateMetadata, validateMigratedConfig, validateNameFormat, validateOrg, validateOrganizationName, validatePath, validateRules2 as validatePermissionRules, validateProject, validateRepositoryName, validateRules, validateUri, writeUnifiedConfig };
7015
7615
  //# sourceMappingURL=index.js.map
7016
7616
  //# sourceMappingURL=index.js.map