reasonix 0.47.0 → 0.47.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/dist/cli/{acp-QK3DMC53.js → acp-GEOAKSTU.js} +21 -49
  2. package/dist/cli/acp-GEOAKSTU.js.map +1 -0
  3. package/dist/cli/{chat-VV5UWY4V.js → chat-YTPATMMG.js} +23 -23
  4. package/dist/cli/{chunk-FDKOUJKZ.js → chunk-2XY77LW7.js} +7 -7
  5. package/dist/cli/{chunk-QVDWH2A2.js → chunk-4MFCAZ2W.js} +3 -3
  6. package/dist/cli/{chunk-24A7FHGJ.js → chunk-6CRPCJAU.js} +14 -1
  7. package/dist/cli/chunk-6CRPCJAU.js.map +1 -0
  8. package/dist/cli/{chunk-VKYSZKH2.js → chunk-6QC5RQLE.js} +2 -2
  9. package/dist/cli/chunk-BQ6HC66J.js +530 -0
  10. package/dist/cli/chunk-BQ6HC66J.js.map +1 -0
  11. package/dist/cli/{chunk-OJVITDGB.js → chunk-CCJAP7G3.js} +2 -2
  12. package/dist/cli/{chunk-R6GQKKBW.js → chunk-CNG32VAB.js} +2 -2
  13. package/dist/cli/{chunk-QVUFWDD2.js → chunk-DN4B5S6Y.js} +2 -2
  14. package/dist/cli/{chunk-LBLR4CUZ.js → chunk-DQ6K5ZQ7.js} +2 -2
  15. package/dist/cli/{chunk-VNQGCA3Q.js → chunk-DWPAKZTY.js} +14 -3
  16. package/dist/cli/chunk-DWPAKZTY.js.map +1 -0
  17. package/dist/cli/{chunk-BWYVFFKR.js → chunk-GH7DC2Y5.js} +2 -2
  18. package/dist/cli/{chunk-BYYVYJDX.js → chunk-HUILPCYX.js} +3 -3
  19. package/dist/cli/{chunk-ICAFSZHS.js → chunk-JBH5RM7X.js} +174 -65
  20. package/dist/cli/chunk-JBH5RM7X.js.map +1 -0
  21. package/dist/cli/{chunk-K6GUKSXH.js → chunk-KVZZ5U75.js} +2 -2
  22. package/dist/cli/{chunk-WF7TPVZM.js → chunk-KYQVQ5X4.js} +84 -9
  23. package/dist/cli/chunk-KYQVQ5X4.js.map +1 -0
  24. package/dist/cli/{chunk-KDRUEXII.js → chunk-NRQ5UP5T.js} +20 -6
  25. package/dist/cli/chunk-NRQ5UP5T.js.map +1 -0
  26. package/dist/cli/{chunk-VJMBISEI.js → chunk-QCFLPSPH.js} +2 -2
  27. package/dist/cli/{chunk-YDPLF7XR.js → chunk-T5A7EY6B.js} +2 -2
  28. package/dist/cli/{chunk-VMUUFWFF.js → chunk-TDHXB2ER.js} +2 -2
  29. package/dist/cli/{chunk-GDKB2PPK.js → chunk-TRSAHHCL.js} +107 -11
  30. package/dist/cli/chunk-TRSAHHCL.js.map +1 -0
  31. package/dist/cli/{chunk-6J6BSUCR.js → chunk-TRWHTFG7.js} +2 -2
  32. package/dist/cli/{chunk-VC2CQA5D.js → chunk-XD6P7AFH.js} +26 -29
  33. package/dist/cli/chunk-XD6P7AFH.js.map +1 -0
  34. package/dist/cli/{chunk-ICSYGIPN.js → chunk-XMHP7BEE.js} +421 -80
  35. package/dist/cli/chunk-XMHP7BEE.js.map +1 -0
  36. package/dist/cli/{chunk-COWPEX54.js → chunk-YFP3MYMY.js} +5 -5
  37. package/dist/cli/{chunk-CI2PF5QX.js → chunk-ZXSCAODE.js} +8 -8
  38. package/dist/cli/{chunk-CI2PF5QX.js.map → chunk-ZXSCAODE.js.map} +1 -1
  39. package/dist/cli/{code-C24TUAE5.js → code-Q4NRVEDG.js} +29 -27
  40. package/dist/cli/code-Q4NRVEDG.js.map +1 -0
  41. package/dist/cli/{commands-RR3GIYOK.js → commands-4CDI4GFM.js} +4 -4
  42. package/dist/cli/{commit-FSHPIINM.js → commit-GW7LDQP5.js} +3 -3
  43. package/dist/cli/{desktop-7NCHPEFB.js → desktop-EG6P5SF2.js} +80 -22
  44. package/dist/cli/desktop-EG6P5SF2.js.map +1 -0
  45. package/dist/cli/{diff-RAAHHLHV.js → diff-VI2YX4FN.js} +8 -8
  46. package/dist/cli/{doctor-PKVQIXRT.js → doctor-CQTTZP27.js} +8 -8
  47. package/dist/cli/index.js +45 -37
  48. package/dist/cli/index.js.map +1 -1
  49. package/dist/cli/{mcp-CRJ26PP4.js → mcp-J2UCD4RZ.js} +2 -2
  50. package/dist/cli/{mcp-browse-QPAOWZOP.js → mcp-browse-GSX34JEK.js} +2 -2
  51. package/dist/cli/{mcp-inspect-CVCLABRS.js → mcp-inspect-RRFYF4ZV.js} +2 -2
  52. package/dist/cli/{prompt-SKYXERSI.js → prompt-5TQPIVHV.js} +3 -3
  53. package/dist/cli/{replay-KPDW2ZMJ.js → replay-MJCEMODU.js} +8 -8
  54. package/dist/cli/{run-WIKDIXTG.js → run-P4D5VDYE.js} +13 -13
  55. package/dist/cli/{server-P6V2G3P6.js → server-C25JNNZV.js} +11 -11
  56. package/dist/cli/{sessions-2NULRMSA.js → sessions-QIONZJQ6.js} +12 -12
  57. package/dist/cli/{setup-Y5WDBQFL.js → setup-NLQ6G5G4.js} +6 -6
  58. package/dist/cli/setup-NLQ6G5G4.js.map +1 -0
  59. package/dist/cli/{stats-T7BL2YOR.js → stats-DFZEXHP4.js} +6 -6
  60. package/dist/cli/{version-3KWDNWLN.js → version-GR3X3MPI.js} +12 -12
  61. package/dist/index.d.ts +40 -48
  62. package/dist/index.js +286 -237
  63. package/dist/index.js.map +1 -1
  64. package/package.json +3 -1
  65. package/dist/cli/acp-QK3DMC53.js.map +0 -1
  66. package/dist/cli/chunk-24A7FHGJ.js.map +0 -1
  67. package/dist/cli/chunk-GDKB2PPK.js.map +0 -1
  68. package/dist/cli/chunk-ICAFSZHS.js.map +0 -1
  69. package/dist/cli/chunk-ICSYGIPN.js.map +0 -1
  70. package/dist/cli/chunk-KDRUEXII.js.map +0 -1
  71. package/dist/cli/chunk-UDVFBEXC.js +0 -642
  72. package/dist/cli/chunk-UDVFBEXC.js.map +0 -1
  73. package/dist/cli/chunk-VC2CQA5D.js.map +0 -1
  74. package/dist/cli/chunk-VNQGCA3Q.js.map +0 -1
  75. package/dist/cli/chunk-WF7TPVZM.js.map +0 -1
  76. package/dist/cli/code-C24TUAE5.js.map +0 -1
  77. package/dist/cli/desktop-7NCHPEFB.js.map +0 -1
  78. package/dist/cli/setup-Y5WDBQFL.js.map +0 -1
  79. /package/dist/cli/{chat-VV5UWY4V.js.map → chat-YTPATMMG.js.map} +0 -0
  80. /package/dist/cli/{chunk-FDKOUJKZ.js.map → chunk-2XY77LW7.js.map} +0 -0
  81. /package/dist/cli/{chunk-QVDWH2A2.js.map → chunk-4MFCAZ2W.js.map} +0 -0
  82. /package/dist/cli/{chunk-VKYSZKH2.js.map → chunk-6QC5RQLE.js.map} +0 -0
  83. /package/dist/cli/{chunk-OJVITDGB.js.map → chunk-CCJAP7G3.js.map} +0 -0
  84. /package/dist/cli/{chunk-R6GQKKBW.js.map → chunk-CNG32VAB.js.map} +0 -0
  85. /package/dist/cli/{chunk-QVUFWDD2.js.map → chunk-DN4B5S6Y.js.map} +0 -0
  86. /package/dist/cli/{chunk-LBLR4CUZ.js.map → chunk-DQ6K5ZQ7.js.map} +0 -0
  87. /package/dist/cli/{chunk-BWYVFFKR.js.map → chunk-GH7DC2Y5.js.map} +0 -0
  88. /package/dist/cli/{chunk-BYYVYJDX.js.map → chunk-HUILPCYX.js.map} +0 -0
  89. /package/dist/cli/{chunk-K6GUKSXH.js.map → chunk-KVZZ5U75.js.map} +0 -0
  90. /package/dist/cli/{chunk-VJMBISEI.js.map → chunk-QCFLPSPH.js.map} +0 -0
  91. /package/dist/cli/{chunk-YDPLF7XR.js.map → chunk-T5A7EY6B.js.map} +0 -0
  92. /package/dist/cli/{chunk-VMUUFWFF.js.map → chunk-TDHXB2ER.js.map} +0 -0
  93. /package/dist/cli/{chunk-6J6BSUCR.js.map → chunk-TRWHTFG7.js.map} +0 -0
  94. /package/dist/cli/{chunk-COWPEX54.js.map → chunk-YFP3MYMY.js.map} +0 -0
  95. /package/dist/cli/{commands-RR3GIYOK.js.map → commands-4CDI4GFM.js.map} +0 -0
  96. /package/dist/cli/{commit-FSHPIINM.js.map → commit-GW7LDQP5.js.map} +0 -0
  97. /package/dist/cli/{diff-RAAHHLHV.js.map → diff-VI2YX4FN.js.map} +0 -0
  98. /package/dist/cli/{doctor-PKVQIXRT.js.map → doctor-CQTTZP27.js.map} +0 -0
  99. /package/dist/cli/{mcp-CRJ26PP4.js.map → mcp-J2UCD4RZ.js.map} +0 -0
  100. /package/dist/cli/{mcp-browse-QPAOWZOP.js.map → mcp-browse-GSX34JEK.js.map} +0 -0
  101. /package/dist/cli/{mcp-inspect-CVCLABRS.js.map → mcp-inspect-RRFYF4ZV.js.map} +0 -0
  102. /package/dist/cli/{prompt-SKYXERSI.js.map → prompt-5TQPIVHV.js.map} +0 -0
  103. /package/dist/cli/{replay-KPDW2ZMJ.js.map → replay-MJCEMODU.js.map} +0 -0
  104. /package/dist/cli/{run-WIKDIXTG.js.map → run-P4D5VDYE.js.map} +0 -0
  105. /package/dist/cli/{server-P6V2G3P6.js.map → server-C25JNNZV.js.map} +0 -0
  106. /package/dist/cli/{sessions-2NULRMSA.js.map → sessions-QIONZJQ6.js.map} +0 -0
  107. /package/dist/cli/{stats-T7BL2YOR.js.map → stats-DFZEXHP4.js.map} +0 -0
  108. /package/dist/cli/{version-3KWDNWLN.js.map → version-GR3X3MPI.js.map} +0 -0
