clawvault 3.0.0-beta.1 → 3.0.0-beta.2

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.
@@ -221,4 +221,24 @@ export function registerCoreCommands(
221
221
  process.exit(1);
222
222
  }
223
223
  });
224
+ // === PLUGIN-PATH ===
225
+ program
226
+ .command('plugin-path')
227
+ .description('Print the OpenClaw plugin path for configuration')
228
+ .action(() => {
229
+ const pluginDir = path.dirname(path.dirname(new URL(import.meta.url).pathname));
230
+ const pluginPath = path.join(pluginDir, 'dist', 'plugin', 'index.js');
231
+ if (fs.existsSync(pluginPath)) {
232
+ console.log(pluginPath);
233
+ } else {
234
+ // Dev mode — use source
235
+ const srcPath = path.join(pluginDir, 'src', 'plugin', 'index.ts');
236
+ if (fs.existsSync(srcPath)) {
237
+ console.log(srcPath);
238
+ } else {
239
+ console.error('Plugin not found. Run: npm run build');
240
+ process.exit(1);
241
+ }
242
+ }
243
+ });
224
244
  }
@@ -800,54 +800,6 @@ function importToVault(vaultPath, extracted, force) {
800
800
  }
801
801
  return summary;
802
802
  }
803
- function printImportSummary(summary) {
804
- const totalCreated = summary.created.people.length + summary.created.preferences.length + summary.created.decisions.length + summary.created.tasks.length;
805
- const totalSkipped = summary.skipped.people.length + summary.skipped.preferences.length + summary.skipped.decisions.length + summary.skipped.tasks.length;
806
- console.log("\n\u{1F4E5} Memory Import Summary");
807
- console.log("\u2500".repeat(40));
808
- if (summary.created.people.length > 0) {
809
- console.log(`\u2713 People (${summary.created.people.length}):`);
810
- for (const name of summary.created.people.slice(0, 5)) {
811
- console.log(` - ${name}`);
812
- }
813
- if (summary.created.people.length > 5) {
814
- console.log(` ... and ${summary.created.people.length - 5} more`);
815
- }
816
- }
817
- if (summary.created.preferences.length > 0) {
818
- console.log(`\u2713 Preferences (${summary.created.preferences.length}):`);
819
- for (const pref of summary.created.preferences.slice(0, 5)) {
820
- console.log(` - ${pref}`);
821
- }
822
- if (summary.created.preferences.length > 5) {
823
- console.log(` ... and ${summary.created.preferences.length - 5} more`);
824
- }
825
- }
826
- if (summary.created.decisions.length > 0) {
827
- console.log(`\u2713 Decisions (${summary.created.decisions.length}):`);
828
- for (const dec of summary.created.decisions.slice(0, 5)) {
829
- console.log(` - ${dec}`);
830
- }
831
- if (summary.created.decisions.length > 5) {
832
- console.log(` ... and ${summary.created.decisions.length - 5} more`);
833
- }
834
- }
835
- if (summary.created.tasks.length > 0) {
836
- console.log(`\u2713 Tasks (${summary.created.tasks.length}):`);
837
- for (const task of summary.created.tasks.slice(0, 5)) {
838
- console.log(` - ${task}`);
839
- }
840
- if (summary.created.tasks.length > 5) {
841
- console.log(` ... and ${summary.created.tasks.length - 5} more`);
842
- }
843
- }
844
- if (totalSkipped > 0) {
845
- console.log(`
846
- \u2298 Skipped ${totalSkipped} items (already exist or similar)`);
847
- }
848
- console.log("\u2500".repeat(40));
849
- console.log(`Total: ${totalCreated} created, ${totalSkipped} skipped`);
850
- }
851
803
  async function setupCommand(options = {}) {
852
804
  const target = resolveVaultTarget(options.vault);
853
805
  if (target.existed && !fs.statSync(target.vaultPath).isDirectory()) {
@@ -864,17 +816,22 @@ async function setupCommand(options = {}) {
864
816
  if (!fs.existsSync(sourcePath)) {
865
817
  throw new Error(`Source path does not exist: ${sourcePath}`);
866
818
  }
819
+ const files = scanMarkdownFiles(sourcePath);
867
820
  console.log(`
868
- \u{1F4C2} Scanning source: ${sourcePath}`);
869
- const extracted = scanAndExtract(sourcePath);
870
- const totalFound = extracted.people.length + extracted.preferences.length + extracted.decisions.length + extracted.tasks.length;
871
- if (totalFound === 0) {
872
- console.log("\u2298 No structured data found in source files.");
873
- } else {
874
- console.log(`Found: ${extracted.people.length} people, ${extracted.preferences.length} preferences, ${extracted.decisions.length} decisions, ${extracted.tasks.length} tasks`);
875
- const summary = importToVault(target.vaultPath, extracted, force);
876
- printImportSummary(summary);
877
- }
821
+ \u{1F4C2} Found ${files.length} markdown files in ${sourcePath}`);
822
+ console.log("\nVault setup from existing memory is best done by your agent.");
823
+ console.log("Give your agent this directive:\n");
824
+ console.log("---");
825
+ console.log(`Read the markdown files in ${sourcePath}.`);
826
+ console.log(`Read the template schemas in ${target.vaultPath}/templates/ to understand primitive types.`);
827
+ console.log("For each piece of durable knowledge:");
828
+ console.log(" - People with contact info \u2192 create people/<name>.md using person template");
829
+ console.log(" - Decisions made \u2192 create decisions/<slug>.md using decision template");
830
+ console.log(" - Lessons learned \u2192 create lessons/<slug>.md using lesson template");
831
+ console.log(" - Active tasks \u2192 create tasks/<slug>.md using task template");
832
+ console.log(" - Preferences/facts \u2192 create memories/<slug>.md using memory-event template");
833
+ console.log("Deduplicate: search existing vault files before creating new ones.");
834
+ console.log("---");
878
835
  }
879
836
  const explicitFlags = options.graphColors !== void 0 || options.bases !== void 0;
880
837
  const fromOnly = options.from && !explicitFlags;
@@ -1207,54 +1207,6 @@ function importToVault(vaultPath, extracted, force) {
1207
1207
  }
1208
1208
  return summary;
1209
1209
  }
1210
- function printImportSummary(summary) {
1211
- const totalCreated = summary.created.people.length + summary.created.preferences.length + summary.created.decisions.length + summary.created.tasks.length;
1212
- const totalSkipped = summary.skipped.people.length + summary.skipped.preferences.length + summary.skipped.decisions.length + summary.skipped.tasks.length;
1213
- console.log("\n\u{1F4E5} Memory Import Summary");
1214
- console.log("\u2500".repeat(40));
1215
- if (summary.created.people.length > 0) {
1216
- console.log(`\u2713 People (${summary.created.people.length}):`);
1217
- for (const name of summary.created.people.slice(0, 5)) {
1218
- console.log(` - ${name}`);
1219
- }
1220
- if (summary.created.people.length > 5) {
1221
- console.log(` ... and ${summary.created.people.length - 5} more`);
1222
- }
1223
- }
1224
- if (summary.created.preferences.length > 0) {
1225
- console.log(`\u2713 Preferences (${summary.created.preferences.length}):`);
1226
- for (const pref of summary.created.preferences.slice(0, 5)) {
1227
- console.log(` - ${pref}`);
1228
- }
1229
- if (summary.created.preferences.length > 5) {
1230
- console.log(` ... and ${summary.created.preferences.length - 5} more`);
1231
- }
1232
- }
1233
- if (summary.created.decisions.length > 0) {
1234
- console.log(`\u2713 Decisions (${summary.created.decisions.length}):`);
1235
- for (const dec of summary.created.decisions.slice(0, 5)) {
1236
- console.log(` - ${dec}`);
1237
- }
1238
- if (summary.created.decisions.length > 5) {
1239
- console.log(` ... and ${summary.created.decisions.length - 5} more`);
1240
- }
1241
- }
1242
- if (summary.created.tasks.length > 0) {
1243
- console.log(`\u2713 Tasks (${summary.created.tasks.length}):`);
1244
- for (const task of summary.created.tasks.slice(0, 5)) {
1245
- console.log(` - ${task}`);
1246
- }
1247
- if (summary.created.tasks.length > 5) {
1248
- console.log(` ... and ${summary.created.tasks.length - 5} more`);
1249
- }
1250
- }
1251
- if (totalSkipped > 0) {
1252
- console.log(`
1253
- \u2298 Skipped ${totalSkipped} items (already exist or similar)`);
1254
- }
1255
- console.log("\u2500".repeat(40));
1256
- console.log(`Total: ${totalCreated} created, ${totalSkipped} skipped`);
1257
- }
1258
1210
  async function setupCommand(options = {}) {
1259
1211
  const target = resolveVaultTarget(options.vault);
1260
1212
  if (target.existed && !fs2.statSync(target.vaultPath).isDirectory()) {
@@ -1271,17 +1223,22 @@ async function setupCommand(options = {}) {
1271
1223
  if (!fs2.existsSync(sourcePath)) {
1272
1224
  throw new Error(`Source path does not exist: ${sourcePath}`);
1273
1225
  }
1226
+ const files = scanMarkdownFiles(sourcePath);
1274
1227
  console.log(`
1275
- \u{1F4C2} Scanning source: ${sourcePath}`);
1276
- const extracted = scanAndExtract(sourcePath);
1277
- const totalFound = extracted.people.length + extracted.preferences.length + extracted.decisions.length + extracted.tasks.length;
1278
- if (totalFound === 0) {
1279
- console.log("\u2298 No structured data found in source files.");
1280
- } else {
1281
- console.log(`Found: ${extracted.people.length} people, ${extracted.preferences.length} preferences, ${extracted.decisions.length} decisions, ${extracted.tasks.length} tasks`);
1282
- const summary = importToVault(target.vaultPath, extracted, force);
1283
- printImportSummary(summary);
1284
- }
1228
+ \u{1F4C2} Found ${files.length} markdown files in ${sourcePath}`);
1229
+ console.log("\nVault setup from existing memory is best done by your agent.");
1230
+ console.log("Give your agent this directive:\n");
1231
+ console.log("---");
1232
+ console.log(`Read the markdown files in ${sourcePath}.`);
1233
+ console.log(`Read the template schemas in ${target.vaultPath}/templates/ to understand primitive types.`);
1234
+ console.log("For each piece of durable knowledge:");
1235
+ console.log(" - People with contact info \u2192 create people/<name>.md using person template");
1236
+ console.log(" - Decisions made \u2192 create decisions/<slug>.md using decision template");
1237
+ console.log(" - Lessons learned \u2192 create lessons/<slug>.md using lesson template");
1238
+ console.log(" - Active tasks \u2192 create tasks/<slug>.md using task template");
1239
+ console.log(" - Preferences/facts \u2192 create memories/<slug>.md using memory-event template");
1240
+ console.log("Deduplicate: search existing vault files before creating new ones.");
1241
+ console.log("---");
1285
1242
  }
1286
1243
  const explicitFlags = options.graphColors !== void 0 || options.bases !== void 0;
1287
1244
  const fromOnly = options.from && !explicitFlags;
@@ -7,7 +7,7 @@ import {
7
7
  importToVault,
8
8
  scanAndExtract,
9
9
  setupCommand
10
- } from "../chunk-DEFFDRVP.js";
10
+ } from "../chunk-2TM7DLOL.js";
11
11
  import "../chunk-LYHGEHXG.js";
