reasonix 0.50.0 → 0.51.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/dashboard/dist/app.css +1 -1
- package/dashboard/dist/app.js +24 -22
- package/dashboard/dist/app.js.map +1 -1
- package/dist/cli/{acp-6B25WIFF.js → acp-XEUHGG7X.js} +34 -31
- package/dist/cli/acp-XEUHGG7X.js.map +1 -0
- package/dist/cli/chat-NJ2Q5KHG.js +50 -0
- package/dist/cli/{chunk-OPGWCKKU.js → chunk-2HVTBFCI.js} +3 -3
- package/dist/cli/{chunk-AJIZ5KFK.js → chunk-2WUEAI2I.js} +3 -3
- package/dist/cli/{chunk-I4Q3QT4W.js → chunk-36BM7INR.js} +2 -2
- package/dist/cli/{chunk-3RNFYDDM.js → chunk-3BTK5BHI.js} +11 -7
- package/dist/cli/chunk-3BTK5BHI.js.map +1 -0
- package/dist/cli/{chunk-GMSAB2TC.js → chunk-3YRTIWFX.js} +2 -2
- package/dist/cli/{chunk-NLRC3DWQ.js → chunk-544J4PXD.js} +5 -5
- package/dist/cli/{chunk-7WITYWKN.js → chunk-5AIDYVH2.js} +2 -2
- package/dist/cli/{chunk-ALCOQP6R.js → chunk-5BBC6YMV.js} +5 -5
- package/dist/cli/{chunk-S4XVGLRW.js → chunk-6UNHNVJR.js} +72 -5
- package/dist/cli/chunk-6UNHNVJR.js.map +1 -0
- package/dist/cli/{chunk-IK6WWRIX.js → chunk-6XWXIVQ3.js} +38 -22
- package/dist/cli/chunk-6XWXIVQ3.js.map +1 -0
- package/dist/cli/{chunk-AAHB2PFX.js → chunk-7YB26OQO.js} +4 -4
- package/dist/cli/chunk-7YB26OQO.js.map +1 -0
- package/dist/cli/{chunk-MXWPAPZW.js → chunk-A5PBEIJ7.js} +53 -10
- package/dist/cli/chunk-A5PBEIJ7.js.map +1 -0
- package/dist/cli/{chunk-FQSQFCBI.js → chunk-BA5R6BAE.js} +2 -2
- package/dist/cli/{chunk-XWPZHWC2.js → chunk-BM6BBFAV.js} +2 -2
- package/dist/cli/{chunk-CAGKEGNE.js → chunk-BOWSNGQC.js} +52 -140
- package/dist/cli/chunk-BOWSNGQC.js.map +1 -0
- package/dist/cli/{chunk-EZ57UEZQ.js → chunk-C2MRSJTV.js} +2 -2
- package/dist/cli/{chunk-PYIZZAVQ.js → chunk-DVD67FXQ.js} +1716 -4
- package/dist/cli/chunk-DVD67FXQ.js.map +1 -0
- package/dist/cli/{chunk-ZAXMJANP.js → chunk-EAMXOWUW.js} +3 -3
- package/dist/cli/{chunk-TX652NBA.js → chunk-EWVFGYT6.js} +2 -2
- package/dist/cli/{chunk-IBRTU5WO.js → chunk-FP7IOWBQ.js} +18 -1182
- package/dist/cli/chunk-FP7IOWBQ.js.map +1 -0
- package/dist/cli/{chunk-I6FBSTTR.js → chunk-HGK57NBN.js} +9 -353
- package/dist/cli/chunk-HGK57NBN.js.map +1 -0
- package/dist/cli/chunk-JHWQDJZA.js +80 -0
- package/dist/cli/chunk-JHWQDJZA.js.map +1 -0
- package/dist/cli/{chunk-X2BQZQEE.js → chunk-K3QJ3GKI.js} +3 -3
- package/dist/cli/{chunk-GPUH2BNM.js → chunk-K4YQFULP.js} +612 -254
- package/dist/cli/chunk-K4YQFULP.js.map +1 -0
- package/dist/cli/chunk-L3VPEESB.js +31 -0
- package/dist/cli/chunk-L3VPEESB.js.map +1 -0
- package/dist/cli/{chunk-ENFBF6HI.js → chunk-N4SEBLU4.js} +383 -5
- package/dist/cli/chunk-N4SEBLU4.js.map +1 -0
- package/dist/cli/chunk-NRROJXXT.js +879 -0
- package/dist/cli/chunk-NRROJXXT.js.map +1 -0
- package/dist/cli/{chunk-3KRRTLC5.js → chunk-R6KIHEF3.js} +1619 -1036
- package/dist/cli/chunk-R6KIHEF3.js.map +1 -0
- package/dist/cli/{chunk-VVMY4M7J.js → chunk-SBHF5NWD.js} +27 -4
- package/dist/cli/chunk-SBHF5NWD.js.map +1 -0
- package/dist/cli/{chunk-OWA42BKS.js → chunk-SXSAWOB7.js} +14 -14
- package/dist/cli/{chunk-6IUMTRFP.js → chunk-UMZ6KHTS.js} +2 -2
- package/dist/cli/{chunk-7X4JJOO7.js → chunk-UO6E7FN3.js} +69 -5
- package/dist/cli/{chunk-7X4JJOO7.js.map → chunk-UO6E7FN3.js.map} +1 -1
- package/dist/cli/{chunk-3ZZXQ3CZ.js → chunk-UPW544V3.js} +2 -2
- package/dist/cli/{chunk-XJZWMU5P.js → chunk-WPOKBW5E.js} +2 -2
- package/dist/cli/{chunk-WSBFVOCO.js → chunk-Z3MKG7MQ.js} +2 -2
- package/dist/cli/{code-TBK2TASK.js → code-BMXLBC7D.js} +37 -36
- package/dist/cli/{code-TBK2TASK.js.map → code-BMXLBC7D.js.map} +1 -1
- package/dist/cli/{commands-NXTKSQTN.js → commands-E4RZXMF6.js} +5 -5
- package/dist/cli/{commit-IR5SPP7A.js → commit-KSRQ64IL.js} +3 -3
- package/dist/cli/{config-XK5WQGTS.js → config-QNDONOTU.js} +4 -2
- package/dist/cli/{desktop-5NTQBADL.js → desktop-H3ZHIMDA.js} +83 -37
- package/dist/cli/desktop-H3ZHIMDA.js.map +1 -0
- package/dist/cli/{diff-JNYX5BSZ.js → diff-I4PYI43W.js} +9 -9
- package/dist/cli/{doctor-IKYLUFXX.js → doctor-Y2E4MY2F.js} +12 -12
- package/dist/cli/{events-HSC57ONU.js → events-47HOT7ZA.js} +5 -5
- package/dist/cli/find-in-code-YLEIK5FK.js +145 -0
- package/dist/cli/find-in-code-YLEIK5FK.js.map +1 -0
- package/dist/cli/index.js +95 -44
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/{mcp-BDJJWOCD.js → mcp-76DK63ZB.js} +3 -3
- package/dist/cli/{mcp-browse-NJRZDI6V.js → mcp-browse-SDNUGO74.js} +3 -3
- package/dist/cli/{mcp-inspect-Y62NWZQL.js → mcp-inspect-BL5DEO5M.js} +3 -3
- package/dist/cli/{prompt-UTOIFUQC.js → prompt-JLATI3P7.js} +5 -5
- package/dist/cli/{prune-sessions-UCUD4XAP.js → prune-sessions-WHZDFUKD.js} +4 -4
- package/dist/cli/{replay-VVIN64MN.js → replay-MHXS7C7Z.js} +10 -10
- package/dist/cli/{run-76OBDZFB.js → run-SXNCPRJE.js} +22 -22
- package/dist/cli/{server-SZZDKTH2.js → server-GEHOE6CO.js} +61 -35
- package/dist/cli/server-GEHOE6CO.js.map +1 -0
- package/dist/cli/{sessions-FZTGRCM5.js → sessions-EPBFYISL.js} +18 -18
- package/dist/cli/{setup-4UNENGOE.js → setup-IW2XR5XI.js} +8 -7
- package/dist/cli/setup-IW2XR5XI.js.map +1 -0
- package/dist/cli/{stats-F4NDOD7D.js → stats-4WB4XHBP.js} +6 -6
- package/dist/cli/symbols-UQ274IOB.js +167 -0
- package/dist/cli/symbols-UQ274IOB.js.map +1 -0
- package/dist/cli/version-4SP3DLLH.js +33 -0
- package/dist/index.d.ts +25 -6
- package/dist/index.js +2700 -578
- package/dist/index.js.map +1 -1
- package/package.json +6 -3
- package/scripts/postinstall.mjs +10 -0
- package/dist/cli/acp-6B25WIFF.js.map +0 -1
- package/dist/cli/chat-7WASPB4O.js +0 -50
- package/dist/cli/chunk-3KRRTLC5.js.map +0 -1
- package/dist/cli/chunk-3RNFYDDM.js.map +0 -1
- package/dist/cli/chunk-AAHB2PFX.js.map +0 -1
- package/dist/cli/chunk-CAGKEGNE.js.map +0 -1
- package/dist/cli/chunk-ENFBF6HI.js.map +0 -1
- package/dist/cli/chunk-GPUH2BNM.js.map +0 -1
- package/dist/cli/chunk-I6FBSTTR.js.map +0 -1
- package/dist/cli/chunk-IBRTU5WO.js.map +0 -1
- package/dist/cli/chunk-IK6WWRIX.js.map +0 -1
- package/dist/cli/chunk-MXWPAPZW.js.map +0 -1
- package/dist/cli/chunk-PYIZZAVQ.js.map +0 -1
- package/dist/cli/chunk-S4XVGLRW.js.map +0 -1
- package/dist/cli/chunk-VVMY4M7J.js.map +0 -1
- package/dist/cli/desktop-5NTQBADL.js.map +0 -1
- package/dist/cli/server-SZZDKTH2.js.map +0 -1
- package/dist/cli/setup-4UNENGOE.js.map +0 -1
- package/dist/cli/version-LUVTWHLL.js +0 -33
- /package/dist/cli/{chat-7WASPB4O.js.map → chat-NJ2Q5KHG.js.map} +0 -0
- /package/dist/cli/{chunk-OPGWCKKU.js.map → chunk-2HVTBFCI.js.map} +0 -0
- /package/dist/cli/{chunk-AJIZ5KFK.js.map → chunk-2WUEAI2I.js.map} +0 -0
- /package/dist/cli/{chunk-I4Q3QT4W.js.map → chunk-36BM7INR.js.map} +0 -0
- /package/dist/cli/{chunk-GMSAB2TC.js.map → chunk-3YRTIWFX.js.map} +0 -0
- /package/dist/cli/{chunk-NLRC3DWQ.js.map → chunk-544J4PXD.js.map} +0 -0
- /package/dist/cli/{chunk-7WITYWKN.js.map → chunk-5AIDYVH2.js.map} +0 -0
- /package/dist/cli/{chunk-ALCOQP6R.js.map → chunk-5BBC6YMV.js.map} +0 -0
- /package/dist/cli/{chunk-FQSQFCBI.js.map → chunk-BA5R6BAE.js.map} +0 -0
- /package/dist/cli/{chunk-XWPZHWC2.js.map → chunk-BM6BBFAV.js.map} +0 -0
- /package/dist/cli/{chunk-EZ57UEZQ.js.map → chunk-C2MRSJTV.js.map} +0 -0
- /package/dist/cli/{chunk-ZAXMJANP.js.map → chunk-EAMXOWUW.js.map} +0 -0
- /package/dist/cli/{chunk-TX652NBA.js.map → chunk-EWVFGYT6.js.map} +0 -0
- /package/dist/cli/{chunk-X2BQZQEE.js.map → chunk-K3QJ3GKI.js.map} +0 -0
- /package/dist/cli/{chunk-OWA42BKS.js.map → chunk-SXSAWOB7.js.map} +0 -0
- /package/dist/cli/{chunk-6IUMTRFP.js.map → chunk-UMZ6KHTS.js.map} +0 -0
- /package/dist/cli/{chunk-3ZZXQ3CZ.js.map → chunk-UPW544V3.js.map} +0 -0
- /package/dist/cli/{chunk-XJZWMU5P.js.map → chunk-WPOKBW5E.js.map} +0 -0
- /package/dist/cli/{chunk-WSBFVOCO.js.map → chunk-Z3MKG7MQ.js.map} +0 -0
- /package/dist/cli/{commands-NXTKSQTN.js.map → commands-E4RZXMF6.js.map} +0 -0
- /package/dist/cli/{commit-IR5SPP7A.js.map → commit-KSRQ64IL.js.map} +0 -0
- /package/dist/cli/{config-XK5WQGTS.js.map → config-QNDONOTU.js.map} +0 -0
- /package/dist/cli/{diff-JNYX5BSZ.js.map → diff-I4PYI43W.js.map} +0 -0
- /package/dist/cli/{doctor-IKYLUFXX.js.map → doctor-Y2E4MY2F.js.map} +0 -0
- /package/dist/cli/{events-HSC57ONU.js.map → events-47HOT7ZA.js.map} +0 -0
- /package/dist/cli/{mcp-BDJJWOCD.js.map → mcp-76DK63ZB.js.map} +0 -0
- /package/dist/cli/{mcp-browse-NJRZDI6V.js.map → mcp-browse-SDNUGO74.js.map} +0 -0
- /package/dist/cli/{mcp-inspect-Y62NWZQL.js.map → mcp-inspect-BL5DEO5M.js.map} +0 -0
- /package/dist/cli/{prompt-UTOIFUQC.js.map → prompt-JLATI3P7.js.map} +0 -0
- /package/dist/cli/{prune-sessions-UCUD4XAP.js.map → prune-sessions-WHZDFUKD.js.map} +0 -0
- /package/dist/cli/{replay-VVIN64MN.js.map → replay-MHXS7C7Z.js.map} +0 -0
- /package/dist/cli/{run-76OBDZFB.js.map → run-SXNCPRJE.js.map} +0 -0
- /package/dist/cli/{sessions-FZTGRCM5.js.map → sessions-EPBFYISL.js.map} +0 -0
- /package/dist/cli/{stats-F4NDOD7D.js.map → stats-4WB4XHBP.js.map} +0 -0
- /package/dist/cli/{version-LUVTWHLL.js.map → version-4SP3DLLH.js.map} +0 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire as __cr } from 'node:module'; if (typeof globalThis.require === 'undefined') { globalThis.require = __cr(import.meta.url); }
|
|
3
|
+
|
|
4
|
+
// src/code-query/grammar-map.ts
|
|
5
|
+
var EXT_TO_GRAMMAR = {
|
|
6
|
+
".ts": "typescript",
|
|
7
|
+
".mts": "typescript",
|
|
8
|
+
".cts": "typescript",
|
|
9
|
+
".tsx": "tsx",
|
|
10
|
+
".js": "javascript",
|
|
11
|
+
".mjs": "javascript",
|
|
12
|
+
".cjs": "javascript",
|
|
13
|
+
".jsx": "javascript",
|
|
14
|
+
".py": "python",
|
|
15
|
+
".pyi": "python",
|
|
16
|
+
".go": "go",
|
|
17
|
+
".rs": "rust",
|
|
18
|
+
".java": "java"
|
|
19
|
+
};
|
|
20
|
+
function grammarForPath(filePath) {
|
|
21
|
+
const lower = filePath.toLowerCase();
|
|
22
|
+
for (const ext of Object.keys(EXT_TO_GRAMMAR)) {
|
|
23
|
+
if (lower.endsWith(ext)) return EXT_TO_GRAMMAR[ext];
|
|
24
|
+
}
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export {
|
|
29
|
+
grammarForPath
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=chunk-L3VPEESB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/code-query/grammar-map.ts"],"sourcesContent":["/** File-extension → tree-sitter grammar name. Pure data — kept free of web-tree-sitter so callers that only need language detection don't pull in the Emscripten runtime. */\n\nexport type GrammarName = \"typescript\" | \"tsx\" | \"javascript\" | \"python\" | \"go\" | \"rust\" | \"java\";\n\nconst EXT_TO_GRAMMAR: Record<string, GrammarName> = {\n \".ts\": \"typescript\",\n \".mts\": \"typescript\",\n \".cts\": \"typescript\",\n \".tsx\": \"tsx\",\n \".js\": \"javascript\",\n \".mjs\": \"javascript\",\n \".cjs\": \"javascript\",\n \".jsx\": \"javascript\",\n \".py\": \"python\",\n \".pyi\": \"python\",\n \".go\": \"go\",\n \".rs\": \"rust\",\n \".java\": \"java\",\n};\n\nexport function grammarForPath(filePath: string): GrammarName | null {\n const lower = filePath.toLowerCase();\n for (const ext of Object.keys(EXT_TO_GRAMMAR)) {\n if (lower.endsWith(ext)) return EXT_TO_GRAMMAR[ext]!;\n }\n return null;\n}\n"],"mappings":";;;;AAIA,IAAM,iBAA8C;AAAA,EAClD,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,OAAO;AAAA,EACP,SAAS;AACX;AAEO,SAAS,eAAe,UAAsC;AACnE,QAAM,QAAQ,SAAS,YAAY;AACnC,aAAW,OAAO,OAAO,KAAK,cAAc,GAAG;AAC7C,QAAI,MAAM,SAAS,GAAG,EAAG,QAAO,eAAe,GAAG;AAAA,EACpD;AACA,SAAO;AACT;","names":[]}
|
|
@@ -2,13 +2,24 @@
|
|
|
2
2
|
import { createRequire as __cr } from 'node:module'; if (typeof globalThis.require === 'undefined') { globalThis.require = __cr(import.meta.url); }
|
|
3
3
|
import {
|
|
4
4
|
t
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-DVD67FXQ.js";
|
|
6
|
+
import {
|
|
7
|
+
loadResolvedSkillPaths,
|
|
8
|
+
memoryTypeDefaults,
|
|
9
|
+
resolveSkillPaths
|
|
10
|
+
} from "./chunk-A5PBEIJ7.js";
|
|
6
11
|
|
|
7
12
|
// src/memory/project.ts
|
|
8
13
|
import { existsSync, readFileSync, statSync } from "fs";
|
|
9
14
|
import { basename, join } from "path";
|
|
10
15
|
var PROJECT_MEMORY_FILE = "REASONIX.md";
|
|
11
|
-
var PROJECT_MEMORY_FILES = [
|
|
16
|
+
var PROJECT_MEMORY_FILES = [
|
|
17
|
+
"REASONIX.md",
|
|
18
|
+
".claude/CLAUDE.md",
|
|
19
|
+
"CLAUDE.md",
|
|
20
|
+
"AGENTS.md",
|
|
21
|
+
"AGENT.md"
|
|
22
|
+
];
|
|
12
23
|
var PROJECT_MEMORY_MAX_CHARS = 8e3;
|
|
13
24
|
var FOREIGN_PLATFORM_FILE_MARKERS = ["SOUL.md", "PERSONA.md"];
|
|
14
25
|
function detectForeignAgentPlatform(rootDir) {
|
|
@@ -634,6 +645,370 @@ var BUILTIN_SKILLS = Object.freeze([
|
|
|
634
645
|
})
|
|
635
646
|
]);
|
|
636
647
|
|
|
648
|
+
// src/memory/user.ts
|
|
649
|
+
import { createHash } from "crypto";
|
|
650
|
+
import {
|
|
651
|
+
existsSync as existsSync3,
|
|
652
|
+
mkdirSync as mkdirSync2,
|
|
653
|
+
readFileSync as readFileSync3,
|
|
654
|
+
readdirSync as readdirSync2,
|
|
655
|
+
unlinkSync,
|
|
656
|
+
writeFileSync as writeFileSync2
|
|
657
|
+
} from "fs";
|
|
658
|
+
import { homedir as homedir2 } from "os";
|
|
659
|
+
import { join as join3, resolve as resolve2 } from "path";
|
|
660
|
+
var USER_MEMORY_DIR = "memory";
|
|
661
|
+
var MEMORY_INDEX_FILE = "MEMORY.md";
|
|
662
|
+
var MEMORY_INDEX_MAX_CHARS = 4e3;
|
|
663
|
+
var VALID_NAME = /^[a-zA-Z0-9_-][a-zA-Z0-9_.-]{1,38}[a-zA-Z0-9]$/;
|
|
664
|
+
function sanitizeMemoryName(raw) {
|
|
665
|
+
const trimmed = String(raw ?? "").trim();
|
|
666
|
+
if (!VALID_NAME.test(trimmed)) {
|
|
667
|
+
throw new Error(
|
|
668
|
+
`invalid memory name: ${JSON.stringify(raw)} \u2014 must be 3-40 chars, alnum/_/-, no path separators`
|
|
669
|
+
);
|
|
670
|
+
}
|
|
671
|
+
return trimmed;
|
|
672
|
+
}
|
|
673
|
+
function projectHash(rootDir) {
|
|
674
|
+
const abs = resolve2(rootDir);
|
|
675
|
+
return createHash("sha1").update(abs).digest("hex").slice(0, 16);
|
|
676
|
+
}
|
|
677
|
+
function scopeDir(opts) {
|
|
678
|
+
if (opts.scope === "global") {
|
|
679
|
+
return join3(opts.homeDir, USER_MEMORY_DIR, "global");
|
|
680
|
+
}
|
|
681
|
+
if (!opts.projectRoot) {
|
|
682
|
+
throw new Error("scope=project requires a projectRoot on MemoryStore");
|
|
683
|
+
}
|
|
684
|
+
return join3(opts.homeDir, USER_MEMORY_DIR, projectHash(opts.projectRoot));
|
|
685
|
+
}
|
|
686
|
+
function ensureDir(p) {
|
|
687
|
+
if (!existsSync3(p)) mkdirSync2(p, { recursive: true });
|
|
688
|
+
}
|
|
689
|
+
function formatFrontmatter(e) {
|
|
690
|
+
const lines = [
|
|
691
|
+
"---",
|
|
692
|
+
`name: ${e.name}`,
|
|
693
|
+
`description: ${e.description.replace(/\n/g, " ")}`,
|
|
694
|
+
`type: ${e.type}`,
|
|
695
|
+
`scope: ${e.scope}`,
|
|
696
|
+
`created: ${e.createdAt}`
|
|
697
|
+
];
|
|
698
|
+
if (e.priority) lines.push(`priority: ${e.priority}`);
|
|
699
|
+
if (e.expires) lines.push(`expires: ${e.expires}`);
|
|
700
|
+
lines.push("---", "");
|
|
701
|
+
return lines.join("\n");
|
|
702
|
+
}
|
|
703
|
+
function coercePriority(v) {
|
|
704
|
+
return v === "low" || v === "medium" || v === "high" ? v : void 0;
|
|
705
|
+
}
|
|
706
|
+
function coerceExpires(v) {
|
|
707
|
+
return v === "project_end" ? v : void 0;
|
|
708
|
+
}
|
|
709
|
+
function todayIso() {
|
|
710
|
+
const d = /* @__PURE__ */ new Date();
|
|
711
|
+
return d.toISOString().slice(0, 10);
|
|
712
|
+
}
|
|
713
|
+
function indexLine(e) {
|
|
714
|
+
const safeDesc = e.description.replace(/\n/g, " ").trim();
|
|
715
|
+
const max = 130 - e.name.length;
|
|
716
|
+
const clipped = safeDesc.length > max ? `${safeDesc.slice(0, Math.max(1, max - 1))}\u2026` : safeDesc;
|
|
717
|
+
return `- [${e.name}](${e.name}.md) \u2014 ${clipped}`;
|
|
718
|
+
}
|
|
719
|
+
var MemoryStore = class {
|
|
720
|
+
homeDir;
|
|
721
|
+
projectRoot;
|
|
722
|
+
constructor(opts = {}) {
|
|
723
|
+
this.homeDir = opts.homeDir ?? join3(homedir2(), ".reasonix");
|
|
724
|
+
this.projectRoot = opts.projectRoot ? resolve2(opts.projectRoot) : void 0;
|
|
725
|
+
}
|
|
726
|
+
/** Directory this store writes `scope` files into, creating it if needed. */
|
|
727
|
+
dir(scope) {
|
|
728
|
+
const d = scopeDir({ homeDir: this.homeDir, scope, projectRoot: this.projectRoot });
|
|
729
|
+
ensureDir(d);
|
|
730
|
+
return d;
|
|
731
|
+
}
|
|
732
|
+
/** Absolute path to a memory file (no existence check). */
|
|
733
|
+
pathFor(scope, name) {
|
|
734
|
+
return join3(this.dir(scope), `${sanitizeMemoryName(name)}.md`);
|
|
735
|
+
}
|
|
736
|
+
/** True iff this store is configured with a project scope available. */
|
|
737
|
+
hasProjectScope() {
|
|
738
|
+
return this.projectRoot !== void 0;
|
|
739
|
+
}
|
|
740
|
+
loadIndex(scope) {
|
|
741
|
+
if (scope === "project" && !this.projectRoot) return null;
|
|
742
|
+
const file = join3(
|
|
743
|
+
scopeDir({ homeDir: this.homeDir, scope, projectRoot: this.projectRoot }),
|
|
744
|
+
MEMORY_INDEX_FILE
|
|
745
|
+
);
|
|
746
|
+
if (!existsSync3(file)) return null;
|
|
747
|
+
let raw;
|
|
748
|
+
try {
|
|
749
|
+
raw = readFileSync3(file, "utf8");
|
|
750
|
+
} catch {
|
|
751
|
+
return null;
|
|
752
|
+
}
|
|
753
|
+
const trimmed = raw.trim();
|
|
754
|
+
if (!trimmed) return null;
|
|
755
|
+
const originalChars = trimmed.length;
|
|
756
|
+
const truncated = originalChars > MEMORY_INDEX_MAX_CHARS;
|
|
757
|
+
const content = truncated ? `${trimmed.slice(0, MEMORY_INDEX_MAX_CHARS)}
|
|
758
|
+
\u2026 (truncated ${originalChars - MEMORY_INDEX_MAX_CHARS} chars)` : trimmed;
|
|
759
|
+
return { content, originalChars, truncated };
|
|
760
|
+
}
|
|
761
|
+
/** Read one memory file's body (frontmatter stripped). Throws if missing. */
|
|
762
|
+
read(scope, name) {
|
|
763
|
+
const file = this.pathFor(scope, name);
|
|
764
|
+
if (!existsSync3(file)) {
|
|
765
|
+
throw new Error(`memory not found: scope=${scope} name=${name}`);
|
|
766
|
+
}
|
|
767
|
+
const raw = readFileSync3(file, "utf8");
|
|
768
|
+
const { data, body } = parseFrontmatter(raw);
|
|
769
|
+
const entry = {
|
|
770
|
+
name: data.name ?? name,
|
|
771
|
+
type: data.type ?? "project",
|
|
772
|
+
scope: data.scope ?? scope,
|
|
773
|
+
description: data.description ?? "",
|
|
774
|
+
body: body.trim(),
|
|
775
|
+
createdAt: data.created ?? ""
|
|
776
|
+
};
|
|
777
|
+
const priority = coercePriority(data.priority);
|
|
778
|
+
if (priority) entry.priority = priority;
|
|
779
|
+
const expires = coerceExpires(data.expires);
|
|
780
|
+
if (expires) entry.expires = expires;
|
|
781
|
+
return entry;
|
|
782
|
+
}
|
|
783
|
+
/** Skips malformed files — index stays queryable even if one file is hand-edited into nonsense. */
|
|
784
|
+
list() {
|
|
785
|
+
const out = [];
|
|
786
|
+
const scopes = this.projectRoot ? ["global", "project"] : ["global"];
|
|
787
|
+
for (const scope of scopes) {
|
|
788
|
+
const dir = scopeDir({ homeDir: this.homeDir, scope, projectRoot: this.projectRoot });
|
|
789
|
+
if (!existsSync3(dir)) continue;
|
|
790
|
+
let entries;
|
|
791
|
+
try {
|
|
792
|
+
entries = readdirSync2(dir);
|
|
793
|
+
} catch {
|
|
794
|
+
continue;
|
|
795
|
+
}
|
|
796
|
+
for (const entry of entries) {
|
|
797
|
+
if (entry === MEMORY_INDEX_FILE) continue;
|
|
798
|
+
if (!entry.endsWith(".md")) continue;
|
|
799
|
+
const name = entry.slice(0, -3);
|
|
800
|
+
try {
|
|
801
|
+
out.push(this.read(scope, name));
|
|
802
|
+
} catch {
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
return out;
|
|
807
|
+
}
|
|
808
|
+
write(input) {
|
|
809
|
+
if (input.scope === "project" && !this.projectRoot) {
|
|
810
|
+
throw new Error("cannot write project-scoped memory: no projectRoot configured");
|
|
811
|
+
}
|
|
812
|
+
const name = sanitizeMemoryName(input.name);
|
|
813
|
+
const desc = String(input.description ?? "").trim();
|
|
814
|
+
if (!desc) throw new Error("memory description cannot be empty");
|
|
815
|
+
const body = String(input.body ?? "").trim();
|
|
816
|
+
if (!body) throw new Error("memory body cannot be empty");
|
|
817
|
+
const entry = {
|
|
818
|
+
...input,
|
|
819
|
+
name,
|
|
820
|
+
description: desc,
|
|
821
|
+
body,
|
|
822
|
+
createdAt: todayIso()
|
|
823
|
+
};
|
|
824
|
+
if (input.priority) entry.priority = input.priority;
|
|
825
|
+
if (input.expires) entry.expires = input.expires;
|
|
826
|
+
const dir = this.dir(input.scope);
|
|
827
|
+
const file = join3(dir, `${name}.md`);
|
|
828
|
+
const content = `${formatFrontmatter(entry)}${body}
|
|
829
|
+
`;
|
|
830
|
+
writeFileSync2(file, content, "utf8");
|
|
831
|
+
this.regenerateIndex(input.scope);
|
|
832
|
+
return file;
|
|
833
|
+
}
|
|
834
|
+
/** Delete one memory + its index line. No-op if the file is already gone. */
|
|
835
|
+
delete(scope, rawName) {
|
|
836
|
+
if (scope === "project" && !this.projectRoot) {
|
|
837
|
+
throw new Error("cannot delete project-scoped memory: no projectRoot configured");
|
|
838
|
+
}
|
|
839
|
+
const file = this.pathFor(scope, rawName);
|
|
840
|
+
if (!existsSync3(file)) return false;
|
|
841
|
+
unlinkSync(file);
|
|
842
|
+
this.regenerateIndex(scope);
|
|
843
|
+
return true;
|
|
844
|
+
}
|
|
845
|
+
/** Sorted by name — same file set must produce byte-identical MEMORY.md for stable prefix hashing. */
|
|
846
|
+
regenerateIndex(scope) {
|
|
847
|
+
const dir = scopeDir({ homeDir: this.homeDir, scope, projectRoot: this.projectRoot });
|
|
848
|
+
if (!existsSync3(dir)) return;
|
|
849
|
+
let files;
|
|
850
|
+
try {
|
|
851
|
+
files = readdirSync2(dir);
|
|
852
|
+
} catch {
|
|
853
|
+
return;
|
|
854
|
+
}
|
|
855
|
+
const mdFiles = files.filter((f) => f !== MEMORY_INDEX_FILE && f.endsWith(".md")).sort((a, b) => a.localeCompare(b));
|
|
856
|
+
const indexPath = join3(dir, MEMORY_INDEX_FILE);
|
|
857
|
+
if (mdFiles.length === 0) {
|
|
858
|
+
if (existsSync3(indexPath)) unlinkSync(indexPath);
|
|
859
|
+
return;
|
|
860
|
+
}
|
|
861
|
+
const lines = [];
|
|
862
|
+
for (const f of mdFiles) {
|
|
863
|
+
const name = f.slice(0, -3);
|
|
864
|
+
try {
|
|
865
|
+
const entry = this.read(scope, name);
|
|
866
|
+
lines.push(indexLine({ name: entry.name || name, description: entry.description }));
|
|
867
|
+
} catch {
|
|
868
|
+
lines.push(`- [${name}](${name}.md) \u2014 (malformed, check frontmatter)`);
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
writeFileSync2(indexPath, `${lines.join("\n")}
|
|
872
|
+
`, "utf8");
|
|
873
|
+
}
|
|
874
|
+
};
|
|
875
|
+
function readGlobalReasonixMemory(homeDir = join3(homedir2(), ".reasonix")) {
|
|
876
|
+
const path = join3(homeDir, "REASONIX.md");
|
|
877
|
+
if (!existsSync3(path)) return null;
|
|
878
|
+
let raw;
|
|
879
|
+
try {
|
|
880
|
+
raw = readFileSync3(path, "utf8");
|
|
881
|
+
} catch {
|
|
882
|
+
return null;
|
|
883
|
+
}
|
|
884
|
+
const trimmed = raw.trim();
|
|
885
|
+
if (!trimmed) return null;
|
|
886
|
+
const originalChars = trimmed.length;
|
|
887
|
+
const truncated = originalChars > 8e3;
|
|
888
|
+
const content = truncated ? `${trimmed.slice(0, 8e3)}
|
|
889
|
+
\u2026 (truncated ${originalChars - 8e3} chars)` : trimmed;
|
|
890
|
+
return { path, content, originalChars, truncated };
|
|
891
|
+
}
|
|
892
|
+
function applyGlobalReasonixMemory(basePrompt, homeDir) {
|
|
893
|
+
if (!memoryEnabled()) return basePrompt;
|
|
894
|
+
const dir = homeDir ?? join3(homedir2(), ".reasonix");
|
|
895
|
+
const mem = readGlobalReasonixMemory(dir);
|
|
896
|
+
if (!mem) return basePrompt;
|
|
897
|
+
return [
|
|
898
|
+
basePrompt,
|
|
899
|
+
"",
|
|
900
|
+
"# Global memory (~/.reasonix/REASONIX.md)",
|
|
901
|
+
"",
|
|
902
|
+
"Cross-project notes the user pinned via the `#g` prompt prefix. Treat as authoritative \u2014 same level of trust as project memory.",
|
|
903
|
+
"",
|
|
904
|
+
"```",
|
|
905
|
+
mem.content,
|
|
906
|
+
"```"
|
|
907
|
+
].join("\n");
|
|
908
|
+
}
|
|
909
|
+
function readGlobalClaudeMemory(homeDir = homedir2()) {
|
|
910
|
+
const path = join3(homeDir, ".claude", "CLAUDE.md");
|
|
911
|
+
if (!existsSync3(path)) return null;
|
|
912
|
+
let raw;
|
|
913
|
+
try {
|
|
914
|
+
raw = readFileSync3(path, "utf8");
|
|
915
|
+
} catch {
|
|
916
|
+
return null;
|
|
917
|
+
}
|
|
918
|
+
const trimmed = raw.trim();
|
|
919
|
+
if (!trimmed) return null;
|
|
920
|
+
const originalChars = trimmed.length;
|
|
921
|
+
const truncated = originalChars > 8e3;
|
|
922
|
+
const content = truncated ? `${trimmed.slice(0, 8e3)}
|
|
923
|
+
\u2026 (truncated ${originalChars - 8e3} chars)` : trimmed;
|
|
924
|
+
return { path, content, originalChars, truncated };
|
|
925
|
+
}
|
|
926
|
+
function applyGlobalClaudeMemory(basePrompt) {
|
|
927
|
+
if (!memoryEnabled()) return basePrompt;
|
|
928
|
+
const mem = readGlobalClaudeMemory();
|
|
929
|
+
if (!mem) return basePrompt;
|
|
930
|
+
return [
|
|
931
|
+
basePrompt,
|
|
932
|
+
"",
|
|
933
|
+
"# Global memory (~/.claude/CLAUDE.md)",
|
|
934
|
+
"",
|
|
935
|
+
"Cross-project notes from your Claude Code configuration. Treat as authoritative \u2014 same level of trust as project memory.",
|
|
936
|
+
"",
|
|
937
|
+
"```",
|
|
938
|
+
mem.content,
|
|
939
|
+
"```"
|
|
940
|
+
].join("\n");
|
|
941
|
+
}
|
|
942
|
+
function effectivePriority(entry, cfg) {
|
|
943
|
+
if (entry.priority) return entry.priority;
|
|
944
|
+
return memoryTypeDefaults(entry.type, cfg).priority;
|
|
945
|
+
}
|
|
946
|
+
function highPriorityBlock(entries, cfg) {
|
|
947
|
+
const high = entries.filter((e) => effectivePriority(e, cfg) === "high");
|
|
948
|
+
if (high.length === 0) return null;
|
|
949
|
+
const lines = [
|
|
950
|
+
"# HIGH PRIORITY constraints (must observe)",
|
|
951
|
+
"",
|
|
952
|
+
"These memories were declared `priority: high` (via config.memory.customTypes or the memory file itself). Treat them as hard rules \u2014 violations override any other guidance below.",
|
|
953
|
+
""
|
|
954
|
+
];
|
|
955
|
+
for (const e of high) {
|
|
956
|
+
const head = `!!! [${e.scope}/${e.type}/${e.name}] ${e.description || "(no description)"}`;
|
|
957
|
+
lines.push(head);
|
|
958
|
+
if (e.body) lines.push("", e.body);
|
|
959
|
+
lines.push("");
|
|
960
|
+
}
|
|
961
|
+
return lines.join("\n").trimEnd();
|
|
962
|
+
}
|
|
963
|
+
function applyUserMemory(basePrompt, opts = {}) {
|
|
964
|
+
if (!memoryEnabled()) return basePrompt;
|
|
965
|
+
const store = new MemoryStore(opts);
|
|
966
|
+
const global = store.loadIndex("global");
|
|
967
|
+
const project = store.hasProjectScope() ? store.loadIndex("project") : null;
|
|
968
|
+
const high = highPriorityBlock(store.list(), opts.cfg);
|
|
969
|
+
if (!global && !project && !high) return basePrompt;
|
|
970
|
+
const parts = [basePrompt];
|
|
971
|
+
if (high) parts.push("", high);
|
|
972
|
+
if (global) {
|
|
973
|
+
parts.push(
|
|
974
|
+
"",
|
|
975
|
+
"# User memory \u2014 global (~/.reasonix/memory/global/MEMORY.md)",
|
|
976
|
+
"",
|
|
977
|
+
"Cross-project facts and preferences the user has told you in prior sessions. TREAT AS AUTHORITATIVE \u2014 don't re-verify via filesystem or web. One-liners index detail files; call `recall_memory` for full bodies only when the one-liner isn't enough.",
|
|
978
|
+
"",
|
|
979
|
+
"```",
|
|
980
|
+
global.content,
|
|
981
|
+
"```"
|
|
982
|
+
);
|
|
983
|
+
}
|
|
984
|
+
if (project) {
|
|
985
|
+
parts.push(
|
|
986
|
+
"",
|
|
987
|
+
"# User memory \u2014 this project",
|
|
988
|
+
"",
|
|
989
|
+
"Per-project facts the user established in prior sessions (not committed to the repo). TREAT AS AUTHORITATIVE. Same recall pattern as global memory.",
|
|
990
|
+
"",
|
|
991
|
+
"```",
|
|
992
|
+
project.content,
|
|
993
|
+
"```"
|
|
994
|
+
);
|
|
995
|
+
}
|
|
996
|
+
return parts.join("\n");
|
|
997
|
+
}
|
|
998
|
+
function applyMemoryStack(basePrompt, rootDir, opts = {}) {
|
|
999
|
+
const homeDir = opts.homeDir;
|
|
1000
|
+
const cfg = opts.cfg;
|
|
1001
|
+
const withProject = applyProjectMemory(basePrompt, rootDir);
|
|
1002
|
+
const withGlobal = applyGlobalReasonixMemory(
|
|
1003
|
+
withProject,
|
|
1004
|
+
homeDir ? join3(homeDir, ".reasonix") : void 0
|
|
1005
|
+
);
|
|
1006
|
+
const withGlobalClaude = applyGlobalClaudeMemory(withGlobal);
|
|
1007
|
+
const withMemory = applyUserMemory(withGlobalClaude, { projectRoot: rootDir, homeDir, cfg });
|
|
1008
|
+
const customSkillPaths = cfg?.skills?.paths ? resolveSkillPaths(cfg.skills.paths, rootDir) : loadResolvedSkillPaths(rootDir);
|
|
1009
|
+
return applySkillsIndex(withMemory, { projectRoot: rootDir, homeDir, customSkillPaths });
|
|
1010
|
+
}
|
|
1011
|
+
|
|
637
1012
|
export {
|
|
638
1013
|
PROJECT_MEMORY_FILE,
|
|
639
1014
|
PROJECT_MEMORY_FILES,
|
|
@@ -643,7 +1018,6 @@ export {
|
|
|
643
1018
|
resolveProjectMemoryWritePath,
|
|
644
1019
|
readProjectMemory,
|
|
645
1020
|
memoryEnabled,
|
|
646
|
-
applyProjectMemory,
|
|
647
1021
|
parseFrontmatter,
|
|
648
1022
|
TUI_FORMATTING_RULES,
|
|
649
1023
|
escalationContract,
|
|
@@ -652,6 +1026,10 @@ export {
|
|
|
652
1026
|
SKILL_FILE,
|
|
653
1027
|
validateSkillFrontmatter,
|
|
654
1028
|
SkillStore,
|
|
655
|
-
|
|
1029
|
+
sanitizeMemoryName,
|
|
1030
|
+
MemoryStore,
|
|
1031
|
+
readGlobalReasonixMemory,
|
|
1032
|
+
effectivePriority,
|
|
1033
|
+
applyMemoryStack
|
|
656
1034
|
};
|
|
657
|
-
//# sourceMappingURL=chunk-
|
|
1035
|
+
//# sourceMappingURL=chunk-N4SEBLU4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/memory/project.ts","../../src/prompt-fragments.ts","../../src/skills.ts","../../src/frontmatter.ts","../../src/memory/user.ts"],"sourcesContent":["/** Reads REASONIX.md → AGENTS.md → AGENT.md (first that exists); writes prefer the file already on disk. */\n\nimport { existsSync, readFileSync, statSync } from \"node:fs\";\nimport { basename, join } from \"node:path\";\n\n/** Default WRITE target — created when no candidate exists yet. */\nexport const PROJECT_MEMORY_FILE = \"REASONIX.md\";\n\n/** READ candidates, in priority order. AGENTS.md is the open spec at agents.md (Linux Foundation).\n * CLAUDE.md candidates support migration from Claude Code (project-root or .claude/ subdirectory). */\nexport const PROJECT_MEMORY_FILES = [\n \"REASONIX.md\",\n \".claude/CLAUDE.md\",\n \"CLAUDE.md\",\n \"AGENTS.md\",\n \"AGENT.md\",\n] as const;\n\nexport const PROJECT_MEMORY_MAX_CHARS = 8000;\n\nconst FOREIGN_PLATFORM_FILE_MARKERS = [\"SOUL.md\", \"PERSONA.md\"] as const;\n\n/** Returns the marker(s) that flagged rootDir as a foreign agent-platform data dir; null on a normal coding project. */\nexport function detectForeignAgentPlatform(rootDir: string): string[] | null {\n const hits: string[] = [];\n for (const name of FOREIGN_PLATFORM_FILE_MARKERS) {\n if (existsSync(join(rootDir, name))) hits.push(name);\n }\n if (isDir(join(rootDir, \"skills\")) && isDir(join(rootDir, \"memories\"))) {\n hits.push(\"skills/ + memories/\");\n }\n return hits.length > 0 ? hits : null;\n}\n\nfunction isDir(path: string): boolean {\n try {\n return statSync(path).isDirectory();\n } catch {\n return false;\n }\n}\n\n/** Absolute path of the first PROJECT_MEMORY_FILES candidate that exists at rootDir, or null. */\nexport function findProjectMemoryPath(rootDir: string): string | null {\n for (const name of PROJECT_MEMORY_FILES) {\n const path = join(rootDir, name);\n if (existsSync(path)) return path;\n }\n return null;\n}\n\n/** Path callers should write to: an existing candidate wins, otherwise rootDir/REASONIX.md. */\nexport function resolveProjectMemoryWritePath(rootDir: string): string {\n return findProjectMemoryPath(rootDir) ?? join(rootDir, PROJECT_MEMORY_FILE);\n}\n\nexport interface ProjectMemory {\n /** Absolute path the memory was read from. */\n path: string;\n /** Post-truncation content (may include a \"… (truncated N chars)\" marker). */\n content: string;\n /** Original byte length before truncation. */\n originalChars: number;\n /** True iff `originalChars > PROJECT_MEMORY_MAX_CHARS`. */\n truncated: boolean;\n}\n\n/** Empty / whitespace-only files return null so they don't perturb the cache prefix. */\nexport function readProjectMemory(rootDir: string): ProjectMemory | null {\n const path = findProjectMemoryPath(rootDir);\n if (!path) return null;\n let raw: string;\n try {\n raw = readFileSync(path, \"utf8\");\n } catch {\n return null;\n }\n const trimmed = raw.trim();\n if (!trimmed) return null;\n const originalChars = trimmed.length;\n const truncated = originalChars > PROJECT_MEMORY_MAX_CHARS;\n const content = truncated\n ? `${trimmed.slice(0, PROJECT_MEMORY_MAX_CHARS)}\\n… (truncated ${\n originalChars - PROJECT_MEMORY_MAX_CHARS\n } chars)`\n : trimmed;\n return { path, content, originalChars, truncated };\n}\n\nexport function memoryEnabled(): boolean {\n const env = process.env.REASONIX_MEMORY;\n if (env === \"off\" || env === \"false\" || env === \"0\") return false;\n return true;\n}\n\n/** Deterministic — same memory file always yields the same prefix hash. */\nexport function applyProjectMemory(basePrompt: string, rootDir: string): string {\n if (!memoryEnabled()) return basePrompt;\n const mem = readProjectMemory(rootDir);\n if (!mem) return basePrompt;\n const filename = basename(mem.path);\n return `${basePrompt}\n\n# Project memory (${filename})\n\nThe user pinned these notes about this project — treat them as authoritative context for every turn:\n\n\\`\\`\\`\n${mem.content}\n\\`\\`\\`\n`;\n}\n","/** Shared prompt fragments — single source so house-style rules can't drift across agent/subagent/skill prompts. */\n\n/** Embedded literally — no interpolation, so prefix-cache hash stays stable across sessions. */\nexport const TUI_FORMATTING_RULES = `Formatting (rendered in a TUI with a real markdown renderer):\n- Tabular data → GitHub-Flavored Markdown tables with ASCII pipes (\\`| col | col |\\` header + \\`| --- | --- |\\` separator). Never use Unicode box-drawing characters (│ ─ ┼ ┌ ┐ └ ┘ ├ ┤) — they look intentional but break terminal word-wrap and render as garbled columns at narrow widths.\n- Keep table cells short (one phrase each). If a cell needs a paragraph, use bullets below the table instead.\n- Code, file paths with line ranges, and shell commands → fenced code blocks (\\`\\`\\`).\n- Do NOT draw decorative frames around content with \\`┌──┐ │ └──┘\\` characters. The renderer adds its own borders; extra ASCII art adds noise and shatters at narrow widths.\n- For flow charts and diagrams: a plain bullet list with \\`→\\` or \\`↓\\` between steps. Don't try to draw boxes-and-arrows in ASCII; it never survives word-wrap.`;\n\n/** Pro is the top tier — escalation is a no-op for it; flash + others get the full ladder. */\nexport function escalationContract(modelId: string): string {\n if (modelId === \"deepseek-v4-pro\") {\n return `Cost-aware escalation note: you are running on \\`${modelId}\\` — the escalation tier. There is no higher tier to escalate to, so the \\`<<<NEEDS_PRO>>>\\` marker is a no-op for you; deliver the strongest answer you can directly. If asked which model you are, answer \\`${modelId}\\`.`;\n }\n return `Cost-aware escalation (you are running on \\`${modelId}\\`):\n\nIf a task CLEARLY exceeds what this tier can do well — complex cross-file architecture refactors, subtle concurrency / security / correctness invariants you can't resolve with confidence, or a design trade-off you'd be guessing at — output the marker as the FIRST line of your response (nothing before it, not even whitespace on a separate line). This aborts the current call and retries this turn on deepseek-v4-pro, one shot.\n\nTwo accepted forms:\n- \\`<<<NEEDS_PRO>>>\\` — bare marker, no rationale.\n- \\`<<<NEEDS_PRO: <one-sentence reason>>>>\\` — preferred. The reason text appears in the user-visible warning (\"⇧ flash requested escalation — <your reason>\"), so they understand WHY a more expensive call is happening. Keep it under ~150 chars, no newlines, no nested \\`>\\` characters. Examples: \\`<<<NEEDS_PRO: cross-file refactor across 6 modules with circular imports>>>\\` or \\`<<<NEEDS_PRO: subtle session-token race; flash would likely miss the locking invariant>>>\\`.\n\nDo NOT emit any other content in the same response when you request escalation. Use this sparingly: normal tasks — reading files, small edits, clear bug fixes, straightforward feature additions — stay on this tier. Request escalation ONLY when you would otherwise produce a guess or a visibly-mediocre answer. If in doubt, attempt the task here first; the system also escalates automatically if you hit 3+ repair / SEARCH-mismatch errors in a single turn (the user sees a typed breakdown). If asked which model you are, answer \\`${modelId}\\`.`;\n}\n\n/** Backward-compat — pre-#582 callers (and the `CODE_SYSTEM_PROMPT` public-API const) keep the historical flash phrasing. */\nexport const ESCALATION_CONTRACT = escalationContract(\"deepseek-v4-flash\");\n\nexport const NEGATIVE_CLAIM_RULE = `Negative claims (\"X is missing\", \"Y isn't implemented\", \"there's no Z\") are the #1 hallucination shape. They feel safe to write because no citation seems possible — but that's exactly why you must NOT write them on instinct.\n\nIf you have a search tool (\\`search_content\\`, \\`grep\\`, web search), call it FIRST before asserting absence:\n- Returns matches → you were wrong; correct yourself and cite the matches.\n- Returns nothing → state the absence WITH the search query as evidence: \\`No callers of \\\\\\`foo()\\\\\\` found (search_content \"foo\").\\`\n\nIf you have no search tool, qualify hard: \"I haven't verified — this is a guess.\" Never assert absence with fake authority.`;\n","/** Project scope wins over global. Only names+descriptions enter the prefix; bodies load lazily into the append-only log. */\n\nimport {\n constants,\n existsSync,\n mkdirSync,\n readFileSync,\n readdirSync,\n statSync,\n writeFileSync,\n} from \"node:fs\";\nimport { accessSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, isAbsolute, join, resolve } from \"node:path\";\nimport { parseFrontmatter } from \"./frontmatter.js\";\nimport { t } from \"./i18n/index.js\";\nimport { NEGATIVE_CLAIM_RULE, TUI_FORMATTING_RULES } from \"./prompt-fragments.js\";\n\nexport const SKILLS_DIRNAME = \"skills\";\nexport const SKILL_FILE = \"SKILL.md\";\n/** Cap on the pinned skills-index block, mirrors memory-index cap. */\nexport const SKILLS_INDEX_MAX_CHARS = 4000;\n/** Skill identifier shape — alnum + `_` + `-` + interior `.`, 1-64 chars. */\nconst VALID_SKILL_NAME = /^[a-zA-Z0-9][a-zA-Z0-9._-]{0,63}$/;\n\nexport type SkillScope = \"project\" | \"custom\" | \"global\" | \"builtin\";\n\nexport type SkillPathStatus = \"ok\" | \"missing\" | \"not-directory\" | \"unreadable\";\n\n/** inline = body enters parent log; subagent = isolated child loop, only final answer returns. */\nexport type SkillRunAs = \"inline\" | \"subagent\";\n\nexport interface Skill {\n /** Canonical name — sanitized, matches the directory / filename stem. */\n name: string;\n /** One-line description shown in the pinned index. */\n description: string;\n /** Full markdown body (post-frontmatter). Loaded on demand. */\n body: string;\n /** Which scope this skill was loaded from. */\n scope: SkillScope;\n /** Absolute path to the SKILL.md (or {name}.md) file, or \"(builtin)\" for shipped defaults. */\n path: string;\n /** Parsed `allowed-tools` frontmatter — when present, the spawned subagent's registry is scoped to these literal tool names. */\n allowedTools?: readonly string[];\n runAs: SkillRunAs;\n /** Subagent model override; only meaningful when `runAs === \"subagent\"`. */\n model?: string;\n}\n\nexport interface SkillRoot {\n dir: string;\n scope: Exclude<SkillScope, \"builtin\">;\n status: SkillPathStatus;\n priority: number;\n}\n\nexport interface SkillStoreOptions {\n /** Override `$HOME` — tests point this at a tmpdir. */\n homeDir?: string;\n /** Required for project-scope skills; omit to read only the global scope. */\n projectRoot?: string;\n customSkillPaths?: readonly string[];\n /** Suppress bundled built-ins — for tests asserting exact list contents. */\n disableBuiltins?: boolean;\n /** Per-skill model override applied to `runAs: subagent` skills (overrides frontmatter `model:`). */\n subagentModels?: Record<string, \"flash\" | \"pro\">;\n}\n\n/** Reject skill files that would silently disappear from the prefix index — `description:` is what `applySkillsIndex` keys on. */\nexport function validateSkillFrontmatter(raw: string): { ok: true } | { error: string } {\n const { data } = parseFrontmatter(raw);\n const desc = (data.description ?? \"\").trim();\n if (!desc) {\n return {\n error:\n 'skill frontmatter is missing a non-empty \"description:\" line — without it the skill will not appear in the model\\'s skills index',\n };\n }\n return { ok: true };\n}\n\nfunction isValidSkillName(name: string): boolean {\n return VALID_SKILL_NAME.test(name);\n}\n\nfunction parseAllowedTools(raw: string | undefined): readonly string[] | undefined {\n if (raw === undefined) return undefined;\n const names = raw\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean);\n return names.length > 0 ? Object.freeze(names) : undefined;\n}\n\n/** flash/pro preset → concrete deepseek model id. Kept local so this file doesn't import the CLI preset bundle. */\nfunction subagentModelForPreset(preset: \"flash\" | \"pro\"): string {\n return preset === \"pro\" ? \"deepseek-v4-pro\" : \"deepseek-v4-flash\";\n}\n\nexport class SkillStore {\n private readonly homeDir: string;\n private readonly projectRoot: string | undefined;\n private readonly customSkillPaths: readonly string[];\n private readonly disableBuiltins: boolean;\n private readonly subagentModels: Record<string, \"flash\" | \"pro\">;\n\n constructor(opts: SkillStoreOptions = {}) {\n this.homeDir = opts.homeDir ?? homedir();\n this.projectRoot = opts.projectRoot ? resolve(opts.projectRoot) : undefined;\n const baseDir = this.projectRoot ?? process.cwd();\n this.customSkillPaths = dedupePaths(\n opts.customSkillPaths?.map((p) => resolveCustomSkillPath(p, baseDir, this.homeDir)) ?? [],\n );\n this.disableBuiltins = opts.disableBuiltins === true;\n this.subagentModels = opts.subagentModels ?? {};\n }\n\n /** True iff this store was configured with a project root. */\n hasProjectScope(): boolean {\n return this.projectRoot !== undefined;\n }\n\n /** Project scope first so per-repo skill overrides custom/global entries with the same name. */\n roots(): SkillRoot[] {\n const out: Array<{ dir: string; scope: Exclude<SkillScope, \"builtin\"> }> = [];\n if (this.projectRoot) {\n out.push({\n dir: join(this.projectRoot, \".reasonix\", SKILLS_DIRNAME),\n scope: \"project\",\n });\n // #870: pick up `.agents/skills` automatically — common convention shared\n // by skills.sh-style tooling, no config required.\n out.push({\n dir: join(this.projectRoot, \".agents\", SKILLS_DIRNAME),\n scope: \"project\",\n });\n // Claude Code compatibility — a user's `.claude/skills/` folder works as-is.\n out.push({\n dir: join(this.projectRoot, \".claude\", SKILLS_DIRNAME),\n scope: \"project\",\n });\n }\n for (const dir of this.customSkillPaths) out.push({ dir, scope: \"custom\" });\n out.push({ dir: join(this.homeDir, \".reasonix\", SKILLS_DIRNAME), scope: \"global\" });\n out.push({ dir: join(this.homeDir, \".agents\", SKILLS_DIRNAME), scope: \"global\" });\n out.push({ dir: join(this.homeDir, \".claude\", SKILLS_DIRNAME), scope: \"global\" });\n return out.map((root, priority) => ({ ...root, priority, status: skillPathStatus(root.dir) }));\n }\n\n customRoots(): SkillRoot[] {\n return this.roots().filter((root) => root.scope === \"custom\");\n }\n\n /** Higher-priority root wins on collision (project > custom > global > builtin); sorted for stable prefix hash. */\n list(): Skill[] {\n const byName = new Map<string, Skill>();\n for (const { dir, scope, status } of this.roots()) {\n if (status !== \"ok\") continue;\n let entries: import(\"node:fs\").Dirent[];\n try {\n entries = readdirSync(dir, { withFileTypes: true });\n } catch {\n continue;\n }\n for (const entry of entries) {\n const skill = this.readEntry(dir, scope, entry);\n if (!skill) continue;\n if (!byName.has(skill.name)) byName.set(skill.name, skill);\n }\n }\n // Builtins last so user/project files override on name collision.\n if (!this.disableBuiltins) {\n for (const skill of BUILTIN_SKILLS) {\n if (!byName.has(skill.name)) byName.set(skill.name, skill);\n }\n }\n return [...byName.values()]\n .map((s) => this.applyModelOverride(s))\n .sort((a, b) => a.name.localeCompare(b.name));\n }\n\n /** Apply `subagentModels` config override on top of frontmatter `model:`. Inline skills are unaffected. */\n private applyModelOverride(skill: Skill): Skill {\n if (skill.runAs !== \"subagent\") return skill;\n const override = this.subagentModels[skill.name];\n if (!override) return skill;\n return { ...skill, model: subagentModelForPreset(override) };\n }\n\n /** Scaffold a new skill stub at the chosen scope. Refuses to overwrite. */\n create(name: string, scope: \"project\" | \"global\"): { path: string } | { error: string } {\n return this.createWithContent(name, scope, skillStubBody(name));\n }\n\n /** Like `create` but writes caller-supplied file contents instead of the stub — used by the scaffold tool. */\n createWithContent(\n name: string,\n scope: \"project\" | \"global\",\n content: string,\n ): { path: string } | { error: string } {\n if (!isValidSkillName(name)) {\n return { error: `invalid skill name: \"${name}\" — use letters, digits, _, -, .` };\n }\n if (scope === \"project\" && !this.projectRoot) {\n return { error: \"project scope requires a workspace — run from `reasonix code`\" };\n }\n const root =\n scope === \"project\"\n ? join(this.projectRoot ?? \"\", \".reasonix\", SKILLS_DIRNAME)\n : join(this.homeDir, \".reasonix\", SKILLS_DIRNAME);\n const flat = join(root, `${name}.md`);\n const folder = join(root, name, SKILL_FILE);\n if (existsSync(folder)) {\n return { error: `skill \"${name}\" already exists at ${folder}` };\n }\n mkdirSync(dirname(flat), { recursive: true });\n try {\n writeFileSync(flat, content, { encoding: \"utf8\", flag: \"wx\" });\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"EEXIST\") {\n return { error: `skill \"${name}\" already exists at ${flat}` };\n }\n throw err;\n }\n return { path: flat };\n }\n\n /** Resolve one skill by name. Returns `null` if not found or malformed. */\n read(name: string): Skill | null {\n if (!isValidSkillName(name)) return null;\n for (const { dir, scope, status } of this.roots()) {\n if (status !== \"ok\") continue;\n const dirCandidate = join(dir, name, SKILL_FILE);\n if (existsSync(dirCandidate) && statSync(dirCandidate).isFile()) {\n return this.parse(dirCandidate, name, scope);\n }\n const flatCandidate = join(dir, `${name}.md`);\n if (existsSync(flatCandidate) && statSync(flatCandidate).isFile()) {\n return this.parse(flatCandidate, name, scope);\n }\n }\n if (!this.disableBuiltins) {\n for (const skill of BUILTIN_SKILLS) {\n if (skill.name === name) return skill;\n }\n }\n return null;\n }\n\n private readEntry(dir: string, scope: SkillScope, entry: import(\"node:fs\").Dirent): Skill | null {\n if (entry.isDirectory()) {\n if (!isValidSkillName(entry.name)) return null;\n const file = join(dir, entry.name, SKILL_FILE);\n if (!existsSync(file)) return null;\n return this.parse(file, entry.name, scope);\n }\n if (entry.isFile() && entry.name.endsWith(\".md\")) {\n const stem = entry.name.slice(0, -3);\n if (!isValidSkillName(stem)) return null;\n return this.parse(join(dir, entry.name), stem, scope);\n }\n return null;\n }\n\n private parse(path: string, stem: string, scope: SkillScope): Skill | null {\n let raw: string;\n try {\n raw = readFileSync(path, \"utf8\");\n } catch {\n return null;\n }\n const { data, body } = parseFrontmatter(raw);\n const name = data.name && isValidSkillName(data.name) ? data.name : stem;\n const description = (data.description ?? \"\").trim();\n // Surface the silent-pin failure mode at parse time. Builtins always have\n // a description so user-authored files are the only ones that hit this.\n if (!description) {\n console.warn(\n `[skills] \"${name}\" at ${path} has no description: — it will be loaded but won't appear in the skills index.`,\n );\n }\n return {\n name,\n description,\n body: body.trim(),\n scope,\n path,\n allowedTools: parseAllowedTools(data[\"allowed-tools\"]),\n runAs: parseRunAs(data.runAs, data.context, data.agent),\n model: data.model?.startsWith(\"deepseek-\") ? data.model : undefined,\n };\n }\n}\n\nfunction dedupePaths(paths: readonly string[]): string[] {\n const out: string[] = [];\n const seen = new Set<string>();\n for (const path of paths) {\n const key = process.platform === \"win32\" ? path.toLowerCase() : path;\n if (seen.has(key)) continue;\n seen.add(key);\n out.push(path);\n }\n return out;\n}\n\nfunction resolveCustomSkillPath(path: string, baseDir: string, homeDir: string): string {\n const trimmed = path.trim();\n const expanded =\n trimmed === \"~\"\n ? homeDir\n : trimmed.startsWith(\"~/\") || trimmed.startsWith(\"~\\\\\")\n ? join(homeDir, trimmed.slice(2))\n : trimmed;\n return resolve(isAbsolute(expanded) ? expanded : join(baseDir, expanded));\n}\n\nexport function skillPathStatus(dir: string): SkillPathStatus {\n try {\n const stat = statSync(dir);\n if (!stat.isDirectory()) return \"not-directory\";\n accessSync(dir, constants.R_OK);\n return \"ok\";\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code === \"ENOENT\") return \"missing\";\n return \"unreadable\";\n }\n}\n\n/** Unknown values default to the safe (non-spawning) `inline` mode. Claude SKILL.md\n * uses `context: fork` or a non-empty `agent:` field for the same intent. */\nfunction parseRunAs(\n raw: string | undefined,\n context: string | undefined,\n agent: string | undefined,\n): SkillRunAs {\n if (raw?.trim() === \"subagent\") return \"subagent\";\n if (context?.trim().toLowerCase() === \"fork\") return \"subagent\";\n if (agent?.trim()) return \"subagent\";\n return \"inline\";\n}\n\n/** Stub markdown for `/skill new` — minimal frontmatter + scaffolding the user fills in. */\nfunction skillStubBody(name: string): string {\n return `---\nname: ${name}\ndescription: One-liner — what does this skill do?\n---\n\n# ${name}\n\nReplace this body with the playbook the model should follow when this skill is invoked.\n\nTips:\n- Reference tools by name (run_command, edit_file, search_content, ...)\n- Add \\`runAs: subagent\\` to frontmatter to spawn an isolated subagent loop\n- Add \\`allowed-tools: read_file, search_content\\` to scope a subagent's tools\n`;\n}\n\nfunction skillDescription(s: Pick<Skill, \"name\" | \"description\" | \"scope\">): string {\n if (s.scope !== \"builtin\") return s.description;\n const key = s.name === \"security-review\" ? \"securityReview\" : s.name;\n return t(`builtinSkills.${key}`);\n}\n\n/** Subagent tag goes AFTER the name in brackets — leading-marker tags get copied into `name` arg verbatim. */\nfunction skillIndexLine(s: Pick<Skill, \"name\" | \"description\" | \"runAs\" | \"scope\">): string {\n const safeDesc = skillDescription(s).replace(/\\n/g, \" \").trim();\n const tag = s.runAs === \"subagent\" ? \" [🧬 subagent]\" : \"\";\n const max = 130 - s.name.length - tag.length;\n const clipped = safeDesc.length > max ? `${safeDesc.slice(0, Math.max(1, max - 1))}…` : safeDesc;\n return clipped ? `- ${s.name}${tag} — ${clipped}` : `- ${s.name}${tag}`;\n}\n\nconst MISSING_DESCRIPTION_PLACEHOLDER =\n '(no description — frontmatter is missing a \"description:\" line; tell the user to add one)';\n\n/** Bodies stay out — prefix must stay short + cacheable; bodies load on demand. */\nexport function applySkillsIndex(basePrompt: string, opts: SkillStoreOptions = {}): string {\n const store = new SkillStore(opts);\n const skills = store.list();\n if (skills.length === 0) return basePrompt;\n const lines = skills.map((s) =>\n skillIndexLine(s.description ? s : { ...s, description: MISSING_DESCRIPTION_PLACEHOLDER }),\n );\n const joined = lines.join(\"\\n\");\n const truncated =\n joined.length > SKILLS_INDEX_MAX_CHARS\n ? `${joined.slice(0, SKILLS_INDEX_MAX_CHARS)}\\n… (truncated ${\n joined.length - SKILLS_INDEX_MAX_CHARS\n } chars)`\n : joined;\n return [\n basePrompt,\n \"\",\n \"# Skills — playbooks you can invoke\",\n \"\",\n 'One-liner index. Each entry is either a built-in or a user-authored playbook. Call `run_skill({ name: \"<skill-name>\", arguments: \"<task>\" })` — the `name` is JUST the skill identifier (e.g. `\"explore\"`), NOT the `[🧬 subagent]` tag that appears after it. Entries tagged `[🧬 subagent]` spawn an **isolated subagent** — its tool calls and reasoning never enter your context, only its final answer does. Use subagent skills for tasks that would otherwise flood your context (deep exploration, multi-step research, anything where you only need the conclusion). Plain skills are inlined: their body becomes a tool result you read and act on directly. The user can also invoke a skill via `/skill <name>`.',\n \"\",\n \"```\",\n truncated,\n \"```\",\n ].join(\"\\n\");\n}\n\nconst BUILTIN_EXPLORE_BODY = `You are running as an exploration subagent. Your job is to investigate the codebase the parent agent pointed you at, then return one focused, distilled answer.\n\nHow to operate:\n- Use read_file, search_files, search_content, directory_tree, list_directory, get_file_info as your primary tools. Stay read-only.\n- For \"find all places that call / reference / use X\" questions, use \\`search_content\\` (content grep) — NOT \\`search_files\\` (which only matches file names). This is the most common subagent mistake; using the wrong tool gives empty results and you waste your iter budget chasing a phantom.\n- Cast a wide net first (search_content for symbol references, directory_tree for structure) to map the territory; then read the 3-10 most relevant files in full.\n- Don't read every file — be selective. Aim for breadth on the first pass, depth only where the question demands it.\n- Stop exploring as soon as you can answer the question. The parent doesn't see your tool calls, so over-exploration is pure waste.\n\nYour final answer:\n- One paragraph (or a few short bullets). Lead with the conclusion.\n- Cite specific file paths + line ranges when they support the answer.\n- If the question can't be answered from what you found, say so plainly and suggest where to look next.\n- No follow-up offers, no \"let me know if you need more.\" The parent will ask again if they need more.\n\n${NEGATIVE_CLAIM_RULE}\n\n${TUI_FORMATTING_RULES}\n\nThe 'task' the parent gave you is the question you must answer. Treat any other reading of it as scope creep.`;\n\nconst BUILTIN_RESEARCH_BODY = `You are running as a research subagent. Your job is to gather information from code AND the web, synthesize it, and return one focused conclusion.\n\nHow to operate:\n- Combine code reading (read_file, search_files) with web tools (web_search, web_fetch) as appropriate to the question.\n- For \"how does X work\" / \"is Y supported\" questions: web first to find the canonical reference, then verify against the local code.\n- For \"what's our policy on Z\" / \"where do we use Q\": local code first, web only if you need to compare against external standards.\n- Cap yourself at ~10 tool calls. If you can't converge in 10, return what you have plus a note about what's missing.\n\nYour final answer:\n- One paragraph (or short bullets). Lead with the conclusion.\n- Cite both code (file:line) AND web sources (URL) when they back the answer.\n- Distinguish \"I verified this in code\" from \"I read this on a docs page\" — the parent will trust the former more.\n- If the answer is uncertain, say so. Don't invent confidence.\n\n${NEGATIVE_CLAIM_RULE}\n\n${TUI_FORMATTING_RULES}\n\nThe 'task' the parent gave you is the research question. Stay on it.`;\n\nconst BUILTIN_REVIEW_BODY = `You are running as a code-review subagent. Your job is to inspect the changes the user is about to ship — usually the current git branch vs its upstream — and produce a focused review the parent can hand back to the user.\n\nHow to operate:\n- Default scope: the current branch's diff vs the default branch. If the user's task names a specific commit range or files, honor that instead.\n- Discover scope first: \\`run_command git status\\`, \\`git diff --stat\\`, \\`git log --oneline\\` to see what changed. Then \\`git diff\\` (or \\`git diff <base>...HEAD\\`) for the actual hunks.\n- Read the touched files (\\`read_file\\`) when the diff alone doesn't carry enough context — function signatures, surrounding invariants, callers.\n- For \"any callers depending on this?\" questions: \\`search_content\\` against the symbol BEFORE asserting impact.\n- Stay read-only. Never \\`run_command git commit\\`, never write files, never propose SEARCH/REPLACE blocks. The parent decides whether to act on your findings.\n- Cap yourself at ~12 tool calls. If the diff is too big to review in one pass, pick the riskiest 2-3 files and say so explicitly.\n\nWhat to look for, in priority order:\n1. **Correctness bugs** — off-by-one, null/undefined handling, race conditions, wrong sign / wrong operator, edge cases the code doesn't handle.\n2. **Security** — injection (SQL, shell, path traversal), secrets in code, missing authz checks, unsafe deserialization.\n3. **Behavior changes the diff hides** — renames that miss callers, removed branches that were load-bearing, error-handling that now swallows what used to surface.\n4. **Tests** — does the change have tests for the new behavior? Are existing tests still meaningful, or did the change make them tautological?\n5. **Style + consistency** — only flag deviations that matter (unsafe \\`any\\`, missing types in TypeScript, inconsistent error shape). Don't pile on cosmetic nits if the substance is clean.\n\nYour final answer:\n- Lead with a one-sentence verdict: \"ship as-is\" / \"minor nits, OK to ship after\" / \"blocking issues, do not ship\".\n- Then a short bulleted list of issues, each with: file:line citation + the problem in one sentence + what to change.\n- Group by severity if you have more than 4 items: **Blocking**, **Should-fix**, **Nits**.\n- If everything looks clean, say so plainly. Don't manufacture concerns.\n\n${NEGATIVE_CLAIM_RULE}\n\n${TUI_FORMATTING_RULES}\n\nThe 'task' the parent gave you describes WHAT to review (a branch, a file set, or \"the pending changes\"). Stay on it; don't redesign the feature.`;\n\nconst BUILTIN_SECURITY_REVIEW_BODY = `You are running as a security-review subagent. Your job is to inspect the changes the user is about to ship — usually the current git branch vs its upstream — through a security lens specifically, and report exploitable issues.\n\nHow to operate:\n- Default scope: the current branch's diff vs the default branch. If the user names a different range or a directory, honor that.\n- Discover scope first: \\`git status\\`, \\`git diff --stat\\`, \\`git diff <base>...HEAD\\`. Read touched files (\\`read_file\\`) when the diff alone doesn't carry security context — auth checks, input validation, the actual handler that calls into the changed function.\n- Use \\`search_content\\` to verify \"is this user-controlled input ever sanitized later?\" / \"are there other call sites that depend on this validation?\" before asserting impact.\n- Stay read-only. Never write, never run destructive commands, never propose SEARCH/REPLACE blocks. The parent decides what to act on.\n- Cap yourself at ~12 tool calls. If the diff is too big, focus on the riskiest 2-3 files and say so explicitly.\n\nThreat model — flag with severity:\n\n**CRITICAL** (do-not-ship):\n- SQL / NoSQL / shell / template injection — user input concatenated into a query, command, or template without parameterization.\n- Path traversal — user-controlled filenames touching the filesystem without canonicalization + sandbox check.\n- Authentication / authorization missing — endpoints / actions that should require a session check but don't.\n- Hardcoded secrets — API keys, passwords, signing tokens visible in the diff.\n- Deserialization of untrusted input — \\`pickle.loads\\`, \\`yaml.load\\` (non-safe), \\`eval\\`, \\`Function()\\`, \\`unserialize()\\`.\n- Cryptographic mistakes — homemade crypto, weak hashes (MD5/SHA-1) for passwords, missing IVs, ECB mode, predictable nonces.\n\n**HIGH**:\n- XSS — user input rendered into HTML without escaping (or wrong escaping context).\n- SSRF — fetching URLs from user input without an allowlist.\n- Race conditions in security-relevant code — TOCTOU on auth/file checks.\n- Open redirects — user-controlled URL passed to a redirect helper.\n- Insufficient logging on security events (login failure, permission denial) — only flag if the codebase clearly DOES log elsewhere.\n\n**MEDIUM**:\n- Verbose error messages leaking internal paths / stack traces / SQL.\n- Missing rate limiting on a credential / token endpoint.\n- Cross-origin / cookie-flag issues (missing \\`Secure\\` / \\`HttpOnly\\` / \\`SameSite\\`).\n\nThings to NOT pile on (out of scope here — the regular /review covers them):\n- Style, formatting, naming.\n- Performance, refactor opportunities, test coverage gaps that aren't security-relevant.\n- \"Should be a constant\" / \"extract this helper\" — irrelevant to ship-blocking.\n\nYour final answer:\n- Lead with a one-sentence verdict: \"no security issues found\", \"minor concerns\", or \"blocking issues\".\n- Then a list grouped by severity. Each item: file:line + 1-sentence threat + 1-sentence fix direction (no full SEARCH/REPLACE — the user / parent agent will write that).\n- If clean, say so plainly. Don't manufacture findings.\n\n${NEGATIVE_CLAIM_RULE}\n\n${TUI_FORMATTING_RULES}\n\nThe 'task' the parent gave you names what to review. Stay on it; don't redesign the feature.`;\n\nconst BUILTIN_TEST_BODY = `You are running as the parent agent — this skill is INLINED, not a subagent. The user invoked /test (or asked you to \"run the tests and fix failures\"). Your job: run the project's test suite, diagnose any failure, propose fixes as SEARCH/REPLACE edit blocks, then re-run. Repeat until green or you hit a wall you should escalate.\n\nHow to operate:\n\n1. **Detect the test command**.\n - Look for \\`package.json\\` → \\`scripts.test\\` first (most common: \\`npm test\\`, \\`pnpm test\\`, \\`yarn test\\`).\n - If no package.json or no test script: try \\`pytest\\`, \\`go test ./...\\`, \\`cargo test\\` based on what files exist (pyproject.toml/requirements.txt → pytest; go.mod → go test; Cargo.toml → cargo test).\n - If you can't tell, ASK the user for the command — don't guess. One question, one tool call to confirm.\n\n2. **Run it via run_command** (typical timeout 120s, bigger if the suite is large). Capture stdout + stderr.\n\n3. **Read the failures**. Pull out: which test names failed, the actual error/traceback, the file + line that threw. Don't just paraphrase — locate the exact assertion or stack frame.\n\n4. **Propose fixes**. For each distinct failure:\n - If the failure is in PRODUCTION code (test catches a real bug) → propose a SEARCH/REPLACE that fixes the production code.\n - If the failure is in TEST code (test is wrong, codebase is right) → propose a SEARCH/REPLACE that updates the test, AND say so explicitly: \"This is a test bug, not a production bug — updating the assertion.\"\n - If the failure is environmental (missing dep, wrong node version, missing fixture file) → say so and stop. Don't try to install packages or change config without checking with the user.\n\n5. **Apply + re-run**. After the user accepts the edit blocks, run the test command again. Iterate.\n\n6. **Stop conditions**:\n - All tests pass → report green, summarize what changed.\n - Same test still failing after 2 fix attempts on the same line → STOP. Tell the user \"I've tried twice, it's still failing — here's what I think is happening, want me to try a different angle?\". Don't loop indefinitely.\n - 3+ unrelated failures → fix one at a time, smallest first, so each pass narrows the surface.\n\nDon't:\n- Run \\`npm install\\` / \\`pip install\\` / \\`cargo update\\` without asking — those mutate lockfiles and have global effects.\n- Disable, skip, or delete failing tests to \"make it green\". If a test seems wrong, update its assertion with a one-sentence explanation, but never add \\`.skip\\` / \\`it.skip\\` / \\`@pytest.mark.skip\\`.\n- Modify the test runner config (vitest.config, jest.config, etc.) to silence failures.\n\nLead each turn with a one-line status: \"▸ running \\`npm test\\` ...\" → \"▸ 2 failures in tests/foo.test.ts — first is …\" → so the user always knows where you are without scrolling tool output.`;\n\nconst BUILTIN_SKILLS: readonly Skill[] = Object.freeze([\n Object.freeze<Skill>({\n name: \"explore\",\n description:\n \"Explore the codebase in an isolated subagent — wide-net read-only investigation that returns one distilled answer. Best for: 'find all places that...', 'how does X work across the project', 'survey the code for Y'.\",\n body: BUILTIN_EXPLORE_BODY,\n scope: \"builtin\",\n path: \"(builtin)\",\n runAs: \"subagent\",\n }),\n Object.freeze<Skill>({\n name: \"research\",\n description:\n \"Research a question by combining web search + code reading in an isolated subagent. Best for: 'is X feature supported by lib Y', 'what's the canonical way to do Z', 'compare our impl against the spec'.\",\n body: BUILTIN_RESEARCH_BODY,\n scope: \"builtin\",\n path: \"(builtin)\",\n runAs: \"subagent\",\n }),\n Object.freeze<Skill>({\n name: \"review\",\n description:\n \"Review the pending changes (current branch diff by default) in an isolated subagent — flags correctness, security, missing tests, hidden behavior changes; reports verdict + per-issue file:line. Read-only; the parent decides what to act on.\",\n body: BUILTIN_REVIEW_BODY,\n scope: \"builtin\",\n path: \"(builtin)\",\n runAs: \"subagent\",\n }),\n Object.freeze<Skill>({\n name: \"security-review\",\n description:\n \"Security-focused review of the current branch diff in an isolated subagent — flags injection/authz/secrets/deserialization/path-traversal/crypto issues, severity-tagged. Read-only. Use when shipping changes that touch auth, input parsing, file IO, or external requests.\",\n body: BUILTIN_SECURITY_REVIEW_BODY,\n scope: \"builtin\",\n path: \"(builtin)\",\n runAs: \"subagent\",\n }),\n Object.freeze<Skill>({\n name: \"test\",\n description:\n \"Run the project's test suite, diagnose failures, propose SEARCH/REPLACE fixes, re-run until green (or stop after 2 fix attempts on the same failure). Inlined — runs in the parent loop so you see the edit blocks and can /apply them. Detects npm/pnpm/yarn/pytest/go/cargo.\",\n body: BUILTIN_TEST_BODY,\n scope: \"builtin\",\n path: \"(builtin)\",\n runAs: \"inline\",\n }),\n]);\n","/** Tiny YAML-frontmatter parser shared by skills / memory loaders. Single source so BOM + folded + quoted handling stay consistent. */\n\nconst KEY_RE = /^([a-zA-Z_][a-zA-Z0-9_-]*):\\s*(.*)$/;\n/** Bracket-write guard — regex permits these as identifiers, but writing them would mutate Object.prototype. */\nconst FORBIDDEN_KEYS = new Set([\"__proto__\", \"constructor\", \"prototype\"]);\n\nfunction stripQuotes(s: string): string {\n if (s.length < 2) return s;\n const first = s[0];\n const last = s[s.length - 1];\n if ((first === '\"' && last === '\"') || (first === \"'\" && last === \"'\")) {\n return s.slice(1, -1);\n }\n return s;\n}\n\nexport function parseFrontmatter(raw: string): { data: Record<string, string>; body: string } {\n const stripped = raw.charCodeAt(0) === 0xfeff ? raw.slice(1) : raw;\n const lines = stripped.split(/\\r?\\n/);\n if (lines[0] !== \"---\") return { data: {}, body: stripped };\n const end = lines.indexOf(\"---\", 1);\n if (end < 0) return { data: {}, body: stripped };\n const entries = new Map<string, string>();\n let currentKey: string | null = null;\n for (let i = 1; i < end; i++) {\n const line = lines[i] ?? \"\";\n if (line.trim() === \"\") {\n currentKey = null;\n continue;\n }\n const m = line.match(KEY_RE);\n if (m?.[1] && !FORBIDDEN_KEYS.has(m[1])) {\n currentKey = m[1];\n entries.set(currentKey, (m[2] ?? \"\").trim());\n } else if (currentKey) {\n const cont = line.trim();\n const prev = entries.get(currentKey) ?? \"\";\n entries.set(currentKey, prev ? `${prev} ${cont}` : cont);\n }\n }\n const data: Record<string, string> = Object.create(null);\n for (const [k, v] of entries) {\n if (FORBIDDEN_KEYS.has(k)) continue;\n data[k] = stripQuotes(v);\n }\n return {\n data,\n body: lines\n .slice(end + 1)\n .join(\"\\n\")\n .replace(/^\\n+/, \"\"),\n };\n}\n","/** User-private memory pinned into the immutable prefix; distinct from committable REASONIX.md. */\n\nimport { createHash } from \"node:crypto\";\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n readdirSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join, resolve } from \"node:path\";\nimport {\n type ReasonixConfig,\n loadResolvedSkillPaths,\n memoryTypeDefaults,\n resolveSkillPaths,\n} from \"../config.js\";\nimport { parseFrontmatter } from \"../frontmatter.js\";\nimport { applySkillsIndex } from \"../skills.js\";\nimport { applyProjectMemory, memoryEnabled } from \"./project.js\";\n\nexport const USER_MEMORY_DIR = \"memory\";\nexport const MEMORY_INDEX_FILE = \"MEMORY.md\";\n/** Cap on the index file content loaded into the prefix, per scope. */\nexport const MEMORY_INDEX_MAX_CHARS = 4000;\n\nexport const BUILTIN_MEMORY_TYPES = [\"user\", \"feedback\", \"project\", \"reference\"] as const;\nexport type BuiltinMemoryType = (typeof BUILTIN_MEMORY_TYPES)[number];\n/** Built-ins plus any string declared in `config.memory.customTypes`. Unknown values are accepted (round-tripped verbatim). */\nexport type MemoryType = BuiltinMemoryType | (string & {});\nexport type MemoryScope = \"global\" | \"project\";\nexport type MemoryPriority = \"low\" | \"medium\" | \"high\";\nexport type MemoryExpires = \"project_end\";\n\nexport interface MemoryEntry {\n name: string;\n type: MemoryType;\n scope: MemoryScope;\n description: string;\n body: string;\n /** ISO date string (YYYY-MM-DD). */\n createdAt: string;\n /** Explicit per-entry priority; absent → resolve from config default for `type`, else \"medium\". */\n priority?: MemoryPriority;\n /** Lifecycle hint. `project_end` → cleared by `/memory clear project`. */\n expires?: MemoryExpires;\n}\n\nexport interface MemoryStoreOptions {\n /** Override `~/.reasonix` — tests set this to a tmpdir. */\n homeDir?: string;\n /** Absolute sandbox root. Required to use `scope: \"project\"`. */\n projectRoot?: string;\n}\n\nexport interface WriteInput {\n name: string;\n type: MemoryType;\n scope: MemoryScope;\n description: string;\n body: string;\n priority?: MemoryPriority;\n expires?: MemoryExpires;\n}\n\nconst VALID_NAME = /^[a-zA-Z0-9_-][a-zA-Z0-9_.-]{1,38}[a-zA-Z0-9]$/;\n\n/** Throws on path-injection (../, /, leading dot). Allowed: 3-40 chars, alnum/_/-, interior `.`. */\nexport function sanitizeMemoryName(raw: string): string {\n const trimmed = String(raw ?? \"\").trim();\n if (!VALID_NAME.test(trimmed)) {\n throw new Error(\n `invalid memory name: ${JSON.stringify(raw)} — must be 3-40 chars, alnum/_/-, no path separators`,\n );\n }\n return trimmed;\n}\n\n/** Stable 16-hex-char hash of an absolute sandbox root path. */\nexport function projectHash(rootDir: string): string {\n const abs = resolve(rootDir);\n return createHash(\"sha1\").update(abs).digest(\"hex\").slice(0, 16);\n}\n\nfunction scopeDir(opts: { homeDir: string; scope: MemoryScope; projectRoot?: string }): string {\n if (opts.scope === \"global\") {\n return join(opts.homeDir, USER_MEMORY_DIR, \"global\");\n }\n if (!opts.projectRoot) {\n throw new Error(\"scope=project requires a projectRoot on MemoryStore\");\n }\n return join(opts.homeDir, USER_MEMORY_DIR, projectHash(opts.projectRoot));\n}\n\nfunction ensureDir(p: string): void {\n if (!existsSync(p)) mkdirSync(p, { recursive: true });\n}\n\nfunction formatFrontmatter(e: WriteInput & { createdAt: string }): string {\n const lines = [\n \"---\",\n `name: ${e.name}`,\n `description: ${e.description.replace(/\\n/g, \" \")}`,\n `type: ${e.type}`,\n `scope: ${e.scope}`,\n `created: ${e.createdAt}`,\n ];\n if (e.priority) lines.push(`priority: ${e.priority}`);\n if (e.expires) lines.push(`expires: ${e.expires}`);\n lines.push(\"---\", \"\");\n return lines.join(\"\\n\");\n}\n\nfunction coercePriority(v: unknown): MemoryPriority | undefined {\n return v === \"low\" || v === \"medium\" || v === \"high\" ? v : undefined;\n}\n\nfunction coerceExpires(v: unknown): MemoryExpires | undefined {\n return v === \"project_end\" ? v : undefined;\n}\n\nfunction todayIso(): string {\n const d = new Date();\n return d.toISOString().slice(0, 10);\n}\n\nfunction indexLine(e: Pick<MemoryEntry, \"name\" | \"description\">): string {\n const safeDesc = e.description.replace(/\\n/g, \" \").trim();\n const max = 130 - e.name.length;\n const clipped = safeDesc.length > max ? `${safeDesc.slice(0, Math.max(1, max - 1))}…` : safeDesc;\n return `- [${e.name}](${e.name}.md) — ${clipped}`;\n}\n\nexport class MemoryStore {\n private readonly homeDir: string;\n private readonly projectRoot: string | undefined;\n\n constructor(opts: MemoryStoreOptions = {}) {\n this.homeDir = opts.homeDir ?? join(homedir(), \".reasonix\");\n this.projectRoot = opts.projectRoot ? resolve(opts.projectRoot) : undefined;\n }\n\n /** Directory this store writes `scope` files into, creating it if needed. */\n dir(scope: MemoryScope): string {\n const d = scopeDir({ homeDir: this.homeDir, scope, projectRoot: this.projectRoot });\n ensureDir(d);\n return d;\n }\n\n /** Absolute path to a memory file (no existence check). */\n pathFor(scope: MemoryScope, name: string): string {\n return join(this.dir(scope), `${sanitizeMemoryName(name)}.md`);\n }\n\n /** True iff this store is configured with a project scope available. */\n hasProjectScope(): boolean {\n return this.projectRoot !== undefined;\n }\n\n loadIndex(\n scope: MemoryScope,\n ): { content: string; originalChars: number; truncated: boolean } | null {\n if (scope === \"project\" && !this.projectRoot) return null;\n const file = join(\n scopeDir({ homeDir: this.homeDir, scope, projectRoot: this.projectRoot }),\n MEMORY_INDEX_FILE,\n );\n if (!existsSync(file)) return null;\n let raw: string;\n try {\n raw = readFileSync(file, \"utf8\");\n } catch {\n return null;\n }\n const trimmed = raw.trim();\n if (!trimmed) return null;\n const originalChars = trimmed.length;\n const truncated = originalChars > MEMORY_INDEX_MAX_CHARS;\n const content = truncated\n ? `${trimmed.slice(0, MEMORY_INDEX_MAX_CHARS)}\\n… (truncated ${originalChars - MEMORY_INDEX_MAX_CHARS} chars)`\n : trimmed;\n return { content, originalChars, truncated };\n }\n\n /** Read one memory file's body (frontmatter stripped). Throws if missing. */\n read(scope: MemoryScope, name: string): MemoryEntry {\n const file = this.pathFor(scope, name);\n if (!existsSync(file)) {\n throw new Error(`memory not found: scope=${scope} name=${name}`);\n }\n const raw = readFileSync(file, \"utf8\");\n const { data, body } = parseFrontmatter(raw);\n const entry: MemoryEntry = {\n name: data.name ?? name,\n type: (data.type as MemoryType) ?? \"project\",\n scope: (data.scope as MemoryScope) ?? scope,\n description: data.description ?? \"\",\n body: body.trim(),\n createdAt: data.created ?? \"\",\n };\n const priority = coercePriority(data.priority);\n if (priority) entry.priority = priority;\n const expires = coerceExpires(data.expires);\n if (expires) entry.expires = expires;\n return entry;\n }\n\n /** Skips malformed files — index stays queryable even if one file is hand-edited into nonsense. */\n list(): MemoryEntry[] {\n const out: MemoryEntry[] = [];\n const scopes: MemoryScope[] = this.projectRoot ? [\"global\", \"project\"] : [\"global\"];\n for (const scope of scopes) {\n const dir = scopeDir({ homeDir: this.homeDir, scope, projectRoot: this.projectRoot });\n if (!existsSync(dir)) continue;\n let entries: string[];\n try {\n entries = readdirSync(dir);\n } catch {\n continue;\n }\n for (const entry of entries) {\n if (entry === MEMORY_INDEX_FILE) continue;\n if (!entry.endsWith(\".md\")) continue;\n const name = entry.slice(0, -3);\n try {\n out.push(this.read(scope, name));\n } catch {\n // malformed file — skip rather than fail the whole list\n }\n }\n }\n return out;\n }\n\n write(input: WriteInput): string {\n if (input.scope === \"project\" && !this.projectRoot) {\n throw new Error(\"cannot write project-scoped memory: no projectRoot configured\");\n }\n const name = sanitizeMemoryName(input.name);\n const desc = String(input.description ?? \"\").trim();\n if (!desc) throw new Error(\"memory description cannot be empty\");\n const body = String(input.body ?? \"\").trim();\n if (!body) throw new Error(\"memory body cannot be empty\");\n const entry: WriteInput & { createdAt: string } = {\n ...input,\n name,\n description: desc,\n body,\n createdAt: todayIso(),\n };\n if (input.priority) entry.priority = input.priority;\n if (input.expires) entry.expires = input.expires;\n const dir = this.dir(input.scope);\n const file = join(dir, `${name}.md`);\n const content = `${formatFrontmatter(entry)}${body}\\n`;\n writeFileSync(file, content, \"utf8\");\n this.regenerateIndex(input.scope);\n return file;\n }\n\n /** Delete one memory + its index line. No-op if the file is already gone. */\n delete(scope: MemoryScope, rawName: string): boolean {\n if (scope === \"project\" && !this.projectRoot) {\n throw new Error(\"cannot delete project-scoped memory: no projectRoot configured\");\n }\n const file = this.pathFor(scope, rawName);\n if (!existsSync(file)) return false;\n unlinkSync(file);\n this.regenerateIndex(scope);\n return true;\n }\n\n /** Sorted by name — same file set must produce byte-identical MEMORY.md for stable prefix hashing. */\n private regenerateIndex(scope: MemoryScope): void {\n const dir = scopeDir({ homeDir: this.homeDir, scope, projectRoot: this.projectRoot });\n if (!existsSync(dir)) return;\n let files: string[];\n try {\n files = readdirSync(dir);\n } catch {\n return;\n }\n const mdFiles = files\n .filter((f) => f !== MEMORY_INDEX_FILE && f.endsWith(\".md\"))\n .sort((a, b) => a.localeCompare(b));\n const indexPath = join(dir, MEMORY_INDEX_FILE);\n if (mdFiles.length === 0) {\n if (existsSync(indexPath)) unlinkSync(indexPath);\n return;\n }\n const lines: string[] = [];\n for (const f of mdFiles) {\n const name = f.slice(0, -3);\n try {\n const entry = this.read(scope, name);\n lines.push(indexLine({ name: entry.name || name, description: entry.description }));\n } catch {\n // Malformed: still surface it in the index so the user notices.\n lines.push(`- [${name}](${name}.md) — (malformed, check frontmatter)`);\n }\n }\n writeFileSync(indexPath, `${lines.join(\"\\n\")}\\n`, \"utf8\");\n }\n}\n\n/** Freeform `#g` destination, distinct from MEMORY.md's curated index of named files. */\nexport function readGlobalReasonixMemory(\n homeDir: string = join(homedir(), \".reasonix\"),\n): { path: string; content: string; originalChars: number; truncated: boolean } | null {\n const path = join(homeDir, \"REASONIX.md\");\n if (!existsSync(path)) return null;\n let raw: string;\n try {\n raw = readFileSync(path, \"utf8\");\n } catch {\n return null;\n }\n const trimmed = raw.trim();\n if (!trimmed) return null;\n const originalChars = trimmed.length;\n // Reuse the project-memory cap so both freeform files have the same\n // headroom (8000 chars ≈ 2k tokens). They serve the same purpose at\n // different scopes.\n const truncated = originalChars > 8000;\n const content = truncated\n ? `${trimmed.slice(0, 8000)}\\n… (truncated ${originalChars - 8000} chars)`\n : trimmed;\n return { path, content, originalChars, truncated };\n}\n\nexport function applyGlobalReasonixMemory(basePrompt: string, homeDir?: string): string {\n if (!memoryEnabled()) return basePrompt;\n const dir = homeDir ?? join(homedir(), \".reasonix\");\n const mem = readGlobalReasonixMemory(dir);\n if (!mem) return basePrompt;\n return [\n basePrompt,\n \"\",\n \"# Global memory (~/.reasonix/REASONIX.md)\",\n \"\",\n \"Cross-project notes the user pinned via the `#g` prompt prefix. Treat as authoritative — same level of trust as project memory.\",\n \"\",\n \"```\",\n mem.content,\n \"```\",\n ].join(\"\\n\");\n}\n\n/** Read ~/.claude/CLAUDE.md — cross-project notes from Claude Code migration.\n * Same cap as global Reasonix memory (8000 chars). */\nexport function readGlobalClaudeMemory(\n homeDir: string = homedir(),\n): { path: string; content: string; originalChars: number; truncated: boolean } | null {\n const path = join(homeDir, \".claude\", \"CLAUDE.md\");\n if (!existsSync(path)) return null;\n let raw: string;\n try {\n raw = readFileSync(path, \"utf8\");\n } catch {\n return null;\n }\n const trimmed = raw.trim();\n if (!trimmed) return null;\n const originalChars = trimmed.length;\n const truncated = originalChars > 8000;\n const content = truncated\n ? `${trimmed.slice(0, 8000)}\\n… (truncated ${originalChars - 8000} chars)`\n : trimmed;\n return { path, content, originalChars, truncated };\n}\n\nexport function applyGlobalClaudeMemory(basePrompt: string): string {\n if (!memoryEnabled()) return basePrompt;\n const mem = readGlobalClaudeMemory();\n if (!mem) return basePrompt;\n return [\n basePrompt,\n \"\",\n \"# Global memory (~/.claude/CLAUDE.md)\",\n \"\",\n \"Cross-project notes from your Claude Code configuration. Treat as authoritative — same level of trust as project memory.\",\n \"\",\n \"```\",\n mem.content,\n \"```\",\n ].join(\"\\n\");\n}\n\n/** Effective priority: entry's own field wins, else the config default for its type, else undefined. */\nexport function effectivePriority(\n entry: MemoryEntry,\n cfg?: ReasonixConfig,\n): MemoryPriority | undefined {\n if (entry.priority) return entry.priority;\n return memoryTypeDefaults(entry.type, cfg).priority;\n}\n\nfunction highPriorityBlock(entries: MemoryEntry[], cfg?: ReasonixConfig): string | null {\n const high = entries.filter((e) => effectivePriority(e, cfg) === \"high\");\n if (high.length === 0) return null;\n const lines: string[] = [\n \"# HIGH PRIORITY constraints (must observe)\",\n \"\",\n \"These memories were declared `priority: high` (via config.memory.customTypes or the memory file itself). Treat them as hard rules — violations override any other guidance below.\",\n \"\",\n ];\n for (const e of high) {\n const head = `!!! [${e.scope}/${e.type}/${e.name}] ${e.description || \"(no description)\"}`;\n lines.push(head);\n if (e.body) lines.push(\"\", e.body);\n lines.push(\"\");\n }\n return lines.join(\"\\n\").trimEnd();\n}\n\n/** Empty index → omit the whole block (otherwise we'd add bytes to the prefix hash for nothing). */\nexport function applyUserMemory(\n basePrompt: string,\n opts: { homeDir?: string; projectRoot?: string; cfg?: ReasonixConfig } = {},\n): string {\n if (!memoryEnabled()) return basePrompt;\n const store = new MemoryStore(opts);\n const global = store.loadIndex(\"global\");\n const project = store.hasProjectScope() ? store.loadIndex(\"project\") : null;\n const high = highPriorityBlock(store.list(), opts.cfg);\n if (!global && !project && !high) return basePrompt;\n const parts: string[] = [basePrompt];\n if (high) parts.push(\"\", high);\n if (global) {\n parts.push(\n \"\",\n \"# User memory — global (~/.reasonix/memory/global/MEMORY.md)\",\n \"\",\n \"Cross-project facts and preferences the user has told you in prior sessions. TREAT AS AUTHORITATIVE — don't re-verify via filesystem or web. One-liners index detail files; call `recall_memory` for full bodies only when the one-liner isn't enough.\",\n \"\",\n \"```\",\n global.content,\n \"```\",\n );\n }\n if (project) {\n parts.push(\n \"\",\n \"# User memory — this project\",\n \"\",\n \"Per-project facts the user established in prior sessions (not committed to the repo). TREAT AS AUTHORITATIVE. Same recall pattern as global memory.\",\n \"\",\n \"```\",\n project.content,\n \"```\",\n );\n }\n return parts.join(\"\\n\");\n}\n\nexport function applyMemoryStack(\n basePrompt: string,\n rootDir: string,\n opts: { homeDir?: string; cfg?: ReasonixConfig } = {},\n): string {\n const homeDir = opts.homeDir;\n const cfg = opts.cfg;\n const withProject = applyProjectMemory(basePrompt, rootDir);\n const withGlobal = applyGlobalReasonixMemory(\n withProject,\n homeDir ? join(homeDir, \".reasonix\") : undefined,\n );\n const withGlobalClaude = applyGlobalClaudeMemory(withGlobal);\n const withMemory = applyUserMemory(withGlobalClaude, { projectRoot: rootDir, homeDir, cfg });\n const customSkillPaths = cfg?.skills?.paths\n ? resolveSkillPaths(cfg.skills.paths, rootDir)\n : loadResolvedSkillPaths(rootDir);\n return applySkillsIndex(withMemory, { projectRoot: rootDir, homeDir, customSkillPaths });\n}\n"],"mappings":"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","names":["existsSync","readFileSync","statSync","join","join","existsSync","statSync","readFileSync","existsSync","mkdirSync","readFileSync","readdirSync","writeFileSync","homedir","join","resolve","resolve","join","existsSync","mkdirSync","homedir","readFileSync","readdirSync","writeFileSync"]}
|