@riconext/hermes-repo 1.1.1 → 1.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.
package/dist/cli.js CHANGED
@@ -1,10 +1,4 @@
1
1
  #!/usr/bin/env node
2
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
3
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
4
- }) : x)(function(x) {
5
- if (typeof require !== "undefined") return require.apply(this, arguments);
6
- throw Error('Dynamic require of "' + x + '" is not supported');
7
- });
8
2
 
9
3
  // src/cli.ts
10
4
  import { Command } from "commander";
@@ -113,8 +107,15 @@ function parseLlmConfig(raw) {
113
107
  }
114
108
  function parseConsolidateConfig(raw) {
115
109
  const c = raw.consolidate;
110
+ const autoFlush = c?.autoFlush && typeof c.autoFlush === "object" && !Array.isArray(c.autoFlush) ? c.autoFlush : {};
116
111
  return {
117
- autoArchiveDays: typeof c?.autoArchiveDays === "number" ? c.autoArchiveDays : 30
112
+ autoArchiveDays: typeof c?.autoArchiveDays === "number" ? c.autoArchiveDays : 30,
113
+ autoFlush: {
114
+ enabled: autoFlush.enabled === true,
115
+ minPendingSessions: typeof autoFlush.minPendingSessions === "number" && autoFlush.minPendingSessions > 0 ? autoFlush.minPendingSessions : 3,
116
+ minIntervalMinutes: typeof autoFlush.minIntervalMinutes === "number" && autoFlush.minIntervalMinutes > 0 ? autoFlush.minIntervalMinutes : 30,
117
+ maxPendingChars: typeof autoFlush.maxPendingChars === "number" && autoFlush.maxPendingChars > 0 ? autoFlush.maxPendingChars : 2e4
118
+ }
118
119
  };
119
120
  }
120
121
  function readConfigAtRepo(repoRoot) {
@@ -151,7 +152,15 @@ function readConfigAtRepo(repoRoot) {
151
152
  maxInputChars: 24e3,
152
153
  mode: "async"
153
154
  },
154
- consolidate: { autoArchiveDays: 30 }
155
+ consolidate: {
156
+ autoArchiveDays: 30,
157
+ autoFlush: {
158
+ enabled: false,
159
+ minPendingSessions: 3,
160
+ minIntervalMinutes: 30,
161
+ maxPendingChars: 2e4
162
+ }
163
+ }
155
164
  };
156
165
  }
157
166
  return null;
@@ -1106,6 +1115,11 @@ function needsLlm(session) {
1106
1115
  return false;
1107
1116
  }
1108
1117
 
1118
+ // src/consolidate/scheduleConsolidate.ts
1119
+ import { spawn as spawn2 } from "child_process";
1120
+ import { dirname as dirname5, join as join11 } from "path";
1121
+ import { fileURLToPath as fileURLToPath2 } from "url";
1122
+
1109
1123
  // src/consolidate/state.ts
