@riconext/hermes-repo 1.1.1 → 1.2.0
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 +6 -0
- package/README.md +10 -0
- package/dist/cli.js +176 -67
- package/dist/cli.js.map +1 -1
- package/dist/templates/AGENTS.md.tpl +10 -0
- package/dist/templates/config.json.tpl +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -272,6 +272,14 @@ npx @riconext/hermes-repo init
|
|
|
272
272
|
"timeoutMs": 60000,
|
|
273
273
|
"maxInputChars": 24000,
|
|
274
274
|
"mode": "async"
|
|
275
|
+
},
|
|
276
|
+
"consolidate": {
|
|
277
|
+
"autoFlush": {
|
|
278
|
+
"enabled": false,
|
|
279
|
+
"minPendingSessions": 3,
|
|
280
|
+
"minIntervalMinutes": 30,
|
|
281
|
+
"maxPendingChars": 20000
|
|
282
|
+
}
|
|
275
283
|
}
|
|
276
284
|
}
|
|
277
285
|
```
|
|
@@ -285,6 +293,8 @@ npx @riconext/hermes-repo init
|
|
|
285
293
|
|
|
286
294
|
非 DeepSeek 时:保持 `enabled: true`,将 `baseUrl`、`model` 换成你所用网关提供的 OpenAI 兼容地址与模型名即可。
|
|
287
295
|
|
|
296
|
+
`consolidate.autoFlush.enabled` 默认关闭。开启后,capture 成功写入时会在后台按阈值触发 `flush`:pending/stale session 数达到 `minPendingSessions`、距离上次 flush 超过 `minIntervalMinutes`,或待处理内容达到 `maxPendingChars` 时触发。
|
|
297
|
+
|
|
288
298
|
**`init -y` 时**:会生成 `enabled: false` 的骨架;再次 `init` **不会覆盖**已有 `apiKey`,可安全补配。
|
|
289
299
|
|
|
290
300
|
### 安全说明
|
package/dist/cli.js
CHANGED
|
@@ -113,8 +113,15 @@ function parseLlmConfig(raw) {
|
|
|
113
113
|
}
|
|
114
114
|
function parseConsolidateConfig(raw) {
|
|
115
115
|
const c = raw.consolidate;
|
|
116
|
+
const autoFlush = c?.autoFlush && typeof c.autoFlush === "object" && !Array.isArray(c.autoFlush) ? c.autoFlush : {};
|
|
116
117
|
return {
|
|
117
|
-
autoArchiveDays: typeof c?.autoArchiveDays === "number" ? c.autoArchiveDays : 30
|
|
118
|
+
autoArchiveDays: typeof c?.autoArchiveDays === "number" ? c.autoArchiveDays : 30,
|
|
119
|
+
autoFlush: {
|
|
120
|
+
enabled: autoFlush.enabled === true,
|
|
121
|
+
minPendingSessions: typeof autoFlush.minPendingSessions === "number" && autoFlush.minPendingSessions > 0 ? autoFlush.minPendingSessions : 3,
|
|
122
|
+
minIntervalMinutes: typeof autoFlush.minIntervalMinutes === "number" && autoFlush.minIntervalMinutes > 0 ? autoFlush.minIntervalMinutes : 30,
|
|
123
|
+
maxPendingChars: typeof autoFlush.maxPendingChars === "number" && autoFlush.maxPendingChars > 0 ? autoFlush.maxPendingChars : 2e4
|
|
124
|
+
}
|
|
118
125
|
};
|
|
119
126
|
}
|
|
120
127
|
function readConfigAtRepo(repoRoot) {
|
|
@@ -151,7 +158,15 @@ function readConfigAtRepo(repoRoot) {
|
|
|
151
158
|
maxInputChars: 24e3,
|
|
152
159
|
mode: "async"
|
|
153
160
|
},
|
|
154
|
-
consolidate: {
|
|
161
|
+
consolidate: {
|
|
162
|
+
autoArchiveDays: 30,
|
|
163
|
+
autoFlush: {
|
|
164
|
+
enabled: false,
|
|
165
|
+
minPendingSessions: 3,
|
|
166
|
+
minIntervalMinutes: 30,
|
|
167
|
+
maxPendingChars: 2e4
|
|
168
|
+
}
|
|
169
|
+
}
|
|
155
170
|
};
|
|
156
171
|
}
|
|
157
172
|
return null;
|
|
@@ -1106,6 +1121,11 @@ function needsLlm(session) {
|
|
|
1106
1121
|
return false;
|
|
1107
1122
|
}
|
|
1108
1123
|
|
|
1124
|
+
// src/consolidate/scheduleConsolidate.ts
|
|
1125
|
+
import { spawn as spawn2 } from "child_process";
|
|
1126
|
+
import { dirname as dirname5, join as join11 } from "path";
|
|
1127
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1128
|
+
|
|
1109
1129
|
// src/consolidate/state.ts
|
|
1110
1130
|
import {
|
|
1111
1131
|
existsSync as existsSync6,
|
|
@@ -1772,6 +1792,9 @@ function extractDomainsFromResults(files) {
|
|
|
1772
1792
|
var CONSOLIDATE_LOCK_TTL_MS = 30 * 60 * 1e3;
|
|
1773
1793
|
|
|
1774
1794
|
// src/consolidate/scheduleConsolidate.ts
|
|
1795
|
+
function cliPath2() {
|
|
1796
|
+
return join11(dirname5(fileURLToPath2(import.meta.url)), "..", "cli.js");
|
|
1797
|
+
}
|
|
1775
1798
|
async function runFlushCommand(opts) {
|
|
1776
1799
|
const ctx = loadRepoContext(opts.cwd);
|
|
1777
1800
|
if (!ctx) {
|
|
@@ -1806,11 +1829,83 @@ async function runFlushCommand(opts) {
|
|
|
1806
1829
|
debug: opts.debug ?? ctx.config.debug
|
|
1807
1830
|
});
|
|
1808
1831
|
}
|
|
1832
|
+
function shouldAutoFlush(sessions, consolidate, lastConsolidatedAt) {
|
|
1833
|
+
const autoFlush = consolidate.autoFlush;
|
|
1834
|
+
if (!autoFlush.enabled || sessions.length === 0) {
|
|
1835
|
+
return false;
|
|
1836
|
+
}
|
|
1837
|
+
if (sessions.length >= autoFlush.minPendingSessions) {
|
|
1838
|
+
return true;
|
|
1839
|
+
}
|
|
1840
|
+
const pendingChars = sessions.reduce(
|
|
1841
|
+
(sum, session) => sum + session.bodyContent.length,
|
|
1842
|
+
0
|
|
1843
|
+
);
|
|
1844
|
+
if (pendingChars >= autoFlush.maxPendingChars) {
|
|
1845
|
+
return true;
|
|
1846
|
+
}
|
|
1847
|
+
const last = Date.parse(lastConsolidatedAt);
|
|
1848
|
+
if (Number.isNaN(last)) {
|
|
1849
|
+
return true;
|
|
1850
|
+
}
|
|
1851
|
+
const minIntervalMs = autoFlush.minIntervalMinutes * 60 * 1e3;
|
|
1852
|
+
return Date.now() - last >= minIntervalMs;
|
|
1853
|
+
}
|
|
1809
1854
|
function maybeScheduleConsolidate(opts) {
|
|
1855
|
+
const ctx = loadRepoContext(opts.repoRoot);
|
|
1856
|
+
if (!ctx) {
|
|
1857
|
+
return;
|
|
1858
|
+
}
|
|
1859
|
+
const autoFlush = ctx.config.consolidate.autoFlush;
|
|
1860
|
+
if (!autoFlush.enabled) {
|
|
1861
|
+
return;
|
|
1862
|
+
}
|
|
1863
|
+
if (!isLlmAvailable(ctx.config.llm)) {
|
|
1864
|
+
debugLog(opts.debug === true, "consolidate", "auto flush skipped: llm not available");
|
|
1865
|
+
return;
|
|
1866
|
+
}
|
|
1810
1867
|
const lock = readConsolidateLock(opts.repoRoot);
|
|
1811
1868
|
if (lock && !isLockStale(lock, CONSOLIDATE_LOCK_TTL_MS)) {
|
|
1869
|
+
debugLog(opts.debug === true, "consolidate", "auto flush skipped: lock held");
|
|
1870
|
+
return;
|
|
1871
|
+
}
|
|
1872
|
+
const pendingSessions = filterPendingSessions(scanAllSessions(opts.repoRoot));
|
|
1873
|
+
const state = readConsolidateState(opts.repoRoot);
|
|
1874
|
+
if (!shouldAutoFlush(
|
|
1875
|
+
pendingSessions,
|
|
1876
|
+
ctx.config.consolidate,
|
|
1877
|
+
state.lastConsolidatedAt
|
|
1878
|
+
)) {
|
|
1879
|
+
debugLog(
|
|
1880
|
+
opts.debug === true,
|
|
1881
|
+
"consolidate",
|
|
1882
|
+
`auto flush skipped: ${pendingSessions.length} pending session(s) below thresholds`
|
|
1883
|
+
);
|
|
1812
1884
|
return;
|
|
1813
1885
|
}
|
|
1886
|
+
try {
|
|
1887
|
+
const child = spawn2(
|
|
1888
|
+
process.execPath,
|
|
1889
|
+
[cliPath2(), "flush", "-C", opts.repoRoot],
|
|
1890
|
+
{
|
|
1891
|
+
detached: true,
|
|
1892
|
+
stdio: "ignore",
|
|
1893
|
+
cwd: opts.repoRoot
|
|
1894
|
+
}
|
|
1895
|
+
);
|
|
1896
|
+
child.unref();
|
|
1897
|
+
debugLog(
|
|
1898
|
+
opts.debug === true,
|
|
1899
|
+
"consolidate",
|
|
1900
|
+
`auto flush scheduled: ${pendingSessions.length} pending session(s)`
|
|
1901
|
+
);
|
|
1902
|
+
} catch (err) {
|
|
1903
|
+
debugLog(
|
|
1904
|
+
opts.debug === true,
|
|
1905
|
+
"consolidate",
|
|
1906
|
+
`auto flush spawn failed: ${err instanceof Error ? err.message : String(err)}`
|
|
1907
|
+
);
|
|
1908
|
+
}
|
|
1814
1909
|
}
|
|
1815
1910
|
|
|
1816
1911
|
// src/capture/commitCapture.ts
|
|
@@ -1883,7 +1978,7 @@ async function commitCapture(opts) {
|
|
|
1883
1978
|
// src/capture/claude-code/resolveSession.ts
|
|
1884
1979
|
import { existsSync as existsSync9, readdirSync as readdirSync4, readFileSync as readFileSync11, statSync } from "fs";
|
|
1885
1980
|
import { homedir } from "os";
|
|
1886
|
-
import { basename as basename2, join as
|
|
1981
|
+
import { basename as basename2, join as join12, resolve as resolve3 } from "path";
|
|
1887
1982
|
function encodeClaudeProjectDir(absPath) {
|
|
1888
1983
|
return resolve3(absPath).replace(/\//g, "-");
|
|
1889
1984
|
}
|
|
@@ -1897,20 +1992,20 @@ function resolveSessionJsonlPath(repoRoot, options = {}) {
|
|
|
1897
1992
|
return resolve3(fromHook);
|
|
1898
1993
|
}
|
|
1899
1994
|
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) :
|
|
1901
|
-
const projectsRoot =
|
|
1995
|
+
const claudeHome = process.env.CLAUDE_CONFIG_DIR ? resolve3(process.env.CLAUDE_CONFIG_DIR) : join12(homedir(), ".claude");
|
|
1996
|
+
const projectsRoot = join12(claudeHome, "projects");
|
|
1902
1997
|
if (!existsSync9(projectsRoot)) {
|
|
1903
1998
|
return null;
|
|
1904
1999
|
}
|
|
1905
2000
|
const cwd = resolve3(options.cwd ?? repoRoot);
|
|
1906
2001
|
const preferredProjectDir = encodeClaudeProjectDir(cwd);
|
|
1907
|
-
const preferredPath =
|
|
2002
|
+
const preferredPath = join12(projectsRoot, preferredProjectDir);
|
|
1908
2003
|
if (existsSync9(preferredPath)) {
|
|
1909
2004
|
const hit = pickNewestJsonl(preferredPath, sessionId);
|
|
1910
2005
|
if (hit) {
|
|
1911
2006
|
return hit;
|
|
1912
2007
|
}
|
|
1913
|
-
const legacySessions =
|
|
2008
|
+
const legacySessions = join12(preferredPath, "sessions");
|
|
1914
2009
|
if (existsSync9(legacySessions)) {
|
|
1915
2010
|
const legacyHit = pickNewestJsonl(legacySessions, sessionId);
|
|
1916
2011
|
if (legacyHit) {
|
|
@@ -1921,9 +2016,9 @@ function resolveSessionJsonlPath(repoRoot, options = {}) {
|
|
|
1921
2016
|
const candidates = [];
|
|
1922
2017
|
for (const projectDir of readdirSync4(projectsRoot, { withFileTypes: true })) {
|
|
1923
2018
|
if (!projectDir.isDirectory()) continue;
|
|
1924
|
-
const projectPath =
|
|
2019
|
+
const projectPath = join12(projectsRoot, projectDir.name);
|
|
1925
2020
|
collectJsonlCandidates(projectPath, sessionId, candidates);
|
|
1926
|
-
const legacySessions =
|
|
2021
|
+
const legacySessions = join12(projectPath, "sessions");
|
|
1927
2022
|
if (existsSync9(legacySessions)) {
|
|
1928
2023
|
collectJsonlCandidates(legacySessions, sessionId, candidates);
|
|
1929
2024
|
}
|
|
@@ -1951,7 +2046,7 @@ function collectJsonlCandidates(dir, sessionId, out) {
|
|
|
1951
2046
|
if (!entry.isFile() || !entry.name.endsWith(".jsonl")) {
|
|
1952
2047
|
continue;
|
|
1953
2048
|
}
|
|
1954
|
-
const fullPath =
|
|
2049
|
+
const fullPath = join12(dir, entry.name);
|
|
1955
2050
|
if (sessionId && !entry.name.includes(sessionId) && basename2(entry.name, ".jsonl") !== sessionId) {
|
|
1956
2051
|
continue;
|
|
1957
2052
|
}
|
|
@@ -1986,7 +2081,7 @@ async function runClaudeCodeCapture(repoRoot, cwd, dryRun, options) {
|
|
|
1986
2081
|
// src/capture/codebuddy/resolveSession.ts
|
|
1987
2082
|
import { existsSync as existsSync10, readdirSync as readdirSync5, statSync as statSync2 } from "fs";
|
|
1988
2083
|
import { homedir as homedir2 } from "os";
|
|
1989
|
-
import { basename as basename3, join as
|
|
2084
|
+
import { basename as basename3, join as join13, resolve as resolve4 } from "path";
|
|
1990
2085
|
function encodeCodebuddyProjectDir(absPath) {
|
|
1991
2086
|
return resolve4(absPath).replace(/^\//, "").replace(/\//g, "-");
|
|
1992
2087
|
}
|
|
@@ -2000,14 +2095,14 @@ function resolveCodebuddySessionJsonl(options) {
|
|
|
2000
2095
|
return resolve4(fromHook);
|
|
2001
2096
|
}
|
|
2002
2097
|
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) :
|
|
2004
|
-
const projectsRoot =
|
|
2098
|
+
const codebuddyHome = process.env.CODEBUDDY_CONFIG_DIR ? resolve4(process.env.CODEBUDDY_CONFIG_DIR) : join13(homedir2(), ".codebuddy");
|
|
2099
|
+
const projectsRoot = join13(codebuddyHome, "projects");
|
|
2005
2100
|
if (!existsSync10(projectsRoot)) {
|
|
2006
2101
|
return null;
|
|
2007
2102
|
}
|
|
2008
2103
|
const cwd = resolve4(options.cwd ?? options.repoRoot);
|
|
2009
2104
|
const preferredProjectDir = encodeCodebuddyProjectDir(cwd);
|
|
2010
|
-
const preferredPath =
|
|
2105
|
+
const preferredPath = join13(projectsRoot, preferredProjectDir);
|
|
2011
2106
|
if (existsSync10(preferredPath)) {
|
|
2012
2107
|
const hit = pickNewestJsonlRecursive(preferredPath, sessionId);
|
|
2013
2108
|
if (hit) {
|
|
@@ -2019,7 +2114,7 @@ function resolveCodebuddySessionJsonl(options) {
|
|
|
2019
2114
|
if (!projectDir.isDirectory()) {
|
|
2020
2115
|
continue;
|
|
2021
2116
|
}
|
|
2022
|
-
collectJsonlRecursive(
|
|
2117
|
+
collectJsonlRecursive(join13(projectsRoot, projectDir.name), sessionId, candidates);
|
|
2023
2118
|
}
|
|
2024
2119
|
if (candidates.length === 0) {
|
|
2025
2120
|
return null;
|
|
@@ -2041,7 +2136,7 @@ function collectJsonlRecursive(dir, sessionId, out) {
|
|
|
2041
2136
|
return;
|
|
2042
2137
|
}
|
|
2043
2138
|
for (const entry of readdirSync5(dir, { withFileTypes: true })) {
|
|
2044
|
-
const full =
|
|
2139
|
+
const full = join13(dir, entry.name);
|
|
2045
2140
|
if (entry.isDirectory()) {
|
|
2046
2141
|
collectJsonlRecursive(full, sessionId, out);
|
|
2047
2142
|
continue;
|
|
@@ -2091,7 +2186,7 @@ async function runCodebuddyCapture(repoRoot, cwd, dryRun, options) {
|
|
|
2091
2186
|
// src/capture/cursor/resolveSession.ts
|
|
2092
2187
|
import { existsSync as existsSync11, readdirSync as readdirSync6, statSync as statSync3 } from "fs";
|
|
2093
2188
|
import { homedir as homedir3 } from "os";
|
|
2094
|
-
import { join as
|
|
2189
|
+
import { join as join14, resolve as resolve5 } from "path";
|
|
2095
2190
|
function encodeCursorProjectDir(absPath) {
|
|
2096
2191
|
return resolve5(absPath).replace(/^\//, "").replace(/\//g, "-");
|
|
2097
2192
|
}
|
|
@@ -2100,25 +2195,25 @@ function resolveCursorSessionJsonl(options) {
|
|
|
2100
2195
|
if (override && existsSync11(override)) {
|
|
2101
2196
|
return resolve5(override);
|
|
2102
2197
|
}
|
|
2103
|
-
const cursorHome = process.env.CURSOR_CONFIG_DIR ? resolve5(process.env.CURSOR_CONFIG_DIR) :
|
|
2104
|
-
const projectsRoot =
|
|
2198
|
+
const cursorHome = process.env.CURSOR_CONFIG_DIR ? resolve5(process.env.CURSOR_CONFIG_DIR) : join14(homedir3(), ".cursor");
|
|
2199
|
+
const projectsRoot = join14(cursorHome, "projects");
|
|
2105
2200
|
if (!existsSync11(projectsRoot)) {
|
|
2106
2201
|
return null;
|
|
2107
2202
|
}
|
|
2108
2203
|
const sessionId = options.hookInput?.sessionId ?? options.hookInput?.conversationId ?? process.env.CURSOR_SESSION_ID ?? process.env.CURSOR_AGENT_SESSION_ID;
|
|
2109
2204
|
const workspace = options.hookInput?.workspaceRoots?.[0] ?? (options.cwd ? resolve5(options.cwd) : resolve5(options.repoRoot));
|
|
2110
2205
|
const encoded = encodeCursorProjectDir(workspace);
|
|
2111
|
-
const projectDir =
|
|
2112
|
-
const transcriptsRoot =
|
|
2206
|
+
const projectDir = join14(projectsRoot, encoded);
|
|
2207
|
+
const transcriptsRoot = join14(projectDir, "agent-transcripts");
|
|
2113
2208
|
if (!existsSync11(transcriptsRoot)) {
|
|
2114
2209
|
return pickNewestCursorJsonl(projectsRoot);
|
|
2115
2210
|
}
|
|
2116
2211
|
if (sessionId) {
|
|
2117
|
-
const direct =
|
|
2212
|
+
const direct = join14(transcriptsRoot, sessionId, `${sessionId}.jsonl`);
|
|
2118
2213
|
if (existsSync11(direct)) {
|
|
2119
2214
|
return direct;
|
|
2120
2215
|
}
|
|
2121
|
-
const nested = findJsonlUnderDir(
|
|
2216
|
+
const nested = findJsonlUnderDir(join14(transcriptsRoot, sessionId), sessionId);
|
|
2122
2217
|
if (nested) {
|
|
2123
2218
|
return nested;
|
|
2124
2219
|
}
|
|
@@ -2129,16 +2224,16 @@ function findJsonlUnderDir(dir, sessionId) {
|
|
|
2129
2224
|
if (!existsSync11(dir)) {
|
|
2130
2225
|
return null;
|
|
2131
2226
|
}
|
|
2132
|
-
const direct =
|
|
2227
|
+
const direct = join14(dir, `${sessionId}.jsonl`);
|
|
2133
2228
|
if (existsSync11(direct)) {
|
|
2134
2229
|
return direct;
|
|
2135
2230
|
}
|
|
2136
2231
|
for (const entry of readdirSync6(dir, { withFileTypes: true })) {
|
|
2137
2232
|
if (entry.isFile() && entry.name.endsWith(".jsonl")) {
|
|
2138
|
-
return
|
|
2233
|
+
return join14(dir, entry.name);
|
|
2139
2234
|
}
|
|
2140
2235
|
if (entry.isDirectory()) {
|
|
2141
|
-
const found = findJsonlUnderDir(
|
|
2236
|
+
const found = findJsonlUnderDir(join14(dir, entry.name), sessionId);
|
|
2142
2237
|
if (found) {
|
|
2143
2238
|
return found;
|
|
2144
2239
|
}
|
|
@@ -2160,7 +2255,7 @@ function collectJsonlRecursive2(dir, out) {
|
|
|
2160
2255
|
return;
|
|
2161
2256
|
}
|
|
2162
2257
|
for (const entry of readdirSync6(dir, { withFileTypes: true })) {
|
|
2163
|
-
const full =
|
|
2258
|
+
const full = join14(dir, entry.name);
|
|
2164
2259
|
if (entry.isDirectory()) {
|
|
2165
2260
|
collectJsonlRecursive2(full, out);
|
|
2166
2261
|
continue;
|
|
@@ -2386,7 +2481,7 @@ async function runFlushCommandCli(opts) {
|
|
|
2386
2481
|
|
|
2387
2482
|
// src/inject/runInject.ts
|
|
2388
2483
|
import { existsSync as existsSync12, readdirSync as readdirSync7, readFileSync as readFileSync12 } from "fs";
|
|
2389
|
-
import { join as
|
|
2484
|
+
import { join as join15 } from "path";
|
|
2390
2485
|
|
|
2391
2486
|
// src/inject/constants.ts
|
|
2392
2487
|
var INJECT_MAX_CHARS = 8e3;
|
|
@@ -2466,7 +2561,7 @@ function readAllRules(repoRoot) {
|
|
|
2466
2561
|
const parts = [];
|
|
2467
2562
|
for (const file of files) {
|
|
2468
2563
|
try {
|
|
2469
|
-
const filePath =
|
|
2564
|
+
const filePath = join15(rulesDir, file);
|
|
2470
2565
|
const content = readFileSync12(filePath, "utf8").trim();
|
|
2471
2566
|
if (!content) continue;
|
|
2472
2567
|
parts.push(`### ${file}`, "", content, "");
|
|
@@ -2494,46 +2589,46 @@ import { resolve as resolve7 } from "path";
|
|
|
2494
2589
|
|
|
2495
2590
|
// src/init/assistants/claude-code.ts
|
|
2496
2591
|
import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync6 } from "fs";
|
|
2497
|
-
import { join as
|
|
2592
|
+
import { join as join19 } from "path";
|
|
2498
2593
|
|
|
2499
2594
|
// src/init/mergeClaudeSettings.ts
|
|
2500
2595
|
import { existsSync as existsSync14, readFileSync as readFileSync15 } from "fs";
|
|
2501
|
-
import { join as
|
|
2596
|
+
import { join as join18 } from "path";
|
|
2502
2597
|
|
|
2503
2598
|
// src/init/templateDir.ts
|
|
2504
2599
|
import { existsSync as existsSync13, readFileSync as readFileSync14 } from "fs";
|
|
2505
|
-
import { dirname as
|
|
2506
|
-
import { fileURLToPath as
|
|
2600
|
+
import { dirname as dirname7, join as join17 } from "path";
|
|
2601
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
2507
2602
|
|
|
2508
2603
|
// src/index.ts
|
|
2509
2604
|
import { readFileSync as readFileSync13 } from "fs";
|
|
2510
|
-
import { dirname as
|
|
2511
|
-
import { fileURLToPath as
|
|
2605
|
+
import { dirname as dirname6, join as join16 } from "path";
|
|
2606
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
2512
2607
|
var PACKAGE_NAME = "@riconext/hermes-repo";
|
|
2513
|
-
var __dirname =
|
|
2608
|
+
var __dirname = dirname6(fileURLToPath3(import.meta.url));
|
|
2514
2609
|
function readPkgVersion() {
|
|
2515
|
-
const pkgPath =
|
|
2610
|
+
const pkgPath = join16(__dirname, "..", "package.json");
|
|
2516
2611
|
const pkg = JSON.parse(readFileSync13(pkgPath, "utf8"));
|
|
2517
2612
|
return pkg.version;
|
|
2518
2613
|
}
|
|
2519
2614
|
|
|
2520
2615
|
// src/init/templateDir.ts
|
|
2521
2616
|
function resolveTemplateDir() {
|
|
2522
|
-
const here =
|
|
2617
|
+
const here = dirname7(fileURLToPath4(import.meta.url));
|
|
2523
2618
|
const candidates = [
|
|
2524
|
-
|
|
2525
|
-
|
|
2619
|
+
join17(here, "templates"),
|
|
2620
|
+
join17(here, "..", "..", "templates")
|
|
2526
2621
|
];
|
|
2527
2622
|
for (const dir of candidates) {
|
|
2528
2623
|
if (existsSync13(dir)) {
|
|
2529
2624
|
return dir;
|
|
2530
2625
|
}
|
|
2531
2626
|
}
|
|
2532
|
-
return
|
|
2627
|
+
return join17(here, "templates");
|
|
2533
2628
|
}
|
|
2534
2629
|
var templateDir = resolveTemplateDir();
|
|
2535
2630
|
function resolveTemplatePath(name) {
|
|
2536
|
-
return
|
|
2631
|
+
return join17(templateDir, name);
|
|
2537
2632
|
}
|
|
2538
2633
|
function readTemplate(name) {
|
|
2539
2634
|
return readFileSync14(resolveTemplatePath(name), "utf8");
|
|
@@ -2546,7 +2641,7 @@ function renderTemplate(name) {
|
|
|
2546
2641
|
// src/init/mergeClaudeSettings.ts
|
|
2547
2642
|
var CLAUDE_SETTINGS_LOCAL_REL = ".claude/settings.local.json";
|
|
2548
2643
|
function claudeSettingsLocalPath(repoRoot) {
|
|
2549
|
-
return
|
|
2644
|
+
return join18(repoRoot, ".claude", "settings.local.json");
|
|
2550
2645
|
}
|
|
2551
2646
|
function mergeClaudeLocalSettings(repoRoot) {
|
|
2552
2647
|
const settingsPath = claudeSettingsLocalPath(repoRoot);
|
|
@@ -2583,7 +2678,7 @@ var claudeCodeAdapter = {
|
|
|
2583
2678
|
available: true,
|
|
2584
2679
|
scaffoldPaths: [CLAUDE_SETTINGS_LOCAL_REL],
|
|
2585
2680
|
write(ctx) {
|
|
2586
|
-
mkdirSync7(
|
|
2681
|
+
mkdirSync7(join19(ctx.repoRoot, ".claude"), { recursive: true });
|
|
2587
2682
|
const { content, action } = mergeClaudeLocalSettings(ctx.repoRoot);
|
|
2588
2683
|
writeFileSync6(claudeSettingsLocalPath(ctx.repoRoot), content, "utf8");
|
|
2589
2684
|
ctx.report.files.push({ path: CLAUDE_SETTINGS_LOCAL_REL, action });
|
|
@@ -2592,11 +2687,11 @@ var claudeCodeAdapter = {
|
|
|
2592
2687
|
|
|
2593
2688
|
// src/init/assistants/codex.ts
|
|
2594
2689
|
import { mkdirSync as mkdirSync8, writeFileSync as writeFileSync7 } from "fs";
|
|
2595
|
-
import { join as
|
|
2690
|
+
import { join as join21 } from "path";
|
|
2596
2691
|
|
|
2597
2692
|
// src/init/mergeCodexConfig.ts
|
|
2598
2693
|
import { existsSync as existsSync15, readFileSync as readFileSync16 } from "fs";
|
|
2599
|
-
import { join as
|
|
2694
|
+
import { join as join20 } from "path";
|
|
2600
2695
|
var CODEX_CONFIG_REL = ".codex/config.toml";
|
|
2601
2696
|
var CODEX_HERMES_START_MARKER = "# >>> hermes-repo codex (do not edit this block manually)";
|
|
2602
2697
|
var CODEX_HERMES_END_MARKER = "# <<< hermes-repo codex";
|
|
@@ -2610,7 +2705,7 @@ function buildCodexHermesBlock() {
|
|
|
2610
2705
|
].join("\n");
|
|
2611
2706
|
}
|
|
2612
2707
|
function codexConfigPath(repoRoot) {
|
|
2613
|
-
return
|
|
2708
|
+
return join20(repoRoot, ".codex", "config.toml");
|
|
2614
2709
|
}
|
|
2615
2710
|
function spliceHermesBlock(existing, block) {
|
|
2616
2711
|
const startIdx = existing.indexOf(CODEX_HERMES_START_MARKER);
|
|
@@ -2657,7 +2752,7 @@ var codexAdapter = {
|
|
|
2657
2752
|
available: true,
|
|
2658
2753
|
scaffoldPaths: [CODEX_CONFIG_REL],
|
|
2659
2754
|
write(ctx) {
|
|
2660
|
-
mkdirSync8(
|
|
2755
|
+
mkdirSync8(join21(ctx.repoRoot, ".codex"), { recursive: true });
|
|
2661
2756
|
const { content, action } = mergeCodexConfig(ctx.repoRoot);
|
|
2662
2757
|
writeFileSync7(codexConfigPath(ctx.repoRoot), content, "utf8");
|
|
2663
2758
|
ctx.report.files.push({ path: CODEX_CONFIG_REL, action });
|
|
@@ -2666,14 +2761,14 @@ var codexAdapter = {
|
|
|
2666
2761
|
|
|
2667
2762
|
// src/init/assistants/codebuddy.ts
|
|
2668
2763
|
import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync8 } from "fs";
|
|
2669
|
-
import { join as
|
|
2764
|
+
import { join as join23 } from "path";
|
|
2670
2765
|
|
|
2671
2766
|
// src/init/mergeCodebuddySettings.ts
|
|
2672
2767
|
import { existsSync as existsSync16, readFileSync as readFileSync17 } from "fs";
|
|
2673
|
-
import { join as
|
|
2768
|
+
import { join as join22 } from "path";
|
|
2674
2769
|
var CODEBUDDY_SETTINGS_LOCAL_REL = ".codebuddy/settings.local.json";
|
|
2675
2770
|
function codebuddySettingsLocalPath(repoRoot) {
|
|
2676
|
-
return
|
|
2771
|
+
return join22(repoRoot, ".codebuddy", "settings.local.json");
|
|
2677
2772
|
}
|
|
2678
2773
|
function mergeCodebuddyLocalSettings(repoRoot) {
|
|
2679
2774
|
const settingsPath = codebuddySettingsLocalPath(repoRoot);
|
|
@@ -2712,7 +2807,7 @@ var codebuddyAdapter = {
|
|
|
2712
2807
|
available: true,
|
|
2713
2808
|
scaffoldPaths: [CODEBUDDY_SETTINGS_LOCAL_REL],
|
|
2714
2809
|
write(ctx) {
|
|
2715
|
-
mkdirSync9(
|
|
2810
|
+
mkdirSync9(join23(ctx.repoRoot, ".codebuddy"), { recursive: true });
|
|
2716
2811
|
const { content, action } = mergeCodebuddyLocalSettings(ctx.repoRoot);
|
|
2717
2812
|
writeFileSync8(codebuddySettingsLocalPath(ctx.repoRoot), content, "utf8");
|
|
2718
2813
|
ctx.report.files.push({ path: CODEBUDDY_SETTINGS_LOCAL_REL, action });
|
|
@@ -2721,14 +2816,14 @@ var codebuddyAdapter = {
|
|
|
2721
2816
|
|
|
2722
2817
|
// src/init/assistants/cursor.ts
|
|
2723
2818
|
import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync9 } from "fs";
|
|
2724
|
-
import { join as
|
|
2819
|
+
import { join as join25 } from "path";
|
|
2725
2820
|
|
|
2726
2821
|
// src/init/mergeCursorHooks.ts
|
|
2727
2822
|
import { existsSync as existsSync17, readFileSync as readFileSync18 } from "fs";
|
|
2728
|
-
import { join as
|
|
2823
|
+
import { join as join24 } from "path";
|
|
2729
2824
|
var CURSOR_HOOKS_REL = ".cursor/hooks.json";
|
|
2730
2825
|
function cursorHooksPath(repoRoot) {
|
|
2731
|
-
return
|
|
2826
|
+
return join24(repoRoot, ".cursor", "hooks.json");
|
|
2732
2827
|
}
|
|
2733
2828
|
function mergeCursorHooks(repoRoot) {
|
|
2734
2829
|
const hooksPath = cursorHooksPath(repoRoot);
|
|
@@ -2766,7 +2861,7 @@ var cursorAdapter = {
|
|
|
2766
2861
|
available: true,
|
|
2767
2862
|
scaffoldPaths: [CURSOR_HOOKS_REL],
|
|
2768
2863
|
write(ctx) {
|
|
2769
|
-
mkdirSync10(
|
|
2864
|
+
mkdirSync10(join25(ctx.repoRoot, ".cursor"), { recursive: true });
|
|
2770
2865
|
const { content, action } = mergeCursorHooks(ctx.repoRoot);
|
|
2771
2866
|
writeFileSync9(cursorHooksPath(ctx.repoRoot), content, "utf8");
|
|
2772
2867
|
ctx.report.files.push({ path: CURSOR_HOOKS_REL, action });
|
|
@@ -2829,16 +2924,16 @@ function validateAssistantSelection(ids) {
|
|
|
2829
2924
|
|
|
2830
2925
|
// src/init/ensureDirs.ts
|
|
2831
2926
|
import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync10 } from "fs";
|
|
2832
|
-
import { join as
|
|
2927
|
+
import { join as join26 } from "path";
|
|
2833
2928
|
function ensureMemoryTree(repoRoot) {
|
|
2834
|
-
const memoryRoot =
|
|
2929
|
+
const memoryRoot = join26(repoRoot, MEMORY_DIR);
|
|
2835
2930
|
mkdirSync11(memoryRoot, { recursive: true });
|
|
2836
2931
|
for (const sub of MEMORY_SUBDIRS) {
|
|
2837
|
-
mkdirSync11(
|
|
2932
|
+
mkdirSync11(join26(memoryRoot, sub), { recursive: true });
|
|
2838
2933
|
}
|
|
2839
|
-
mkdirSync11(
|
|
2934
|
+
mkdirSync11(join26(repoRoot, ".claude"), { recursive: true });
|
|
2840
2935
|
for (const sub of GITKEEP_DIRS) {
|
|
2841
|
-
const keepPath =
|
|
2936
|
+
const keepPath = join26(memoryRoot, sub, ".gitkeep");
|
|
2842
2937
|
writeFileSync10(keepPath, "", { flag: "a" });
|
|
2843
2938
|
}
|
|
2844
2939
|
}
|
|
@@ -2867,12 +2962,12 @@ function mergeAssistants(repoRoot, selected) {
|
|
|
2867
2962
|
|
|
2868
2963
|
// src/init/mergeGitignore.ts
|
|
2869
2964
|
import { existsSync as existsSync19, readFileSync as readFileSync20, writeFileSync as writeFileSync11 } from "fs";
|
|
2870
|
-
import { join as
|
|
2965
|
+
import { join as join27 } from "path";
|
|
2871
2966
|
var START_MARKER = "# >>> hermes-repo memory (do not edit this block manually)";
|
|
2872
2967
|
var END_MARKER = "# <<< hermes-repo memory";
|
|
2873
2968
|
function mergeHermesGitignore(repoRoot) {
|
|
2874
2969
|
const block = readTemplate("gitignore-block.txt").trimEnd() + "\n";
|
|
2875
|
-
const gitignorePath =
|
|
2970
|
+
const gitignorePath = join27(repoRoot, ".gitignore");
|
|
2876
2971
|
const contentBefore = existsSync19(gitignorePath) ? readFileSync20(gitignorePath, "utf8") : "";
|
|
2877
2972
|
const warnBroadMemoryIgnore = contentBefore.length > 0 && !contentBefore.includes(START_MARKER) && /(^|\n)\.memory\/\s*$/m.test(contentBefore);
|
|
2878
2973
|
if (!existsSync19(gitignorePath)) {
|
|
@@ -2919,7 +3014,13 @@ var DEFAULT_LLM = {
|
|
|
2919
3014
|
mode: "async"
|
|
2920
3015
|
};
|
|
2921
3016
|
var DEFAULT_CONSOLIDATE = {
|
|
2922
|
-
autoArchiveDays: 30
|
|
3017
|
+
autoArchiveDays: 30,
|
|
3018
|
+
autoFlush: {
|
|
3019
|
+
enabled: false,
|
|
3020
|
+
minPendingSessions: 3,
|
|
3021
|
+
minIntervalMinutes: 30,
|
|
3022
|
+
maxPendingChars: 2e4
|
|
3023
|
+
}
|
|
2923
3024
|
};
|
|
2924
3025
|
function mergeConfigForInit(repoRoot, assistants) {
|
|
2925
3026
|
const configPath = memoryPath(repoRoot, "config.json");
|
|
@@ -2935,6 +3036,7 @@ function mergeConfigForInit(repoRoot, assistants) {
|
|
|
2935
3036
|
const prevStorage = existing.storage && typeof existing.storage === "object" && !Array.isArray(existing.storage) ? existing.storage : {};
|
|
2936
3037
|
const prevLlm = existing.llm && typeof existing.llm === "object" && !Array.isArray(existing.llm) ? existing.llm : {};
|
|
2937
3038
|
const prevConsolidate = existing.consolidate && typeof existing.consolidate === "object" && !Array.isArray(existing.consolidate) ? existing.consolidate : {};
|
|
3039
|
+
const prevAutoFlush = prevConsolidate.autoFlush && typeof prevConsolidate.autoFlush === "object" && !Array.isArray(prevConsolidate.autoFlush) ? prevConsolidate.autoFlush : {};
|
|
2938
3040
|
const merged = {
|
|
2939
3041
|
...existing,
|
|
2940
3042
|
version: 2,
|
|
@@ -2945,7 +3047,14 @@ function mergeConfigForInit(repoRoot, assistants) {
|
|
|
2945
3047
|
assistants,
|
|
2946
3048
|
debug: existing.debug === true,
|
|
2947
3049
|
llm: { ...DEFAULT_LLM, ...prevLlm },
|
|
2948
|
-
consolidate: {
|
|
3050
|
+
consolidate: {
|
|
3051
|
+
...DEFAULT_CONSOLIDATE,
|
|
3052
|
+
...prevConsolidate,
|
|
3053
|
+
autoFlush: {
|
|
3054
|
+
...DEFAULT_CONSOLIDATE.autoFlush,
|
|
3055
|
+
...prevAutoFlush
|
|
3056
|
+
}
|
|
3057
|
+
}
|
|
2949
3058
|
};
|
|
2950
3059
|
return {
|
|
2951
3060
|
content: `${JSON.stringify(merged, null, 2)}
|
|
@@ -2956,7 +3065,7 @@ function mergeConfigForInit(repoRoot, assistants) {
|
|
|
2956
3065
|
|
|
2957
3066
|
// src/init/mergeAgentsMd.ts
|
|
2958
3067
|
import { existsSync as existsSync21, readFileSync as readFileSync22, writeFileSync as writeFileSync12 } from "fs";
|
|
2959
|
-
import { join as
|
|
3068
|
+
import { join as join28 } from "path";
|
|
2960
3069
|
var HERMES_AGENTS_START_MARKER = "<!-- >>> hermes-repo agents (do not edit this block manually) -->";
|
|
2961
3070
|
var HERMES_AGENTS_END_MARKER = "<!-- <<< hermes-repo agents -->";
|
|
2962
3071
|
function buildHermesAgentsBlockBody() {
|
|
@@ -3012,7 +3121,7 @@ function spliceHermesBlock2(existing, block) {
|
|
|
3012
3121
|
`;
|
|
3013
3122
|
}
|
|
3014
3123
|
function mergeAgentsMd(repoRoot, force) {
|
|
3015
|
-
const agentsPath =
|
|
3124
|
+
const agentsPath = join28(repoRoot, "AGENTS.md");
|
|
3016
3125
|
const block = buildHermesAgentsMarkedBlock();
|
|
3017
3126
|
if (!existsSync21(agentsPath)) {
|
|
3018
3127
|
writeFileSync12(agentsPath, buildNewAgentsMd(), "utf8");
|