@riconext/hermes-repo 1.2.1 → 1.2.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.2.2
4
+
5
+ ### Patch Changes
6
+
7
+ - a8aff7f: 记录 flush 执行过程到 debug 日志,并在写入 MEMORY.md 前校验知识文件链接是否真实存在。
8
+
3
9
  ## 1.2.1
4
10
 
5
11
  ### Patch Changes
package/dist/cli.js CHANGED
@@ -1537,6 +1537,13 @@ function isSkippedEntry(raw) {
1537
1537
  // src/consolidate/writeKnowledge.ts
1538
1538
  import { existsSync as existsSync7, mkdirSync as mkdirSync5, readFileSync as readFileSync10, writeFileSync as writeFileSync5 } from "fs";
1539
1539
  import { dirname as dirname4 } from "path";
1540
+ var KNOWLEDGE_LINK_PREFIXES = [
1541
+ "rules/",
1542
+ "domains/",
1543
+ "workflows/",
1544
+ "decisions/",
1545
+ "incidents/"
1546
+ ];
1540
1547
  function writeKnowledgeFiles(repoRoot, files) {
1541
1548
  const result = {
1542
1549
  created: [],
@@ -1580,6 +1587,38 @@ function writeMemoryMd(repoRoot, memoryMd) {
1580
1587
  writeFileSync5(memoryPathAbs, `${memoryMd}
1581
1588
  `, "utf8");
1582
1589
  }
1590
+ function assertMemoryKnowledgeLinksExist(repoRoot, memoryMd) {
1591
+ const missing = findMissingKnowledgeLinks(repoRoot, memoryMd);
1592
+ if (missing.length > 0) {
1593
+ throw new Error(
1594
+ `MEMORY.md \u5F15\u7528\u4E86\u4E0D\u5B58\u5728\u7684\u77E5\u8BC6\u6587\u4EF6: ${missing.join(", ")}`
1595
+ );
1596
+ }
1597
+ }
1598
+ function findMissingKnowledgeLinks(repoRoot, memoryMd) {
1599
+ const links = extractKnowledgeLinks(memoryMd);
1600
+ return links.filter((link) => !existsSync7(memoryPath(repoRoot, link)));
1601
+ }
1602
+ function extractKnowledgeLinks(memoryMd) {
1603
+ const links = /* @__PURE__ */ new Set();
1604
+ const markdownLink = /\[[^\]]+\]\(([^)]+)\)/g;
1605
+ let match;
1606
+ while ((match = markdownLink.exec(memoryMd)) !== null) {
1607
+ const normalized = normalizeKnowledgeLink(match[1]);
1608
+ if (normalized) {
1609
+ links.add(normalized);
1610
+ }
1611
+ }
1612
+ return [...links];
1613
+ }
1614
+ function normalizeKnowledgeLink(rawLink) {
1615
+ const withoutAnchor = rawLink.split("#")[0].trim();
1616
+ const withoutDotSlash = withoutAnchor.startsWith("./") ? withoutAnchor.slice(2) : withoutAnchor;
1617
+ if (withoutDotSlash.includes("://") || withoutDotSlash.startsWith("/") || withoutDotSlash.includes("..") || !withoutDotSlash.endsWith(".md")) {
1618
+ return null;
1619
+ }
1620
+ return KNOWLEDGE_LINK_PREFIXES.some((prefix) => withoutDotSlash.startsWith(prefix)) ? withoutDotSlash : null;
1621
+ }
1583
1622
  function serializeKnowledgeFile(frontmatter, body) {
1584
1623
  const lines = ["---"];
1585
1624
  const fieldOrder = ["title", "domain", "type", "status", "confidence", "lastReviewed"];
@@ -1666,10 +1705,17 @@ function archiveDoneSessions(repoRoot, sessions, autoArchiveDays = 30) {
1666
1705
  // src/consolidate/runConsolidate.ts
1667
1706
  async function runConsolidate(opts) {
1668
1707
  const { repoRoot, config, force, dryRun, debug } = opts;
1708
+ debugLog(
1709
+ debug === true,
1710
+ "consolidate",
1711
+ `start: force=${force === true}, dryRun=${dryRun === true}`
1712
+ );
1669
1713
  writeConsolidateLock(repoRoot);
1714
+ debugLog(debug === true, "consolidate", "lock acquired");
1670
1715
  try {
1671
1716
  const llmConfig = config.llm;
1672
1717
  if (!llmConfig.enabled) {
1718
+ debugLog(debug === true, "consolidate", "skip: llm not enabled");
1673
1719
  return {
1674
1720
  ran: false,
1675
1721
  reason: "llm-not-enabled",
@@ -1688,6 +1734,7 @@ async function runConsolidate(opts) {
1688
1734
  `\u626B\u63CF\u5230 ${allSessions.length} \u4E2A session\uFF0C\u5176\u4E2D ${pendingSessions.length} \u4E2A\u5F85\u5904\u7406`
1689
1735
  );
1690
1736
  if (pendingSessions.length === 0 && !force) {
1737
+ debugLog(debug === true, "consolidate", "skip: no pending sessions");
1691
1738
  return {
1692
1739
  ran: false,
1693
1740
  reason: "no-pending-sessions",
@@ -1699,6 +1746,11 @@ async function runConsolidate(opts) {
1699
1746
  };
1700
1747
  }
1701
1748
  if (dryRun) {
1749
+ debugLog(
1750
+ debug === true,
1751
+ "consolidate",
1752
+ `dry-run: would process ${pendingSessions.length} session(s)`
1753
+ );
1702
1754
  return {
1703
1755
  ran: true,
1704
1756
  reason: "dry-run",
@@ -1710,7 +1762,11 @@ async function runConsolidate(opts) {
1710
1762
  };
1711
1763
  }
1712
1764
  const llmInput = buildLlmConsolidateInput(repoRoot, pendingSessions);
1713
- debugLog(debug === true, "consolidate", `LLM \u8F93\u5165: ${llmInput.pendingSessions.length} sessions, ${llmInput.existingKnowledge.length} existing knowledge`);
1765
+ debugLog(
1766
+ debug === true,
1767
+ "consolidate",
1768
+ `LLM \u8F93\u5165: ${llmInput.pendingSessions.length} sessions, ${llmInput.existingKnowledge.length} existing knowledge`
1769
+ );
1714
1770
  let llmResult;
1715
1771
  try {
1716
1772
  llmResult = await callLlmConsolidate(llmInput, llmConfig);
@@ -1723,8 +1779,33 @@ async function runConsolidate(opts) {
1723
1779
  "consolidate",
1724
1780
  `LLM \u8FD4\u56DE: ${llmResult.knowledgeFiles.length} knowledge files, ${llmResult.skippedSessions.length} skipped`
1725
1781
  );
1782
+ debugLog(debug === true, "consolidate", "writing knowledge files");
1726
1783
  const writeResult = writeKnowledgeFiles(repoRoot, llmResult.knowledgeFiles);
1784
+ if (writeResult.failed.length > 0) {
1785
+ debugLog(
1786
+ debug === true,
1787
+ "consolidate",
1788
+ `write failed: ${writeResult.failed.join(", ")}`
1789
+ );
1790
+ throw new Error(
1791
+ `\u77E5\u8BC6\u6587\u4EF6\u5199\u5165\u5931\u8D25: ${writeResult.failed.join(", ")}`
1792
+ );
1793
+ }
1794
+ debugLog(
1795
+ debug === true,
1796
+ "consolidate",
1797
+ `knowledge files written: created=${writeResult.created.length}, updated=${writeResult.updated.length}`
1798
+ );
1799
+ debugLog(debug === true, "consolidate", "validating MEMORY.md links");
1800
+ assertMemoryKnowledgeLinksExist(repoRoot, llmResult.memoryMd);
1801
+ debugLog(debug === true, "consolidate", "MEMORY.md links ok");
1802
+ debugLog(debug === true, "consolidate", "writing MEMORY.md");
1727
1803
  writeMemoryMd(repoRoot, llmResult.memoryMd);
1804
+ debugLog(
1805
+ debug === true,
1806
+ "consolidate",
1807
+ `marking sessions done: ${pendingSessions.length} processed, ${llmResult.skippedSessions.length} skipped`
1808
+ );
1728
1809
  const processedSessionIds = /* @__PURE__ */ new Set();
1729
1810
  for (const s of pendingSessions) {
1730
1811
  markSessionConsolidated(repoRoot, s.sessionId);
@@ -1736,6 +1817,7 @@ async function runConsolidate(opts) {
1736
1817
  }
1737
1818
  const prevState = readConsolidateState(repoRoot);
1738
1819
  const newDomains = extractDomainsFromResults(llmResult.knowledgeFiles);
1820
+ debugLog(debug === true, "consolidate", "updating consolidate state");
1739
1821
  writeConsolidateState(repoRoot, {
1740
1822
  version: 2,
1741
1823
  lastConsolidatedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -1759,6 +1841,12 @@ async function runConsolidate(opts) {
1759
1841
  allSessions,
1760
1842
  config.consolidate.autoArchiveDays
1761
1843
  );
1844
+ debugLog(debug === true, "consolidate", `archived sessions: ${archived}`);
1845
+ debugLog(
1846
+ debug === true,
1847
+ "consolidate",
1848
+ `done: sessions=${pendingSessions.length}, created=${writeResult.created.length}, updated=${writeResult.updated.length}, skipped=${llmResult.skippedSessions.length}, archived=${archived}`
1849
+ );
1762
1850
  return {
1763
1851
  ran: true,
1764
1852
  sessionsProcessed: pendingSessions.length,
@@ -1769,6 +1857,7 @@ async function runConsolidate(opts) {
1769
1857
  };
1770
1858
  } finally {
1771
1859
  releaseConsolidateLock(repoRoot);
1860
+ debugLog(debug === true, "consolidate", "lock released");
1772
1861
  }
1773
1862
  }
1774
1863
  function extractDomainsFromResults(files) {
@@ -2421,12 +2510,25 @@ function runCaptureCommand(opts) {
2421
2510
 
2422
2511
  // src/commands/flush.ts
2423
2512
  async function runFlushCommandCli(opts) {
2513
+ const ctx = loadRepoContext(opts.cwd);
2514
+ const debug = ctx?.config.debug === true;
2515
+ configureDebugLogging(ctx?.repoRoot ?? null, debug);
2516
+ debugLog(
2517
+ debug,
2518
+ "flush",
2519
+ `start: force=${opts.force === true}, dryRun=${opts.dryRun === true}`
2520
+ );
2424
2521
  try {
2425
2522
  const result = await runFlushCommand({
2426
2523
  cwd: opts.cwd,
2427
2524
  force: opts.force,
2428
2525
  dryRun: opts.dryRun
2429
2526
  });
2527
+ debugLog(
2528
+ debug,
2529
+ "flush",
2530
+ `result: ran=${result.ran}, reason=${result.reason ?? "ok"}, sessions=${result.sessionsProcessed}, created=${result.knowledgeCreated}, updated=${result.knowledgeUpdated}, skipped=${result.skippedCount}, archived=${result.archived}`
2531
+ );
2430
2532
  if (result.ran) {
2431
2533
  if (result.reason === "dry-run") {
2432
2534
  console.error(
@@ -2466,6 +2568,11 @@ async function runFlushCommandCli(opts) {
2466
2568
  }
2467
2569
  hookExit(0, opts.strict);
2468
2570
  } catch (err) {
2571
+ debugLog(
2572
+ debug,
2573
+ "flush",
2574
+ `error: ${err instanceof Error ? err.message : String(err)}`
2575
+ );
2469
2576
  console.error(
2470
2577
  `hermes-repo flush: ${err instanceof Error ? err.message : String(err)}`
2471
2578
  );