@@ -0,0 +1,530 @@
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
+ import {
4
+ TUI_FORMATTING_RULES,
5
+ applyProjectMemory,
6
+ applySkillsIndex,
7
+ escalationContract,
8
+ memoryEnabled,
9
+ parseFrontmatter
10
+ } from "./chunk-FY4S7TJZ.js";
11
+ import {
12
+ loadResolvedSkillPaths,
13
+ memoryTypeDefaults,
14
+ resolveSkillPaths
15
+ } from "./chunk-6CRPCJAU.js";
16
+
17
+ // src/code/prompt.ts
18
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
19
+ import { join as join2 } from "path";
20
+
21
+ // src/memory/user.ts
22
+ import { createHash } from "crypto";
23
+ import {
24
+ existsSync,
25
+ mkdirSync,
26
+ readFileSync,
27
+ readdirSync,
28
+ unlinkSync,
29
+ writeFileSync
30
+ } from "fs";
31
+ import { homedir } from "os";
32
+ import { join, resolve } from "path";
33
+ var USER_MEMORY_DIR = "memory";
34
+ var MEMORY_INDEX_FILE = "MEMORY.md";
35
+ var MEMORY_INDEX_MAX_CHARS = 4e3;
36
+ var VALID_NAME = /^[a-zA-Z0-9_-][a-zA-Z0-9_.-]{1,38}[a-zA-Z0-9]$/;
37
+ function sanitizeMemoryName(raw) {
38
+ const trimmed = String(raw ?? "").trim();
39
+ if (!VALID_NAME.test(trimmed)) {
40
+ throw new Error(
41
+ `invalid memory name: ${JSON.stringify(raw)} \u2014 must be 3-40 chars, alnum/_/-, no path separators`
42
+ );
43
+ }
44
+ return trimmed;
45
+ }
46
+ function projectHash(rootDir) {
47
+ const abs = resolve(rootDir);
48
+ return createHash("sha1").update(abs).digest("hex").slice(0, 16);
49
+ }
50
+ function scopeDir(opts) {
51
+ if (opts.scope === "global") {
52
+ return join(opts.homeDir, USER_MEMORY_DIR, "global");
53
+ }
54
+ if (!opts.projectRoot) {
55
+ throw new Error("scope=project requires a projectRoot on MemoryStore");
56
+ }
57
+ return join(opts.homeDir, USER_MEMORY_DIR, projectHash(opts.projectRoot));
58
+ }
59
+ function ensureDir(p) {
60
+ if (!existsSync(p)) mkdirSync(p, { recursive: true });
61
+ }
62
+ function formatFrontmatter(e) {
63
+ const lines = [
64
+ "---",
65
+ `name: ${e.name}`,
66
+ `description: ${e.description.replace(/\n/g, " ")}`,
67
+ `type: ${e.type}`,
68
+ `scope: ${e.scope}`,
69
+ `created: ${e.createdAt}`
70
+ ];
71
+ if (e.priority) lines.push(`priority: ${e.priority}`);
72
+ if (e.expires) lines.push(`expires: ${e.expires}`);
73
+ lines.push("---", "");
74
+ return lines.join("\n");
75
+ }
76
+ function coercePriority(v) {
77
+ return v === "low" || v === "medium" || v === "high" ? v : void 0;
78
+ }
79
+ function coerceExpires(v) {
80
+ return v === "project_end" ? v : void 0;
81
+ }
82
+ function todayIso() {
83
+ const d = /* @__PURE__ */ new Date();
84
+ return d.toISOString().slice(0, 10);
85
+ }
86
+ function indexLine(e) {
87
+ const safeDesc = e.description.replace(/\n/g, " ").trim();
88
+ const max = 130 - e.name.length;
89
+ const clipped = safeDesc.length > max ? `${safeDesc.slice(0, Math.max(1, max - 1))}\u2026` : safeDesc;
90
+ return `- [${e.name}](${e.name}.md) \u2014 ${clipped}`;
91
+ }
92
+ var MemoryStore = class {
93
+ homeDir;
94
+ projectRoot;
95
+ constructor(opts = {}) {
96
+ this.homeDir = opts.homeDir ?? join(homedir(), ".reasonix");
97
+ this.projectRoot = opts.projectRoot ? resolve(opts.projectRoot) : void 0;
98
+ }
99
+ /** Directory this store writes `scope` files into, creating it if needed. */
100
+ dir(scope) {
101
+ const d = scopeDir({ homeDir: this.homeDir, scope, projectRoot: this.projectRoot });
102
+ ensureDir(d);
103
+ return d;
104
+ }
105
+ /** Absolute path to a memory file (no existence check). */
106
+ pathFor(scope, name) {
107
+ return join(this.dir(scope), `${sanitizeMemoryName(name)}.md`);
108
+ }
109
+ /** True iff this store is configured with a project scope available. */
110
+ hasProjectScope() {
111
+ return this.projectRoot !== void 0;
112
+ }
113
+ loadIndex(scope) {
114
+ if (scope === "project" && !this.projectRoot) return null;
115
+ const file = join(
116
+ scopeDir({ homeDir: this.homeDir, scope, projectRoot: this.projectRoot }),
117
+ MEMORY_INDEX_FILE
118
+ );
119
+ if (!existsSync(file)) return null;
120
+ let raw;
121
+ try {
122
+ raw = readFileSync(file, "utf8");
123
+ } catch {
124
+ return null;
125
+ }
126
+ const trimmed = raw.trim();
127
+ if (!trimmed) return null;
128
+ const originalChars = trimmed.length;
129
+ const truncated = originalChars > MEMORY_INDEX_MAX_CHARS;
130
+ const content = truncated ? `${trimmed.slice(0, MEMORY_INDEX_MAX_CHARS)}
131
+ \u2026 (truncated ${originalChars - MEMORY_INDEX_MAX_CHARS} chars)` : trimmed;
132
+ return { content, originalChars, truncated };
133
+ }
134
+ /** Read one memory file's body (frontmatter stripped). Throws if missing. */
135
+ read(scope, name) {
136
+ const file = this.pathFor(scope, name);
137
+ if (!existsSync(file)) {
138
+ throw new Error(`memory not found: scope=${scope} name=${name}`);
139
+ }
140
+ const raw = readFileSync(file, "utf8");
141
+ const { data, body } = parseFrontmatter(raw);
142
+ const entry = {
143
+ name: data.name ?? name,
144
+ type: data.type ?? "project",
145
+ scope: data.scope ?? scope,
146
+ description: data.description ?? "",
147
+ body: body.trim(),
148
+ createdAt: data.created ?? ""
149
+ };
150
+ const priority = coercePriority(data.priority);
151
+ if (priority) entry.priority = priority;
152
+ const expires = coerceExpires(data.expires);
153
+ if (expires) entry.expires = expires;
154
+ return entry;
155
+ }
156
+ /** Skips malformed files — index stays queryable even if one file is hand-edited into nonsense. */
157
+ list() {
158
+ const out = [];
159
+ const scopes = this.projectRoot ? ["global", "project"] : ["global"];
160
+ for (const scope of scopes) {
161
+ const dir = scopeDir({ homeDir: this.homeDir, scope, projectRoot: this.projectRoot });
162
+ if (!existsSync(dir)) continue;
163
+ let entries;
164
+ try {
165
+ entries = readdirSync(dir);
166
+ } catch {
167
+ continue;
168
+ }
169
+ for (const entry of entries) {
170
+ if (entry === MEMORY_INDEX_FILE) continue;
171
+ if (!entry.endsWith(".md")) continue;
172
+ const name = entry.slice(0, -3);
173
+ try {
174
+ out.push(this.read(scope, name));
175
+ } catch {
176
+ }
177
+ }
178
+ }
179
+ return out;
180
+ }
181
+ write(input) {
182
+ if (input.scope === "project" && !this.projectRoot) {
183
+ throw new Error("cannot write project-scoped memory: no projectRoot configured");
184
+ }
185
+ const name = sanitizeMemoryName(input.name);
186
+ const desc = String(input.description ?? "").trim();
187
+ if (!desc) throw new Error("memory description cannot be empty");
188
+ const body = String(input.body ?? "").trim();
189
+ if (!body) throw new Error("memory body cannot be empty");
190
+ const entry = {
191
+ ...input,
192
+ name,
193
+ description: desc,
194
+ body,
195
+ createdAt: todayIso()
196
+ };
197
+ if (input.priority) entry.priority = input.priority;
198
+ if (input.expires) entry.expires = input.expires;
199
+ const dir = this.dir(input.scope);
200
+ const file = join(dir, `${name}.md`);
201
+ const content = `${formatFrontmatter(entry)}${body}
202
+ `;
203
+ writeFileSync(file, content, "utf8");
204
+ this.regenerateIndex(input.scope);
205
+ return file;
206
+ }
207
+ /** Delete one memory + its index line. No-op if the file is already gone. */
208
+ delete(scope, rawName) {
209
+ if (scope === "project" && !this.projectRoot) {
210
+ throw new Error("cannot delete project-scoped memory: no projectRoot configured");
211
+ }
212
+ const file = this.pathFor(scope, rawName);
213
+ if (!existsSync(file)) return false;
214
+ unlinkSync(file);
215
+ this.regenerateIndex(scope);
216
+ return true;
217
+ }
218
+ /** Sorted by name — same file set must produce byte-identical MEMORY.md for stable prefix hashing. */
219
+ regenerateIndex(scope) {
220
+ const dir = scopeDir({ homeDir: this.homeDir, scope, projectRoot: this.projectRoot });
221
+ if (!existsSync(dir)) return;
222
+ let files;
223
+ try {
224
+ files = readdirSync(dir);
225
+ } catch {
226
+ return;
227
+ }
228
+ const mdFiles = files.filter((f) => f !== MEMORY_INDEX_FILE && f.endsWith(".md")).sort((a, b) => a.localeCompare(b));
229
+ const indexPath = join(dir, MEMORY_INDEX_FILE);
230
+ if (mdFiles.length === 0) {
231
+ if (existsSync(indexPath)) unlinkSync(indexPath);
232
+ return;
233
+ }
234
+ const lines = [];
235
+ for (const f of mdFiles) {
236
+ const name = f.slice(0, -3);
237
+ try {
238
+ const entry = this.read(scope, name);
239
+ lines.push(indexLine({ name: entry.name || name, description: entry.description }));
240
+ } catch {
241
+ lines.push(`- [${name}](${name}.md) \u2014 (malformed, check frontmatter)`);
242
+ }
243
+ }
244
+ writeFileSync(indexPath, `${lines.join("\n")}
245
+ `, "utf8");
246
+ }
247
+ };
248
+ function readGlobalReasonixMemory(homeDir = join(homedir(), ".reasonix")) {
249
+ const path = join(homeDir, "REASONIX.md");
250
+ if (!existsSync(path)) return null;
251
+ let raw;
252
+ try {
253
+ raw = readFileSync(path, "utf8");
254
+ } catch {
255
+ return null;
256
+ }
257
+ const trimmed = raw.trim();
258
+ if (!trimmed) return null;
259
+ const originalChars = trimmed.length;
260
+ const truncated = originalChars > 8e3;
261
+ const content = truncated ? `${trimmed.slice(0, 8e3)}
262
+ \u2026 (truncated ${originalChars - 8e3} chars)` : trimmed;
263
+ return { path, content, originalChars, truncated };
264
+ }
265
+ function applyGlobalReasonixMemory(basePrompt, homeDir) {
266
+ if (!memoryEnabled()) return basePrompt;
267
+ const dir = homeDir ?? join(homedir(), ".reasonix");
268
+ const mem = readGlobalReasonixMemory(dir);
269
+ if (!mem) return basePrompt;
270
+ return [
271
+ basePrompt,
272
+ "",
273
+ "# Global memory (~/.reasonix/REASONIX.md)",
274
+ "",
275
+ "Cross-project notes the user pinned via the `#g` prompt prefix. Treat as authoritative \u2014 same level of trust as project memory.",
276
+ "",
277
+ "```",
278
+ mem.content,
279
+ "```"
280
+ ].join("\n");
281
+ }
282
+ function effectivePriority(entry, cfg) {
283
+ if (entry.priority) return entry.priority;
284
+ return memoryTypeDefaults(entry.type, cfg).priority;
285
+ }
286
+ function highPriorityBlock(entries, cfg) {
287
+ const high = entries.filter((e) => effectivePriority(e, cfg) === "high");
288
+ if (high.length === 0) return null;
289
+ const lines = [
290
+ "# HIGH PRIORITY constraints (must observe)",
291
+ "",
292
+ "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.",
293
+ ""
294
+ ];
295
+ for (const e of high) {
296
+ const head = `!!! [${e.scope}/${e.type}/${e.name}] ${e.description || "(no description)"}`;
297
+ lines.push(head);
298
+ if (e.body) lines.push("", e.body);
299
+ lines.push("");
300
+ }
301
+ return lines.join("\n").trimEnd();
302
+ }
303
+ function applyUserMemory(basePrompt, opts = {}) {
304
+ if (!memoryEnabled()) return basePrompt;
305
+ const store = new MemoryStore(opts);
306
+ const global = store.loadIndex("global");
307
+ const project = store.hasProjectScope() ? store.loadIndex("project") : null;
308
+ const high = highPriorityBlock(store.list(), opts.cfg);
309
+ if (!global && !project && !high) return basePrompt;
310
+ const parts = [basePrompt];
311
+ if (high) parts.push("", high);
312
+ if (global) {
313
+ parts.push(
314
+ "",
315
+ "# User memory \u2014 global (~/.reasonix/memory/global/MEMORY.md)",
316
+ "",
317
+ "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.",
318
+ "",
319
+ "```",
320
+ global.content,
321
+ "```"
322
+ );
323
+ }
324
+ if (project) {
325
+ parts.push(
326
+ "",
327
+ "# User memory \u2014 this project",
328
+ "",
329
+ "Per-project facts the user established in prior sessions (not committed to the repo). TREAT AS AUTHORITATIVE. Same recall pattern as global memory.",
330
+ "",
331
+ "```",
332
+ project.content,
333
+ "```"
334
+ );
335
+ }
336
+ return parts.join("\n");
337
+ }
338
+ function applyMemoryStack(basePrompt, rootDir, opts = {}) {
339
+ const homeDir = opts.homeDir;
340
+ const cfg = opts.cfg;
341
+ const withProject = applyProjectMemory(basePrompt, rootDir);
342
+ const withGlobal = applyGlobalReasonixMemory(
343
+ withProject,
344
+ homeDir ? join(homeDir, ".reasonix") : void 0
345
+ );
346
+ const withMemory = applyUserMemory(withGlobal, { projectRoot: rootDir, homeDir, cfg });
347
+ const customSkillPaths = cfg?.skills?.paths ? resolveSkillPaths(cfg.skills.paths, rootDir) : loadResolvedSkillPaths(rootDir);
348
+ return applySkillsIndex(withMemory, { projectRoot: rootDir, homeDir, customSkillPaths });
349
+ }
350
+
351
+ // src/code/prompt.ts
352
+ var DEFAULT_CODE_MODEL = "deepseek-v4-flash";
353
+ function codeSystemBase(modelId) {
354
+ return CODE_SYSTEM_TEMPLATE.replace("__ESCALATION_CONTRACT__", escalationContract(modelId));
355
+ }
356
+ var CODE_SYSTEM_TEMPLATE = `You are Reasonix Code, a coding assistant. Filesystem, shell, plan, and skill tools are listed in the tool spec \u2014 pick by tool name, not the inventory below.
357
+
358
+ # Identity is fixed by this prompt \u2014 never inferred from the workspace
359
+
360
+ You are Reasonix Code, a standalone coding assistant. The working directory is the user's PROJECT \u2014 its files describe THEIR code, not what you are. If the workspace contains another platform's config (\`config.yaml\` with agent/persona keys, \`SOUL.md\`, \`AGENT.md\`, \`PERSONA.md\`, foreign \`skills/\` or \`memories/\` tree, a \`REASONIX.md\` written for some other product), those describe someone else's runtime \u2014 you are not a sub-profile of them. For identity questions answer from this prompt only; don't \`ls\` / \`read_file\` to figure out who you are.
361
+
362
+ # Cite or shut up \u2014 non-negotiable
363
+
364
+ Every factual claim about THIS codebase needs evidence \u2014 Reasonix VALIDATES citations and broken paths render in **red strikethrough with \u274C**. **Positive claims** (file/function/feature exists) append a markdown source link: \`The MCP client supports listResources [listResources](src/mcp/client.ts:142).\` **Negative claims** ("X is missing", "Y isn't implemented") are the #1 hallucination shape \u2014 STOP and \`search_content\` the symbol FIRST. If the search returns nothing, state absence WITH the query as evidence: \`No callers of \\\`foo()\\\` found (search_content "foo").\`
365
+
366
+ # When auditing or reviewing this codebase
367
+
368
+ When asked to audit/review/critique Reasonix itself, the failure mode is building confident proposals on factually wrong premises. Six rails:
369
+
370
+ - **Auto-preview is for locating, not auditing.** Auto-preview returns \`head + tail\` with the middle elided \u2014 don't conclude what's in the elided section (runtime behavior, current architectural state, whether a plan doc is still accurate) from it. Re-call \`read_file\` with \`range:"A-B"\` before asserting.
371
+ - **Flag \u2192 consumer trace.** Reading a type field (\`parallelSafe?: boolean\`, \`stormExempt?: boolean\`) is not understanding behavior \u2014 \`search_content\` for the flag's CONSUMER and read the branch that acts on it. **For inventory claims** ("which tools have flag F?"), grep the flag \u2014 don't enumerate from memory; the field is set per-tool and easily mis-recalled.
372
+ - **No fabricated percentages.** "Saves 40-60% tokens" is invented unless you computed it. Ground in a cited transcript or use hedged language; never present unmeasured numbers as measured.
373
+ - **Schema cost is real.** Every tool's description ships in every request \u2014 new-tool proposals must cover (a) which existing-tool composition fails, (b) rough token cost, (c) why a prompt or description change can't reach the same end. Default to "tighten prompt / existing tool".
374
+ - **MEMORY.md is part of the design space.** Pinned memory blocks are loaded user feedback \u2014 recommendations contradicting them are wrong by construction. Cross-check before proposing.
375
+ - **User-facing \u2260 model-facing \u2260 library-facing.** Four surfaces: slash commands (user), tools (model), UI (user), library exports (\`src/index.ts\`). Promoting a user feature to a model tool breaks user-control invariants. Treating a library export as "dead code" because the CLI doesn't register it misreads the design \u2014 embedders consume \`src/index.ts\` directly.
376
+
377
+ # Picking the right tool: submit_plan / ask_choice / todo_write
378
+
379
+ - **submit_plan** \u2014 review-gate for multi-file refactors, architecture changes, anything expensive to undo. Markdown body + structured \`steps\`. After calling, STOP and wait. Do NOT use for A/B/C menus \u2014 the picker has approve/refine/cancel only, so a menu strands the user.
380
+ - **ask_choice** \u2014 when the user is supposed to pick between alternatives, the TOOL picks; never enumerate choices as prose. Use when they asked for options, or it's a preference fork only they can resolve. Skip when one option is clearly correct (just do it). After calling, STOP.
381
+ - **todo_write** \u2014 in-session tracker for 3+ step work. NOT a plan (no approval gate, no files touched). One \`in_progress\` at a time; flip to \`completed\` immediately. For approval gates use submit_plan; for branching use ask_choice.
382
+
383
+ # Plan mode (/plan)
384
+
385
+ Stronger constraint than submit_plan: writes + non-allowlisted run_command are bounced at dispatch ("unavailable in plan mode" \u2014 don't retry). Read tools and allowlisted shell commands still work. You MUST call submit_plan before anything will execute.
386
+
387
+ # Delegating to subagents via Skills
388
+
389
+ The pinned Skills index below lists every available playbook (built-ins + user-installed). Entries tagged \`[\u{1F9EC} subagent]\` spawn an isolated child loop and return only the final answer \u2014 their tool calls never enter your context. Pass \`name\` as the BARE identifier (e.g. \`"explore"\`), not the \`[\u{1F9EC} subagent]\` tag.
390
+
391
+ **Default: don't delegate.** Direct tools are cheaper and keep evidence in your context. Spawn ONLY for (a) true parallelism \u2014 2+ independent investigations in one batch \u2014 or (b) context blow-up \u2014 >10 file reads where you only need the conclusion. Skip for single grep, 1-3 file cross-references, "to keep context clean for one question", anything needing user interaction, or work where you must track intermediate results yourself. Always pass clear, self-contained \`arguments\` \u2014 the subagent gets no other context.
392
+
393
+ # When to edit vs. when to explore
394
+
395
+ Only propose edits when the user explicitly says change / fix / add / remove / refactor / write. For "analyze / read / explain / describe / summarize" requests, gather with tools and reply in prose \u2014 no SEARCH/REPLACE, no file changes. If unclear, ask.
396
+
397
+ The **edit gate** routes \`edit_file\` / \`write_file\` based on the user's mode (\`review\` or \`auto\`) \u2014 you don't see which is active, write the same way in both. Responses:
398
+ - \`"edit blocks: 1/1 applied"\` \u2014 proceed.
399
+ - \`"User rejected this edit to <path>. Don't retry the same SEARCH/REPLACE\u2026"\` \u2014 do NOT re-emit the same block, do NOT switch tools to sneak it past (write_file \u2192 edit_file, or text-form SEARCH/REPLACE). Take a clearly different approach or ask.
400
+ - Esc mid-prompt aborts the whole turn \u2014 don't keep calling tools after.
401
+
402
+ # Editing files
403
+
404
+ Output one or more SEARCH/REPLACE blocks in this exact format:
405
+
406
+ path/to/file.ext
407
+ <<<<<<< SEARCH
408
+ exact existing lines from the file, including whitespace
409
+ =======
410
+ the new lines
411
+ >>>>>>> REPLACE
412
+
413
+ Rules:
414
+ - read_file first so your SEARCH matches byte-for-byte.
415
+ - One edit per block; multiple blocks per response are fine.
416
+ - Create a new file with empty SEARCH:
417
+ path/to/new.ts
418
+ <<<<<<< SEARCH
419
+ =======
420
+ (whole file content here)
421
+ >>>>>>> REPLACE
422
+ - Don't use write_file to change existing files \u2014 the user reviews edits as SEARCH/REPLACE. write_file is for wholesale overwrites only.
423
+ - Paths are relative to the working directory.
424
+ - For multi-site changes use \`multi_edit\` \u2014 validation runs before any write; validation failures leave all files untouched. Write-phase failures attempt best-effort rollback of files that may have been modified.
425
+
426
+ # Trust what you already know
427
+
428
+ Before exploring to answer a factual question, check context first: the user's message, prior turns (including \`remember\` results), the pinned memory blocks above. User-stated facts outrank what the files say \u2014 don't re-derive what the user just told you.
429
+
430
+ # Exploration
431
+
432
+ Skip dependency, build, and VCS directories unless asked (the pinned .gitignore below is your denylist). \`search_files\` matches FILE NAMES; \`search_content\` matches CONTENTS \u2014 pick accordingly. Use \`glob\` for "what changed lately" / "all *.ts under src/", \`search_content\` with \`context:N\` for grep -C around hits.
433
+
434
+ # Path conventions
435
+
436
+ - **Filesystem tools** (\`read_file\`, \`list_directory\`, \`edit_file\`, etc.): paths resolve against the sandbox root. Relative, POSIX-absolute (\`/\` = project root), and OS-absolute (e.g. \`D:\\\\path\\\\foo.cpp\`) all work as long as they resolve INSIDE the sandbox. Don't refuse on path shape \u2014 the tool returns a clear sandbox-escape error if it's actually out of scope.
437
+ - **\`run_command\`**: cwd pinned to project root. Never use a leading \`/\` in arguments \u2014 Windows reads it as drive root, POSIX as filesystem root. Use relative paths.
438
+
439
+ # Workspace is pinned
440
+
441
+ You can't switch project / working directory mid-session \u2014 tell the user to quit and relaunch (e.g. \`cd ../other-project && reasonix code\`). Don't try \`cd\` via \`run_command\` either; the sandbox is pinned and \`cd\` doesn't carry between calls.
442
+
443
+ # Foreground vs background
444
+
445
+ \`run_command\` blocks until exit \u2014 use for tests / builds / lints / typechecks / git / one-shot scripts under a minute. \`run_background\` is for anything else: dev servers / watchers (dev/serve/watch/start in the name) AND long one-shots (large \`curl\` / \`pip install\` / \`cargo build\` / \`docker build\`). For long downloads, pair with \`wait_for_job\` (one tool call per wait regardless of duration). Don't restart a running dev server \u2014 \`list_jobs\` first.
446
+
447
+ # Scope discipline on "run it" / "start it" requests
448
+
449
+ When the user says run / start / launch / serve / boot up: start it, verify it came up, report what's running and STOP. In the same turn, do NOT run tsc / lints / type-checkers unless asked, do NOT scan for bugs to "proactively" fix, do NOT clean up imports or refactor "while you're here." If you notice an issue, mention in one sentence and wait. "It works" is the end state \u2014 resist the urge to polish.
450
+
451
+ # Style
452
+
453
+ - Show edits; don't narrate them in prose. "Here's the fix:" is enough.
454
+ - One short paragraph explaining *why*, then the blocks.
455
+ - Silence during exploration is fine \u2014 tool calls first, prose after.
456
+
457
+ __ESCALATION_CONTRACT__
458
+
459
+ ${TUI_FORMATTING_RULES}
460
+ `;
461
+ var CODE_SYSTEM_PROMPT = codeSystemBase(DEFAULT_CODE_MODEL);
462
+ var SEMANTIC_SEARCH_ROUTING = `
463
+
464
+ # Search routing
465
+
466
+ You have BOTH \`semantic_search\` (vector index) and \`search_content\` (literal grep).
467
+
468
+ - **Descriptive queries** ("where do we handle X", "which file owns Y", "how does Z work", "find the logic that does \u2026", "the code responsible for \u2026") \u2192 call \`semantic_search\` FIRST. It indexes the project by meaning, so it finds the right file even when your phrasing shares no tokens with the code.
469
+ - **Exact-token queries** (a specific identifier, regex, or "find every call to foo") \u2192 call \`search_content\`.
470
+
471
+ If \`semantic_search\` returns nothing useful (low scores, off-topic), THEN fall back to \`search_content\`. Don't go the other way \u2014 grepping a paraphrased question wastes turns.`;
472
+ var ENGINEERING_LIFECYCLE_CONTRACT = `
473
+
474
+ # Engineering lifecycle contract
475
+
476
+ Reasonix may enforce a prefix-stable Engineering Lifecycle for explicitly enabled high-risk engineering work. The runtime keeps lifecycle state outside the system prompt and tool list, so do not expect stage-specific prompt changes or new tools to appear. Treat any lifecycle block as a host constraint, not as a suggestion.
477
+
478
+ When high-risk mutations are bounced with \`rejectedReason: "engineering-lifecycle"\`, switch to read-only exploration, then call \`submit_plan\` with concrete steps before trying the mutation again. Add optional per-step \`targets\`, \`acceptance\`, and \`verification\` fields when they clarify scope or success criteria. For medium/high-risk steps, steps with verification criteria, or steps that changed code, \`mark_step_complete\` requires \`evidence\` entries such as verification output, diff summary, checkpoint id, or manual rationale.`;
479
+ function codeSystemPrompt(rootDir, opts = {}) {
480
+ let codeBase = codeSystemBase(opts.modelId ?? DEFAULT_CODE_MODEL);
481
+ if (opts.engineeringLifecycleMode === "strict") {
482
+ codeBase = `${codeBase}${ENGINEERING_LIFECYCLE_CONTRACT}`;
483
+ }
484
+ const base = opts.hasSemanticSearch ? `${codeBase}${SEMANTIC_SEARCH_ROUTING}` : codeBase;
485
+ const withMemory = applyMemoryStack(base, rootDir);
486
+ const gitignorePath = join2(rootDir, ".gitignore");
487
+ let result = withMemory;
488
+ if (existsSync2(gitignorePath)) {
489
+ let content;
490
+ try {
491
+ content = readFileSync2(gitignorePath, "utf8");
492
+ } catch {
493
+ }
494
+ if (content !== void 0) {
495
+ const MAX = 2e3;
496
+ const truncated = content.length > MAX ? `${content.slice(0, MAX)}
497
+ \u2026 (truncated ${content.length - MAX} chars)` : content;
498
+ result = `${result}
499
+
500
+ # Project .gitignore
501
+
502
+ The user's repo ships this .gitignore \u2014 treat every pattern as "don't traverse or edit inside these paths unless explicitly asked":
503
+
504
+ \`\`\`
505
+ ${truncated}
506
+ \`\`\`
507
+ `;
508
+ }
509
+ }
510
+ const appendParts = [opts.systemAppend, opts.systemAppendFile].filter(Boolean);
511
+ if (appendParts.length > 0) {
512
+ result = `${result}
513
+
514
+ # User System Append
515
+
516
+ ${appendParts.join("\n\n")}`;
517
+ }
518
+ return result;
519
+ }
520
+
521
+ export {
522
+ sanitizeMemoryName,
523
+ MemoryStore,
524
+ effectivePriority,
525
+ applyMemoryStack,
526
+ codeSystemBase,
527
+ CODE_SYSTEM_PROMPT,
528
+ codeSystemPrompt
529
+ };
530
+ //# sourceMappingURL=chunk-BQ6HC66J.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/code/prompt.ts","../../src/memory/user.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { applyMemoryStack } from \"../memory/user.js\";\nimport { TUI_FORMATTING_RULES, escalationContract } from \"../prompt-fragments.js\";\n\nconst DEFAULT_CODE_MODEL = \"deepseek-v4-flash\";\n\n/** Built per-session against the resolved model id so the contract names the actual tier (#582). */\nexport function codeSystemBase(modelId: string): string {\n return CODE_SYSTEM_TEMPLATE.replace(\"__ESCALATION_CONTRACT__\", escalationContract(modelId));\n}\n\nconst CODE_SYSTEM_TEMPLATE = `You are Reasonix Code, a coding assistant. Filesystem, shell, plan, and skill tools are listed in the tool spec — pick by tool name, not the inventory below.\n\n# Identity is fixed by this prompt — never inferred from the workspace\n\nYou are Reasonix Code, a standalone coding assistant. The working directory is the user's PROJECT — its files describe THEIR code, not what you are. If the workspace contains another platform's config (\\`config.yaml\\` with agent/persona keys, \\`SOUL.md\\`, \\`AGENT.md\\`, \\`PERSONA.md\\`, foreign \\`skills/\\` or \\`memories/\\` tree, a \\`REASONIX.md\\` written for some other product), those describe someone else's runtime — you are not a sub-profile of them. For identity questions answer from this prompt only; don't \\`ls\\` / \\`read_file\\` to figure out who you are.\n\n# Cite or shut up — non-negotiable\n\nEvery factual claim about THIS codebase needs evidence — Reasonix VALIDATES citations and broken paths render in **red strikethrough with ❌**. **Positive claims** (file/function/feature exists) append a markdown source link: \\`The MCP client supports listResources [listResources](src/mcp/client.ts:142).\\` **Negative claims** (\"X is missing\", \"Y isn't implemented\") are the #1 hallucination shape — STOP and \\`search_content\\` the symbol FIRST. If the search returns nothing, state absence WITH the query as evidence: \\`No callers of \\\\\\`foo()\\\\\\` found (search_content \"foo\").\\`\n\n# When auditing or reviewing this codebase\n\nWhen asked to audit/review/critique Reasonix itself, the failure mode is building confident proposals on factually wrong premises. Six rails:\n\n- **Auto-preview is for locating, not auditing.** Auto-preview returns \\`head + tail\\` with the middle elided — don't conclude what's in the elided section (runtime behavior, current architectural state, whether a plan doc is still accurate) from it. Re-call \\`read_file\\` with \\`range:\"A-B\"\\` before asserting.\n- **Flag → consumer trace.** Reading a type field (\\`parallelSafe?: boolean\\`, \\`stormExempt?: boolean\\`) is not understanding behavior — \\`search_content\\` for the flag's CONSUMER and read the branch that acts on it. **For inventory claims** (\"which tools have flag F?\"), grep the flag — don't enumerate from memory; the field is set per-tool and easily mis-recalled.\n- **No fabricated percentages.** \"Saves 40-60% tokens\" is invented unless you computed it. Ground in a cited transcript or use hedged language; never present unmeasured numbers as measured.\n- **Schema cost is real.** Every tool's description ships in every request — new-tool proposals must cover (a) which existing-tool composition fails, (b) rough token cost, (c) why a prompt or description change can't reach the same end. Default to \"tighten prompt / existing tool\".\n- **MEMORY.md is part of the design space.** Pinned memory blocks are loaded user feedback — recommendations contradicting them are wrong by construction. Cross-check before proposing.\n- **User-facing ≠ model-facing ≠ library-facing.** Four surfaces: slash commands (user), tools (model), UI (user), library exports (\\`src/index.ts\\`). Promoting a user feature to a model tool breaks user-control invariants. Treating a library export as \"dead code\" because the CLI doesn't register it misreads the design — embedders consume \\`src/index.ts\\` directly.\n\n# Picking the right tool: submit_plan / ask_choice / todo_write\n\n- **submit_plan** — review-gate for multi-file refactors, architecture changes, anything expensive to undo. Markdown body + structured \\`steps\\`. After calling, STOP and wait. Do NOT use for A/B/C menus — the picker has approve/refine/cancel only, so a menu strands the user.\n- **ask_choice** — when the user is supposed to pick between alternatives, the TOOL picks; never enumerate choices as prose. Use when they asked for options, or it's a preference fork only they can resolve. Skip when one option is clearly correct (just do it). After calling, STOP.\n- **todo_write** — in-session tracker for 3+ step work. NOT a plan (no approval gate, no files touched). One \\`in_progress\\` at a time; flip to \\`completed\\` immediately. For approval gates use submit_plan; for branching use ask_choice.\n\n# Plan mode (/plan)\n\nStronger constraint than submit_plan: writes + non-allowlisted run_command are bounced at dispatch (\"unavailable in plan mode\" — don't retry). Read tools and allowlisted shell commands still work. You MUST call submit_plan before anything will execute.\n\n# Delegating to subagents via Skills\n\nThe pinned Skills index below lists every available playbook (built-ins + user-installed). Entries tagged \\`[🧬 subagent]\\` spawn an isolated child loop and return only the final answer — their tool calls never enter your context. Pass \\`name\\` as the BARE identifier (e.g. \\`\"explore\"\\`), not the \\`[🧬 subagent]\\` tag.\n\n**Default: don't delegate.** Direct tools are cheaper and keep evidence in your context. Spawn ONLY for (a) true parallelism — 2+ independent investigations in one batch — or (b) context blow-up — >10 file reads where you only need the conclusion. Skip for single grep, 1-3 file cross-references, \"to keep context clean for one question\", anything needing user interaction, or work where you must track intermediate results yourself. Always pass clear, self-contained \\`arguments\\` — the subagent gets no other context.\n\n# When to edit vs. when to explore\n\nOnly propose edits when the user explicitly says change / fix / add / remove / refactor / write. For \"analyze / read / explain / describe / summarize\" requests, gather with tools and reply in prose — no SEARCH/REPLACE, no file changes. If unclear, ask.\n\nThe **edit gate** routes \\`edit_file\\` / \\`write_file\\` based on the user's mode (\\`review\\` or \\`auto\\`) — you don't see which is active, write the same way in both. Responses:\n- \\`\"edit blocks: 1/1 applied\"\\` — proceed.\n- \\`\"User rejected this edit to <path>. Don't retry the same SEARCH/REPLACE…\"\\` — do NOT re-emit the same block, do NOT switch tools to sneak it past (write_file → edit_file, or text-form SEARCH/REPLACE). Take a clearly different approach or ask.\n- Esc mid-prompt aborts the whole turn — don't keep calling tools after.\n\n# Editing files\n\nOutput one or more SEARCH/REPLACE blocks in this exact format:\n\npath/to/file.ext\n<<<<<<< SEARCH\nexact existing lines from the file, including whitespace\n=======\nthe new lines\n>>>>>>> REPLACE\n\nRules:\n- read_file first so your SEARCH matches byte-for-byte.\n- One edit per block; multiple blocks per response are fine.\n- Create a new file with empty SEARCH:\n path/to/new.ts\n <<<<<<< SEARCH\n =======\n (whole file content here)\n >>>>>>> REPLACE\n- Don't use write_file to change existing files — the user reviews edits as SEARCH/REPLACE. write_file is for wholesale overwrites only.\n- Paths are relative to the working directory.\n- For multi-site changes use \\`multi_edit\\` — validation runs before any write; validation failures leave all files untouched. Write-phase failures attempt best-effort rollback of files that may have been modified.\n\n# Trust what you already know\n\nBefore exploring to answer a factual question, check context first: the user's message, prior turns (including \\`remember\\` results), the pinned memory blocks above. User-stated facts outrank what the files say — don't re-derive what the user just told you.\n\n# Exploration\n\nSkip dependency, build, and VCS directories unless asked (the pinned .gitignore below is your denylist). \\`search_files\\` matches FILE NAMES; \\`search_content\\` matches CONTENTS — pick accordingly. Use \\`glob\\` for \"what changed lately\" / \"all *.ts under src/\", \\`search_content\\` with \\`context:N\\` for grep -C around hits.\n\n# Path conventions\n\n- **Filesystem tools** (\\`read_file\\`, \\`list_directory\\`, \\`edit_file\\`, etc.): paths resolve against the sandbox root. Relative, POSIX-absolute (\\`/\\` = project root), and OS-absolute (e.g. \\`D:\\\\\\\\path\\\\\\\\foo.cpp\\`) all work as long as they resolve INSIDE the sandbox. Don't refuse on path shape — the tool returns a clear sandbox-escape error if it's actually out of scope.\n- **\\`run_command\\`**: cwd pinned to project root. Never use a leading \\`/\\` in arguments — Windows reads it as drive root, POSIX as filesystem root. Use relative paths.\n\n# Workspace is pinned\n\nYou can't switch project / working directory mid-session — tell the user to quit and relaunch (e.g. \\`cd ../other-project && reasonix code\\`). Don't try \\`cd\\` via \\`run_command\\` either; the sandbox is pinned and \\`cd\\` doesn't carry between calls.\n\n# Foreground vs background\n\n\\`run_command\\` blocks until exit — use for tests / builds / lints / typechecks / git / one-shot scripts under a minute. \\`run_background\\` is for anything else: dev servers / watchers (dev/serve/watch/start in the name) AND long one-shots (large \\`curl\\` / \\`pip install\\` / \\`cargo build\\` / \\`docker build\\`). For long downloads, pair with \\`wait_for_job\\` (one tool call per wait regardless of duration). Don't restart a running dev server — \\`list_jobs\\` first.\n\n# Scope discipline on \"run it\" / \"start it\" requests\n\nWhen the user says run / start / launch / serve / boot up: start it, verify it came up, report what's running and STOP. In the same turn, do NOT run tsc / lints / type-checkers unless asked, do NOT scan for bugs to \"proactively\" fix, do NOT clean up imports or refactor \"while you're here.\" If you notice an issue, mention in one sentence and wait. \"It works\" is the end state — resist the urge to polish.\n\n# Style\n\n- Show edits; don't narrate them in prose. \"Here's the fix:\" is enough.\n- One short paragraph explaining *why*, then the blocks.\n- Silence during exploration is fine — tool calls first, prose after.\n\n__ESCALATION_CONTRACT__\n\n${TUI_FORMATTING_RULES}\n`;\n\n/** Backward-compat — public-API const, frozen at the historical flash phrasing. Internal callers use codeSystemPrompt(rootDir, { modelId }) so the contract names the real tier (#582). */\nexport const CODE_SYSTEM_PROMPT = codeSystemBase(DEFAULT_CODE_MODEL);\n\n/** Stack order (stable for cache prefix): base → REASONIX.md → global → project → .gitignore. */\nconst SEMANTIC_SEARCH_ROUTING = `\n\n# Search routing\n\nYou have BOTH \\`semantic_search\\` (vector index) and \\`search_content\\` (literal grep).\n\n- **Descriptive queries** (\"where do we handle X\", \"which file owns Y\", \"how does Z work\", \"find the logic that does …\", \"the code responsible for …\") → call \\`semantic_search\\` FIRST. It indexes the project by meaning, so it finds the right file even when your phrasing shares no tokens with the code.\n- **Exact-token queries** (a specific identifier, regex, or \"find every call to foo\") → call \\`search_content\\`.\n\nIf \\`semantic_search\\` returns nothing useful (low scores, off-topic), THEN fall back to \\`search_content\\`. Don't go the other way — grepping a paraphrased question wastes turns.`;\n\nconst ENGINEERING_LIFECYCLE_CONTRACT = `\n\n# Engineering lifecycle contract\n\nReasonix may enforce a prefix-stable Engineering Lifecycle for explicitly enabled high-risk engineering work. The runtime keeps lifecycle state outside the system prompt and tool list, so do not expect stage-specific prompt changes or new tools to appear. Treat any lifecycle block as a host constraint, not as a suggestion.\n\nWhen high-risk mutations are bounced with \\`rejectedReason: \"engineering-lifecycle\"\\`, switch to read-only exploration, then call \\`submit_plan\\` with concrete steps before trying the mutation again. Add optional per-step \\`targets\\`, \\`acceptance\\`, and \\`verification\\` fields when they clarify scope or success criteria. For medium/high-risk steps, steps with verification criteria, or steps that changed code, \\`mark_step_complete\\` requires \\`evidence\\` entries such as verification output, diff summary, checkpoint id, or manual rationale.`;\n\nexport interface CodeSystemPromptOptions {\n /** True when semantic_search is registered for this run. Adds an\n * explicit routing fragment so the model picks it for intent-style\n * queries instead of defaulting to grep. */\n hasSemanticSearch?: boolean;\n /** Inline string appended after the generated code system prompt.\n * Preserves the default prompt — this is append-only, not a replacement. */\n systemAppend?: string;\n /** UTF-8 file contents appended after the generated code system prompt.\n * Preserves the default prompt — this is append-only, not a replacement. */\n systemAppendFile?: string;\n /** Model the loop will run on — interpolated into the escalation contract so the model can name itself correctly when asked (#582). */\n modelId?: string;\n /** Include the lifecycle contract only for users who explicitly opt in. */\n engineeringLifecycleMode?: \"off\" | \"strict\";\n}\n\nexport function codeSystemPrompt(rootDir: string, opts: CodeSystemPromptOptions = {}): string {\n let codeBase = codeSystemBase(opts.modelId ?? DEFAULT_CODE_MODEL);\n if (opts.engineeringLifecycleMode === \"strict\") {\n codeBase = `${codeBase}${ENGINEERING_LIFECYCLE_CONTRACT}`;\n }\n const base = opts.hasSemanticSearch ? `${codeBase}${SEMANTIC_SEARCH_ROUTING}` : codeBase;\n const withMemory = applyMemoryStack(base, rootDir);\n const gitignorePath = join(rootDir, \".gitignore\");\n let result = withMemory;\n if (existsSync(gitignorePath)) {\n let content: string | undefined;\n try {\n content = readFileSync(gitignorePath, \"utf8\");\n } catch {}\n if (content !== undefined) {\n const MAX = 2000;\n const truncated =\n content.length > MAX\n ? `${content.slice(0, MAX)}\\n… (truncated ${content.length - MAX} chars)`\n : content;\n result = `${result}\\n\\n# Project .gitignore\\n\\nThe user's repo ships this .gitignore — treat every pattern as \"don't traverse or edit inside these paths unless explicitly asked\":\\n\\n\\`\\`\\`\\n${truncated}\\n\\`\\`\\`\\n`;\n }\n }\n const appendParts = [opts.systemAppend, opts.systemAppendFile].filter(Boolean);\n if (appendParts.length > 0) {\n result = `${result}\\n\\n# User System Append\\n\\n${appendParts.join(\"\\n\\n\")}`;\n }\n return result;\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/** 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 withMemory = applyUserMemory(withGlobal, { 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","join","join","existsSync","readFileSync"]}
@@ -13,7 +13,7 @@ import {
13
13
  TONE_ACTIVE,
14
14
  resolveThemeName,
15
15
  setActiveTheme
16
- } from "./chunk-24A7FHGJ.js";
16
+ } from "./chunk-6CRPCJAU.js";
17
17
  import {
18
18
  __toESM
19
19
  } from "./chunk-TUK7OWJA.js";
@@ -157,4 +157,4 @@ export {
157
157
  COLOR,
158
158
  GLYPH
159
159
  };
160
- //# sourceMappingURL=chunk-OJVITDGB.js.map
160
+ //# sourceMappingURL=chunk-CCJAP7G3.js.map
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-X53B3JIX.js";
8
8
  import {
9
9
  t
10
- } from "./chunk-KDRUEXII.js";
10
+ } from "./chunk-NRQ5UP5T.js";
11
11
  import {
12
12
  __toESM
13
13
  } from "./chunk-TUK7OWJA.js";
@@ -51,4 +51,4 @@ function truncate(s, max) {
51
51
  export {
52
52
  RecordView
53
53
  };
54
- //# sourceMappingURL=chunk-R6GQKKBW.js.map
54
+ //# sourceMappingURL=chunk-CNG32VAB.js.map