opencarly 1.0.1 → 1.0.3

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.
@@ -16,6 +16,7 @@
16
16
  import { TRIM_THRESHOLDS } from "../config/schema";
17
17
  class TrimContext {
18
18
  fileOps = new Map();
19
+ baseNames = new Map();
19
20
  constructor(messages) {
20
21
  for (let mi = 0; mi < messages.length; mi++) {
21
22
  for (const part of messages[mi].parts) {
@@ -24,6 +25,21 @@ class TrimContext {
24
25
  const toolPart = part;
25
26
  if (toolPart.state.status !== "completed" && toolPart.state.status !== "error")
26
27
  continue;
28
+ if (toolPart.tool === "bash") {
29
+ const command = toolPart.state.input.command;
30
+ if (command) {
31
+ const isReadOnly = /^\s*(cat|grep|tail|head|ls|find)\s/.test(command);
32
+ if (!isReadOnly) {
33
+ for (const knownPath of this.fileOps.keys()) {
34
+ const basename = this.baseNames.get(knownPath) || knownPath;
35
+ if (command.includes(knownPath) || command.includes(basename)) {
36
+ this.fileOps.get(knownPath).push({ messageIndex: mi, op: "edit" });
37
+ }
38
+ }
39
+ }
40
+ }
41
+ continue;
42
+ }
27
43
  const filePath = toolPart.state.input.filePath;
28
44
  if (!filePath)
29
45
  continue;
@@ -35,6 +51,7 @@ class TrimContext {
35
51
  }
36
52
  else {
37
53
  this.fileOps.set(filePath, [entry]);
54
+ this.baseNames.set(filePath, filePath.split("/").pop() || filePath);
38
55
  }
39
56
  }
40
57
  }
@@ -89,15 +106,17 @@ function estimateTokens(text) {
89
106
  */
90
107
  function scoreToolPart(toolPart, messageIndex, totalMessages, context) {
91
108
  const state = toolPart.state;
92
- // Only trim completed tool outputs
93
- if (state.status !== "completed")
109
+ // Only trim completed or error tool outputs
110
+ if (state.status !== "completed" && state.status !== "error")
94
111
  return 200;
95
- const completed = state;
112
+ const anyState = state;
96
113
  // Already trimmed by us or by OpenCode's own compaction
97
- if (completed.time.compacted)
114
+ if (anyState.time?.compacted)
98
115
  return 200;
99
116
  // Don't bother trimming tiny outputs
100
- const tokenEstimate = estimateTokens(completed.output);
117
+ const outputText = typeof anyState.output === "string" ? anyState.output :
118
+ (typeof anyState.error === "string" ? anyState.error : "");
119
+ const tokenEstimate = estimateTokens(outputText);
101
120
  if (tokenEstimate < MIN_TRIM_TOKENS)
102
121
  return 200;
103
122
  let score = 100;
@@ -138,11 +157,19 @@ function scoreToolPart(toolPart, messageIndex, totalMessages, context) {
138
157
  * Build a compact summary to replace trimmed tool output.
139
158
  */
140
159
  function buildTrimSummary(toolPart, tokensSaved) {
141
- const completed = toolPart.state;
142
- const title = completed.title || toolPart.tool;
160
+ const anyState = toolPart.state;
161
+ if (anyState.status === "error") {
162
+ return `[Trimmed by OpenCarly] Tool Error (~${tokensSaved} tokens saved)\nError output trimmed from history.`;
163
+ }
164
+ const title = anyState.title || toolPart.tool;
143
165
  if (toolPart.tool === "read") {
144
166
  const filePath = toolPart.state.input.filePath || "unknown file";
145
- const lineCount = completed.output.split("\n").length;
167
+ const output = anyState.output || "";
168
+ let lineCount = 1;
169
+ for (let i = 0; i < output.length; i++) {
170
+ if (output[i] === '\n')
171
+ lineCount++;
172
+ }
146
173
  return (`[Trimmed by OpenCarly] Read ${filePath} (${lineCount} lines, ~${tokensSaved} tokens saved)\n` +
147
174
  `Re-read this file if its contents are needed.`);
148
175
  }
@@ -174,39 +201,75 @@ function buildTrimSummary(toolPart, tokensSaved) {
174
201
  * - If score < threshold: replace output with compact summary
175
202
  * 3. Return stats for logging
176
203
  */
177
- export function trimMessageHistory(messages, config) {
178
- // Step 1: Build context for cross-referencing file operations
179
- const context = new TrimContext(messages);
180
- const totalMessages = messages.length;
204
+ export function trimMessageHistory(inputMessages, config, countedTrims) {
181
205
  const stats = {
182
206
  partsTrimmed: 0,
183
207
  tokensSaved: 0,
184
208
  carlyBlocksStripped: 0,
185
209
  carlyTokensSaved: 0,
186
- activeFiles: context.getRecentFiles(totalMessages, 5),
210
+ activeFiles: [],
187
211
  };
212
+ if (inputMessages.length === 0 || config.mode === "off") {
213
+ return { stats, messages: inputMessages };
214
+ }
215
+ const context = new TrimContext(inputMessages);
216
+ const totalMessages = inputMessages.length;
217
+ stats.activeFiles = context.getRecentFiles(totalMessages, 5);
188
218
  if (!config.enabled)
189
- return stats;
219
+ return { stats, messages: inputMessages };
190
220
  const threshold = TRIM_THRESHOLDS[config.mode] ?? 40;
191
221
  const protectedStart = Math.max(0, totalMessages - config.preserveLastN);
222
+ const messages = [...inputMessages];
223
+ let messagesCloned = false;
224
+ const getMutablePart = (mi, pi) => {
225
+ if (!messagesCloned)
226
+ messagesCloned = true;
227
+ if (messages[mi] === inputMessages[mi]) {
228
+ messages[mi] = { ...messages[mi] };
229
+ messages[mi].parts = [...messages[mi].parts];
230
+ }
231
+ const msg = messages[mi];
232
+ if (msg.parts[pi] === inputMessages[mi].parts[pi]) {
233
+ const part = { ...msg.parts[pi] };
234
+ if (part.type === "tool") {
235
+ const toolPart = part;
236
+ toolPart.state = { ...toolPart.state };
237
+ if (toolPart.state.status === "completed" || toolPart.state.status === "error") {
238
+ const anyState = toolPart.state;
239
+ if (anyState.time) {
240
+ anyState.time = { ...anyState.time };
241
+ }
242
+ }
243
+ }
244
+ msg.parts[pi] = part;
245
+ }
246
+ return msg.parts[pi];
247
+ };
192
248
  // Step 2: Process each message
193
249
  for (let mi = 0; mi < totalMessages; mi++) {
194
- const message = messages[mi];
250
+ const message = inputMessages[mi];
195
251
  for (let pi = 0; pi < message.parts.length; pi++) {
196
252
  const part = message.parts[pi];
197
253
  // --- Strip <carly-rules> from text parts (all messages) ---
198
- if (part.type === "text") {
254
+ if (part.type === "text" && message.info?.role !== "user") {
199
255
  const textPart = part;
200
256
  if (typeof textPart.text === "string" && textPart.text.includes("<carly-rules>")) {
201
257
  const tokensBefore = estimateTokens(textPart.text);
202
- const textBefore = textPart.text;
203
- textPart.text = textPart.text
204
- .replace(/<carly-rules>[\s\S]*?<\/carly-rules>/g, "")
258
+ const newText = textPart.text
259
+ .replace(/<carly-rules>[\s\S]*?(?:<\/carly-rules>|$)/g, "")
205
260
  .trim();
206
- if (textPart.text !== textBefore) {
207
- const tokensAfter = estimateTokens(textPart.text);
208
- stats.carlyBlocksStripped++;
209
- stats.carlyTokensSaved += Math.max(0, tokensBefore - tokensAfter);
261
+ if (newText !== textPart.text) {
262
+ const tokensAfter = estimateTokens(newText);
263
+ const saved = Math.max(0, tokensBefore - tokensAfter);
264
+ const trimId = `text-${message.info?.time?.created}-${pi}`;
265
+ if (!countedTrims || !countedTrims.has(trimId)) {
266
+ stats.carlyBlocksStripped++;
267
+ stats.carlyTokensSaved += saved;
268
+ if (countedTrims)
269
+ countedTrims.add(trimId);
270
+ }
271
+ const mutablePart = getMutablePart(mi, pi);
272
+ mutablePart.text = newText;
210
273
  }
211
274
  }
212
275
  continue;
@@ -219,18 +282,35 @@ export function trimMessageHistory(messages, config) {
219
282
  const toolPart = part;
220
283
  const score = scoreToolPart(toolPart, mi, totalMessages, context);
221
284
  if (score < threshold) {
222
- const completed = toolPart.state;
223
- const tokensBefore = estimateTokens(completed.output);
285
+ const anyState = toolPart.state;
286
+ const outputText = typeof anyState.output === "string" ? anyState.output :
287
+ (typeof anyState.error === "string" ? anyState.error : "");
288
+ const tokensBefore = estimateTokens(outputText);
224
289
  const summary = buildTrimSummary(toolPart, tokensBefore);
225
290
  const tokensAfter = estimateTokens(summary);
291
+ const saved = Math.max(0, tokensBefore - tokensAfter);
292
+ const trimId = `tool-${toolPart.callID || (message.info?.time?.created + '-' + pi)}`;
293
+ if (!countedTrims || !countedTrims.has(trimId)) {
294
+ stats.partsTrimmed++;
295
+ stats.tokensSaved += saved;
296
+ if (countedTrims)
297
+ countedTrims.add(trimId);
298
+ }
299
+ const mutablePart = getMutablePart(mi, pi);
300
+ const mutableState = mutablePart.state;
226
301
  // Replace output with summary
227
- completed.output = summary;
228
- completed.time.compacted = Date.now();
229
- stats.partsTrimmed++;
230
- stats.tokensSaved += Math.max(0, tokensBefore - tokensAfter);
302
+ if (typeof mutableState.error === "string") {
303
+ mutableState.error = summary;
304
+ }
305
+ else {
306
+ mutableState.output = summary;
307
+ }
308
+ if (!mutableState.time)
309
+ mutableState.time = { start: 0, end: 0 };
310
+ mutableState.time.compacted = Date.now();
231
311
  }
232
312
  }
233
313
  }
234
- return stats;
314
+ return { stats, messages: messagesCloned ? messages : inputMessages };
235
315
  }
236
316
  //# sourceMappingURL=trimmer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"trimmer.js","sourceRoot":"","sources":["../../src/engine/trimmer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,eAAe,EAAuB,MAAM,kBAAkB,CAAC;AAkExE,MAAM,WAAW;IACP,OAAO,GAA0B,IAAI,GAAG,EAAE,CAAC;IAEnD,YAAY,QAA4B;QACtC,KAAK,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,QAAQ,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC;YAC5C,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC;gBACtC,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM;oBAAE,SAAS;gBAEnC,MAAM,QAAQ,GAAG,IAAgB,CAAC;gBAClC,IAAI,QAAQ,CAAC,KAAK,CAAC,MAAM,KAAK,WAAW,IAAI,QAAQ,CAAC,KAAK,CAAC,MAAM,KAAK,OAAO;oBAAE,SAAS;gBAEzF,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,QAA8B,CAAC;gBACrE,IAAI,CAAC,QAAQ;oBAAE,SAAS;gBAExB,IAAI,QAAQ,CAAC,IAAI,KAAK,MAAM,IAAI,QAAQ,CAAC,IAAI,KAAK,MAAM,IAAI,QAAQ,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;oBACtF,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;oBACvC,MAAM,KAAK,GAAW,EAAE,YAAY,EAAE,EAAE,EAAE,EAAE,EAAE,QAAQ,CAAC,IAAoB,EAAE,CAAC;oBAC9E,IAAI,GAAG,EAAE,CAAC;wBACR,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;oBAClB,CAAC;yBAAM,CAAC;wBACN,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;oBACtC,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,yDAAyD;IACzD,YAAY,CAAC,QAAgB,EAAE,YAAoB;QACjD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACvC,IAAI,CAAC,GAAG;YAAE,OAAO,KAAK,CAAC;QACvB,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,MAAM,IAAI,EAAE,CAAC,YAAY,GAAG,YAAY,CAAC,CAAC;IAC9E,CAAC;IAED,iEAAiE;IACjE,cAAc,CAAC,QAAgB,EAAE,YAAoB;QACnD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACvC,IAAI,CAAC,GAAG;YAAE,OAAO,KAAK,CAAC;QACvB,OAAO,GAAG,CAAC,IAAI,CACb,CAAC,EAAE,EAAE,EAAE,CACL,CAAC,EAAE,CAAC,EAAE,KAAK,MAAM,IAAI,EAAE,CAAC,EAAE,KAAK,OAAO,CAAC;YACvC,EAAE,CAAC,YAAY,GAAG,YAAY,CACjC,CAAC;IACJ,CAAC;IAED,+DAA+D;IAC/D,cAAc,CAAC,aAAqB,EAAE,KAAa;QACjD,MAAM,WAAW,GAAG,IAAI,GAAG,EAAU,CAAC;QACtC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,aAAa,GAAG,KAAK,CAAC,CAAC;QAEpD,KAAK,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;YACrD,IAAI,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,IAAI,QAAQ,CAAC,EAAE,CAAC;gBAChD,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAC5B,CAAC;QACH,CAAC;QAED,OAAO,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACjC,CAAC;CACF;AAED,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E,oDAAoD;AACpD,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAE1D,gDAAgD;AAChD,MAAM,eAAe,GAAG,GAAG,CAAC;AAE5B;;;GAGG;AACH,SAAS,cAAc,CAAC,IAAY;IAClC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACpC,CAAC;AAED;;;;;GAKG;AACH,SAAS,aAAa,CACpB,QAAkB,EAClB,YAAoB,EACpB,aAAqB,EACrB,OAAoB;IAEpB,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC;IAE7B,mCAAmC;IACnC,IAAI,KAAK,CAAC,MAAM,KAAK,WAAW;QAAE,OAAO,GAAG,CAAC;IAE7C,MAAM,SAAS,GAAG,KAA2B,CAAC;IAE9C,wDAAwD;IACxD,IAAI,SAAS,CAAC,IAAI,CAAC,SAAS;QAAE,OAAO,GAAG,CAAC;IAEzC,qCAAqC;IACrC,MAAM,aAAa,GAAG,cAAc,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACvD,IAAI,aAAa,GAAG,eAAe;QAAE,OAAO,GAAG,CAAC;IAEhD,IAAI,KAAK,GAAG,GAAG,CAAC;IAChB,MAAM,QAAQ,GAAG,aAAa,GAAG,CAAC,GAAG,YAAY,CAAC;IAElD,kDAAkD;IAClD,KAAK,IAAI,QAAQ,GAAG,CAAC,CAAC;IAEtB,0CAA0C;IAC1C,IAAI,QAAQ,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAC7B,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,QAA8B,CAAC;QACrE,IAAI,QAAQ,IAAI,OAAO,CAAC,YAAY,CAAC,QAAQ,EAAE,YAAY,CAAC,EAAE,CAAC;YAC7D,KAAK,IAAI,EAAE,CAAC;QACd,CAAC;IACH,CAAC;IAED,oDAAoD;IACpD,IAAI,QAAQ,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAC7B,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,QAA8B,CAAC;QACrE,IAAI,QAAQ,IAAI,OAAO,CAAC,cAAc,CAAC,QAAQ,EAAE,YAAY,CAAC,EAAE,CAAC;YAC/D,KAAK,IAAI,EAAE,CAAC;QACd,CAAC;IACH,CAAC;IAED,iEAAiE;IACjE,IAAI,aAAa,GAAG,IAAI,EAAE,CAAC;QACzB,KAAK,IAAI,EAAE,CAAC;IACd,CAAC;SAAM,IAAI,aAAa,GAAG,GAAG,EAAE,CAAC;QAC/B,KAAK,IAAI,CAAC,CAAC;IACb,CAAC;IAED,yCAAyC;IACzC,IAAI,eAAe,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACvC,KAAK,IAAI,EAAE,CAAC;IACd,CAAC;IAED,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;AAC5B,CAAC;AAED,8EAA8E;AAC9E,0BAA0B;AAC1B,8EAA8E;AAE9E;;GAEG;AACH,SAAS,gBAAgB,CAAC,QAAkB,EAAE,WAAmB;IAC/D,MAAM,SAAS,GAAG,QAAQ,CAAC,KAA2B,CAAC;IACvD,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,IAAI,QAAQ,CAAC,IAAI,CAAC;IAE/C,IAAI,QAAQ,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAC7B,MAAM,QAAQ,GAAI,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,QAAmB,IAAI,cAAc,CAAC;QAC7E,MAAM,SAAS,GAAG,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;QACtD,OAAO,CACL,+BAA+B,QAAQ,KAAK,SAAS,YAAY,WAAW,kBAAkB;YAC9F,+CAA+C,CAChD,CAAC;IACJ,CAAC;IAED,IAAI,QAAQ,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAI,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,OAAkB,IAAI,iBAAiB,CAAC;QAC9E,iCAAiC;QACjC,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC;QAC9E,OAAO,CACL,+BAA+B,QAAQ,MAAM,WAAW,kBAAkB;YAC1E,0CAA0C,CAC3C,CAAC;IACJ,CAAC;IAED,IAAI,QAAQ,CAAC,IAAI,KAAK,MAAM,IAAI,QAAQ,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QACzD,MAAM,OAAO,GAAI,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,OAAkB,IAAI,EAAE,CAAC;QAC/D,OAAO,CACL,0BAA0B,QAAQ,CAAC,IAAI,KAAK,OAAO,MAAM,WAAW,kBAAkB;YACtF,2CAA2C,CAC5C,CAAC;IACJ,CAAC;IAED,mBAAmB;IACnB,OAAO,CACL,0BAA0B,KAAK,MAAM,WAAW,kBAAkB;QAClE,mCAAmC,CACpC,CAAC;AACJ,CAAC;AAmBD;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,kBAAkB,CAChC,QAA4B,EAC5B,MAAsB;IAEtB,8DAA8D;IAC9D,MAAM,OAAO,GAAG,IAAI,WAAW,CAAC,QAAQ,CAAC,CAAC;IAC1C,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC;IAEtC,MAAM,KAAK,GAAc;QACvB,YAAY,EAAE,CAAC;QACf,WAAW,EAAE,CAAC;QACd,mBAAmB,EAAE,CAAC;QACtB,gBAAgB,EAAE,CAAC;QACnB,WAAW,EAAE,OAAO,CAAC,cAAc,CAAC,aAAa,EAAE,CAAC,CAAC;KACtD,CAAC;IAEF,IAAI,CAAC,MAAM,CAAC,OAAO;QAAE,OAAO,KAAK,CAAC;IAElC,MAAM,SAAS,GAAG,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;IACrD,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,aAAa,GAAG,MAAM,CAAC,aAAa,CAAC,CAAC;IAEzE,+BAA+B;IAC/B,KAAK,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,aAAa,EAAE,EAAE,EAAE,EAAE,CAAC;QAC1C,MAAM,OAAO,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;QAE7B,KAAK,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC;YACjD,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAE/B,6DAA6D;YAC7D,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;gBACzB,MAAM,QAAQ,GAAG,IAAgB,CAAC;gBAClC,IAAI,OAAO,QAAQ,CAAC,IAAI,KAAK,QAAQ,IAAI,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC;oBACjF,MAAM,YAAY,GAAG,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;oBACnD,MAAM,UAAU,GAAG,QAAQ,CAAC,IAAI,CAAC;oBACjC,QAAQ,CAAC,IAAI,GAAG,QAAQ,CAAC,IAAI;yBAC1B,OAAO,CAAC,uCAAuC,EAAE,EAAE,CAAC;yBACpD,IAAI,EAAE,CAAC;oBAEV,IAAI,QAAQ,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;wBACjC,MAAM,WAAW,GAAG,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;wBAClD,KAAK,CAAC,mBAAmB,EAAE,CAAC;wBAC5B,KAAK,CAAC,gBAAgB,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,YAAY,GAAG,WAAW,CAAC,CAAC;oBACpE,CAAC;gBACH,CAAC;gBACD,SAAS;YACX,CAAC;YAED,yDAAyD;YACzD,IAAI,EAAE,IAAI,cAAc;gBAAE,SAAS;YACnC,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM;gBAAE,SAAS;YAEnC,MAAM,QAAQ,GAAG,IAAgB,CAAC;YAClC,MAAM,KAAK,GAAG,aAAa,CAAC,QAAQ,EAAE,EAAE,EAAE,aAAa,EAAE,OAAO,CAAC,CAAC;YAElE,IAAI,KAAK,GAAG,SAAS,EAAE,CAAC;gBACtB,MAAM,SAAS,GAAG,QAAQ,CAAC,KAA2B,CAAC;gBACvD,MAAM,YAAY,GAAG,cAAc,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;gBACtD,MAAM,OAAO,GAAG,gBAAgB,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;gBACzD,MAAM,WAAW,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;gBAE5C,8BAA8B;gBAC9B,SAAS,CAAC,MAAM,GAAG,OAAO,CAAC;gBAC3B,SAAS,CAAC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBAEtC,KAAK,CAAC,YAAY,EAAE,CAAC;gBACrB,KAAK,CAAC,WAAW,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,YAAY,GAAG,WAAW,CAAC,CAAC;YAC/D,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
1
+ {"version":3,"file":"trimmer.js","sourceRoot":"","sources":["../../src/engine/trimmer.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAiOlD,eAAO,MAAM,SAAS,EAAE,MAgXvB,CAAC;AAGF,eAAe,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AA+NlD,eAAO,MAAM,SAAS,EAAE,MAmavB,CAAC;AAGF,eAAe,SAAS,CAAC"}
package/dist/index.js CHANGED
@@ -79,10 +79,10 @@ function estimateTokens(text) {
79
79
  return Math.ceil(text.length / 4);
80
80
  }
81
81
  async function generateStatsReport(configPath, activeSessionId, activeModel) {
82
- const stats = loadCumulativeStats(configPath);
82
+ const stats = await loadCumulativeStats(configPath);
83
83
  let currentSessionSummary = activeSessionId
84
84
  ? stats.sessions.find(s => s.sessionId === activeSessionId)
85
- : stats.sessions[stats.sessions.length - 1];
85
+ : stats.sessions[0];
86
86
  let currentTokenStats = {
87
87
  tokensSkippedBySelection: 0,
88
88
  tokensTrimmedFromHistory: 0,
@@ -140,7 +140,7 @@ async function generateStatsReport(configPath, activeSessionId, activeModel) {
140
140
  output += `| ↳ *Stale Carly-Blocks* | ${formatNumber(currentTokenStats.tokensTrimmedCarlyBlocks)} |\n\n`;
141
141
  output += `## 🕒 RECENT SESSION HISTORY\n`;
142
142
  output += `| Date | Session ID | Prompts | Tokens Saved |\n|---|---|---|---|\n`;
143
- for (const session of stats.sessions.slice().reverse().slice(0, 10)) {
143
+ for (const session of stats.sessions.slice(0, 10)) {
144
144
  const shortId = session.sessionId.replace("ses_", "").slice(0, 8) + "...";
145
145
  output += `| ${session.date?.split("T")[0] || "Unknown"} | \`${shortId}\` | ${session.promptsProcessed} | ${formatNumber(session.tokensSaved || 0)} |\n`;
146
146
  }
@@ -187,7 +187,7 @@ export const OpenCarly = async ({ directory, client }) => {
187
187
  // Load config
188
188
  let config;
189
189
  try {
190
- config = loadConfig(discovery.configPath);
190
+ config = await loadConfig(discovery.configPath);
191
191
  }
192
192
  catch (err) {
193
193
  const message = err instanceof Error ? err.message : String(err);
@@ -202,7 +202,7 @@ export const OpenCarly = async ({ directory, client }) => {
202
202
  await log("warn", warning, { configPath: discovery.configPath });
203
203
  }
204
204
  // Calculate baseline (all rules loaded every prompt)
205
- const baselineTokensPerPrompt = calculateBaseline(config);
205
+ const baselineTokensPerPrompt = await calculateBaseline(config);
206
206
  // Log startup summary
207
207
  const domainNames = Object.keys(config.manifest.domains);
208
208
  const commandNames = Object.keys(config.commands);
@@ -216,28 +216,27 @@ export const OpenCarly = async ({ directory, client }) => {
216
216
  commandsSystem: config.manifest.commands.state,
217
217
  baselineTokensPerPrompt,
218
218
  });
219
+ // Clean stale sessions on startup FIRST
220
+ try {
221
+ const cleaned = await cleanStaleSessions(discovery.configPath);
222
+ if (cleaned > 0) {
223
+ await log("debug", `Cleaned ${cleaned} stale session(s)`);
224
+ }
225
+ }
226
+ catch {
227
+ // Non-critical
228
+ }
219
229
  // Initialize state
220
- const cumulativeStats = loadCumulativeStats(discovery.configPath);
230
+ const cumulativeStats = await loadCumulativeStats(discovery.configPath, config.context.stats.trackDuration);
221
231
  const state = {
222
232
  config,
223
233
  sessions: new Map(),
224
234
  lastMatch: new Map(),
225
235
  lastPrompt: new Map(),
226
- activeSessionID: null,
227
- activeModel: null,
228
236
  baselineTokensPerPrompt,
229
237
  cumulativeStats,
238
+ sessionTrimState: new Map(),
230
239
  };
231
- // Clean stale sessions on startup
232
- try {
233
- const cleaned = cleanStaleSessions(discovery.configPath);
234
- if (cleaned > 0) {
235
- await log("debug", `Cleaned ${cleaned} stale session(s)`);
236
- }
237
- }
238
- catch {
239
- // Non-critical
240
- }
241
240
  return {
242
241
  // -----------------------------------------------------------------
243
242
  // Event hook: track session lifecycle and intercept commands
@@ -245,7 +244,7 @@ export const OpenCarly = async ({ directory, client }) => {
245
244
  event: async ({ event }) => {
246
245
  if (event.type === "session.created") {
247
246
  try {
248
- cleanStaleSessions(discovery.configPath);
247
+ await cleanStaleSessions(discovery.configPath);
249
248
  }
250
249
  catch {
251
250
  // ignore
@@ -257,17 +256,27 @@ export const OpenCarly = async ({ directory, client }) => {
257
256
  // -----------------------------------------------------------------
258
257
  "chat.message": async (input, output) => {
259
258
  const { sessionID, model } = input;
259
+ const promptParts = output.parts || [];
260
+ const promptText = extractPromptText(promptParts);
261
+ // Get or create session
262
+ const { session, isNew } = await getOrCreateSession(discovery.configPath, sessionID, directory);
260
263
  // Capture the active model ID for stats reporting
261
264
  if (model?.modelID) {
262
- state.activeModel = model.modelID;
265
+ session.activeModel = model.modelID;
263
266
  }
264
- const promptText = extractPromptText(output.parts);
265
- if (!promptText)
266
- return;
267
- // Get or create session
268
- const { session, isNew } = getOrCreateSession(discovery.configPath, sessionID, directory);
269
267
  if (isNew || !state.sessions.has(sessionID)) {
270
268
  state.sessions.set(sessionID, session);
269
+ // Simple LRU eviction to prevent memory leaks
270
+ if (state.sessions.size > 50) {
271
+ const oldestKey = state.sessions.keys().next().value;
272
+ if (oldestKey)
273
+ state.sessions.delete(oldestKey);
274
+ }
275
+ }
276
+ else {
277
+ // Move to end of Map to mark as recently used
278
+ state.sessions.delete(sessionID);
279
+ state.sessions.set(sessionID, session);
271
280
  }
272
281
  const currentSession = state.sessions.get(sessionID);
273
282
  // Set baseline on session if not set
@@ -279,11 +288,21 @@ export const OpenCarly = async ({ directory, client }) => {
279
288
  // Apply session overrides
280
289
  const effectiveManifest = applySessionOverrides(state.config.manifest, currentSession);
281
290
  // Run domain matcher
282
- const matchResult = matchDomains(promptText, effectiveManifest);
291
+ const matchResult = matchDomains(promptText, effectiveManifest, currentSession.activeFiles);
283
292
  // Cache for system.transform hook
284
293
  state.lastMatch.set(sessionID, matchResult);
285
294
  state.lastPrompt.set(sessionID, promptText);
286
- state.activeSessionID = sessionID;
295
+ // Prevent memory leaks if hooks are aborted
296
+ if (state.lastMatch.size > 50) {
297
+ const oldestMatchKey = state.lastMatch.keys().next().value;
298
+ if (oldestMatchKey)
299
+ state.lastMatch.delete(oldestMatchKey);
300
+ }
301
+ if (state.lastPrompt.size > 50) {
302
+ const oldestPromptKey = state.lastPrompt.keys().next().value;
303
+ if (oldestPromptKey)
304
+ state.lastPrompt.delete(oldestPromptKey);
305
+ }
287
306
  // Log match results
288
307
  await log("debug", "Prompt matched", {
289
308
  sessionID,
@@ -296,7 +315,7 @@ export const OpenCarly = async ({ directory, client }) => {
296
315
  });
297
316
  // Persist session
298
317
  try {
299
- saveSession(discovery.configPath, currentSession);
318
+ await saveSession(discovery.configPath, currentSession);
300
319
  }
301
320
  catch {
302
321
  // Non-critical
@@ -335,7 +354,7 @@ export const OpenCarly = async ({ directory, client }) => {
335
354
  manifest: effectiveManifest,
336
355
  };
337
356
  // Load rules
338
- const loaded = loadRules(matchResult, effectiveConfig, bracket, promptCount);
357
+ const loaded = await loadRules(matchResult, effectiveConfig, bracket, promptCount);
339
358
  // Override devmode from effective manifest
340
359
  loaded.devmode = effectiveManifest.devmode;
341
360
  loaded.contextEnabled = effectiveManifest.context.state === "active";
@@ -359,8 +378,13 @@ export const OpenCarly = async ({ directory, client }) => {
359
378
  if (session) {
360
379
  session.tokenStats = tokenStats;
361
380
  try {
362
- saveSession(discovery.configPath, session);
363
- state.cumulativeStats = updateCumulativeStats(discovery.configPath, session);
381
+ await saveSession(discovery.configPath, session);
382
+ const currentDelta = {
383
+ tokensInjected: tokensInjectedThisPrompt,
384
+ tokensSkippedBySelection: tokensSkippedThisPrompt,
385
+ tokensSaved: tokensSkippedThisPrompt
386
+ };
387
+ state.cumulativeStats = await updateCumulativeStats(discovery.configPath, session, state.config.context.stats.trackDuration, currentDelta, state.cumulativeStats);
364
388
  }
365
389
  catch {
366
390
  // Non-critical
@@ -375,18 +399,19 @@ export const OpenCarly = async ({ directory, client }) => {
375
399
  ? Math.round((tokenStats.rulesInjected || 0) / tokenStats.promptsProcessed)
376
400
  : totalRulesThisPrompt,
377
401
  };
402
+ loaded.tokenSavings = {
403
+ skippedBySelection: tokenStats.tokensSkippedBySelection,
404
+ trimmedFromHistory: tokenStats.tokensTrimmedFromHistory,
405
+ trimmedCarlyBlocks: tokenStats.tokensTrimmedCarlyBlocks,
406
+ tokensInjected: tokenStats.tokensInjected,
407
+ baselinePerPrompt: tokenStats.baselineTokensPerPrompt,
408
+ totalSaved: tokenStats.tokensSkippedBySelection + tokenStats.tokensTrimmedFromHistory + tokenStats.tokensTrimmedCarlyBlocks,
409
+ promptsProcessed: tokenStats.promptsProcessed,
410
+ showFullReport: matchResult.starCommands.includes("stats"),
411
+ };
378
412
  // Format and inject
379
413
  const formatted = formatRules(loaded);
380
414
  output.system.push(formatted);
381
- // Persist session with updated stats
382
- if (session) {
383
- try {
384
- saveSession(discovery.configPath, session);
385
- }
386
- catch {
387
- // Non-critical
388
- }
389
- }
390
415
  // Cleanup cached match
391
416
  state.lastMatch.delete(sessionID);
392
417
  state.lastPrompt.delete(sessionID);
@@ -394,36 +419,47 @@ export const OpenCarly = async ({ directory, client }) => {
394
419
  // -----------------------------------------------------------------
395
420
  // experimental.chat.messages.transform: smart tool output trimming
396
421
  // -----------------------------------------------------------------
397
- "experimental.chat.messages.transform": async (_input, output) => {
422
+ "experimental.chat.messages.transform": async (input, output) => {
398
423
  const trimConfig = state.config.context.trimming;
399
- const trimStats = trimMessageHistory(output.messages, trimConfig);
400
- // Accumulate trim stats to the session
401
- if (trimStats.tokensSaved > 0 || trimStats.carlyBlocksStripped > 0) {
402
- const sessionID = state.activeSessionID;
403
- const session = sessionID ? state.sessions.get(sessionID) : undefined;
404
- if (session) {
405
- session.tokenStats.tokensTrimmedFromHistory += trimStats.tokensSaved;
406
- session.tokenStats.tokensTrimmedCarlyBlocks += trimStats.carlyTokensSaved;
407
- try {
408
- saveSession(discovery.configPath, session);
409
- }
410
- catch {
411
- // Non-critical
424
+ const sessionID = input.sessionID;
425
+ let countedTrims;
426
+ if (sessionID) {
427
+ if (!state.sessionTrimState.has(sessionID)) {
428
+ state.sessionTrimState.set(sessionID, new Set());
429
+ if (state.sessionTrimState.size > 50) {
430
+ const oldestKey = state.sessionTrimState.keys().next().value;
431
+ if (oldestKey)
432
+ state.sessionTrimState.delete(oldestKey);
412
433
  }
413
434
  }
414
- await log("debug", "History trimmed", {
415
- partsTrimmed: trimStats.partsTrimmed,
416
- tokensSaved: trimStats.tokensSaved,
417
- carlyBlocksStripped: trimStats.carlyBlocksStripped,
418
- mode: trimConfig.mode,
419
- });
435
+ countedTrims = state.sessionTrimState.get(sessionID);
420
436
  }
421
- // Always update cumulative stats after messages transform completes
422
- const sessionID = state.activeSessionID;
437
+ const trimResult = trimMessageHistory(output.messages, trimConfig, countedTrims);
438
+ output.messages = trimResult.messages;
439
+ const trimStats = trimResult.stats;
423
440
  const session = sessionID ? state.sessions.get(sessionID) : undefined;
424
441
  if (session) {
442
+ // Always update active files
443
+ session.activeFiles = [...new Set([...trimStats.activeFiles, ...(session.activeFiles || [])])].slice(0, 15);
444
+ // Accumulate trim stats to the session
445
+ if (trimStats.tokensSaved > 0 || trimStats.carlyBlocksStripped > 0) {
446
+ session.tokenStats.tokensTrimmedFromHistory += trimStats.tokensSaved;
447
+ session.tokenStats.tokensTrimmedCarlyBlocks += trimStats.carlyTokensSaved;
448
+ await log("debug", "History trimmed", {
449
+ partsTrimmed: trimStats.partsTrimmed,
450
+ tokensSaved: trimStats.tokensSaved,
451
+ carlyBlocksStripped: trimStats.carlyBlocksStripped,
452
+ mode: trimConfig.mode,
453
+ });
454
+ }
425
455
  try {
426
- state.cumulativeStats = updateCumulativeStats(discovery.configPath, session);
456
+ await saveSession(discovery.configPath, session);
457
+ const currentDelta = {
458
+ tokensTrimmedFromHistory: trimStats.tokensSaved,
459
+ tokensTrimmedCarlyBlocks: trimStats.carlyTokensSaved,
460
+ tokensSaved: trimStats.tokensSaved + trimStats.carlyTokensSaved
461
+ };
462
+ state.cumulativeStats = await updateCumulativeStats(discovery.configPath, session, state.config.context.stats.trackDuration, currentDelta, state.cumulativeStats);
427
463
  }
428
464
  catch {
429
465
  // Non-critical
@@ -442,15 +478,18 @@ export const OpenCarly = async ({ directory, client }) => {
442
478
  stats: tool({
443
479
  description: "Get OpenCarly token savings statistics",
444
480
  args: {},
445
- execute: async (_args, _context) => {
446
- return generateStatsReport(discovery.configPath, state.activeSessionID || undefined, state.activeModel);
481
+ execute: async (_args, context) => {
482
+ const sessionID = context.sessionID;
483
+ const session = sessionID ? state.sessions.get(sessionID) : undefined;
484
+ const activeModel = session?.activeModel;
485
+ return generateStatsReport(discovery.configPath, sessionID, activeModel);
447
486
  },
448
487
  }),
449
488
  clear_stats: tool({
450
489
  description: "Clear all OpenCarly token savings statistics",
451
490
  args: {},
452
491
  execute: async (_args, _context) => {
453
- clearAllStats(discovery.configPath);
492
+ await clearAllStats(discovery.configPath);
454
493
  state.cumulativeStats = {
455
494
  version: 1,
456
495
  cumulative: {
@@ -472,6 +511,8 @@ export const OpenCarly = async ({ directory, client }) => {
472
511
  rulesInjected: 0,
473
512
  baselineTokensPerPrompt: state.baselineTokensPerPrompt,
474
513
  };
514
+ if (session)
515
+ await saveSession(discovery.configPath, session);
475
516
  }
476
517
  return "All OpenCarly token savings statistics have been successfully reset to zero.";
477
518
  },