va-claw 0.1.4 → 0.2.1

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.
@@ -149,6 +149,12 @@ function toClaudeMdSnippet(config) {
149
149
  "- Manage claws with `va-claw claw list | add | set | remove | heartbeat`.",
150
150
  '- If asked "va/claw \u5728\u5E72\u4EC0\u4E48" / "my claws are doing what" / similar fleet questions, call `va-claw protocol --text` and answer from it.',
151
151
  '- If the user asks a non-technical phrasing like "\u73B0\u5728\u90FD\u5728\u5E72\u561B", interpret it as a fleet status request and run `va-claw protocol --text`.',
152
+ "",
153
+ "Memory protocol:",
154
+ '- At session start, run `va-claw memory recall "<current topic or task>"` before answering.',
155
+ '- After important work, run `va-claw memory memorize "<key>" "<essence>" --tags <tags> --importance <0.0-1.0>`.',
156
+ "- Use importance `0.8-1.0` for decisions or hard-won knowledge; use `0.5` for routine outputs.",
157
+ "- Do not memorize every message; store only things worth remembering across sessions.",
152
158
  "<!-- va-claw:identity:end -->"
153
159
  ].join("\n");
154
160
  }
@@ -172,7 +178,13 @@ function toCodexSystemPrompt(config) {
172
178
  "Use `va-claw protocol` in terminal to get long-running claw state.",
173
179
  'Use `va-claw protocol --text` when a user asks in plain language, including Chinese phrases like "va/claw \u5728\u5E72\u4EC0\u4E48".',
174
180
  "Use `va-claw claw list` and `va-claw claw set <name> --status <status>` to manage claws.",
175
- "If the user asks what claws are doing, run `va-claw protocol --text` and summarize only from that output."
181
+ "If the user asks what claws are doing, run `va-claw protocol --text` and summarize only from that output.",
182
+ "",
183
+ "Memory protocol:",
184
+ 'At session start, run `va-claw memory recall "<current topic or task>"` before answering.',
185
+ 'After important work, run `va-claw memory memorize "<key>" "<essence>" --tags <tags> --importance <0.0-1.0>`.',
186
+ "Use importance `0.8-1.0` for decisions or hard-won knowledge; use `0.5` for routine outputs.",
187
+ "Do not memorize every message; store only things worth remembering across sessions."
176
188
  ].join("\n");
177
189
  }
178
190
 
