@riconext/hermes-repo 0.13.0 → 0.14.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 +13 -0
- package/README.md +23 -4
- package/dist/cli.js +257 -145
- package/dist/cli.js.map +1 -1
- package/package.json +8 -2
package/dist/cli.js
CHANGED
|
@@ -201,10 +201,36 @@ function serializeLlmConfig(cfg) {
|
|
|
201
201
|
import { readFileSync as readFileSync3 } from "fs";
|
|
202
202
|
import { basename } from "path";
|
|
203
203
|
var FILE_CHANGE_TOOLS = /^(Write|Edit|MultiEdit|NotebookEdit|write|edit)$/i;
|
|
204
|
+
var SKIP_LINE_TYPES = /* @__PURE__ */ new Set([
|
|
205
|
+
"file-history-snapshot",
|
|
206
|
+
"summary",
|
|
207
|
+
"function_call_result"
|
|
208
|
+
]);
|
|
209
|
+
function textFromContentParts(content) {
|
|
210
|
+
if (!Array.isArray(content)) {
|
|
211
|
+
return "";
|
|
212
|
+
}
|
|
213
|
+
return content.map((part) => {
|
|
214
|
+
if (!part || typeof part !== "object") {
|
|
215
|
+
return "";
|
|
216
|
+
}
|
|
217
|
+
const p = part;
|
|
218
|
+
if (typeof p.text === "string") {
|
|
219
|
+
return p.text;
|
|
220
|
+
}
|
|
221
|
+
return "";
|
|
222
|
+
}).filter(Boolean).join("\n");
|
|
223
|
+
}
|
|
204
224
|
function extractText(record) {
|
|
205
225
|
if (typeof record.content === "string") {
|
|
206
226
|
return record.content;
|
|
207
227
|
}
|
|
228
|
+
if (Array.isArray(record.content)) {
|
|
229
|
+
const top = textFromContentParts(record.content);
|
|
230
|
+
if (top) {
|
|
231
|
+
return top;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
208
234
|
const message = record.message;
|
|
209
235
|
if (message && typeof message === "object") {
|
|
210
236
|
const msg = message;
|
|
@@ -212,12 +238,7 @@ function extractText(record) {
|
|
|
212
238
|
return msg.content;
|
|
213
239
|
}
|
|
214
240
|
if (Array.isArray(msg.content)) {
|
|
215
|
-
return msg.content
|
|
216
|
-
if (part && typeof part === "object" && "text" in part) {
|
|
217
|
-
return String(part.text);
|
|
218
|
-
}
|
|
219
|
-
return "";
|
|
220
|
-
}).join("\n");
|
|
241
|
+
return textFromContentParts(msg.content);
|
|
221
242
|
}
|
|
222
243
|
}
|
|
223
244
|
return "";
|
|
@@ -233,9 +254,13 @@ function inferRole(record) {
|
|
|
233
254
|
}
|
|
234
255
|
return "unknown";
|
|
235
256
|
}
|
|
257
|
+
function isSkippedLine(record) {
|
|
258
|
+
const t = String(record.type ?? "").toLowerCase();
|
|
259
|
+
return SKIP_LINE_TYPES.has(t);
|
|
260
|
+
}
|
|
236
261
|
function isToolUse(record) {
|
|
237
262
|
const t = String(record.type ?? "").toLowerCase();
|
|
238
|
-
return t === "tool_use" || t === "tool";
|
|
263
|
+
return t === "tool_use" || t === "tool" || t === "function_call";
|
|
239
264
|
}
|
|
240
265
|
function toolName(record) {
|
|
241
266
|
if (typeof record.name === "string") return record.name;
|
|
@@ -284,6 +309,9 @@ function parseJsonlFile(jsonlPath) {
|
|
|
284
309
|
if (!trimmed) continue;
|
|
285
310
|
try {
|
|
286
311
|
const record = JSON.parse(trimmed);
|
|
312
|
+
if (isSkippedLine(record)) {
|
|
313
|
+
continue;
|
|
314
|
+
}
|
|
287
315
|
if (isToolUse(record)) {
|
|
288
316
|
toolCalls += 1;
|
|
289
317
|
const name = toolName(record);
|
|
@@ -907,6 +935,7 @@ function parseHookInputJson(raw) {
|
|
|
907
935
|
const transcriptPath = transcriptRaw && existsSync6(transcriptRaw) ? resolve2(transcriptRaw) : void 0;
|
|
908
936
|
return {
|
|
909
937
|
transcriptPath,
|
|
938
|
+
transcriptPathRaw: transcriptRaw,
|
|
910
939
|
hookEventName: pickString(parsed, "hook_event_name", "hookEventName"),
|
|
911
940
|
sessionId: pickString(parsed, "session_id", "sessionId"),
|
|
912
941
|
conversationId: pickString(parsed, "conversation_id", "conversationId"),
|
|
@@ -932,7 +961,7 @@ function isCodebuddyCaptureHook(hook) {
|
|
|
932
961
|
if (!hook) {
|
|
933
962
|
return false;
|
|
934
963
|
}
|
|
935
|
-
return isTranscriptUnderAssistant(hook.transcriptPath, ".codebuddy");
|
|
964
|
+
return isTranscriptUnderAssistant(hook.transcriptPath, ".codebuddy") || isTranscriptUnderAssistant(hook.transcriptPathRaw, ".codebuddy");
|
|
936
965
|
}
|
|
937
966
|
function isClaudeCaptureHook(hook) {
|
|
938
967
|
if (!hook) {
|
|
@@ -3498,6 +3527,14 @@ function runCaptureCommand(opts) {
|
|
|
3498
3527
|
const debug = ctx?.config.debug === true;
|
|
3499
3528
|
configureDebugLogging(ctx?.repoRoot ?? null, debug);
|
|
3500
3529
|
const hookInput = readHookInputSync();
|
|
3530
|
+
if (hookInput && isCodebuddyCaptureHook(hookInput)) {
|
|
3531
|
+
const stdinPath = hookInput.transcriptPathRaw ?? hookInput.transcriptPath ?? "(missing)";
|
|
3532
|
+
debugLog(
|
|
3533
|
+
debug,
|
|
3534
|
+
"capture",
|
|
3535
|
+
`codebuddy stop stdin transcript_path=${stdinPath}`
|
|
3536
|
+
);
|
|
3537
|
+
}
|
|
3501
3538
|
finalizeHookCommand(async () => {
|
|
3502
3539
|
await runCapture({
|
|
3503
3540
|
cwd: opts.cwd,
|
|
@@ -3698,27 +3735,101 @@ var claudeCodeAdapter = {
|
|
|
3698
3735
|
}
|
|
3699
3736
|
};
|
|
3700
3737
|
|
|
3701
|
-
// src/init/assistants/
|
|
3738
|
+
// src/init/assistants/codex.ts
|
|
3702
3739
|
import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync14 } from "fs";
|
|
3703
3740
|
import { join as join27 } from "path";
|
|
3704
3741
|
|
|
3705
|
-
// src/init/
|
|
3742
|
+
// src/init/mergeCodexConfig.ts
|
|
3706
3743
|
import { existsSync as existsSync24, readFileSync as readFileSync24 } from "fs";
|
|
3707
3744
|
import { join as join26 } from "path";
|
|
3745
|
+
var CODEX_CONFIG_REL = ".codex/config.toml";
|
|
3746
|
+
var CODEX_HERMES_START_MARKER = "# >>> hermes-repo codex (do not edit this block manually)";
|
|
3747
|
+
var CODEX_HERMES_END_MARKER = "# <<< hermes-repo codex";
|
|
3748
|
+
function buildCodexHermesBlock() {
|
|
3749
|
+
return [
|
|
3750
|
+
CODEX_HERMES_START_MARKER,
|
|
3751
|
+
"# Hermes uses AGENTS.md as the shared Codex project guidance entry.",
|
|
3752
|
+
"# Run `npx @riconext/hermes-repo search <keyword>` to inspect project memory.",
|
|
3753
|
+
'# Run `npx @riconext/hermes-repo ref --capture <path> --reason "..."` after using memory.',
|
|
3754
|
+
CODEX_HERMES_END_MARKER
|
|
3755
|
+
].join("\n");
|
|
3756
|
+
}
|
|
3757
|
+
function codexConfigPath(repoRoot) {
|
|
3758
|
+
return join26(repoRoot, ".codex", "config.toml");
|
|
3759
|
+
}
|
|
3760
|
+
function spliceHermesBlock(existing, block) {
|
|
3761
|
+
const startIdx = existing.indexOf(CODEX_HERMES_START_MARKER);
|
|
3762
|
+
const endIdx = existing.indexOf(CODEX_HERMES_END_MARKER);
|
|
3763
|
+
if (startIdx >= 0 && endIdx >= startIdx) {
|
|
3764
|
+
const before = existing.slice(0, startIdx).trimEnd();
|
|
3765
|
+
const after = existing.slice(endIdx + CODEX_HERMES_END_MARKER.length).trimStart();
|
|
3766
|
+
return `${before ? `${before}
|
|
3767
|
+
|
|
3768
|
+
` : ""}${block}${after ? `
|
|
3769
|
+
|
|
3770
|
+
${after}` : ""}
|
|
3771
|
+
`;
|
|
3772
|
+
}
|
|
3773
|
+
const trimmed = existing.trimEnd();
|
|
3774
|
+
return `${trimmed ? `${trimmed}
|
|
3775
|
+
|
|
3776
|
+
` : ""}${block}
|
|
3777
|
+
`;
|
|
3778
|
+
}
|
|
3779
|
+
function mergeCodexConfig(repoRoot) {
|
|
3780
|
+
const configPath = codexConfigPath(repoRoot);
|
|
3781
|
+
const existed = existsSync24(configPath);
|
|
3782
|
+
const block = buildCodexHermesBlock();
|
|
3783
|
+
if (!existed) {
|
|
3784
|
+
return {
|
|
3785
|
+
content: `${block}
|
|
3786
|
+
`,
|
|
3787
|
+
action: "created"
|
|
3788
|
+
};
|
|
3789
|
+
}
|
|
3790
|
+
const existing = readFileSync24(configPath, "utf8");
|
|
3791
|
+
const hasBlock = existing.includes(CODEX_HERMES_START_MARKER) && existing.includes(CODEX_HERMES_END_MARKER);
|
|
3792
|
+
return {
|
|
3793
|
+
content: spliceHermesBlock(existing, block),
|
|
3794
|
+
action: hasBlock ? "replaced" : "appended"
|
|
3795
|
+
};
|
|
3796
|
+
}
|
|
3797
|
+
|
|
3798
|
+
// src/init/assistants/codex.ts
|
|
3799
|
+
var codexAdapter = {
|
|
3800
|
+
id: "codex",
|
|
3801
|
+
label: "OpenAI Codex\uFF08AGENTS.md + .codex/config.toml\uFF09",
|
|
3802
|
+
available: true,
|
|
3803
|
+
scaffoldPaths: [CODEX_CONFIG_REL],
|
|
3804
|
+
write(ctx) {
|
|
3805
|
+
mkdirSync9(join27(ctx.repoRoot, ".codex"), { recursive: true });
|
|
3806
|
+
const { content, action } = mergeCodexConfig(ctx.repoRoot);
|
|
3807
|
+
writeFileSync14(codexConfigPath(ctx.repoRoot), content, "utf8");
|
|
3808
|
+
ctx.report.files.push({ path: CODEX_CONFIG_REL, action });
|
|
3809
|
+
}
|
|
3810
|
+
};
|
|
3811
|
+
|
|
3812
|
+
// src/init/assistants/codebuddy.ts
|
|
3813
|
+
import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync15 } from "fs";
|
|
3814
|
+
import { join as join29 } from "path";
|
|
3815
|
+
|
|
3816
|
+
// src/init/mergeCodebuddySettings.ts
|
|
3817
|
+
import { existsSync as existsSync25, readFileSync as readFileSync25 } from "fs";
|
|
3818
|
+
import { join as join28 } from "path";
|
|
3708
3819
|
var CODEBUDDY_SETTINGS_LOCAL_REL = ".codebuddy/settings.local.json";
|
|
3709
3820
|
function codebuddySettingsLocalPath(repoRoot) {
|
|
3710
|
-
return
|
|
3821
|
+
return join28(repoRoot, ".codebuddy", "settings.local.json");
|
|
3711
3822
|
}
|
|
3712
3823
|
function mergeCodebuddyLocalSettings(repoRoot) {
|
|
3713
3824
|
const settingsPath = codebuddySettingsLocalPath(repoRoot);
|
|
3714
|
-
const existed =
|
|
3825
|
+
const existed = existsSync25(settingsPath);
|
|
3715
3826
|
const templateParsed = JSON.parse(
|
|
3716
3827
|
renderTemplate("hooks.codebuddy.json.tpl")
|
|
3717
3828
|
);
|
|
3718
3829
|
let existing = {};
|
|
3719
3830
|
if (existed) {
|
|
3720
3831
|
try {
|
|
3721
|
-
existing = JSON.parse(
|
|
3832
|
+
existing = JSON.parse(readFileSync25(settingsPath, "utf8"));
|
|
3722
3833
|
} catch {
|
|
3723
3834
|
existing = {};
|
|
3724
3835
|
}
|
|
@@ -3746,32 +3857,32 @@ var codebuddyAdapter = {
|
|
|
3746
3857
|
available: true,
|
|
3747
3858
|
scaffoldPaths: [CODEBUDDY_SETTINGS_LOCAL_REL],
|
|
3748
3859
|
write(ctx) {
|
|
3749
|
-
|
|
3860
|
+
mkdirSync10(join29(ctx.repoRoot, ".codebuddy"), { recursive: true });
|
|
3750
3861
|
const { content, action } = mergeCodebuddyLocalSettings(ctx.repoRoot);
|
|
3751
|
-
|
|
3862
|
+
writeFileSync15(codebuddySettingsLocalPath(ctx.repoRoot), content, "utf8");
|
|
3752
3863
|
ctx.report.files.push({ path: CODEBUDDY_SETTINGS_LOCAL_REL, action });
|
|
3753
3864
|
}
|
|
3754
3865
|
};
|
|
3755
3866
|
|
|
3756
3867
|
// src/init/assistants/cursor.ts
|
|
3757
|
-
import { mkdirSync as
|
|
3758
|
-
import { join as
|
|
3868
|
+
import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync16 } from "fs";
|
|
3869
|
+
import { join as join31 } from "path";
|
|
3759
3870
|
|
|
3760
3871
|
// src/init/mergeCursorHooks.ts
|
|
3761
|
-
import { existsSync as
|
|
3762
|
-
import { join as
|
|
3872
|
+
import { existsSync as existsSync26, readFileSync as readFileSync26 } from "fs";
|
|
3873
|
+
import { join as join30 } from "path";
|
|
3763
3874
|
var CURSOR_HOOKS_REL = ".cursor/hooks.json";
|
|
3764
3875
|
function cursorHooksPath(repoRoot) {
|
|
3765
|
-
return
|
|
3876
|
+
return join30(repoRoot, ".cursor", "hooks.json");
|
|
3766
3877
|
}
|
|
3767
3878
|
function mergeCursorHooks(repoRoot) {
|
|
3768
3879
|
const hooksPath = cursorHooksPath(repoRoot);
|
|
3769
|
-
const existed =
|
|
3880
|
+
const existed = existsSync26(hooksPath);
|
|
3770
3881
|
const templateParsed = JSON.parse(renderTemplate("hooks.cursor.json.tpl"));
|
|
3771
3882
|
let existing = {};
|
|
3772
3883
|
if (existed) {
|
|
3773
3884
|
try {
|
|
3774
|
-
existing = JSON.parse(
|
|
3885
|
+
existing = JSON.parse(readFileSync26(hooksPath, "utf8"));
|
|
3775
3886
|
} catch {
|
|
3776
3887
|
existing = {};
|
|
3777
3888
|
}
|
|
@@ -3800,9 +3911,9 @@ var cursorAdapter = {
|
|
|
3800
3911
|
available: true,
|
|
3801
3912
|
scaffoldPaths: [CURSOR_HOOKS_REL],
|
|
3802
3913
|
write(ctx) {
|
|
3803
|
-
|
|
3914
|
+
mkdirSync11(join31(ctx.repoRoot, ".cursor"), { recursive: true });
|
|
3804
3915
|
const { content, action } = mergeCursorHooks(ctx.repoRoot);
|
|
3805
|
-
|
|
3916
|
+
writeFileSync16(cursorHooksPath(ctx.repoRoot), content, "utf8");
|
|
3806
3917
|
ctx.report.files.push({ path: CURSOR_HOOKS_REL, action });
|
|
3807
3918
|
}
|
|
3808
3919
|
};
|
|
@@ -3812,7 +3923,8 @@ var DEFAULT_ASSISTANT_IDS = ["claude-code"];
|
|
|
3812
3923
|
var ALL_ADAPTERS = [
|
|
3813
3924
|
claudeCodeAdapter,
|
|
3814
3925
|
cursorAdapter,
|
|
3815
|
-
codebuddyAdapter
|
|
3926
|
+
codebuddyAdapter,
|
|
3927
|
+
codexAdapter
|
|
3816
3928
|
];
|
|
3817
3929
|
var ADAPTER_BY_ID = new Map(
|
|
3818
3930
|
ALL_ADAPTERS.map((a) => [a.id, a])
|
|
@@ -3861,30 +3973,30 @@ function validateAssistantSelection(ids) {
|
|
|
3861
3973
|
}
|
|
3862
3974
|
|
|
3863
3975
|
// src/init/ensureDirs.ts
|
|
3864
|
-
import { mkdirSync as
|
|
3865
|
-
import { join as
|
|
3976
|
+
import { mkdirSync as mkdirSync12, writeFileSync as writeFileSync17 } from "fs";
|
|
3977
|
+
import { join as join32 } from "path";
|
|
3866
3978
|
function ensureMemoryTree(repoRoot) {
|
|
3867
|
-
const memoryRoot =
|
|
3868
|
-
|
|
3979
|
+
const memoryRoot = join32(repoRoot, MEMORY_DIR);
|
|
3980
|
+
mkdirSync12(memoryRoot, { recursive: true });
|
|
3869
3981
|
for (const sub of MEMORY_SUBDIRS) {
|
|
3870
|
-
|
|
3982
|
+
mkdirSync12(join32(memoryRoot, sub), { recursive: true });
|
|
3871
3983
|
}
|
|
3872
|
-
|
|
3984
|
+
mkdirSync12(join32(repoRoot, ".claude"), { recursive: true });
|
|
3873
3985
|
for (const sub of GITKEEP_DIRS) {
|
|
3874
|
-
const keepPath =
|
|
3875
|
-
|
|
3986
|
+
const keepPath = join32(memoryRoot, sub, ".gitkeep");
|
|
3987
|
+
writeFileSync17(keepPath, "", { flag: "a" });
|
|
3876
3988
|
}
|
|
3877
3989
|
}
|
|
3878
3990
|
|
|
3879
3991
|
// src/init/mergeAssistants.ts
|
|
3880
|
-
import { existsSync as
|
|
3992
|
+
import { existsSync as existsSync27, readFileSync as readFileSync27 } from "fs";
|
|
3881
3993
|
function readExistingAssistants(repoRoot) {
|
|
3882
3994
|
const configPath = memoryPath(repoRoot, "config.json");
|
|
3883
|
-
if (!
|
|
3995
|
+
if (!existsSync27(configPath)) {
|
|
3884
3996
|
return [];
|
|
3885
3997
|
}
|
|
3886
3998
|
try {
|
|
3887
|
-
const config = JSON.parse(
|
|
3999
|
+
const config = JSON.parse(readFileSync27(configPath, "utf8"));
|
|
3888
4000
|
if (!Array.isArray(config.assistants)) {
|
|
3889
4001
|
return [];
|
|
3890
4002
|
}
|
|
@@ -3899,17 +4011,17 @@ function mergeAssistants(repoRoot, selected) {
|
|
|
3899
4011
|
}
|
|
3900
4012
|
|
|
3901
4013
|
// src/init/mergeGitignore.ts
|
|
3902
|
-
import { existsSync as
|
|
3903
|
-
import { join as
|
|
4014
|
+
import { existsSync as existsSync28, readFileSync as readFileSync28, writeFileSync as writeFileSync18 } from "fs";
|
|
4015
|
+
import { join as join33 } from "path";
|
|
3904
4016
|
var START_MARKER = "# >>> hermes-repo memory (do not edit this block manually)";
|
|
3905
4017
|
var END_MARKER = "# <<< hermes-repo memory";
|
|
3906
4018
|
function mergeHermesGitignore(repoRoot) {
|
|
3907
4019
|
const block = readTemplate("gitignore-block.txt").trimEnd() + "\n";
|
|
3908
|
-
const gitignorePath =
|
|
3909
|
-
const contentBefore =
|
|
4020
|
+
const gitignorePath = join33(repoRoot, ".gitignore");
|
|
4021
|
+
const contentBefore = existsSync28(gitignorePath) ? readFileSync28(gitignorePath, "utf8") : "";
|
|
3910
4022
|
const warnBroadMemoryIgnore = contentBefore.length > 0 && !contentBefore.includes(START_MARKER) && /(^|\n)\.memory\/\s*$/m.test(contentBefore);
|
|
3911
|
-
if (!
|
|
3912
|
-
|
|
4023
|
+
if (!existsSync28(gitignorePath)) {
|
|
4024
|
+
writeFileSync18(gitignorePath, `${block}
|
|
3913
4025
|
`, "utf8");
|
|
3914
4026
|
return { action: "created", warnBroadMemoryIgnore: false };
|
|
3915
4027
|
}
|
|
@@ -3919,7 +4031,7 @@ function mergeHermesGitignore(repoRoot) {
|
|
|
3919
4031
|
const before = contentBefore.slice(0, startIdx);
|
|
3920
4032
|
const after = contentBefore.slice(endIdx + END_MARKER.length);
|
|
3921
4033
|
const next = `${before}${block}${after}`.replace(/\n{3,}/g, "\n\n");
|
|
3922
|
-
|
|
4034
|
+
writeFileSync18(gitignorePath, next.endsWith("\n") ? next : `${next}
|
|
3923
4035
|
`, "utf8");
|
|
3924
4036
|
return { action: "replaced", warnBroadMemoryIgnore };
|
|
3925
4037
|
}
|
|
@@ -3927,11 +4039,11 @@ function mergeHermesGitignore(repoRoot) {
|
|
|
3927
4039
|
const before = contentBefore.slice(0, startIdx);
|
|
3928
4040
|
const next = `${before}${block}
|
|
3929
4041
|
`;
|
|
3930
|
-
|
|
4042
|
+
writeFileSync18(gitignorePath, next, "utf8");
|
|
3931
4043
|
return { action: "updated", warnBroadMemoryIgnore };
|
|
3932
4044
|
}
|
|
3933
4045
|
const separator = contentBefore.endsWith("\n") || contentBefore.length === 0 ? "\n" : "\n\n";
|
|
3934
|
-
|
|
4046
|
+
writeFileSync18(gitignorePath, `${contentBefore}${separator}${block}
|
|
3935
4047
|
`, "utf8");
|
|
3936
4048
|
return { action: "appended", warnBroadMemoryIgnore };
|
|
3937
4049
|
}
|
|
@@ -4002,8 +4114,8 @@ async function withSpinnerProgress(label, fn, formatDone, stream = process.stder
|
|
|
4002
4114
|
}
|
|
4003
4115
|
|
|
4004
4116
|
// src/coldstart/collectors/existingRules.ts
|
|
4005
|
-
import { existsSync as
|
|
4006
|
-
import { join as
|
|
4117
|
+
import { existsSync as existsSync29, readFileSync as readFileSync29, readdirSync as readdirSync9 } from "fs";
|
|
4118
|
+
import { join as join34 } from "path";
|
|
4007
4119
|
var MAX_EXCERPT = 3500;
|
|
4008
4120
|
var RULE_CANDIDATES = [
|
|
4009
4121
|
"AGENTS.md",
|
|
@@ -4011,12 +4123,12 @@ var RULE_CANDIDATES = [
|
|
|
4011
4123
|
".cursorrules"
|
|
4012
4124
|
];
|
|
4013
4125
|
function readExcerpt(repoRoot, rel) {
|
|
4014
|
-
const full =
|
|
4015
|
-
if (!
|
|
4126
|
+
const full = join34(repoRoot, rel);
|
|
4127
|
+
if (!existsSync29(full)) {
|
|
4016
4128
|
return null;
|
|
4017
4129
|
}
|
|
4018
4130
|
try {
|
|
4019
|
-
const raw =
|
|
4131
|
+
const raw = readFileSync29(full, "utf8");
|
|
4020
4132
|
return raw.length > MAX_EXCERPT ? `${raw.slice(0, MAX_EXCERPT)}
|
|
4021
4133
|
...(truncated)` : raw;
|
|
4022
4134
|
} catch {
|
|
@@ -4024,8 +4136,8 @@ function readExcerpt(repoRoot, rel) {
|
|
|
4024
4136
|
}
|
|
4025
4137
|
}
|
|
4026
4138
|
function collectCursorRules(repoRoot) {
|
|
4027
|
-
const dir =
|
|
4028
|
-
if (!
|
|
4139
|
+
const dir = join34(repoRoot, ".cursor", "rules");
|
|
4140
|
+
if (!existsSync29(dir)) {
|
|
4029
4141
|
return [];
|
|
4030
4142
|
}
|
|
4031
4143
|
const out = [];
|
|
@@ -4076,8 +4188,8 @@ function collectGitLog(repoRoot, limit = 50) {
|
|
|
4076
4188
|
}
|
|
4077
4189
|
|
|
4078
4190
|
// src/coldstart/collectors/packageJson.ts
|
|
4079
|
-
import { existsSync as
|
|
4080
|
-
import { join as
|
|
4191
|
+
import { existsSync as existsSync30, readFileSync as readFileSync30 } from "fs";
|
|
4192
|
+
import { join as join35 } from "path";
|
|
4081
4193
|
var STACK_HINTS = {
|
|
4082
4194
|
react: "react",
|
|
4083
4195
|
vue: "vue",
|
|
@@ -4110,12 +4222,12 @@ function inferStackTags(deps) {
|
|
|
4110
4222
|
return [...tags];
|
|
4111
4223
|
}
|
|
4112
4224
|
function collectPackageJson(repoRoot) {
|
|
4113
|
-
const path =
|
|
4114
|
-
if (!
|
|
4225
|
+
const path = join35(repoRoot, "package.json");
|
|
4226
|
+
if (!existsSync30(path)) {
|
|
4115
4227
|
return null;
|
|
4116
4228
|
}
|
|
4117
4229
|
try {
|
|
4118
|
-
const raw = JSON.parse(
|
|
4230
|
+
const raw = JSON.parse(readFileSync30(path, "utf8"));
|
|
4119
4231
|
return {
|
|
4120
4232
|
name: raw.name,
|
|
4121
4233
|
dependencies: depKeys(raw.dependencies),
|
|
@@ -4127,8 +4239,8 @@ function collectPackageJson(repoRoot) {
|
|
|
4127
4239
|
}
|
|
4128
4240
|
|
|
4129
4241
|
// src/coldstart/collectors/repoSignals.ts
|
|
4130
|
-
import { existsSync as
|
|
4131
|
-
import { join as
|
|
4242
|
+
import { existsSync as existsSync31, readdirSync as readdirSync10 } from "fs";
|
|
4243
|
+
import { join as join36 } from "path";
|
|
4132
4244
|
var SIGNAL_FILES = [
|
|
4133
4245
|
"Dockerfile",
|
|
4134
4246
|
"Makefile",
|
|
@@ -4140,12 +4252,12 @@ var SIGNAL_FILES = [
|
|
|
4140
4252
|
function collectRepoSignals(repoRoot) {
|
|
4141
4253
|
const signals = [];
|
|
4142
4254
|
for (const rel of SIGNAL_FILES) {
|
|
4143
|
-
const full =
|
|
4144
|
-
if (
|
|
4255
|
+
const full = join36(repoRoot, rel);
|
|
4256
|
+
if (existsSync31(full)) {
|
|
4145
4257
|
signals.push(rel);
|
|
4146
4258
|
}
|
|
4147
4259
|
}
|
|
4148
|
-
if (
|
|
4260
|
+
if (existsSync31(join36(repoRoot, ".gitignore"))) {
|
|
4149
4261
|
signals.push(".gitignore");
|
|
4150
4262
|
}
|
|
4151
4263
|
try {
|
|
@@ -4290,7 +4402,7 @@ function runProjectScan(repoRoot) {
|
|
|
4290
4402
|
|
|
4291
4403
|
// src/init/prompts.ts
|
|
4292
4404
|
import { checkbox, confirm, input, password } from "@inquirer/prompts";
|
|
4293
|
-
import { existsSync as
|
|
4405
|
+
import { existsSync as existsSync32, readFileSync as readFileSync31 } from "fs";
|
|
4294
4406
|
import { resolve as resolve6 } from "path";
|
|
4295
4407
|
|
|
4296
4408
|
// src/coldstart/countCaptures.ts
|
|
@@ -4301,11 +4413,11 @@ function countExistingCaptures(repoRoot) {
|
|
|
4301
4413
|
// src/init/prompts.ts
|
|
4302
4414
|
function isInitialized(targetDir) {
|
|
4303
4415
|
const configPath = memoryPath(targetDir, "config.json");
|
|
4304
|
-
if (!
|
|
4416
|
+
if (!existsSync32(configPath)) {
|
|
4305
4417
|
return false;
|
|
4306
4418
|
}
|
|
4307
4419
|
try {
|
|
4308
|
-
const config = JSON.parse(
|
|
4420
|
+
const config = JSON.parse(readFileSync31(configPath, "utf8"));
|
|
4309
4421
|
return config.version === 1;
|
|
4310
4422
|
} catch {
|
|
4311
4423
|
return false;
|
|
@@ -4404,7 +4516,7 @@ async function promptLlmFields(defaults = {}, options = {}) {
|
|
|
4404
4516
|
}
|
|
4405
4517
|
async function gatherLlmInitInput(targetDir) {
|
|
4406
4518
|
const llmPath = memoryPath(targetDir, "llm.json");
|
|
4407
|
-
if (
|
|
4519
|
+
if (existsSync32(llmPath)) {
|
|
4408
4520
|
const overwrite = await confirm({
|
|
4409
4521
|
message: "\u68C0\u6D4B\u5230\u5DF2\u6709 .memory/llm.json\uFF0C\u662F\u5426\u8986\u76D6\u5E76\u91CD\u65B0\u914D\u7F6E\uFF1F",
|
|
4410
4522
|
default: false
|
|
@@ -4435,17 +4547,17 @@ async function gatherLlmInitInput(targetDir) {
|
|
|
4435
4547
|
}
|
|
4436
4548
|
|
|
4437
4549
|
// src/init/writeScaffoldFile.ts
|
|
4438
|
-
import { copyFileSync, writeFileSync as
|
|
4550
|
+
import { copyFileSync, writeFileSync as writeFileSync22 } from "fs";
|
|
4439
4551
|
|
|
4440
4552
|
// src/init/mergeConfig.ts
|
|
4441
|
-
import { existsSync as
|
|
4553
|
+
import { existsSync as existsSync33, readFileSync as readFileSync32 } from "fs";
|
|
4442
4554
|
function mergeConfigForInit(repoRoot, assistants) {
|
|
4443
4555
|
const configPath = memoryPath(repoRoot, "config.json");
|
|
4444
|
-
const existed =
|
|
4556
|
+
const existed = existsSync33(configPath);
|
|
4445
4557
|
let existing = {};
|
|
4446
4558
|
if (existed) {
|
|
4447
4559
|
try {
|
|
4448
|
-
existing = JSON.parse(
|
|
4560
|
+
existing = JSON.parse(readFileSync32(configPath, "utf8"));
|
|
4449
4561
|
} catch {
|
|
4450
4562
|
existing = {};
|
|
4451
4563
|
}
|
|
@@ -4469,8 +4581,8 @@ function mergeConfigForInit(repoRoot, assistants) {
|
|
|
4469
4581
|
}
|
|
4470
4582
|
|
|
4471
4583
|
// src/init/mergeAgentsMd.ts
|
|
4472
|
-
import { existsSync as
|
|
4473
|
-
import { join as
|
|
4584
|
+
import { existsSync as existsSync34, readFileSync as readFileSync33, writeFileSync as writeFileSync19 } from "fs";
|
|
4585
|
+
import { join as join37 } from "path";
|
|
4474
4586
|
var HERMES_AGENTS_START_MARKER = "<!-- >>> hermes-repo agents (do not edit this block manually) -->";
|
|
4475
4587
|
var HERMES_AGENTS_END_MARKER = "<!-- <<< hermes-repo agents -->";
|
|
4476
4588
|
function buildHermesAgentsBlockBody() {
|
|
@@ -4507,7 +4619,7 @@ function withGapBeforeHermesBlock(prefix) {
|
|
|
4507
4619
|
}
|
|
4508
4620
|
return `${trimmed}${GAP_BEFORE_HERMES_BLOCK}`;
|
|
4509
4621
|
}
|
|
4510
|
-
function
|
|
4622
|
+
function spliceHermesBlock2(existing, block) {
|
|
4511
4623
|
const startIdx = existing.indexOf(HERMES_AGENTS_START_MARKER);
|
|
4512
4624
|
const endIdx = existing.indexOf(HERMES_AGENTS_END_MARKER);
|
|
4513
4625
|
if (startIdx !== -1 && endIdx !== -1 && endIdx > startIdx) {
|
|
@@ -4526,32 +4638,32 @@ function spliceHermesBlock(existing, block) {
|
|
|
4526
4638
|
`;
|
|
4527
4639
|
}
|
|
4528
4640
|
function mergeAgentsMd(repoRoot, force) {
|
|
4529
|
-
const agentsPath =
|
|
4641
|
+
const agentsPath = join37(repoRoot, "AGENTS.md");
|
|
4530
4642
|
const block = buildHermesAgentsMarkedBlock();
|
|
4531
|
-
if (!
|
|
4532
|
-
|
|
4643
|
+
if (!existsSync34(agentsPath)) {
|
|
4644
|
+
writeFileSync19(agentsPath, buildNewAgentsMd(), "utf8");
|
|
4533
4645
|
return "created";
|
|
4534
4646
|
}
|
|
4535
|
-
const content =
|
|
4647
|
+
const content = readFileSync33(agentsPath, "utf8");
|
|
4536
4648
|
if (agentsMdHasHermesBlock(content)) {
|
|
4537
4649
|
if (!force) {
|
|
4538
4650
|
return "skipped";
|
|
4539
4651
|
}
|
|
4540
|
-
|
|
4652
|
+
writeFileSync19(agentsPath, spliceHermesBlock2(content, block), "utf8");
|
|
4541
4653
|
return "replaced";
|
|
4542
4654
|
}
|
|
4543
4655
|
if (agentsMdHasLegacyHermesContent(content)) {
|
|
4544
4656
|
return "skipped";
|
|
4545
4657
|
}
|
|
4546
|
-
|
|
4658
|
+
writeFileSync19(agentsPath, spliceHermesBlock2(content, block), "utf8");
|
|
4547
4659
|
return "appended";
|
|
4548
4660
|
}
|
|
4549
4661
|
|
|
4550
4662
|
// src/init/mergeLlmConfig.ts
|
|
4551
|
-
import { existsSync as
|
|
4663
|
+
import { existsSync as existsSync35, writeFileSync as writeFileSync20 } from "fs";
|
|
4552
4664
|
function mergeLlmConfigForInit(repoRoot, input2) {
|
|
4553
4665
|
const llmPath = memoryPath(repoRoot, "llm.json");
|
|
4554
|
-
const existed =
|
|
4666
|
+
const existed = existsSync35(llmPath);
|
|
4555
4667
|
let existing = {};
|
|
4556
4668
|
if (existed) {
|
|
4557
4669
|
try {
|
|
@@ -4580,14 +4692,14 @@ function mergeLlmConfigForInit(repoRoot, input2) {
|
|
|
4580
4692
|
}
|
|
4581
4693
|
function writeLlmJson(repoRoot, input2) {
|
|
4582
4694
|
const { content, action } = mergeLlmConfigForInit(repoRoot, input2);
|
|
4583
|
-
|
|
4695
|
+
writeFileSync20(memoryPath(repoRoot, "llm.json"), content, "utf8");
|
|
4584
4696
|
return action;
|
|
4585
4697
|
}
|
|
4586
4698
|
|
|
4587
4699
|
// src/init/scaffoldWrite.ts
|
|
4588
|
-
import { existsSync as
|
|
4700
|
+
import { existsSync as existsSync36, writeFileSync as writeFileSync21 } from "fs";
|
|
4589
4701
|
function shouldWriteFile(absolutePath, force) {
|
|
4590
|
-
if (!
|
|
4702
|
+
if (!existsSync36(absolutePath)) {
|
|
4591
4703
|
return { write: true, action: "created" };
|
|
4592
4704
|
}
|
|
4593
4705
|
if (force) {
|
|
@@ -4601,7 +4713,7 @@ function writeIfAllowed(report, absolutePath, relativePath, content, force) {
|
|
|
4601
4713
|
report.files.push({ path: relativePath, action });
|
|
4602
4714
|
return;
|
|
4603
4715
|
}
|
|
4604
|
-
|
|
4716
|
+
writeFileSync21(absolutePath, content, "utf8");
|
|
4605
4717
|
report.files.push({ path: relativePath, action });
|
|
4606
4718
|
}
|
|
4607
4719
|
|
|
@@ -4609,7 +4721,7 @@ function writeIfAllowed(report, absolutePath, relativePath, content, force) {
|
|
|
4609
4721
|
function writeConfigJson(report, repoRoot, assistants) {
|
|
4610
4722
|
const { content, action } = mergeConfigForInit(repoRoot, assistants);
|
|
4611
4723
|
const absolutePath = memoryPath(repoRoot, "config.json");
|
|
4612
|
-
|
|
4724
|
+
writeFileSync22(absolutePath, content, "utf8");
|
|
4613
4725
|
report.files.push({ path: ".memory/config.json", action });
|
|
4614
4726
|
}
|
|
4615
4727
|
function copyTemplateIfAllowed(report, templateName, destAbsolute, relativePath, force) {
|
|
@@ -4896,10 +5008,10 @@ async function runInitCommand(opts) {
|
|
|
4896
5008
|
}
|
|
4897
5009
|
|
|
4898
5010
|
// src/feedback/writeRef.ts
|
|
4899
|
-
import { existsSync as
|
|
4900
|
-
import { join as
|
|
5011
|
+
import { existsSync as existsSync37, mkdirSync as mkdirSync13, writeFileSync as writeFileSync23 } from "fs";
|
|
5012
|
+
import { join as join38 } from "path";
|
|
4901
5013
|
function targetExists(repoRoot, target) {
|
|
4902
|
-
return
|
|
5014
|
+
return existsSync37(join38(repoRoot, ".memory", target));
|
|
4903
5015
|
}
|
|
4904
5016
|
function writeRef(opts) {
|
|
4905
5017
|
const { repoRoot, reason, session } = opts;
|
|
@@ -4921,16 +5033,16 @@ function writeRef(opts) {
|
|
|
4921
5033
|
date,
|
|
4922
5034
|
...session ? { session } : {}
|
|
4923
5035
|
};
|
|
4924
|
-
|
|
5036
|
+
mkdirSync13(refsDir(repoRoot), { recursive: true });
|
|
4925
5037
|
const filePath = refFilePath(repoRoot, target, date);
|
|
4926
5038
|
const base = filePath.replace(/\.json$/, "");
|
|
4927
5039
|
let finalPath = `${filePath}`;
|
|
4928
5040
|
let n = 0;
|
|
4929
|
-
while (
|
|
5041
|
+
while (existsSync37(finalPath)) {
|
|
4930
5042
|
n++;
|
|
4931
5043
|
finalPath = `${base}-${n}.json`;
|
|
4932
5044
|
}
|
|
4933
|
-
|
|
5045
|
+
writeFileSync23(finalPath, `${JSON.stringify(record, null, 2)}
|
|
4934
5046
|
`, "utf8");
|
|
4935
5047
|
const file = finalPath.split("/refs/").pop() ?? finalPath;
|
|
4936
5048
|
return { target, file: `refs/${file}` };
|
|
@@ -4970,15 +5082,15 @@ function runRefCommand(opts) {
|
|
|
4970
5082
|
}
|
|
4971
5083
|
|
|
4972
5084
|
// src/search/runSearch.ts
|
|
4973
|
-
import { existsSync as
|
|
4974
|
-
import { join as
|
|
5085
|
+
import { existsSync as existsSync38, readdirSync as readdirSync11, readFileSync as readFileSync35 } from "fs";
|
|
5086
|
+
import { join as join39 } from "path";
|
|
4975
5087
|
function walkMdFiles(dir) {
|
|
4976
|
-
if (!
|
|
5088
|
+
if (!existsSync38(dir)) {
|
|
4977
5089
|
return [];
|
|
4978
5090
|
}
|
|
4979
5091
|
const out = [];
|
|
4980
5092
|
for (const name of readdirSync11(dir)) {
|
|
4981
|
-
const full =
|
|
5093
|
+
const full = join39(dir, name);
|
|
4982
5094
|
if (name.endsWith(".md")) {
|
|
4983
5095
|
out.push(full);
|
|
4984
5096
|
} else if (!name.startsWith(".")) {
|
|
@@ -4987,7 +5099,7 @@ function walkMdFiles(dir) {
|
|
|
4987
5099
|
if (Array.isArray(st)) {
|
|
4988
5100
|
for (const child of readdirSync11(full)) {
|
|
4989
5101
|
if (child.endsWith(".md")) {
|
|
4990
|
-
out.push(
|
|
5102
|
+
out.push(join39(full, child));
|
|
4991
5103
|
}
|
|
4992
5104
|
}
|
|
4993
5105
|
}
|
|
@@ -4999,13 +5111,13 @@ function walkMdFiles(dir) {
|
|
|
4999
5111
|
}
|
|
5000
5112
|
function listSkillMd(repoRoot) {
|
|
5001
5113
|
const skillsDir = memoryPath(repoRoot, "skills");
|
|
5002
|
-
if (!
|
|
5114
|
+
if (!existsSync38(skillsDir)) {
|
|
5003
5115
|
return [];
|
|
5004
5116
|
}
|
|
5005
5117
|
const out = [];
|
|
5006
5118
|
for (const slug of readdirSync11(skillsDir)) {
|
|
5007
|
-
const f =
|
|
5008
|
-
if (
|
|
5119
|
+
const f = join39(skillsDir, slug, "SKILL.md");
|
|
5120
|
+
if (existsSync38(f)) {
|
|
5009
5121
|
out.push(f);
|
|
5010
5122
|
}
|
|
5011
5123
|
}
|
|
@@ -5013,7 +5125,7 @@ function listSkillMd(repoRoot) {
|
|
|
5013
5125
|
}
|
|
5014
5126
|
function summaryFromFile(absPath, relFromMemory) {
|
|
5015
5127
|
try {
|
|
5016
|
-
const content =
|
|
5128
|
+
const content = readFileSync35(absPath, "utf8");
|
|
5017
5129
|
if (relFromMemory.startsWith("captures/")) {
|
|
5018
5130
|
const parsed = parseCaptureMarkdown(content, relFromMemory, absPath);
|
|
5019
5131
|
if (parsed) {
|
|
@@ -5036,10 +5148,10 @@ function runSearch(opts) {
|
|
|
5036
5148
|
const memRoot = memoryPath(opts.repoRoot);
|
|
5037
5149
|
const captureTypes = opts.type ? [opts.type] : ["semantic", "episodic", "procedural"];
|
|
5038
5150
|
for (const t of captureTypes) {
|
|
5039
|
-
const dir =
|
|
5151
|
+
const dir = join39(memRoot, "captures", t);
|
|
5040
5152
|
for (const abs of walkMdFiles(dir)) {
|
|
5041
5153
|
const rel = abs.replace(memRoot + "/", "").replace(/\\/g, "/");
|
|
5042
|
-
const content =
|
|
5154
|
+
const content = readFileSync35(abs, "utf8").toLowerCase();
|
|
5043
5155
|
if (content.includes(kw)) {
|
|
5044
5156
|
hits.push({
|
|
5045
5157
|
path: rel,
|
|
@@ -5051,10 +5163,10 @@ function runSearch(opts) {
|
|
|
5051
5163
|
}
|
|
5052
5164
|
}
|
|
5053
5165
|
}
|
|
5054
|
-
const topicsDir =
|
|
5166
|
+
const topicsDir = join39(memRoot, "topics");
|
|
5055
5167
|
for (const abs of walkMdFiles(topicsDir)) {
|
|
5056
5168
|
const rel = abs.replace(memRoot + "/", "").replace(/\\/g, "/");
|
|
5057
|
-
if (
|
|
5169
|
+
if (readFileSync35(abs, "utf8").toLowerCase().includes(kw)) {
|
|
5058
5170
|
hits.push({ path: rel, summary: summaryFromFile(abs, rel) });
|
|
5059
5171
|
}
|
|
5060
5172
|
if (hits.length >= limit) {
|
|
@@ -5063,7 +5175,7 @@ function runSearch(opts) {
|
|
|
5063
5175
|
}
|
|
5064
5176
|
for (const abs of listSkillMd(opts.repoRoot)) {
|
|
5065
5177
|
const rel = abs.replace(memRoot + "/", "").replace(/\\/g, "/");
|
|
5066
|
-
if (
|
|
5178
|
+
if (readFileSync35(abs, "utf8").toLowerCase().includes(kw)) {
|
|
5067
5179
|
hits.push({ path: rel, summary: summaryFromFile(abs, rel) });
|
|
5068
5180
|
}
|
|
5069
5181
|
if (hits.length >= limit) {
|
|
@@ -5116,7 +5228,7 @@ function runSearchCommand(opts) {
|
|
|
5116
5228
|
}
|
|
5117
5229
|
|
|
5118
5230
|
// src/stats/runStats.ts
|
|
5119
|
-
import { existsSync as
|
|
5231
|
+
import { existsSync as existsSync39, statSync as statSync6 } from "fs";
|
|
5120
5232
|
function collectStats(repoRoot, nowMs = Date.now()) {
|
|
5121
5233
|
const all = listAllCaptures(repoRoot);
|
|
5122
5234
|
const active = filterActiveCaptures(all);
|
|
@@ -5146,7 +5258,7 @@ function collectStats(repoRoot, nowMs = Date.now()) {
|
|
|
5146
5258
|
}
|
|
5147
5259
|
}
|
|
5148
5260
|
const memoryFile = memoryPath(repoRoot, "MEMORY.md");
|
|
5149
|
-
const memoryBytes =
|
|
5261
|
+
const memoryBytes = existsSync39(memoryFile) ? statSync6(memoryFile).size : 0;
|
|
5150
5262
|
const allSkills = listSkillIndex(repoRoot);
|
|
5151
5263
|
const skillUsage = readSkillUsage(repoRoot);
|
|
5152
5264
|
const inMemory = filterSkillIndexForMemory(allSkills, skillUsage, repoRoot, nowMs);
|
|
@@ -5213,11 +5325,11 @@ function runStatsCommand(opts) {
|
|
|
5213
5325
|
}
|
|
5214
5326
|
|
|
5215
5327
|
// src/promote/runPromote.ts
|
|
5216
|
-
import { existsSync as
|
|
5328
|
+
import { existsSync as existsSync45, mkdirSync as mkdirSync15, writeFileSync as writeFileSync25 } from "fs";
|
|
5217
5329
|
import { resolve as resolve8 } from "path";
|
|
5218
5330
|
|
|
5219
5331
|
// src/promote/buildTopicDraft.ts
|
|
5220
|
-
import { existsSync as
|
|
5332
|
+
import { existsSync as existsSync40, readFileSync as readFileSync36 } from "fs";
|
|
5221
5333
|
function ruleTopicDraftBody(tag, captures, existing) {
|
|
5222
5334
|
const lines = captures.map(
|
|
5223
5335
|
(c) => `- [${c.date}] [${c.type}] ${c.summary.slice(0, 120)} (${c.path}) [\u664B\u5347\u5019\u9009]`
|
|
@@ -5244,9 +5356,9 @@ async function buildTopicDraftBody(repoRoot, captures, llm) {
|
|
|
5244
5356
|
const slug = tagToSlug(tag);
|
|
5245
5357
|
const abs = memoryPath(repoRoot, "topics", `${slug}.md`);
|
|
5246
5358
|
let existing = "";
|
|
5247
|
-
if (
|
|
5359
|
+
if (existsSync40(abs)) {
|
|
5248
5360
|
try {
|
|
5249
|
-
existing =
|
|
5361
|
+
existing = readFileSync36(abs, "utf8");
|
|
5250
5362
|
} catch {
|
|
5251
5363
|
existing = "";
|
|
5252
5364
|
}
|
|
@@ -5271,7 +5383,7 @@ ${c.findings.slice(0, 300)}`
|
|
|
5271
5383
|
}
|
|
5272
5384
|
|
|
5273
5385
|
// src/promote/detectTopicConflict.ts
|
|
5274
|
-
import { existsSync as
|
|
5386
|
+
import { existsSync as existsSync41, readFileSync as readFileSync37 } from "fs";
|
|
5275
5387
|
var MUTEX_PAIRS2 = [
|
|
5276
5388
|
["localstorage", "httponly"],
|
|
5277
5389
|
["local storage", "httponly"],
|
|
@@ -5301,12 +5413,12 @@ function detectTopicConflict(repoRoot, capture) {
|
|
|
5301
5413
|
const slug = tagToSlug(tag);
|
|
5302
5414
|
const topicPath = memoryPath(repoRoot, "topics", `${slug}.md`);
|
|
5303
5415
|
const relTopic = `topics/${slug}.md`;
|
|
5304
|
-
if (!
|
|
5416
|
+
if (!existsSync41(topicPath)) {
|
|
5305
5417
|
return { hasConflict: false, reason: "none" };
|
|
5306
5418
|
}
|
|
5307
5419
|
let existing = "";
|
|
5308
5420
|
try {
|
|
5309
|
-
existing =
|
|
5421
|
+
existing = readFileSync37(topicPath, "utf8");
|
|
5310
5422
|
} catch {
|
|
5311
5423
|
return { hasConflict: false, reason: "none" };
|
|
5312
5424
|
}
|
|
@@ -5472,17 +5584,17 @@ async function buildMergedStagingDrafts(repoRoot, analyses, llm) {
|
|
|
5472
5584
|
|
|
5473
5585
|
// src/promote/applyDecisions.ts
|
|
5474
5586
|
import {
|
|
5475
|
-
existsSync as
|
|
5476
|
-
mkdirSync as
|
|
5587
|
+
existsSync as existsSync42,
|
|
5588
|
+
mkdirSync as mkdirSync14,
|
|
5477
5589
|
readdirSync as readdirSync12,
|
|
5478
|
-
readFileSync as
|
|
5590
|
+
readFileSync as readFileSync38,
|
|
5479
5591
|
unlinkSync as unlinkSync3,
|
|
5480
|
-
writeFileSync as
|
|
5592
|
+
writeFileSync as writeFileSync24
|
|
5481
5593
|
} from "fs";
|
|
5482
|
-
import { join as
|
|
5594
|
+
import { join as join41 } from "path";
|
|
5483
5595
|
|
|
5484
5596
|
// src/promote/paths.ts
|
|
5485
|
-
import { join as
|
|
5597
|
+
import { join as join40 } from "path";
|
|
5486
5598
|
function promoteDir(repoRoot) {
|
|
5487
5599
|
return memoryPath(repoRoot, "promote");
|
|
5488
5600
|
}
|
|
@@ -5500,7 +5612,7 @@ function resolvePromoteTemplatePath(repoRoot) {
|
|
|
5500
5612
|
return inMemory;
|
|
5501
5613
|
}
|
|
5502
5614
|
function stagingTopicPath(repoRoot, slug) {
|
|
5503
|
-
return
|
|
5615
|
+
return join40(promoteStagingTopicsDir(repoRoot), `${slug}.md`);
|
|
5504
5616
|
}
|
|
5505
5617
|
|
|
5506
5618
|
// src/promote/applyDecisions.ts
|
|
@@ -5536,17 +5648,17 @@ function buildManifestTemplate(capturePaths, dateIso) {
|
|
|
5536
5648
|
}
|
|
5537
5649
|
function removePromoteMarker(repoRoot, capturePath) {
|
|
5538
5650
|
const marker = promoteMarkerPath(repoRoot, capturePath);
|
|
5539
|
-
if (
|
|
5651
|
+
if (existsSync42(marker)) {
|
|
5540
5652
|
unlinkSync3(marker);
|
|
5541
5653
|
}
|
|
5542
5654
|
}
|
|
5543
5655
|
function annotateReject(repoRoot, capturePath, note) {
|
|
5544
|
-
const abs =
|
|
5545
|
-
if (!
|
|
5656
|
+
const abs = join41(repoRoot, ".memory", capturePath);
|
|
5657
|
+
if (!existsSync42(abs)) {
|
|
5546
5658
|
return;
|
|
5547
5659
|
}
|
|
5548
5660
|
try {
|
|
5549
|
-
let content =
|
|
5661
|
+
let content = readFileSync38(abs, "utf8");
|
|
5550
5662
|
const fields = {
|
|
5551
5663
|
promote_rejected_at: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10)
|
|
5552
5664
|
};
|
|
@@ -5554,22 +5666,22 @@ function annotateReject(repoRoot, capturePath, note) {
|
|
|
5554
5666
|
fields.promote_note = note.trim().slice(0, 200);
|
|
5555
5667
|
}
|
|
5556
5668
|
content = setFrontmatterScalars(content, fields);
|
|
5557
|
-
|
|
5669
|
+
writeFileSync24(abs, content, "utf8");
|
|
5558
5670
|
} catch {
|
|
5559
5671
|
}
|
|
5560
5672
|
}
|
|
5561
5673
|
function mergeTopicFromStaging(repoRoot, slug, dryRun) {
|
|
5562
5674
|
const staging = stagingTopicPath(repoRoot, slug);
|
|
5563
|
-
if (!
|
|
5675
|
+
if (!existsSync42(staging)) {
|
|
5564
5676
|
return null;
|
|
5565
5677
|
}
|
|
5566
|
-
const draft =
|
|
5678
|
+
const draft = readFileSync38(staging, "utf8");
|
|
5567
5679
|
const dest = memoryPath(repoRoot, "topics", `${slug}.md`);
|
|
5568
5680
|
if (dryRun) {
|
|
5569
5681
|
return `topics/${slug}.md`;
|
|
5570
5682
|
}
|
|
5571
|
-
|
|
5572
|
-
|
|
5683
|
+
mkdirSync14(memoryPath(repoRoot, "topics"), { recursive: true });
|
|
5684
|
+
writeFileSync24(dest, draft.endsWith("\n") ? draft : `${draft}
|
|
5573
5685
|
`, "utf8");
|
|
5574
5686
|
return `topics/${slug}.md`;
|
|
5575
5687
|
}
|
|
@@ -5605,7 +5717,7 @@ function applyDecisions(repoRoot, manifest, opts) {
|
|
|
5605
5717
|
}
|
|
5606
5718
|
if (slugsToMerge.size === 0 && result.approved.length > 0) {
|
|
5607
5719
|
const stagingDir = promoteStagingTopicsDir(repoRoot);
|
|
5608
|
-
if (
|
|
5720
|
+
if (existsSync42(stagingDir)) {
|
|
5609
5721
|
for (const name of readdirSync12(stagingDir)) {
|
|
5610
5722
|
if (name.endsWith(".md")) {
|
|
5611
5723
|
slugsToMerge.add(name.replace(/\.md$/, ""));
|
|
@@ -5622,21 +5734,21 @@ function applyDecisions(repoRoot, manifest, opts) {
|
|
|
5622
5734
|
return result;
|
|
5623
5735
|
}
|
|
5624
5736
|
function readManifestFile(manifestPath) {
|
|
5625
|
-
const raw =
|
|
5737
|
+
const raw = readFileSync38(manifestPath, "utf8");
|
|
5626
5738
|
return parseManifestJson(raw);
|
|
5627
5739
|
}
|
|
5628
5740
|
function writeManifestTemplate(repoRoot, capturePaths) {
|
|
5629
5741
|
const dateIso = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
5630
5742
|
const manifest = buildManifestTemplate(capturePaths, dateIso);
|
|
5631
5743
|
const path = decisionsTemplatePath(repoRoot);
|
|
5632
|
-
|
|
5633
|
-
|
|
5744
|
+
mkdirSync14(memoryPath(repoRoot, "promote"), { recursive: true });
|
|
5745
|
+
writeFileSync24(path, `${JSON.stringify(manifest, null, 2)}
|
|
5634
5746
|
`, "utf8");
|
|
5635
5747
|
return path;
|
|
5636
5748
|
}
|
|
5637
5749
|
|
|
5638
5750
|
// src/promote/buildPrBody.ts
|
|
5639
|
-
import { existsSync as
|
|
5751
|
+
import { existsSync as existsSync43, readFileSync as readFileSync39 } from "fs";
|
|
5640
5752
|
function actionLabel(action) {
|
|
5641
5753
|
if (action === "approve") {
|
|
5642
5754
|
return "\u6279\u51C6\u664B\u5347";
|
|
@@ -5676,9 +5788,9 @@ ${conflictLine}
|
|
|
5676
5788
|
}
|
|
5677
5789
|
function loadTemplate(repoRoot) {
|
|
5678
5790
|
const path = resolvePromoteTemplatePath(repoRoot);
|
|
5679
|
-
if (
|
|
5791
|
+
if (existsSync43(path)) {
|
|
5680
5792
|
try {
|
|
5681
|
-
return
|
|
5793
|
+
return readFileSync39(path, "utf8");
|
|
5682
5794
|
} catch {
|
|
5683
5795
|
}
|
|
5684
5796
|
}
|
|
@@ -5726,7 +5838,7 @@ ${items}
|
|
|
5726
5838
|
}
|
|
5727
5839
|
|
|
5728
5840
|
// src/promote/listPromoteCandidates.ts
|
|
5729
|
-
import { existsSync as
|
|
5841
|
+
import { existsSync as existsSync44, readdirSync as readdirSync13 } from "fs";
|
|
5730
5842
|
var TYPES2 = ["semantic", "episodic", "procedural"];
|
|
5731
5843
|
function normalizeCapturePath(input2) {
|
|
5732
5844
|
let p = input2.replace(/\\/g, "/").trim();
|
|
@@ -5743,7 +5855,7 @@ function listPromoteCandidates(repoRoot, filterPaths) {
|
|
|
5743
5855
|
const results = [];
|
|
5744
5856
|
for (const type of TYPES2) {
|
|
5745
5857
|
const dir = memoryPath(repoRoot, "captures", type);
|
|
5746
|
-
if (!
|
|
5858
|
+
if (!existsSync44(dir)) {
|
|
5747
5859
|
continue;
|
|
5748
5860
|
}
|
|
5749
5861
|
for (const name of readdirSync13(dir)) {
|
|
@@ -5770,8 +5882,8 @@ function listPromoteCandidates(repoRoot, filterPaths) {
|
|
|
5770
5882
|
|
|
5771
5883
|
// src/promote/runPromote.ts
|
|
5772
5884
|
function ensurePromoteDirs(repoRoot) {
|
|
5773
|
-
|
|
5774
|
-
|
|
5885
|
+
mkdirSync15(promoteDir(repoRoot), { recursive: true });
|
|
5886
|
+
mkdirSync15(promoteStagingTopicsDir(repoRoot), { recursive: true });
|
|
5775
5887
|
}
|
|
5776
5888
|
function formatPreviewTable(analyses) {
|
|
5777
5889
|
const lines = [
|
|
@@ -5815,15 +5927,15 @@ async function runPromote(opts) {
|
|
|
5815
5927
|
const stagingTopicPaths = [];
|
|
5816
5928
|
for (const [slug, body] of mergedDrafts) {
|
|
5817
5929
|
const path = stagingTopicPath(repoRoot, slug);
|
|
5818
|
-
|
|
5930
|
+
writeFileSync25(path, body, "utf8");
|
|
5819
5931
|
stagingTopicPaths.push(
|
|
5820
5932
|
`.memory/promote/staging/topics/${slug}.md`
|
|
5821
5933
|
);
|
|
5822
5934
|
}
|
|
5823
5935
|
const prBody = buildPrBody(repoRoot, analyses);
|
|
5824
5936
|
const prBodyPath = opts.outPath ? resolve8(opts.outPath) : defaultPrBodyPath(repoRoot, dateIso);
|
|
5825
|
-
|
|
5826
|
-
|
|
5937
|
+
mkdirSync15(memoryPath(repoRoot, "promote"), { recursive: true });
|
|
5938
|
+
writeFileSync25(prBodyPath, prBody, "utf8");
|
|
5827
5939
|
const manifestTemplatePath = writeManifestTemplate(
|
|
5828
5940
|
repoRoot,
|
|
5829
5941
|
candidates.map((c) => c.path)
|