1110
1124
  import {
1111
1125
  existsSync as existsSync6,
@@ -1521,7 +1535,7 @@ function isSkippedEntry(raw) {
1521
1535
  }
1522
1536
 
1523
1537
  // src/consolidate/writeKnowledge.ts
1524
- import { existsSync as existsSync7, mkdirSync as mkdirSync5, writeFileSync as writeFileSync5 } from "fs";
1538
+ import { existsSync as existsSync7, mkdirSync as mkdirSync5, readFileSync as readFileSync10, writeFileSync as writeFileSync5 } from "fs";
1525
1539
  import { dirname as dirname4 } from "path";
1526
1540
  function writeKnowledgeFiles(repoRoot, files) {
1527
1541
  const result = {
@@ -1556,7 +1570,7 @@ function writeKnowledgeFiles(repoRoot, files) {
1556
1570
  function writeMemoryMd(repoRoot, memoryMd) {
1557
1571
  const memoryPathAbs = memoryPath(repoRoot, "MEMORY.md");
1558
1572
  if (existsSync7(memoryPathAbs)) {
1559
- const existing = __require("fs").readFileSync(memoryPathAbs, "utf8");
1573
+ const existing = readFileSync10(memoryPathAbs, "utf8");
1560
1574
  const preserved = extractUserEditedSections(existing);
1561
1575
  if (preserved.length > 0) {
1562
1576
  memoryMd = injectUserSections(memoryMd, preserved);
@@ -1772,6 +1786,9 @@ function extractDomainsFromResults(files) {
1772
1786
  var CONSOLIDATE_LOCK_TTL_MS = 30 * 60 * 1e3;
1773
1787
 
1774
1788
  // src/consolidate/scheduleConsolidate.ts
1789
+ function cliPath2() {
1790
+ return join11(dirname5(fileURLToPath2(import.meta.url)), "..", "cli.js");
1791
+ }
1775
1792
  async function runFlushCommand(opts) {
1776
1793
  const ctx = loadRepoContext(opts.cwd);
1777
1794
  if (!ctx) {
@@ -1806,11 +1823,83 @@ async function runFlushCommand(opts) {
1806
1823
  debug: opts.debug ?? ctx.config.debug
1807
1824
  });
1808
1825
  }
1826
+ function shouldAutoFlush(sessions, consolidate, lastConsolidatedAt) {
1827
+ const autoFlush = consolidate.autoFlush;
1828
+ if (!autoFlush.enabled || sessions.length === 0) {
1829
+ return false;
1830
+ }
1831
+ if (sessions.length >= autoFlush.minPendingSessions) {
1832
+ return true;
1833
+ }
1834
+ const pendingChars = sessions.reduce(
1835
+ (sum, session) => sum + session.bodyContent.length,
1836
+ 0
1837
+ );
1838
+ if (pendingChars >= autoFlush.maxPendingChars) {
1839
+ return true;
1840
+ }
1841
+ const last = Date.parse(lastConsolidatedAt);
1842
+ if (Number.isNaN(last)) {
1843
+ return true;
1844
+ }
1845
+ const minIntervalMs = autoFlush.minIntervalMinutes * 60 * 1e3;
1846
+ return Date.now() - last >= minIntervalMs;
1847
+ }
1809
1848
  function maybeScheduleConsolidate(opts) {
1849
+ const ctx = loadRepoContext(opts.repoRoot);
1850
+ if (!ctx) {
1851
+ return;
1852
+ }
1853
+ const autoFlush = ctx.config.consolidate.autoFlush;
1854
+ if (!autoFlush.enabled) {
1855
+ return;
1856
+ }
1857
+ if (!isLlmAvailable(ctx.config.llm)) {
1858
+ debugLog(opts.debug === true, "consolidate", "auto flush skipped: llm not available");
1859
+ return;
1860
+ }
1810
1861
  const lock = readConsolidateLock(opts.repoRoot);
1811
1862
  if (lock && !isLockStale(lock, CONSOLIDATE_LOCK_TTL_MS)) {
1863
+ debugLog(opts.debug === true, "consolidate", "auto flush skipped: lock held");
1864
+ return;
1865
+ }
1866
+ const pendingSessions = filterPendingSessions(scanAllSessions(opts.repoRoot));
1867
+ const state = readConsolidateState(opts.repoRoot);
1868
+ if (!shouldAutoFlush(
1869
+ pendingSessions,
1870
+ ctx.config.consolidate,
1871
+ state.lastConsolidatedAt
1872
+ )) {
1873
+ debugLog(
1874
+ opts.debug === true,
1875
+ "consolidate",
1876
+ `auto flush skipped: ${pendingSessions.length} pending session(s) below thresholds`
1877
+ );
1812
1878
  return;
1813
1879
  }
1880
+ try {
1881
+ const child = spawn2(
1882
+ process.execPath,
1883
+ [cliPath2(), "flush", "-C", opts.repoRoot],
1884
+ {
1885
+ detached: true,
1886
+ stdio: "ignore",
1887
+ cwd: opts.repoRoot
1888
+ }
1889
+ );
1890
+ child.unref();
1891
+ debugLog(
1892
+ opts.debug === true,
1893
+ "consolidate",
1894
+ `auto flush scheduled: ${pendingSessions.length} pending session(s)`
1895
+ );
1896
+ } catch (err) {
1897
+ debugLog(
1898
+ opts.debug === true,
1899
+ "consolidate",
1900
+ `auto flush spawn failed: ${err instanceof Error ? err.message : String(err)}`
1901
+ );
1902
+ }
1814
1903
  }
1815
1904
 
1816
1905
  // src/capture/commitCapture.ts
@@ -1881,9 +1970,9 @@ async function commitCapture(opts) {
1881
1970
  }
1882
1971
 
1883
1972
  // src/capture/claude-code/resolveSession.ts
1884
- import { existsSync as existsSync9, readdirSync as readdirSync4, readFileSync as readFileSync11, statSync } from "fs";
1973
+ import { existsSync as existsSync9, readdirSync as readdirSync4, readFileSync as readFileSync12, statSync } from "fs";
1885
1974
  import { homedir } from "os";
1886
- import { basename as basename2, join as join11, resolve as resolve3 } from "path";
1975
+ import { basename as basename2, join as join12, resolve as resolve3 } from "path";
1887
1976
  function encodeClaudeProjectDir(absPath) {
1888
1977
  return resolve3(absPath).replace(/\//g, "-");
1889
1978
  }
@@ -1897,20 +1986,20 @@ function resolveSessionJsonlPath(repoRoot, options = {}) {
1897
1986
  return resolve3(fromHook);
1898
1987
  }
1899
1988
  const sessionId = process.env.CLAUDE_SESSION_ID ?? process.env.CLAUDE_CODE_SESSION_ID ?? process.env.SESSION_ID;
1900
- const claudeHome = process.env.CLAUDE_CONFIG_DIR ? resolve3(process.env.CLAUDE_CONFIG_DIR) : join11(homedir(), ".claude");
1901
- const projectsRoot = join11(claudeHome, "projects");
1989
+ const claudeHome = process.env.CLAUDE_CONFIG_DIR ? resolve3(process.env.CLAUDE_CONFIG_DIR) : join12(homedir(), ".claude");
1990
+ const projectsRoot = join12(claudeHome, "projects");
1902
1991
  if (!existsSync9(projectsRoot)) {
1903
1992
  return null;
1904
1993
  }
1905
1994
  const cwd = resolve3(options.cwd ?? repoRoot);
1906
1995
  const preferredProjectDir = encodeClaudeProjectDir(cwd);
1907
- const preferredPath = join11(projectsRoot, preferredProjectDir);
1996
+ const preferredPath = join12(projectsRoot, preferredProjectDir);
1908
1997
  if (existsSync9(preferredPath)) {
1909
1998
  const hit = pickNewestJsonl(preferredPath, sessionId);
1910
1999
  if (hit) {
1911
2000
  return hit;
1912
2001
  }
1913
- const legacySessions = join11(preferredPath, "sessions");
2002
+ const legacySessions = join12(preferredPath, "sessions");
1914
2003
  if (existsSync9(legacySessions)) {
1915
2004
  const legacyHit = pickNewestJsonl(legacySessions, sessionId);
1916
2005
  if (legacyHit) {
@@ -1921,9 +2010,9 @@ function resolveSessionJsonlPath(repoRoot, options = {}) {
1921
2010
  const candidates = [];
1922
2011
  for (const projectDir of readdirSync4(projectsRoot, { withFileTypes: true })) {
1923
2012
  if (!projectDir.isDirectory()) continue;
1924
- const projectPath = join11(projectsRoot, projectDir.name);
2013
+ const projectPath = join12(projectsRoot, projectDir.name);
1925
2014
  collectJsonlCandidates(projectPath, sessionId, candidates);
1926
- const legacySessions = join11(projectPath, "sessions");
2015
+ const legacySessions = join12(projectPath, "sessions");
1927
2016
  if (existsSync9(legacySessions)) {
1928
2017
  collectJsonlCandidates(legacySessions, sessionId, candidates);
1929
2018
  }
@@ -1951,7 +2040,7 @@ function collectJsonlCandidates(dir, sessionId, out) {
1951
2040
  if (!entry.isFile() || !entry.name.endsWith(".jsonl")) {
1952
2041
  continue;
1953
2042
  }
1954
- const fullPath = join11(dir, entry.name);
2043
+ const fullPath = join12(dir, entry.name);
1955
2044
  if (sessionId && !entry.name.includes(sessionId) && basename2(entry.name, ".jsonl") !== sessionId) {
1956
2045
  continue;
1957
2046
  }
@@ -1986,7 +2075,7 @@ async function runClaudeCodeCapture(repoRoot, cwd, dryRun, options) {
1986
2075
  // src/capture/codebuddy/resolveSession.ts
1987
2076
  import { existsSync as existsSync10, readdirSync as readdirSync5, statSync as statSync2 } from "fs";
1988
2077
  import { homedir as homedir2 } from "os";
1989
- import { basename as basename3, join as join12, resolve as resolve4 } from "path";
2078
+ import { basename as basename3, join as join13, resolve as resolve4 } from "path";
1990
2079
  function encodeCodebuddyProjectDir(absPath) {
1991
2080
  return resolve4(absPath).replace(/^\//, "").replace(/\//g, "-");
1992
2081
  }
@@ -2000,14 +2089,14 @@ function resolveCodebuddySessionJsonl(options) {
2000
2089
  return resolve4(fromHook);
2001
2090
  }
2002
2091
  const sessionId = process.env.CODEBUDDY_SESSION_ID ?? process.env.SESSION_ID;
2003
- const codebuddyHome = process.env.CODEBUDDY_CONFIG_DIR ? resolve4(process.env.CODEBUDDY_CONFIG_DIR) : join12(homedir2(), ".codebuddy");
2004
- const projectsRoot = join12(codebuddyHome, "projects");
2092
+ const codebuddyHome = process.env.CODEBUDDY_CONFIG_DIR ? resolve4(process.env.CODEBUDDY_CONFIG_DIR) : join13(homedir2(), ".codebuddy");
2093
+ const projectsRoot = join13(codebuddyHome, "projects");
2005
2094
  if (!existsSync10(projectsRoot)) {
2006
2095
  return null;
2007
2096
  }
2008
2097
  const cwd = resolve4(options.cwd ?? options.repoRoot);
2009
2098
  const preferredProjectDir = encodeCodebuddyProjectDir(cwd);
2010
- const preferredPath = join12(projectsRoot, preferredProjectDir);
2099
+ const preferredPath = join13(projectsRoot, preferredProjectDir);
2011
2100
  if (existsSync10(preferredPath)) {
2012
2101
  const hit = pickNewestJsonlRecursive(preferredPath, sessionId);
2013
2102
  if (hit) {
@@ -2019,7 +2108,7 @@ function resolveCodebuddySessionJsonl(options) {
2019
2108
  if (!projectDir.isDirectory()) {
2020
2109
  continue;
2021
2110
  }
2022
- collectJsonlRecursive(join12(projectsRoot, projectDir.name), sessionId, candidates);
2111
+ collectJsonlRecursive(join13(projectsRoot, projectDir.name), sessionId, candidates);
2023
2112
  }
2024
2113
  if (candidates.length === 0) {
2025
2114
  return null;
@@ -2041,7 +2130,7 @@ function collectJsonlRecursive(dir, sessionId, out) {
2041
2130
  return;
2042
2131
  }
2043
2132
  for (const entry of readdirSync5(dir, { withFileTypes: true })) {
2044
- const full = join12(dir, entry.name);
2133
+ const full = join13(dir, entry.name);
2045
2134
  if (entry.isDirectory()) {
2046
2135
  collectJsonlRecursive(full, sessionId, out);
2047
2136
  continue;
@@ -2091,7 +2180,7 @@ async function runCodebuddyCapture(repoRoot, cwd, dryRun, options) {
2091
2180
  // src/capture/cursor/resolveSession.ts
2092
2181
  import { existsSync as existsSync11, readdirSync as readdirSync6, statSync as statSync3 } from "fs";
2093
2182
  import { homedir as homedir3 } from "os";
2094
- import { join as join13, resolve as resolve5 } from "path";
2183
+ import { join as join14, resolve as resolve5 } from "path";
2095
2184
  function encodeCursorProjectDir(absPath) {
2096
2185
  return resolve5(absPath).replace(/^\//, "").replace(/\//g, "-");
2097
2186
  }
@@ -2100,25 +2189,25 @@ function resolveCursorSessionJsonl(options) {
2100
2189
  if (override && existsSync11(override)) {
2101
2190
  return resolve5(override);
2102
2191
  }
2103
- const cursorHome = process.env.CURSOR_CONFIG_DIR ? resolve5(process.env.CURSOR_CONFIG_DIR) : join13(homedir3(), ".cursor");
2104
- const projectsRoot = join13(cursorHome, "projects");
2192
+ const cursorHome = process.env.CURSOR_CONFIG_DIR ? resolve5(process.env.CURSOR_CONFIG_DIR) : join14(homedir3(), ".cursor");
2193
+ const projectsRoot = join14(cursorHome, "projects");
2105
2194
  if (!existsSync11(projectsRoot)) {
2106
2195
  return null;
2107
2196
  }
2108
2197
  const sessionId = options.hookInput?.sessionId ?? options.hookInput?.conversationId ?? process.env.CURSOR_SESSION_ID ?? process.env.CURSOR_AGENT_SESSION_ID;
2109
2198
  const workspace = options.hookInput?.workspaceRoots?.[0] ?? (options.cwd ? resolve5(options.cwd) : resolve5(options.repoRoot));
2110
2199
  const encoded = encodeCursorProjectDir(workspace);
2111
- const projectDir = join13(projectsRoot, encoded);
2112
- const transcriptsRoot = join13(projectDir, "agent-transcripts");
2200
+ const projectDir = join14(projectsRoot, encoded);
2201
+ const transcriptsRoot = join14(projectDir, "agent-transcripts");
2113
2202
  if (!existsSync11(transcriptsRoot)) {
2114
2203
  return pickNewestCursorJsonl(projectsRoot);
2115
2204
  }
2116
2205
  if (sessionId) {
2117
- const direct = join13(transcriptsRoot, sessionId, `${sessionId}.jsonl`);
2206
+ const direct = join14(transcriptsRoot, sessionId, `${sessionId}.jsonl`);
2118
2207
  if (existsSync11(direct)) {
2119
2208
  return direct;
2120
2209
  }
2121
- const nested = findJsonlUnderDir(join13(transcriptsRoot, sessionId), sessionId);
2210
+ const nested = findJsonlUnderDir(join14(transcriptsRoot, sessionId), sessionId);
2122
2211
  if (nested) {
2123
2212
  return nested;
2124
2213
  }
@@ -2129,16 +2218,16 @@ function findJsonlUnderDir(dir, sessionId) {
2129
2218
  if (!existsSync11(dir)) {
2130
2219
  return null;
2131
2220
  }
2132
- const direct = join13(dir, `${sessionId}.jsonl`);
2221
+ const direct = join14(dir, `${sessionId}.jsonl`);
2133
2222
  if (existsSync11(direct)) {
2134
2223
  return direct;
2135
2224
  }
2136
2225
  for (const entry of readdirSync6(dir, { withFileTypes: true })) {
2137
2226
  if (entry.isFile() && entry.name.endsWith(".jsonl")) {
2138
- return join13(dir, entry.name);
2227
+ return join14(dir, entry.name);
2139
2228
  }
2140
2229
  if (entry.isDirectory()) {
2141
- const found = findJsonlUnderDir(join13(dir, entry.name), sessionId);
2230
+ const found = findJsonlUnderDir(join14(dir, entry.name), sessionId);
2142
2231
  if (found) {
2143
2232
  return found;
2144
2233
  }
@@ -2160,7 +2249,7 @@ function collectJsonlRecursive2(dir, out) {
2160
2249
  return;
2161
2250
  }
2162
2251
  for (const entry of readdirSync6(dir, { withFileTypes: true })) {
2163
- const full = join13(dir, entry.name);
2252
+ const full = join14(dir, entry.name);
2164
2253
  if (entry.isDirectory()) {
2165
2254
  collectJsonlRecursive2(full, out);
2166
2255
  continue;
@@ -2385,8 +2474,8 @@ async function runFlushCommandCli(opts) {
2385
2474
  }
2386
2475
 
2387
2476
  // src/inject/runInject.ts
2388
- import { existsSync as existsSync12, readdirSync as readdirSync7, readFileSync as readFileSync12 } from "fs";
2389
- import { join as join14 } from "path";
2477
+ import { existsSync as existsSync12, readdirSync as readdirSync7, readFileSync as readFileSync13 } from "fs";
2478
+ import { join as join15 } from "path";
2390
2479
 
2391
2480
  // src/inject/constants.ts
2392
2481
  var INJECT_MAX_CHARS = 8e3;
@@ -2448,7 +2537,7 @@ function readMemoryMd(repoRoot) {
2448
2537
  const path = memoryPathOnDisk(repoRoot);
2449
2538
  if (!existsSync12(path)) return null;
2450
2539
  try {
2451
- const content = readFileSync12(path, "utf8");
2540
+ const content = readFileSync13(path, "utf8");
2452
2541
  return content.trim() || null;
2453
2542
  } catch {
2454
2543
  return null;
@@ -2466,8 +2555,8 @@ function readAllRules(repoRoot) {
2466
2555
  const parts = [];
2467
2556
  for (const file of files) {
2468
2557
  try {
2469
- const filePath = join14(rulesDir, file);
2470
- const content = readFileSync12(filePath, "utf8").trim();
2558
+ const filePath = join15(rulesDir, file);
2559
+ const content = readFileSync13(filePath, "utf8").trim();
2471
2560
  if (!content) continue;
2472
2561
  parts.push(`### ${file}`, "", content, "");
2473
2562
  } catch {
@@ -2494,49 +2583,49 @@ import { resolve as resolve7 } from "path";
2494
2583
 
2495
2584
  // src/init/assistants/claude-code.ts
2496
2585
  import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync6 } from "fs";
2497
- import { join as join18 } from "path";
2586
+ import { join as join19 } from "path";
2498
2587
 
2499
2588
  // src/init/mergeClaudeSettings.ts
2500
- import { existsSync as existsSync14, readFileSync as readFileSync15 } from "fs";
2501
- import { join as join17 } from "path";
2589
+ import { existsSync as existsSync14, readFileSync as readFileSync16 } from "fs";
2590
+ import { join as join18 } from "path";
2502
2591
 
2503
2592
  // src/init/templateDir.ts
2504
- import { existsSync as existsSync13, readFileSync as readFileSync14 } from "fs";
2505
- import { dirname as dirname6, join as join16 } from "path";
2506
- import { fileURLToPath as fileURLToPath3 } from "url";
2593
+ import { existsSync as existsSync13, readFileSync as readFileSync15 } from "fs";
2594
+ import { dirname as dirname7, join as join17 } from "path";
2595
+ import { fileURLToPath as fileURLToPath4 } from "url";
2507
2596
 
2508
2597
  // src/index.ts
2509
- import { readFileSync as readFileSync13 } from "fs";
2510
- import { dirname as dirname5, join as join15 } from "path";
2511
- import { fileURLToPath as fileURLToPath2 } from "url";
2598
+ import { readFileSync as readFileSync14 } from "fs";
2599
+ import { dirname as dirname6, join as join16 } from "path";
2600
+ import { fileURLToPath as fileURLToPath3 } from "url";
2512
2601
  var PACKAGE_NAME = "@riconext/hermes-repo";
2513
- var __dirname = dirname5(fileURLToPath2(import.meta.url));
2602
+ var __dirname = dirname6(fileURLToPath3(import.meta.url));
2514
2603
  function readPkgVersion() {
2515
- const pkgPath = join15(__dirname, "..", "package.json");
2516
- const pkg = JSON.parse(readFileSync13(pkgPath, "utf8"));
2604
+ const pkgPath = join16(__dirname, "..", "package.json");
2605
+ const pkg = JSON.parse(readFileSync14(pkgPath, "utf8"));
2517
2606
  return pkg.version;
2518
2607
  }
2519
2608
 
2520
2609
  // src/init/templateDir.ts
2521
2610
  function resolveTemplateDir() {
2522
- const here = dirname6(fileURLToPath3(import.meta.url));
2611
+ const here = dirname7(fileURLToPath4(import.meta.url));
2523
2612
  const candidates = [
2524
- join16(here, "templates"),
2525
- join16(here, "..", "..", "templates")
2613
+ join17(here, "templates"),
2614
+ join17(here, "..", "..", "templates")
2526
2615
  ];
2527
2616
  for (const dir of candidates) {
2528
2617
  if (existsSync13(dir)) {
2529
2618
  return dir;
2530
2619
  }
2531
2620
  }
2532
- return join16(here, "templates");
2621
+ return join17(here, "templates");
2533
2622
  }
2534
2623
  var templateDir = resolveTemplateDir();
2535
2624
  function resolveTemplatePath(name) {
2536
- return join16(templateDir, name);
2625
+ return join17(templateDir, name);
2537
2626
  }
2538
2627
  function readTemplate(name) {
2539
- return readFileSync14(resolveTemplatePath(name), "utf8");
2628
+ return readFileSync15(resolveTemplatePath(name), "utf8");
2540
2629
  }
2541
2630
  function renderTemplate(name) {
2542
2631
  const raw = readTemplate(name);
@@ -2546,7 +2635,7 @@ function renderTemplate(name) {
2546
2635
  // src/init/mergeClaudeSettings.ts
2547
2636
  var CLAUDE_SETTINGS_LOCAL_REL = ".claude/settings.local.json";
2548
2637
  function claudeSettingsLocalPath(repoRoot) {
2549
- return join17(repoRoot, ".claude", "settings.local.json");
2638
+ return join18(repoRoot, ".claude", "settings.local.json");
2550
2639
  }
2551
2640
  function mergeClaudeLocalSettings(repoRoot) {
2552
2641
  const settingsPath = claudeSettingsLocalPath(repoRoot);
@@ -2555,7 +2644,7 @@ function mergeClaudeLocalSettings(repoRoot) {
2555
2644
  let existing = {};
2556
2645
  if (existed) {
2557
2646
  try {
2558
- existing = JSON.parse(readFileSync15(settingsPath, "utf8"));
2647
+ existing = JSON.parse(readFileSync16(settingsPath, "utf8"));
2559
2648
  } catch {
2560
2649
  existing = {};
2561
2650
  }
@@ -2583,7 +2672,7 @@ var claudeCodeAdapter = {
2583
2672
  available: true,
2584
2673
  scaffoldPaths: [CLAUDE_SETTINGS_LOCAL_REL],
2585
2674
  write(ctx) {
2586
- mkdirSync7(join18(ctx.repoRoot, ".claude"), { recursive: true });
2675
+ mkdirSync7(join19(ctx.repoRoot, ".claude"), { recursive: true });
2587
2676
  const { content, action } = mergeClaudeLocalSettings(ctx.repoRoot);
2588
2677
  writeFileSync6(claudeSettingsLocalPath(ctx.repoRoot), content, "utf8");
2589
2678
  ctx.report.files.push({ path: CLAUDE_SETTINGS_LOCAL_REL, action });
@@ -2592,11 +2681,11 @@ var claudeCodeAdapter = {
2592
2681
 
2593
2682
  // src/init/assistants/codex.ts
2594
2683
  import { mkdirSync as mkdirSync8, writeFileSync as writeFileSync7 } from "fs";
2595
- import { join as join20 } from "path";
2684
+ import { join as join21 } from "path";
2596
2685
 
2597
2686
  // src/init/mergeCodexConfig.ts
2598
- import { existsSync as existsSync15, readFileSync as readFileSync16 } from "fs";
2599
- import { join as join19 } from "path";
2687
+ import { existsSync as existsSync15, readFileSync as readFileSync17 } from "fs";
2688
+ import { join as join20 } from "path";
2600
2689
  var CODEX_CONFIG_REL = ".codex/config.toml";
2601
2690
  var CODEX_HERMES_START_MARKER = "# >>> hermes-repo codex (do not edit this block manually)";
2602
2691
  var CODEX_HERMES_END_MARKER = "# <<< hermes-repo codex";
@@ -2610,7 +2699,7 @@ function buildCodexHermesBlock() {
2610
2699
  ].join("\n");
2611
2700
  }
2612
2701
  function codexConfigPath(repoRoot) {
2613
- return join19(repoRoot, ".codex", "config.toml");
2702
+ return join20(repoRoot, ".codex", "config.toml");
2614
2703
  }
2615
2704
  function spliceHermesBlock(existing, block) {
2616
2705
  const startIdx = existing.indexOf(CODEX_HERMES_START_MARKER);
@@ -2642,7 +2731,7 @@ function mergeCodexConfig(repoRoot) {
2642
2731
  action: "created"
2643
2732
  };
2644
2733
  }
2645
- const existing = readFileSync16(configPath, "utf8");
2734
+ const existing = readFileSync17(configPath, "utf8");
2646
2735
  const hasBlock = existing.includes(CODEX_HERMES_START_MARKER) && existing.includes(CODEX_HERMES_END_MARKER);
2647
2736
  return {
2648
2737
  content: spliceHermesBlock(existing, block),
@@ -2657,7 +2746,7 @@ var codexAdapter = {
2657
2746
  available: true,
2658
2747
  scaffoldPaths: [CODEX_CONFIG_REL],
2659
2748
  write(ctx) {
2660
- mkdirSync8(join20(ctx.repoRoot, ".codex"), { recursive: true });
2749
+ mkdirSync8(join21(ctx.repoRoot, ".codex"), { recursive: true });
2661
2750
  const { content, action } = mergeCodexConfig(ctx.repoRoot);
2662
2751
  writeFileSync7(codexConfigPath(ctx.repoRoot), content, "utf8");
2663
2752
  ctx.report.files.push({ path: CODEX_CONFIG_REL, action });
@@ -2666,14 +2755,14 @@ var codexAdapter = {
2666
2755
 
2667
2756
  // src/init/assistants/codebuddy.ts
2668
2757
  import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync8 } from "fs";
2669
- import { join as join22 } from "path";
2758
+ import { join as join23 } from "path";
2670
2759
 
2671
2760
  // src/init/mergeCodebuddySettings.ts
2672
- import { existsSync as existsSync16, readFileSync as readFileSync17 } from "fs";
2673
- import { join as join21 } from "path";
2761
+ import { existsSync as existsSync16, readFileSync as readFileSync18 } from "fs";
2762
+ import { join as join22 } from "path";
2674
2763
  var CODEBUDDY_SETTINGS_LOCAL_REL = ".codebuddy/settings.local.json";
2675
2764
  function codebuddySettingsLocalPath(repoRoot) {
2676
- return join21(repoRoot, ".codebuddy", "settings.local.json");
2765
+ return join22(repoRoot, ".codebuddy", "settings.local.json");
2677
2766
  }
2678
2767
  function mergeCodebuddyLocalSettings(repoRoot) {
2679
2768
  const settingsPath = codebuddySettingsLocalPath(repoRoot);
@@ -2684,7 +2773,7 @@ function mergeCodebuddyLocalSettings(repoRoot) {
2684
2773
  let existing = {};
2685
2774
  if (existed) {
2686
2775
  try {
2687
- existing = JSON.parse(readFileSync17(settingsPath, "utf8"));
2776
+ existing = JSON.parse(readFileSync18(settingsPath, "utf8"));
2688
2777
  } catch {
2689
2778
  existing = {};
2690
2779
  }
@@ -2712,7 +2801,7 @@ var codebuddyAdapter = {
2712
2801
  available: true,
2713
2802
  scaffoldPaths: [CODEBUDDY_SETTINGS_LOCAL_REL],
2714
2803
  write(ctx) {
2715
- mkdirSync9(join22(ctx.repoRoot, ".codebuddy"), { recursive: true });
2804
+ mkdirSync9(join23(ctx.repoRoot, ".codebuddy"), { recursive: true });
2716
2805
  const { content, action } = mergeCodebuddyLocalSettings(ctx.repoRoot);
2717
2806
  writeFileSync8(codebuddySettingsLocalPath(ctx.repoRoot), content, "utf8");
2718
2807
  ctx.report.files.push({ path: CODEBUDDY_SETTINGS_LOCAL_REL, action });
@@ -2721,14 +2810,14 @@ var codebuddyAdapter = {
2721
2810
 
2722
2811
  // src/init/assistants/cursor.ts
2723
2812
  import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync9 } from "fs";
2724
- import { join as join24 } from "path";
2813
+ import { join as join25 } from "path";
2725
2814
 
2726
2815
  // src/init/mergeCursorHooks.ts
2727
- import { existsSync as existsSync17, readFileSync as readFileSync18 } from "fs";
2728
- import { join as join23 } from "path";
2816
+ import { existsSync as existsSync17, readFileSync as readFileSync19 } from "fs";
2817
+ import { join as join24 } from "path";
2729
2818
  var CURSOR_HOOKS_REL = ".cursor/hooks.json";
2730
2819
  function cursorHooksPath(repoRoot) {
2731
- return join23(repoRoot, ".cursor", "hooks.json");
2820
+ return join24(repoRoot, ".cursor", "hooks.json");
2732
2821
  }
2733
2822
  function mergeCursorHooks(repoRoot) {
2734
2823
  const hooksPath = cursorHooksPath(repoRoot);
@@ -2737,7 +2826,7 @@ function mergeCursorHooks(repoRoot) {
2737
2826
  let existing = {};
2738
2827
  if (existed) {
2739
2828
  try {
2740
- existing = JSON.parse(readFileSync18(hooksPath, "utf8"));
2829
+ existing = JSON.parse(readFileSync19(hooksPath, "utf8"));
2741
2830
  } catch {
2742
2831
  existing = {};
2743
2832
  }
@@ -2766,7 +2855,7 @@ var cursorAdapter = {
2766
2855
  available: true,
2767
2856
  scaffoldPaths: [CURSOR_HOOKS_REL],
2768
2857
  write(ctx) {
2769
- mkdirSync10(join24(ctx.repoRoot, ".cursor"), { recursive: true });
2858
+ mkdirSync10(join25(ctx.repoRoot, ".cursor"), { recursive: true });
2770
2859
  const { content, action } = mergeCursorHooks(ctx.repoRoot);
2771
2860
  writeFileSync9(cursorHooksPath(ctx.repoRoot), content, "utf8");
2772
2861
  ctx.report.files.push({ path: CURSOR_HOOKS_REL, action });
@@ -2829,29 +2918,29 @@ function validateAssistantSelection(ids) {
2829
2918
 
2830
2919
  // src/init/ensureDirs.ts
2831
2920
  import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync10 } from "fs";
2832
- import { join as join25 } from "path";
2921
+ import { join as join26 } from "path";
2833
2922
  function ensureMemoryTree(repoRoot) {
2834
- const memoryRoot = join25(repoRoot, MEMORY_DIR);
2923
+ const memoryRoot = join26(repoRoot, MEMORY_DIR);
2835
2924
  mkdirSync11(memoryRoot, { recursive: true });
2836
2925
  for (const sub of MEMORY_SUBDIRS) {
2837
- mkdirSync11(join25(memoryRoot, sub), { recursive: true });
2926
+ mkdirSync11(join26(memoryRoot, sub), { recursive: true });
2838
2927
  }
2839
- mkdirSync11(join25(repoRoot, ".claude"), { recursive: true });
2928
+ mkdirSync11(join26(repoRoot, ".claude"), { recursive: true });
2840
2929
  for (const sub of GITKEEP_DIRS) {
2841
- const keepPath = join25(memoryRoot, sub, ".gitkeep");
2930
+ const keepPath = join26(memoryRoot, sub, ".gitkeep");
2842
2931
  writeFileSync10(keepPath, "", { flag: "a" });
2843
2932
  }
2844
2933
  }
2845
2934
 
2846
2935
  // src/init/mergeAssistants.ts
2847
- import { existsSync as existsSync18, readFileSync as readFileSync19 } from "fs";
2936
+ import { existsSync as existsSync18, readFileSync as readFileSync20 } from "fs";
2848
2937
  function readExistingAssistants(repoRoot) {
2849
2938
  const configPath = memoryPath(repoRoot, "config.json");
2850
2939
  if (!existsSync18(configPath)) {
2851
2940
  return [];
2852
2941
  }
2853
2942
  try {
2854
- const config = JSON.parse(readFileSync19(configPath, "utf8"));
2943
+ const config = JSON.parse(readFileSync20(configPath, "utf8"));
2855
2944
  if (!Array.isArray(config.assistants)) {
2856
2945
  return [];
2857
2946
  }
@@ -2866,14 +2955,14 @@ function mergeAssistants(repoRoot, selected) {
2866
2955
  }
2867
2956
 
2868
2957
  // src/init/mergeGitignore.ts
2869
- import { existsSync as existsSync19, readFileSync as readFileSync20, writeFileSync as writeFileSync11 } from "fs";
2870
- import { join as join26 } from "path";
2958
+ import { existsSync as existsSync19, readFileSync as readFileSync21, writeFileSync as writeFileSync11 } from "fs";
2959
+ import { join as join27 } from "path";
2871
2960
  var START_MARKER = "# >>> hermes-repo memory (do not edit this block manually)";
2872
2961
  var END_MARKER = "# <<< hermes-repo memory";
2873
2962
  function mergeHermesGitignore(repoRoot) {
2874
2963
  const block = readTemplate("gitignore-block.txt").trimEnd() + "\n";
2875
- const gitignorePath = join26(repoRoot, ".gitignore");
2876
- const contentBefore = existsSync19(gitignorePath) ? readFileSync20(gitignorePath, "utf8") : "";
2964
+ const gitignorePath = join27(repoRoot, ".gitignore");
2965
+ const contentBefore = existsSync19(gitignorePath) ? readFileSync21(gitignorePath, "utf8") : "";
2877
2966
  const warnBroadMemoryIgnore = contentBefore.length > 0 && !contentBefore.includes(START_MARKER) && /(^|\n)\.memory\/\s*$/m.test(contentBefore);
2878
2967
  if (!existsSync19(gitignorePath)) {
2879
2968
  writeFileSync11(gitignorePath, `${block}
@@ -2907,7 +2996,7 @@ function mergeHermesGitignore(repoRoot) {
2907
2996
  import { copyFileSync, mkdirSync as mkdirSync12, writeFileSync as writeFileSync14 } from "fs";
2908
2997
 
2909
2998
  // src/init/mergeConfig.ts
2910
- import { existsSync as existsSync20, readFileSync as readFileSync21 } from "fs";
2999
+ import { existsSync as existsSync20, readFileSync as readFileSync22 } from "fs";
2911
3000
  var DEFAULT_LLM = {
2912
3001
  enabled: false,
2913
3002
  provider: "openai",
@@ -2919,7 +3008,13 @@ var DEFAULT_LLM = {
2919
3008
  mode: "async"
2920
3009
  };
2921
3010
  var DEFAULT_CONSOLIDATE = {
2922
- autoArchiveDays: 30
3011
+ autoArchiveDays: 30,
3012
+ autoFlush: {
3013
+ enabled: false,
3014
+ minPendingSessions: 3,
3015
+ minIntervalMinutes: 30,
3016
+ maxPendingChars: 2e4
3017
+ }
2923
3018
  };
2924
3019
  function mergeConfigForInit(repoRoot, assistants) {
2925
3020
  const configPath = memoryPath(repoRoot, "config.json");
@@ -2927,7 +3022,7 @@ function mergeConfigForInit(repoRoot, assistants) {
2927
3022
  let existing = {};
2928
3023
  if (existed) {
2929
3024
  try {
2930
- existing = JSON.parse(readFileSync21(configPath, "utf8"));
3025
+ existing = JSON.parse(readFileSync22(configPath, "utf8"));
2931
3026
  } catch {
2932
3027
  existing = {};
2933
3028
  }
@@ -2935,6 +3030,7 @@ function mergeConfigForInit(repoRoot, assistants) {
2935
3030
  const prevStorage = existing.storage && typeof existing.storage === "object" && !Array.isArray(existing.storage) ? existing.storage : {};
2936
3031
  const prevLlm = existing.llm && typeof existing.llm === "object" && !Array.isArray(existing.llm) ? existing.llm : {};
2937
3032
  const prevConsolidate = existing.consolidate && typeof existing.consolidate === "object" && !Array.isArray(existing.consolidate) ? existing.consolidate : {};
3033
+ const prevAutoFlush = prevConsolidate.autoFlush && typeof prevConsolidate.autoFlush === "object" && !Array.isArray(prevConsolidate.autoFlush) ? prevConsolidate.autoFlush : {};
2938
3034
  const merged = {
2939
3035
  ...existing,
2940
3036
  version: 2,
@@ -2945,7 +3041,14 @@ function mergeConfigForInit(repoRoot, assistants) {
2945
3041
  assistants,
2946
3042
  debug: existing.debug === true,
2947
3043
  llm: { ...DEFAULT_LLM, ...prevLlm },
2948
- consolidate: { ...DEFAULT_CONSOLIDATE, ...prevConsolidate }
3044
+ consolidate: {
3045
+ ...DEFAULT_CONSOLIDATE,
3046
+ ...prevConsolidate,
3047
+ autoFlush: {
3048
+ ...DEFAULT_CONSOLIDATE.autoFlush,
3049
+ ...prevAutoFlush
3050
+ }
3051
+ }
2949
3052
  };
2950
3053
  return {
2951
3054
  content: `${JSON.stringify(merged, null, 2)}
@@ -2955,8 +3058,8 @@ function mergeConfigForInit(repoRoot, assistants) {
2955
3058
  }
2956
3059
 
2957
3060
  // src/init/mergeAgentsMd.ts
2958
- import { existsSync as existsSync21, readFileSync as readFileSync22, writeFileSync as writeFileSync12 } from "fs";
2959
- import { join as join27 } from "path";
3061
+ import { existsSync as existsSync21, readFileSync as readFileSync23, writeFileSync as writeFileSync12 } from "fs";
3062
+ import { join as join28 } from "path";
2960
3063
  var HERMES_AGENTS_START_MARKER = "<!-- >>> hermes-repo agents (do not edit this block manually) -->";
2961
3064
  var HERMES_AGENTS_END_MARKER = "<!-- <<< hermes-repo agents -->";
2962
3065
  function buildHermesAgentsBlockBody() {
@@ -3012,13 +3115,13 @@ function spliceHermesBlock2(existing, block) {
3012
3115
  `;
3013
3116
  }
3014
3117
  function mergeAgentsMd(repoRoot, force) {
3015
- const agentsPath = join27(repoRoot, "AGENTS.md");
3118
+ const agentsPath = join28(repoRoot, "AGENTS.md");
3016
3119
  const block = buildHermesAgentsMarkedBlock();
3017
3120
  if (!existsSync21(agentsPath)) {
3018
3121
  writeFileSync12(agentsPath, buildNewAgentsMd(), "utf8");
3019
3122
  return "created";
3020
3123
  }
3021
- const content = readFileSync22(agentsPath, "utf8");
3124
+ const content = readFileSync23(agentsPath, "utf8");
3022
3125
  if (agentsMdHasHermesBlock(content)) {
3023
3126
  if (!force) {
3024
3127
  return "skipped";
@@ -3126,7 +3229,7 @@ function writeScaffoldFiles(repoRoot, opts, report) {
3126
3229
 
3127
3230
  // src/init/prompts.ts
3128
3231
  import { checkbox, confirm, input } from "@inquirer/prompts";
3129
- import { existsSync as existsSync23, readFileSync as readFileSync23 } from "fs";
3232
+ import { existsSync as existsSync23, readFileSync as readFileSync24 } from "fs";
3130
3233
  import { resolve as resolve6 } from "path";
3131
3234
  function isInitialized(targetDir) {
3132
3235
  const configPath = memoryPath(targetDir, "config.json");
@@ -3134,7 +3237,7 @@ function isInitialized(targetDir) {
3134
3237
  return false;
3135
3238
  }
3136
3239
  try {
3137
- const config = JSON.parse(readFileSync23(configPath, "utf8"));
3240
+ const config = JSON.parse(readFileSync24(configPath, "utf8"));
3138
3241
  return typeof config.version === "number" && config.version >= 1;
3139
3242
  } catch {
3140
3243
  return false;