@@ -947,31 +959,40 @@ var E = class {
947
959
  // packages/daemon/dist/wake-cycle.js
948
960
  import { spawn } from "node:child_process";
949
961
  import { appendFile, mkdir as mkdir3 } from "node:fs/promises";
950
- import { homedir as homedir4 } from "node:os";
962
+ import { homedir as homedir5 } from "node:os";
951
963
  import { dirname as dirname3, resolve as resolve3 } from "node:path";
952
964
 
953
965
  // packages/memory/dist/default-store.js
954
- import { homedir as homedir2 } from "node:os";
955
- import { join } from "node:path";
966
+ import { homedir as homedir3 } from "node:os";
967
+ import { join as join2 } from "node:path";
956
968
 
957
969
  // packages/memory/dist/memory-store.js
958
970
  import { randomUUID } from "node:crypto";
959
971
 
960
972
  // packages/memory/dist/embedding.js
961
- var EMBEDDING_DIMENSIONS = 32;
973
+ import { homedir as homedir2 } from "node:os";
974
+ import { join } from "node:path";
975
+ var EMBEDDING_DIMENSIONS = 384;
976
+ var EMBEDDING_MODEL = "Xenova/paraphrase-multilingual-MiniLM-L12-v2";
977
+ var EMBEDDING_CACHE_DIR = join(homedir2(), ".va-claw", "models");
978
+ var embeddingExtractorPromise;
979
+ var embeddingExtractorOverride;
962
980
  function buildSearchText(text2, metadata) {
963
981
  const metadataText = metadata ? flattenMetadata(metadata).join(" ") : "";
964
982
  return `${text2} ${metadataText}`.trim().toLowerCase();
965
983
  }
966
- function createEmbedding(input) {
967
- const vector = Array.from({ length: EMBEDDING_DIMENSIONS }, () => 0);
968
- for (const token of tokenize(input)) {
969
- const hash = hashToken(token);
970
- const index = Math.abs(hash) % EMBEDDING_DIMENSIONS;
971
- vector[index] += hash < 0 ? -1 : 1;
984
+ async function createEmbedding(input) {
985
+ const normalizedInput = input.trim();
986
+ if (!normalizedInput) {
987
+ return Array.from({ length: EMBEDDING_DIMENSIONS }, () => 0);
972
988
  }
973
- const magnitude = Math.hypot(...vector) || 1;
974
- return vector.map((value) => value / magnitude);
989
+ const extractor = await getEmbeddingExtractor();
990
+ const tensor = await extractor(normalizedInput, { pooling: "mean", normalize: true });
991
+ const vector = Array.from(tensor.data);
992
+ if (vector.length !== EMBEDDING_DIMENSIONS) {
993
+ throw new Error(`Expected ${EMBEDDING_DIMENSIONS}-dim embedding from ${EMBEDDING_MODEL}, received ${vector.length}.`);
994
+ }
995
+ return vector;
975
996
  }
976
997
  function cosineSimilarity(left, right) {
977
998
  const size = Math.min(left.length, right.length);
@@ -1005,13 +1026,25 @@ function flattenMetadata(value) {
1005
1026
  }
1006
1027
  return [];
1007
1028
  }
1008
- function hashToken(token) {
1009
- let hash = 2166136261;
1010
- for (let index = 0; index < token.length; index += 1) {
1011
- hash ^= token.charCodeAt(index);
1012
- hash = Math.imul(hash, 16777619);
1029
+ async function getEmbeddingExtractor() {
1030
+ if (embeddingExtractorOverride) {
1031
+ return embeddingExtractorOverride;
1013
1032
  }
1014
- return hash | 0;
1033
+ if (!embeddingExtractorPromise) {
1034
+ embeddingExtractorPromise = loadEmbeddingExtractor().catch((error) => {
1035
+ embeddingExtractorPromise = void 0;
1036
+ throw error;
1037
+ });
1038
+ }
1039
+ return embeddingExtractorPromise;
1040
+ }
1041
+ async function loadEmbeddingExtractor() {
1042
+ const transformers = await import("@huggingface/transformers");
1043
+ process.env.HF_HOME ??= EMBEDDING_CACHE_DIR;
1044
+ process.env.TRANSFORMERS_CACHE ??= EMBEDDING_CACHE_DIR;
1045
+ transformers.env.cacheDir = EMBEDDING_CACHE_DIR;
1046
+ const extractor = await transformers.pipeline("feature-extraction", EMBEDDING_MODEL);
1047
+ return extractor;
1015
1048
  }
1016
1049
 
1017
1050
  // packages/memory/dist/forgetting-curve.js
@@ -1213,8 +1246,10 @@ var KEYWORD_WEIGHTS = {
1213
1246
  };
1214
1247
  var MemoryStore = class {
1215
1248
  db;
1249
+ embeddingEnabled;
1216
1250
  constructor(options = {}) {
1217
1251
  this.db = new SqliteMemoryDb(options);
1252
+ this.embeddingEnabled = this.db.vectorAvailable;
1218
1253
  }
1219
1254
  async memorize(key, essence, options = {}) {
1220
1255
  const existing = this.db.getByKey(key);
@@ -1238,7 +1273,7 @@ var MemoryStore = class {
1238
1273
  metadata: existingEntry?.metadata ? JSON.stringify(existingEntry.metadata) : null,
1239
1274
  created_at: existingEntry?.createdAt ?? now,
1240
1275
  search_text: searchText,
1241
- embedding: this.db.vectorAvailable ? JSON.stringify(createEmbedding(searchText)) : null,
1276
+ embedding: await this.createStoredEmbedding(searchText),
1242
1277
  key,
1243
1278
  tags: JSON.stringify(tags),
1244
1279
  trigger_conditions: JSON.stringify(triggerConditions),
@@ -1282,7 +1317,7 @@ var MemoryStore = class {
1282
1317
  trigger_conditions: JSON.stringify(normalizeStringArray(nextTriggerConditions)),
1283
1318
  importance: nextImportance,
1284
1319
  search_text: searchText,
1285
- embedding: this.db.vectorAvailable ? JSON.stringify(createEmbedding(searchText)) : row.embedding,
1320
+ embedding: await this.createStoredEmbedding(searchText, searchText === row.search_text ? row.embedding : null),
1286
1321
  updated_at: nowString()
1287
1322
  };
1288
1323
  this.db.upsertByKey(updated);
@@ -1294,26 +1329,28 @@ var MemoryStore = class {
1294
1329
  async recall(query, limit = 5) {
1295
1330
  const safeLimit = Number.isFinite(limit) ? Math.max(0, Math.floor(limit)) : 5;
1296
1331
  const tokens = keywordTokens(query);
1297
- if (tokens.length === 0) {
1332
+ const queryEmbedding = await this.loadQueryEmbedding(query);
1333
+ if (tokens.length === 0 && !queryEmbedding) {
1298
1334
  return [];
1299
1335
  }
1300
1336
  const now = nowString();
1301
- const candidates = this.db.listAll().map((row) => toMemoryEntry(row));
1302
- const scored = candidates.map((entry) => {
1337
+ const scoredRows = this.db.listAll().map((row) => {
1338
+ const entry = toMemoryEntry(row);
1303
1339
  const keywordScore = computeKeywordScore(entry, tokens);
1304
- if (keywordScore <= 0) {
1340
+ const embeddingScore = queryEmbedding && row.embedding ? cosineSimilarity(queryEmbedding, parseEmbedding(row.embedding)) : 0;
1341
+ const relevanceScore = keywordScore > 0 ? keywordScore : embeddingScore;
1342
+ if (relevanceScore <= 0) {
1305
1343
  return void 0;
1306
1344
  }
1307
1345
  const retention = computeRetention(entry.strength, entry.lastAccessedAt ?? entry.updatedAt, entry.decayTau, entry.importance, entry.accessCount);
1308
1346
  return {
1309
1347
  entry,
1310
1348
  keywordScore,
1311
- retention
1349
+ retention,
1350
+ finalScore: relevanceScore * 0.7 + retention * 0.3
1312
1351
  };
1313
- }).filter((candidate) => candidate !== void 0).map((candidate) => {
1314
- const finalScore = candidate.keywordScore * 0.7 + candidate.retention * 0.3;
1315
- return { ...candidate, finalScore };
1316
- }).sort((left, right) => right.finalScore - left.finalScore || right.retention - left.retention);
1352
+ });
1353
+ const scored = scoredRows.filter((candidate) => candidate !== void 0).sort((left, right) => right.finalScore - left.finalScore || right.retention - left.retention);
1317
1354
  const results = [];
1318
1355
  for (const selected of scored.slice(0, safeLimit)) {
1319
1356
  const strengthenedStrength = reinforceOnAccess(selected.entry.strength, selected.entry.importance);
@@ -1391,7 +1428,7 @@ var MemoryStore = class {
1391
1428
  last_accessed_at: nowIso,
1392
1429
  updated_at: nowIso,
1393
1430
  search_text: searchText,
1394
- embedding: this.db.vectorAvailable ? JSON.stringify(createEmbedding(searchText)) : row.embedding
1431
+ embedding: await this.createStoredEmbedding(searchText, row.embedding)
1395
1432
  };
1396
1433
  this.db.upsertByKey(updated);
1397
1434
  survivors.push(toMemoryEntry(updated));
@@ -1437,9 +1474,16 @@ var MemoryStore = class {
1437
1474
  if (safeTopK <= 0) {
1438
1475
  return [];
1439
1476
  }
1440
- if (this.db.vectorAvailable) {
1441
- const queryEmbedding = createEmbedding(query);
1442
- return this.db.listWithEmbeddings().map((row) => ({ row, score: cosineSimilarity(queryEmbedding, parseEmbedding(row.embedding)) })).sort((left, right) => right.score - left.score || compareRows(left.row, right.row)).slice(0, safeTopK).map(({ row }) => toMemoryEntry(row));
1477
+ if (query.trim().length === 0) {
1478
+ return this.db.searchByKeywords(query, safeTopK).map((row) => toMemoryEntry(row));
1479
+ }
1480
+ const queryEmbedding = await this.loadQueryEmbedding(query);
1481
+ if (queryEmbedding) {
1482
+ const tokens = keywordTokens(query);
1483
+ return this.db.listAll().map((row) => {
1484
+ const score = row.embedding ? cosineSimilarity(queryEmbedding, parseEmbedding(row.embedding)) : computeKeywordScore(toMemoryEntry(row), tokens);
1485
+ return { row, score };
1486
+ }).filter(({ score }) => score > 0).sort((left, right) => right.score - left.score || compareRows(left.row, right.row)).slice(0, safeTopK).map(({ row }) => toMemoryEntry(row));
1443
1487
  }
1444
1488
  return this.db.searchByKeywords(query, safeTopK).map((row) => toMemoryEntry(row));
1445
1489
  }
@@ -1467,7 +1511,7 @@ var MemoryStore = class {
1467
1511
  ...row,
1468
1512
  metadata: serializedMetadata,
1469
1513
  search_text: searchText,
1470
- embedding: this.db.vectorAvailable ? JSON.stringify(createEmbedding(searchText)) : row.embedding
1514
+ embedding: await this.createStoredEmbedding(searchText, row.embedding)
1471
1515
  });
1472
1516
  }
1473
1517
  }
@@ -1479,6 +1523,18 @@ var MemoryStore = class {
1479
1523
  close() {
1480
1524
  this.db.close();
1481
1525
  }
1526
+ async createStoredEmbedding(searchText, fallback = null) {
1527
+ if (!this.embeddingEnabled) {
1528
+ return null;
1529
+ }
1530
+ return createStoredEmbedding(searchText, fallback);
1531
+ }
1532
+ async loadQueryEmbedding(query) {
1533
+ if (!this.embeddingEnabled) {
1534
+ return null;
1535
+ }
1536
+ return loadQueryEmbedding(query);
1537
+ }
1482
1538
  };
1483
1539
  function buildSearchTextFromParts(essence, context) {
1484
1540
  const searchMetadata = {
@@ -1518,6 +1574,20 @@ function parseEmbedding(embedding) {
1518
1574
  const value = JSON.parse(embedding);
1519
1575
  return Array.isArray(value) ? value.filter((item) => typeof item === "number") : [];
1520
1576
  }
1577
+ async function createStoredEmbedding(searchText, fallback = null) {
1578
+ try {
1579
+ return JSON.stringify(await createEmbedding(searchText));
1580
+ } catch {
1581
+ return fallback;
1582
+ }
1583
+ }
1584
+ async function loadQueryEmbedding(query) {
1585
+ try {
1586
+ return await createEmbedding(query);
1587
+ } catch {
1588
+ return null;
1589
+ }
1590
+ }
1521
1591
  function parseMetadata(metadata) {
1522
1592
  if (!metadata) {
1523
1593
  return null;
@@ -1595,7 +1665,7 @@ function toISOString(time) {
1595
1665
  var defaultStore = null;
1596
1666
  function createMemoryStore(options = {}) {
1597
1667
  return new MemoryStore({
1598
- dbPath: options.dbPath ?? join(homedir2(), ".va-claw", "memory.db"),
1668
+ dbPath: options.dbPath ?? join2(homedir3(), ".va-claw", "memory.db"),
1599
1669
  enableVectorSearch: options.enableVectorSearch,
1600
1670
  vectorExtensionPath: options.vectorExtensionPath
1601
1671
  });
@@ -1758,16 +1828,16 @@ function splitInlineArray(value) {
1758
1828
  }
1759
1829
 
1760
1830
  // packages/skills/dist/paths.js
1761
- import { homedir as homedir3 } from "node:os";
1762
- import { isAbsolute, join as join2, resolve as resolve2 } from "node:path";
1831
+ import { homedir as homedir4 } from "node:os";
1832
+ import { isAbsolute, join as join3, resolve as resolve2 } from "node:path";
1763
1833
  var overrides = {};
1764
1834
  function resolveInstalledSkillsDir() {
1765
- const baseDir = overrides.homeDir ? resolve2(overrides.homeDir) : resolve2(homedir3(), ".va-claw");
1766
- return join2(baseDir, "skills");
1835
+ const baseDir = overrides.homeDir ? resolve2(overrides.homeDir) : resolve2(homedir4(), ".va-claw");
1836
+ return join3(baseDir, "skills");
1767
1837
  }
1768
1838
  function resolveProjectSkillsDir() {
1769
1839
  const baseDir = overrides.projectDir ? resolve2(overrides.projectDir) : process.cwd();
1770
- return join2(baseDir, "skills");
1840
+ return join3(baseDir, "skills");
1771
1841
  }
1772
1842
  function resolveSkillLookupDirs(dir) {
1773
1843
  if (dir) {
@@ -1777,10 +1847,10 @@ function resolveSkillLookupDirs(dir) {
1777
1847
  }
1778
1848
  function resolvePathInput(value) {
1779
1849
  if (value === "~") {
1780
- return homedir3();
1850
+ return homedir4();
1781
1851
  }
1782
1852
  if (value.startsWith("~/")) {
1783
- return resolve2(homedir3(), value.slice(2));
1853
+ return resolve2(homedir4(), value.slice(2));
1784
1854
  }
1785
1855
  return isAbsolute(value) ? value : resolve2(value);
1786
1856
  }
@@ -1816,7 +1886,7 @@ function normalize(value) {
1816
1886
 
1817
1887
  // packages/skills/dist/store.js
1818
1888
  import { access, mkdir as mkdir2, readFile as readFile2, readdir, rm, writeFile as writeFile2 } from "node:fs/promises";
1819
- import { join as join3 } from "node:path";
1889
+ import { join as join4 } from "node:path";
1820
1890
  async function loadSkill(nameOrPath) {
1821
1891
  const path = await resolveSkillPath(nameOrPath);
1822
1892
  return readSkillFile(path);
@@ -1836,14 +1906,14 @@ async function listSkills(dir) {
1836
1906
  return skills;
1837
1907
  }
1838
1908
  async function installSkill(content, name) {
1839
- const skillPath = join3(resolveInstalledSkillsDir(), toSkillFileName(name));
1909
+ const skillPath = join4(resolveInstalledSkillsDir(), toSkillFileName(name));
1840
1910
  parseSkillMarkdown(content, skillPath);
1841
1911
  await mkdir2(resolveInstalledSkillsDir(), { recursive: true });
1842
1912
  await writeFile2(skillPath, content, "utf8");
1843
1913
  return skillPath;
1844
1914
  }
1845
1915
  async function removeSkill(name) {
1846
- await rm(join3(resolveInstalledSkillsDir(), toSkillFileName(name)), { force: true });
1916
+ await rm(join4(resolveInstalledSkillsDir(), toSkillFileName(name)), { force: true });
1847
1917
  }
1848
1918
  function injectSkillIntoPrompt(skill, basePrompt) {
1849
1919
  const prompt = basePrompt.trimEnd();
@@ -1853,7 +1923,7 @@ function injectSkillIntoPrompt(skill, basePrompt) {
1853
1923
  ${skillBlock}`;
1854
1924
  }
1855
1925
  async function resolveSkillPath(nameOrPath) {
1856
- const candidates = looksLikePath(nameOrPath) ? [resolvePathInput(nameOrPath)] : resolveSkillLookupDirs().map((dir) => join3(dir, toSkillFileName(nameOrPath)));
1926
+ const candidates = looksLikePath(nameOrPath) ? [resolvePathInput(nameOrPath)] : resolveSkillLookupDirs().map((dir) => join4(dir, toSkillFileName(nameOrPath)));
1857
1927
  for (const candidate of candidates) {
1858
1928
  if (await exists(candidate)) {
1859
1929
  return candidate;
@@ -1866,7 +1936,7 @@ async function readSkillsFromDir(dir) {
1866
1936
  return [];
1867
1937
  }
1868
1938
  const names = (await readdir(dir)).filter((entry) => entry.toLowerCase().endsWith(".md")).sort();
1869
- return Promise.all(names.map((name) => readSkillFile(join3(dir, name))));
1939
+ return Promise.all(names.map((name) => readSkillFile(join4(dir, name))));
1870
1940
  }
1871
1941
  async function readSkillFile(path) {
1872
1942
  return parseSkillMarkdown(await readFile2(path, "utf8"), path);
@@ -2085,7 +2155,7 @@ async function writeWakeLogSafe(entry, deps) {
2085
2155
  }
2086
2156
  }
2087
2157
  async function writeWakeLog(entry) {
2088
- const logPath = resolve3(homedir4(), ".va-claw", "wake.log");
2158
+ const logPath = resolve3(homedir5(), ".va-claw", "wake.log");
2089
2159
  await mkdir3(dirname3(logPath), { recursive: true });
2090
2160
  await appendFile(logPath, `${JSON.stringify(entry)}
2091
2161
  `, "utf8");
@@ -2164,24 +2234,24 @@ import { dirname as dirname5 } from "node:path";
2164
2234
  import { spawnSync as spawnSync2 } from "node:child_process";
2165
2235
 
2166
2236
  // packages/daemon/dist/service-files.js
2167
- import { homedir as homedir5 } from "node:os";
2168
- import { dirname as dirname4, join as join4, resolve as resolve4 } from "node:path";
2237
+ import { homedir as homedir6 } from "node:os";
2238
+ import { dirname as dirname4, join as join5, resolve as resolve4 } from "node:path";
2169
2239
  import { fileURLToPath } from "node:url";
2170
2240
  function createServiceDefinition(type) {
2171
2241
  const packageRoot = resolve4(dirname4(fileURLToPath(import.meta.url)), "..");
2172
2242
  const repoRoot = resolve4(packageRoot, "../..");
2173
- const runnerPath = join4(packageRoot, "dist", "runner.js");
2243
+ const runnerPath = join5(packageRoot, "dist", "runner.js");
2174
2244
  const nodePath = process.execPath;
2175
2245
  if (type === "launchd") {
2176
2246
  return {
2177
- path: join4(homedir5(), "Library", "LaunchAgents", "com.va-claw.daemon.plist"),
2247
+ path: join5(homedir6(), "Library", "LaunchAgents", "com.va-claw.daemon.plist"),
2178
2248
  content: renderLaunchdPlist(repoRoot, [nodePath, runnerPath]),
2179
2249
  command: "launchctl",
2180
- args: ["load", join4(homedir5(), "Library", "LaunchAgents", "com.va-claw.daemon.plist")]
2250
+ args: ["load", join5(homedir6(), "Library", "LaunchAgents", "com.va-claw.daemon.plist")]
2181
2251
  };
2182
2252
  }
2183
2253
  return {
2184
- path: join4(homedir5(), ".config", "systemd", "user", "va-claw.service"),
2254
+ path: join5(homedir6(), ".config", "systemd", "user", "va-claw.service"),
2185
2255
  content: renderSystemdUnit(repoRoot, [nodePath, runnerPath]),
2186
2256
  command: "systemctl",
2187
2257
  args: ["--user", "enable", "--now", "va-claw.service"]
@@ -2191,7 +2261,7 @@ function createUninstallCommand(type) {
2191
2261
  if (type === "launchd") {
2192
2262
  return {
2193
2263
  command: "launchctl",
2194
- args: ["unload", join4(homedir5(), "Library", "LaunchAgents", "com.va-claw.daemon.plist")]
2264
+ args: ["unload", join5(homedir6(), "Library", "LaunchAgents", "com.va-claw.daemon.plist")]
2195
2265
  };
2196
2266
  }
2197
2267
  return {
@@ -2273,8 +2343,8 @@ function runCommand(command, args, allowFailure = false) {
2273
2343
 
2274
2344
  // packages/cli/dist/install-files.js
2275
2345
  import { access as access2, mkdir as mkdir5, readFile as readFile3, writeFile as writeFile4 } from "node:fs/promises";
2276
- import { homedir as homedir6 } from "node:os";
2277
- import { dirname as dirname6, join as join5 } from "node:path";
2346
+ import { homedir as homedir7 } from "node:os";
2347
+ import { dirname as dirname6, join as join6 } from "node:path";
2278
2348
  var CLAUDE_MARKERS = {
2279
2349
  start: "<!-- va-claw:identity:start -->",
2280
2350
  end: "<!-- va-claw:identity:end -->"
@@ -2283,17 +2353,17 @@ var CODEX_MARKERS = {
2283
2353
  start: "<!-- va-claw:codex:start -->",
2284
2354
  end: "<!-- va-claw:codex:end -->"
2285
2355
  };
2286
- function resolveClaudeMdPath(home = homedir6()) {
2287
- return join5(home, ".claude", "CLAUDE.md");
2356
+ function resolveClaudeMdPath(home = homedir7()) {
2357
+ return join6(home, ".claude", "CLAUDE.md");
2288
2358
  }
2289
- function resolveCodexInstructionsPath(home = homedir6()) {
2290
- return join5(home, ".codex", "instructions.md");
2359
+ function resolveCodexInstructionsPath(home = homedir7()) {
2360
+ return join6(home, ".codex", "instructions.md");
2291
2361
  }
2292
- function resolveMemoryDbPath(home = homedir6()) {
2293
- return join5(home, ".va-claw", "memory.db");
2362
+ function resolveMemoryDbPath(home = homedir7()) {
2363
+ return join6(home, ".va-claw", "memory.db");
2294
2364
  }
2295
- function resolveClawRegistryPath(home = homedir6()) {
2296
- return join5(home, ".va-claw", "claws.json");
2365
+ function resolveClawRegistryPath(home = homedir7()) {
2366
+ return join6(home, ".va-claw", "claws.json");
2297
2367
  }
2298
2368
  async function fileExists(path) {
2299
2369
  try {
@@ -2632,8 +2702,8 @@ function parseMetadata2(raw) {
2632
2702
  }
2633
2703
 
2634
2704
  // packages/cli/dist/platform.js
2635
- import { homedir as homedir7 } from "node:os";
2636
- import { join as join6 } from "node:path";
2705
+ import { homedir as homedir8 } from "node:os";
2706
+ import { join as join7 } from "node:path";
2637
2707
  function detectServiceType(platform) {
2638
2708
  if (platform === "darwin") {
2639
2709
  return "launchd";
@@ -2660,7 +2730,7 @@ function stopInstalledService(type, spawnSync4) {
2660
2730
  spawnSync4("systemctl", ["--user", "stop", "va-claw.service"], { encoding: "utf8" });
2661
2731
  }
2662
2732
  function resolveLaunchdPath() {
2663
- return join6(homedir7(), "Library", "LaunchAgents", "com.va-claw.daemon.plist");
2733
+ return join7(homedir8(), "Library", "LaunchAgents", "com.va-claw.daemon.plist");
2664
2734
  }
2665
2735
 
2666
2736
  // packages/cli/dist/claw-store.js
@@ -2799,6 +2869,7 @@ async function saveClawRegistry(registryPath, registry) {
2799
2869
 
2800
2870
  // packages/cli/dist/handlers.js
2801
2871
  var CLAW_FLEET_PROTOCOL_SKILL_URL = "https://raw.githubusercontent.com/Vadaski/va-claw/main/skills/claw-fleet-protocol.md";
2872
+ var MEMORY_SKILL_URL = "https://raw.githubusercontent.com/Vadaski/va-claw/main/skills/memory-protocol.md";
2802
2873
  async function runInstall(target, deps) {
2803
2874
  const installTarget = normalizeInstallTarget(target);
2804
2875
  const config = await deps.fileExists(deps.configPath) ? await deps.loadIdentity() : await deps.runInstallWizard();
@@ -2819,6 +2890,10 @@ async function runInstall(target, deps) {
2819
2890
  if (fleetSkillName) {
2820
2891
  summary.push(`Claw fleet protocol skill: ${fleetSkillName}`);
2821
2892
  }
2893
+ const memorySkillName = await installMemoryProtocolSkill(deps);
2894
+ if (memorySkillName) {
2895
+ summary.push(`Memory protocol skill: ${memorySkillName}`);
2896
+ }
2822
2897
  for (const line of summary) {
2823
2898
  writeLine(deps.stdout, line);
2824
2899
  }
@@ -2978,13 +3053,19 @@ async function buildProtocolReport(deps) {
2978
3053
  };
2979
3054
  }
2980
3055
  async function installFleetProtocolSkill(deps) {
3056
+ return installRemoteSkill(deps, CLAW_FLEET_PROTOCOL_SKILL_URL, "claw-fleet-protocol");
3057
+ }
3058
+ async function installMemoryProtocolSkill(deps) {
3059
+ return installRemoteSkill(deps, MEMORY_SKILL_URL, "memory-protocol");
3060
+ }
3061
+ async function installRemoteSkill(deps, url, name) {
2981
3062
  try {
2982
- const response = await fetch(CLAW_FLEET_PROTOCOL_SKILL_URL);
3063
+ const response = await fetch(url);
2983
3064
  if (!response.ok) {
2984
3065
  return null;
2985
3066
  }
2986
3067
  const content = await response.text();
2987
- return await deps.skillInstall(content, "claw-fleet-protocol");
3068
+ return await deps.skillInstall(content, name);
2988
3069
  } catch {
2989
3070
  return null;
2990
3071
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "va-claw",
3
- "version": "0.1.4",
3
+ "version": "0.2.1",
4
4
  "description": "Persistent memory, identity, and wake-loop daemon for Claude Code & Codex",
5
5
  "keywords": [
6
6
  "claude-code",
@@ -38,6 +38,9 @@
38
38
  "bundle": "node scripts/bundle.mjs",
39
39
  "prepublishOnly": "pnpm run build && node scripts/bundle.mjs"
40
40
  },
41
+ "dependencies": {
42
+ "@huggingface/transformers": "latest"
43
+ },
41
44
  "devDependencies": {
42
45
  "esbuild": "^0.27.3",
43
46
  "typescript": "file:vendor/typescript"