12
12
  import "../chunk-7766SIJP.js";
13
13
  import "../chunk-K234IDRJ.js";
package/dist/index.cjs CHANGED
@@ -11551,9 +11551,6 @@ function getQmdConfig(vaultPath) {
11551
11551
  }
11552
11552
  return { collection: path26.basename(vaultPath), root: vaultPath };
11553
11553
  }
11554
- function slugify2(text) {
11555
- return text.toLowerCase().replace(/[^\w\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "").trim();
11556
- }
11557
11554
  function scanMarkdownFiles(dirPath) {
11558
11555
  const files = [];
11559
11556
  const resolvedPath = path26.resolve(dirPath);
@@ -11578,533 +11575,6 @@ function scanMarkdownFiles(dirPath) {
11578
11575
  }
11579
11576
  return files;
11580
11577
  }
11581
- function extractPeople(content) {
11582
- const people = [];
11583
- const seenNames = /* @__PURE__ */ new Set();
11584
- const emailPattern = /([A-Z][a-z]+(?:\s+[A-Z][a-z]+)+)\s*<([^>]+@[^>]+)>/g;
11585
- let match;
11586
- while ((match = emailPattern.exec(content)) !== null) {
11587
- const name = match[1].trim();
11588
- const email = match[2].trim();
11589
- if (!seenNames.has(name.toLowerCase())) {
11590
- seenNames.add(name.toLowerCase());
11591
- people.push({ name, email });
11592
- }
11593
- }
11594
- const rolePatterns = [
11595
- /([A-Z][a-z]+(?:\s+[A-Z][a-z]+)+)\s*\(([^)]+)\)/g,
11596
- /([A-Z][a-z]+(?:\s+[A-Z][a-z]+)+),\s*(CEO|CTO|CFO|COO|VP|Director|Manager|Engineer|Designer|Lead|Head of [A-Za-z]+)/gi
11597
- ];
11598
- for (const pattern of rolePatterns) {
11599
- while ((match = pattern.exec(content)) !== null) {
11600
- const name = match[1].trim();
11601
- const role = match[2].trim();
11602
- if (!seenNames.has(name.toLowerCase())) {
11603
- seenNames.add(name.toLowerCase());
11604
- people.push({ name, role });
11605
- }
11606
- }
11607
- }
11608
- const contextPatterns = [
11609
- /(?:contact|met with|spoke with|emailed|called|messaged|talked to|meeting with)\s+([A-Z][a-zA-Z]*(?:\s+[A-Z][a-zA-Z]*)+)/g,
11610
- /([A-Z][a-zA-Z]*(?:\s+[A-Z][a-zA-Z]*)+)\s+(?:said|mentioned|suggested|recommended|asked|told me)/g
11611
- ];
11612
- for (const pattern of contextPatterns) {
11613
- while ((match = pattern.exec(content)) !== null) {
11614
- const name = match[1].trim();
11615
- if (!seenNames.has(name.toLowerCase()) && name.split(" ").length >= 2) {
11616
- seenNames.add(name.toLowerCase());
11617
- const lineStart = content.lastIndexOf("\n", match.index) + 1;
11618
- const lineEnd = content.indexOf("\n", match.index + match[0].length);
11619
- const context = content.slice(lineStart, lineEnd === -1 ? void 0 : lineEnd).trim();
11620
- people.push({ name, context: context.slice(0, 200) });
11621
- }
11622
- }
11623
- }
11624
- return people;
11625
- }
11626
- function extractPreferences2(content) {
11627
- const preferences = [];
11628
- const seenPrefs = /* @__PURE__ */ new Set();
11629
- const patterns = [
11630
- // "prefers X" / "prefer X" / "I prefer X"
11631
- /(?:I\s+)?prefer(?:s)?\s+(?:to\s+)?([^.,\n]+)/gi,
11632
- // "likes X" / "like X"
11633
- /(?:I\s+)?like(?:s)?\s+(?:to\s+)?([^.,\n]+)/gi,
11634
- // "always use X"
11635
- /always\s+(?:use|uses?)\s+([^.,\n]+)/gi,
11636
- // "never use X"
11637
- /never\s+(?:use|uses?)\s+([^.,\n]+)/gi,
11638
- // "favorite X is Y"
11639
- /(?:my\s+)?favorite\s+(\w+)\s+is\s+([^.,\n]+)/gi,
11640
- // "prefer X over Y"
11641
- /prefer(?:s)?\s+([^.,\n]+)\s+over\s+([^.,\n]+)/gi,
11642
- // "use X instead of Y"
11643
- /use(?:s)?\s+([^.,\n]+)\s+instead\s+of\s+([^.,\n]+)/gi
11644
- ];
11645
- for (const pattern of patterns) {
11646
- let match;
11647
- while ((match = pattern.exec(content)) !== null) {
11648
- const fullMatch = match[0].trim();
11649
- const key = fullMatch.toLowerCase();
11650
- if (!seenPrefs.has(key) && fullMatch.length > 5 && fullMatch.length < 200) {
11651
- seenPrefs.add(key);
11652
- const lineStart = content.lastIndexOf("\n", match.index) + 1;
11653
- const lineEnd = content.indexOf("\n", match.index + match[0].length);
11654
- const context = content.slice(lineStart, lineEnd === -1 ? void 0 : lineEnd).trim();
11655
- let subject = "general";
11656
- let preference = fullMatch;
11657
- if (match[2]) {
11658
- subject = match[1].trim();
11659
- preference = match[2].trim();
11660
- } else if (match[1]) {
11661
- preference = match[1].trim();
11662
- }
11663
- preferences.push({ subject, preference, context: context.slice(0, 200) });
11664
- }
11665
- }
11666
- }
11667
- return preferences;
11668
- }
11669
- function extractDecisions(content) {
11670
- const decisions = [];
11671
- const seenDecisions = /* @__PURE__ */ new Set();
11672
- const patterns = [
11673
- // "decided to X"
11674
- /(?:I\s+|we\s+)?decided\s+(?:to\s+)?([^.,\n]+)/gi,
11675
- // "decision: X" or "Decision - X"
11676
- /decision[:\s-]+([^.,\n]+)/gi,
11677
- // "we chose X" / "chose to X"
11678
- /(?:we\s+)?chose\s+(?:to\s+)?([^.,\n]+)/gi,
11679
- // "going with X"
11680
- /going\s+with\s+([^.,\n]+)/gi,
11681
- // "settled on X"
11682
- /settled\s+on\s+([^.,\n]+)/gi,
11683
- // "will use X" / "using X going forward"
11684
- /(?:will\s+use|using)\s+([^.,\n]+)\s+(?:going\s+forward|from\s+now\s+on)/gi
11685
- ];
11686
- for (const pattern of patterns) {
11687
- let match;
11688
- while ((match = pattern.exec(content)) !== null) {
11689
- const decision = match[1].trim();
11690
- const key = decision.toLowerCase();
11691
- if (!seenDecisions.has(key) && decision.length > 5 && decision.length < 200) {
11692
- seenDecisions.add(key);
11693
- const lineStart = content.lastIndexOf("\n", match.index) + 1;
11694
- const lineEnd = content.indexOf("\n", match.index + match[0].length);
11695
- const context = content.slice(lineStart, lineEnd === -1 ? void 0 : lineEnd).trim();
11696
- const title = decision.length > 50 ? decision.slice(0, 50).trim() + "..." : decision;
11697
- decisions.push({ title, decision, context: context.slice(0, 200) });
11698
- }
11699
- }
11700
- }
11701
- return decisions;
11702
- }
11703
- function extractTasks(content) {
11704
- const tasks = [];
11705
- const seenTasks = /* @__PURE__ */ new Set();
11706
- const patterns = [
11707
- // Markdown checkbox "- [ ] task"
11708
- /^[\s]*[-*]\s*\[\s*\]\s*(.+)$/gm,
11709
- // "TODO: task" or "TODO - task"
11710
- /TODO[:\s-]+(.+)/gi,
11711
- // "FIXME: task"
11712
- /FIXME[:\s-]+(.+)/gi,
11713
- // "need to X"
11714
- /(?:I\s+|we\s+)?need\s+to\s+([^.,\n]+)/gi,
11715
- // "should X" (but not "should have" which is past)
11716
- /(?:I\s+|we\s+)?should\s+(?!have)([^.,\n]+)/gi,
11717
- // "must X"
11718
- /(?:I\s+|we\s+)?must\s+([^.,\n]+)/gi,
11719
- // "remember to X"
11720
- /remember\s+to\s+([^.,\n]+)/gi,
11721
- // "don't forget to X"
11722
- /don'?t\s+forget\s+to\s+([^.,\n]+)/gi
11723
- ];
11724
- for (const pattern of patterns) {
11725
- let match;
11726
- while ((match = pattern.exec(content)) !== null) {
11727
- const taskText = match[1].trim();
11728
- const key = taskText.toLowerCase();
11729
- if (!seenTasks.has(key) && taskText.length > 3 && taskText.length < 200) {
11730
- seenTasks.add(key);
11731
- let priority = "medium";
11732
- const lowerTask = taskText.toLowerCase();
11733
- if (lowerTask.includes("urgent") || lowerTask.includes("asap") || lowerTask.includes("critical")) {
11734
- priority = "critical";
11735
- } else if (lowerTask.includes("important") || lowerTask.includes("high priority")) {
11736
- priority = "high";
11737
- } else if (lowerTask.includes("low priority") || lowerTask.includes("eventually") || lowerTask.includes("someday")) {
11738
- priority = "low";
11739
- }
11740
- tasks.push({ title: taskText, priority });
11741
- }
11742
- }
11743
- }
11744
- return tasks;
11745
- }
11746
- function extractFromContent(content) {
11747
- return {
11748
- people: extractPeople(content),
11749
- preferences: extractPreferences2(content),
11750
- decisions: extractDecisions(content),
11751
- tasks: extractTasks(content)
11752
- };
11753
- }
11754
- function scanAndExtract(sourcePath) {
11755
- const files = scanMarkdownFiles(sourcePath);
11756
- const combined = {
11757
- people: [],
11758
- preferences: [],
11759
- decisions: [],
11760
- tasks: []
11761
- };
11762
- for (const file of files) {
11763
- try {
11764
- const content = fs26.readFileSync(file, "utf-8");
11765
- const extracted = extractFromContent(content);
11766
- combined.people.push(...extracted.people);
11767
- combined.preferences.push(...extracted.preferences);
11768
- combined.decisions.push(...extracted.decisions);
11769
- combined.tasks.push(...extracted.tasks);
11770
- } catch {
11771
- }
11772
- }
11773
- const seenPeople = /* @__PURE__ */ new Set();
11774
- combined.people = combined.people.filter((p) => {
11775
- const key = p.name.toLowerCase();
11776
- if (seenPeople.has(key)) return false;
11777
- seenPeople.add(key);
11778
- return true;
11779
- });
11780
- const seenPrefs = /* @__PURE__ */ new Set();
11781
- combined.preferences = combined.preferences.filter((p) => {
11782
- const key = `${p.subject}:${p.preference}`.toLowerCase();
11783
- if (seenPrefs.has(key)) return false;
11784
- seenPrefs.add(key);
11785
- return true;
11786
- });
11787
- const seenDecisions = /* @__PURE__ */ new Set();
11788
- combined.decisions = combined.decisions.filter((d) => {
11789
- const key = d.decision.toLowerCase();
11790
- if (seenDecisions.has(key)) return false;
11791
- seenDecisions.add(key);
11792
- return true;
11793
- });
11794
- const seenTasks = /* @__PURE__ */ new Set();
11795
- combined.tasks = combined.tasks.filter((t) => {
11796
- const key = t.title.toLowerCase();
11797
- if (seenTasks.has(key)) return false;
11798
- seenTasks.add(key);
11799
- return true;
11800
- });
11801
- return combined;
11802
- }
11803
- function fileExistsWithSimilarName(dir, slug) {
11804
- if (!fs26.existsSync(dir)) return false;
11805
- const files = fs26.readdirSync(dir);
11806
- const targetSlug = slug.toLowerCase();
11807
- return files.some((f) => {
11808
- const fileSlug = path26.basename(f, ".md").toLowerCase();
11809
- return fileSlug === targetSlug || fileSlug.includes(targetSlug) || targetSlug.includes(fileSlug);
11810
- });
11811
- }
11812
- function writePerson(vaultPath, person, force) {
11813
- const peopleDir = path26.join(vaultPath, "people");
11814
- fs26.mkdirSync(peopleDir, { recursive: true });
11815
- const slug = slugify2(person.name);
11816
- if (!slug) return null;
11817
- const filePath = path26.join(peopleDir, `${slug}.md`);
11818
- if (!force && (fs26.existsSync(filePath) || fileExistsWithSimilarName(peopleDir, slug))) {
11819
- return null;
11820
- }
11821
- const template = loadTemplateDefinition("person");
11822
- const now = /* @__PURE__ */ new Date();
11823
- const date = now.toISOString().split("T")[0];
11824
- let content;
11825
- if (template) {
11826
- const rendered = renderDocumentFromTemplate(template, {
11827
- title: person.name,
11828
- now,
11829
- overrides: {
11830
- relationship: person.role ? "colleague" : "contact"
11831
- }
11832
- });
11833
- let body = rendered.content;
11834
- if (person.context) {
11835
- body = body.replace(/## Context\n-\s*/, `## Context
11836
- - ${person.context}
11837
- `);
11838
- }
11839
- if (person.email || person.role) {
11840
- const details = [];
11841
- if (person.email) details.push(`- Contact: ${person.email}`);
11842
- if (person.role) details.push(`- Role: ${person.role}`);
11843
- body = body.replace(/## Details\n- Contact:\n- Role:\n- Timezone:/, `## Details
11844
- ${details.join("\n")}
11845
- - Timezone:`);
11846
- }
11847
- content = import_gray_matter7.default.stringify(body, rendered.frontmatter);
11848
- } else {
11849
- const frontmatter = {
11850
- title: person.name,
11851
- date,
11852
- type: "person",
11853
- relationship: person.role ? "colleague" : "contact"
11854
- };
11855
- let body = `# ${person.name}
11856
-
11857
- ## Context
11858
- `;
11859
- if (person.context) body += `- ${person.context}
11860
- `;
11861
- else body += "- \n";
11862
- body += "\n## Details\n";
11863
- if (person.email) body += `- Contact: ${person.email}
11864
- `;
11865
- else body += "- Contact:\n";
11866
- if (person.role) body += `- Role: ${person.role}
11867
- `;
11868
- else body += "- Role:\n";
11869
- body += "- Timezone:\n";
11870
- body += `
11871
- ## History
11872
- - ${date}: Added from memory import
11873
- `;
11874
- content = import_gray_matter7.default.stringify(body, frontmatter);
11875
- }
11876
- fs26.writeFileSync(filePath, content);
11877
- return slug;
11878
- }
11879
- function writePreference(vaultPath, pref, force) {
11880
- const prefsDir = path26.join(vaultPath, "preferences");
11881
- fs26.mkdirSync(prefsDir, { recursive: true });
11882
- const slug = slugify2(`${pref.subject}-${pref.preference}`.slice(0, 60));
11883
- if (!slug) return null;
11884
- const filePath = path26.join(prefsDir, `${slug}.md`);
11885
- if (!force && (fs26.existsSync(filePath) || fileExistsWithSimilarName(prefsDir, slug))) {
11886
- return null;
11887
- }
11888
- const now = /* @__PURE__ */ new Date();
11889
- const date = now.toISOString().split("T")[0];
11890
- const frontmatter = {
11891
- title: `${pref.subject}: ${pref.preference}`.slice(0, 100),
11892
- date,
11893
- type: "preference",
11894
- category: pref.subject
11895
- };
11896
- let body = `# ${frontmatter.title}
11897
-
11898
- `;
11899
- body += `## Preference
11900
- - ${pref.preference}
11901
- `;
11902
- if (pref.context) {
11903
- body += `
11904
- ## Context
11905
- - ${pref.context}
11906
- `;
11907
- }
11908
- body += `
11909
- ## Source
11910
- - Imported from memory on ${date}
11911
- `;
11912
- const content = import_gray_matter7.default.stringify(body, frontmatter);
11913
- fs26.writeFileSync(filePath, content);
11914
- return slug;
11915
- }
11916
- function writeDecision(vaultPath, decision, force) {
11917
- const decisionsDir = path26.join(vaultPath, "decisions");
11918
- fs26.mkdirSync(decisionsDir, { recursive: true });
11919
- const slug = slugify2(decision.title);
11920
- if (!slug) return null;
11921
- const filePath = path26.join(decisionsDir, `${slug}.md`);
11922
- if (!force && (fs26.existsSync(filePath) || fileExistsWithSimilarName(decisionsDir, slug))) {
11923
- return null;
11924
- }
11925
- const template = loadTemplateDefinition("decision");
11926
- const now = /* @__PURE__ */ new Date();
11927
- const date = now.toISOString().split("T")[0];
11928
- let content;
11929
- if (template) {
11930
- const rendered = renderDocumentFromTemplate(template, {
11931
- title: decision.title,
11932
- now,
11933
- overrides: {
11934
- status: "decided"
11935
- }
11936
- });
11937
- let body = rendered.content;
11938
- if (decision.context) {
11939
- body = body.replace(/## Context\n-\s*/, `## Context
11940
- - ${decision.context}
11941
- `);
11942
- }
11943
- body = body.replace(/## Decision\n-\s*/, `## Decision
11944
- - ${decision.decision}
11945
- `);
11946
- body = body.replace(/## Consequences\n-\s*/, `## Consequences
11947
- - Imported from memory on ${date}
11948
- `);
11949
- content = import_gray_matter7.default.stringify(body, rendered.frontmatter);
11950
- } else {
11951
- const frontmatter = {
11952
- title: decision.title,
11953
- date,
11954
- type: "decision",
11955
- status: "decided"
11956
- };
11957
- let body = `# Decision: ${decision.title}
11958
-
11959
- `;
11960
- body += `## Context
11961
- `;
11962
- if (decision.context) body += `- ${decision.context}
11963
- `;
11964
- else body += "- \n";
11965
- body += `
11966
- ## Decision
11967
- - ${decision.decision}
11968
- `;
11969
- body += `
11970
- ## Consequences
11971
- - Imported from memory on ${date}
11972
- `;
11973
- content = import_gray_matter7.default.stringify(body, frontmatter);
11974
- }
11975
- fs26.writeFileSync(filePath, content);
11976
- return slug;
11977
- }
11978
- function writeTask(vaultPath, task, force) {
11979
- const tasksDir = path26.join(vaultPath, "tasks");
11980
- fs26.mkdirSync(tasksDir, { recursive: true });
11981
- const slug = slugify2(task.title);
11982
- if (!slug) return null;
11983
- const filePath = path26.join(tasksDir, `${slug}.md`);
11984
- if (!force && (fs26.existsSync(filePath) || fileExistsWithSimilarName(tasksDir, slug))) {
11985
- return null;
11986
- }
11987
- const template = loadTemplateDefinition("task");
11988
- const now = /* @__PURE__ */ new Date();
11989
- const datetime = now.toISOString();
11990
- let content;
11991
- if (template) {
11992
- const rendered = renderDocumentFromTemplate(template, {
11993
- title: task.title,
11994
- now,
11995
- overrides: {
11996
- status: "open",
11997
- priority: task.priority || "medium",
11998
- source: "memory-import",
11999
- description: task.description
12000
- },
12001
- frontmatter: { pruneEmpty: true }
12002
- });
12003
- content = rendered.markdown;
12004
- } else {
12005
- const frontmatter = {
12006
- status: "open",
12007
- source: "memory-import",
12008
- created: datetime,
12009
- updated: datetime,
12010
- priority: task.priority || "medium"
12011
- };
12012
- if (task.description) frontmatter.description = task.description;
12013
- const body = `# ${task.title}
12014
-
12015
- `;
12016
- content = import_gray_matter7.default.stringify(body, frontmatter);
12017
- }
12018
- fs26.writeFileSync(filePath, content);
12019
- return slug;
12020
- }
12021
- function importToVault(vaultPath, extracted, force) {
12022
- const summary = {
12023
- created: { people: [], preferences: [], decisions: [], tasks: [] },
12024
- skipped: { people: [], preferences: [], decisions: [], tasks: [] }
12025
- };
12026
- for (const person of extracted.people) {
12027
- const slug = writePerson(vaultPath, person, force);
12028
- if (slug) {
12029
- summary.created.people.push(person.name);
12030
- } else {
12031
- summary.skipped.people.push(person.name);
12032
- }
12033
- }
12034
- for (const pref of extracted.preferences) {
12035
- const slug = writePreference(vaultPath, pref, force);
12036
- if (slug) {
12037
- summary.created.preferences.push(`${pref.subject}: ${pref.preference}`.slice(0, 50));
12038
- } else {
12039
- summary.skipped.preferences.push(`${pref.subject}: ${pref.preference}`.slice(0, 50));
12040
- }
12041
- }
12042
- for (const decision of extracted.decisions) {
12043
- const slug = writeDecision(vaultPath, decision, force);
12044
- if (slug) {
12045
- summary.created.decisions.push(decision.title);
12046
- } else {
12047
- summary.skipped.decisions.push(decision.title);
12048
- }
12049
- }
12050
- for (const task of extracted.tasks) {
12051
- const slug = writeTask(vaultPath, task, force);
12052
- if (slug) {
12053
- summary.created.tasks.push(task.title);
12054
- } else {
12055
- summary.skipped.tasks.push(task.title);
12056
- }
12057
- }
12058
- return summary;
12059
- }
12060
- function printImportSummary(summary) {
12061
- const totalCreated = summary.created.people.length + summary.created.preferences.length + summary.created.decisions.length + summary.created.tasks.length;
12062
- const totalSkipped = summary.skipped.people.length + summary.skipped.preferences.length + summary.skipped.decisions.length + summary.skipped.tasks.length;
12063
- console.log("\n\u{1F4E5} Memory Import Summary");
12064
- console.log("\u2500".repeat(40));
12065
- if (summary.created.people.length > 0) {
12066
- console.log(`\u2713 People (${summary.created.people.length}):`);
12067
- for (const name of summary.created.people.slice(0, 5)) {
12068
- console.log(` - ${name}`);
12069
- }
12070
- if (summary.created.people.length > 5) {
12071
- console.log(` ... and ${summary.created.people.length - 5} more`);
12072
- }
12073
- }
12074
- if (summary.created.preferences.length > 0) {
12075
- console.log(`\u2713 Preferences (${summary.created.preferences.length}):`);
12076
- for (const pref of summary.created.preferences.slice(0, 5)) {
12077
- console.log(` - ${pref}`);
12078
- }
12079
- if (summary.created.preferences.length > 5) {
12080
- console.log(` ... and ${summary.created.preferences.length - 5} more`);
12081
- }
12082
- }
12083
- if (summary.created.decisions.length > 0) {
12084
- console.log(`\u2713 Decisions (${summary.created.decisions.length}):`);
12085
- for (const dec of summary.created.decisions.slice(0, 5)) {
12086
- console.log(` - ${dec}`);
12087
- }
12088
- if (summary.created.decisions.length > 5) {
12089
- console.log(` ... and ${summary.created.decisions.length - 5} more`);
12090
- }
12091
- }
12092
- if (summary.created.tasks.length > 0) {
12093
- console.log(`\u2713 Tasks (${summary.created.tasks.length}):`);
12094
- for (const task of summary.created.tasks.slice(0, 5)) {
12095
- console.log(` - ${task}`);
12096
- }
12097
- if (summary.created.tasks.length > 5) {
12098
- console.log(` ... and ${summary.created.tasks.length - 5} more`);
12099
- }
12100
- }
12101
- if (totalSkipped > 0) {
12102
- console.log(`
12103
- \u2298 Skipped ${totalSkipped} items (already exist or similar)`);
12104
- }
12105
- console.log("\u2500".repeat(40));
12106
- console.log(`Total: ${totalCreated} created, ${totalSkipped} skipped`);
12107
- }
12108
11578
  async function setupCommand(options = {}) {
12109
11579
  const target = resolveVaultTarget(options.vault);
12110
11580
  if (target.existed && !fs26.statSync(target.vaultPath).isDirectory()) {
@@ -12121,17 +11591,22 @@ async function setupCommand(options = {}) {
12121
11591
  if (!fs26.existsSync(sourcePath)) {
12122
11592
  throw new Error(`Source path does not exist: ${sourcePath}`);
12123
11593
  }
11594
+ const files = scanMarkdownFiles(sourcePath);
12124
11595
  console.log(`
12125
- \u{1F4C2} Scanning source: ${sourcePath}`);
12126
- const extracted = scanAndExtract(sourcePath);
12127
- const totalFound = extracted.people.length + extracted.preferences.length + extracted.decisions.length + extracted.tasks.length;
12128
- if (totalFound === 0) {
12129
- console.log("\u2298 No structured data found in source files.");
12130
- } else {
12131
- console.log(`Found: ${extracted.people.length} people, ${extracted.preferences.length} preferences, ${extracted.decisions.length} decisions, ${extracted.tasks.length} tasks`);
12132
- const summary = importToVault(target.vaultPath, extracted, force);
12133
- printImportSummary(summary);
12134
- }
11596
+ \u{1F4C2} Found ${files.length} markdown files in ${sourcePath}`);
11597
+ console.log("\nVault setup from existing memory is best done by your agent.");
11598
+ console.log("Give your agent this directive:\n");
11599
+ console.log("---");
11600
+ console.log(`Read the markdown files in ${sourcePath}.`);
11601
+ console.log(`Read the template schemas in ${target.vaultPath}/templates/ to understand primitive types.`);
11602
+ console.log("For each piece of durable knowledge:");
11603
+ console.log(" - People with contact info \u2192 create people/<name>.md using person template");
11604
+ console.log(" - Decisions made \u2192 create decisions/<slug>.md using decision template");
11605
+ console.log(" - Lessons learned \u2192 create lessons/<slug>.md using lesson template");
11606
+ console.log(" - Active tasks \u2192 create tasks/<slug>.md using task template");
11607
+ console.log(" - Preferences/facts \u2192 create memories/<slug>.md using memory-event template");
11608
+ console.log("Deduplicate: search existing vault files before creating new ones.");
11609
+ console.log("---");
12135
11610
  }
12136
11611
  const explicitFlags = options.graphColors !== void 0 || options.bases !== void 0;
12137
11612
  const fromOnly = options.from && !explicitFlags;
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  setupCommand
3
- } from "./chunk-DEFFDRVP.js";
3
+ } from "./chunk-2TM7DLOL.js";
4
4
  import {
5
5
  rebuildCommand,
6
6
  registerRebuildCommand
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clawvault",
3
- "version": "3.0.0-beta.1",
3
+ "version": "3.0.0-beta.2",
4
4
  "description": "Structured memory system for AI agents — typed storage, knowledge graph, context profiles, canvas dashboards, neural graph themes, and Obsidian-native task views. An elephant never forgets. 🐘",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",