claude-token-saver 3.5.2 → 3.5.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-token-saver",
3
- "version": "3.5.2",
3
+ "version": "3.5.3",
4
4
  "description": "Save tokens on Claude Code — spike diagnosis, 1M-context detection, TTL countdown, statusline. (formerly claude-cache-monitor)",
5
5
  "type": "module",
6
6
  "bin": {
@@ -39,6 +39,16 @@ const DELEGATION_TOOLS = new Set(['Task', 'Agent']);
39
39
  // classifier denials out of 142 is_error results (~25% of the numerator).
40
40
  const REJECTION_RE = /doesn't want to proceed|tool use was rejected|doesn't want to take this action|denied by the claude code auto mode classifier|permission for this action was denied|requires approval/i;
41
41
 
42
+ // Harness-mechanical / self-corrected tool errors also arrive as is_error
43
+ // tool_results, but they reflect edit-ordering mechanics and the agent's own
44
+ // immediate correction loop — not task difficulty. Counting them poisons the
45
+ // rule-health error rate the same way permission denials do (v3.4.2). Measured
46
+ // on a 14-day window they dominate the numerator (e.g. "File has not been read
47
+ // yet" was 7/65 real errors in one project, edit-races + Task-lifecycle several
48
+ // more). Kept NARROW on purpose: ambiguous shell failures ("Exit code N", "File
49
+ // does not exist" on a Read) stay counted — those are genuine difficulty signal.
50
+ const SELF_CORRECTED_RE = /File has not been read yet|has been modified since read|String to replace not found|is not running \(status:|<tool_use_error>Blocked:/i;
51
+
42
52
  function toolResultText(content) {
43
53
  if (typeof content === 'string') return content;
44
54
  if (!Array.isArray(content)) return '';
@@ -46,8 +56,9 @@ function toolResultText(content) {
46
56
  }
47
57
 
48
58
  function isRealToolError(block) {
49
- return block && block.type === 'tool_result' && block.is_error &&
50
- !REJECTION_RE.test(toolResultText(block.content));
59
+ if (!block || block.type !== 'tool_result' || !block.is_error) return false;
60
+ const txt = toolResultText(block.content);
61
+ return !REJECTION_RE.test(txt) && !SELF_CORRECTED_RE.test(txt);
51
62
  }
52
63
 
53
64
  export async function collectSessionRecords(filePath, { includeContent = true } = {}) {