claude-code-infinite 1.0.11 → 1.0.16

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 (136) hide show
  1. package/README.md +214 -47
  2. package/dist/cc-request.d.ts +94 -0
  3. package/dist/cc-request.d.ts.map +1 -0
  4. package/dist/cc-request.js +194 -0
  5. package/dist/cc-request.js.map +1 -0
  6. package/dist/claude-env.d.ts +30 -0
  7. package/dist/claude-env.d.ts.map +1 -0
  8. package/dist/claude-env.js +55 -0
  9. package/dist/claude-env.js.map +1 -0
  10. package/dist/cli-args.d.ts +32 -0
  11. package/dist/cli-args.d.ts.map +1 -0
  12. package/dist/cli-args.js +72 -0
  13. package/dist/cli-args.js.map +1 -0
  14. package/dist/cli-lifecycle.d.ts +17 -0
  15. package/dist/cli-lifecycle.d.ts.map +1 -0
  16. package/dist/cli-lifecycle.js +30 -0
  17. package/dist/cli-lifecycle.js.map +1 -0
  18. package/dist/cli-main.d.ts +15 -0
  19. package/dist/cli-main.d.ts.map +1 -0
  20. package/dist/cli-main.js +464 -0
  21. package/dist/cli-main.js.map +1 -0
  22. package/dist/cli.js +13 -178
  23. package/dist/cli.js.map +1 -1
  24. package/dist/config.d.ts +3 -0
  25. package/dist/config.d.ts.map +1 -1
  26. package/dist/config.js +29 -3
  27. package/dist/config.js.map +1 -1
  28. package/dist/count-tokens.d.ts +78 -0
  29. package/dist/count-tokens.d.ts.map +1 -0
  30. package/dist/count-tokens.js +277 -0
  31. package/dist/count-tokens.js.map +1 -0
  32. package/dist/final-index.d.ts +10 -0
  33. package/dist/final-index.d.ts.map +1 -0
  34. package/dist/final-index.js +37 -0
  35. package/dist/final-index.js.map +1 -0
  36. package/dist/hooks.d.ts +239 -0
  37. package/dist/hooks.d.ts.map +1 -0
  38. package/dist/hooks.js +618 -0
  39. package/dist/hooks.js.map +1 -0
  40. package/dist/index.d.ts +9 -0
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +8 -0
  43. package/dist/index.js.map +1 -1
  44. package/dist/memtree-fetch.d.ts +24 -0
  45. package/dist/memtree-fetch.d.ts.map +1 -0
  46. package/dist/memtree-fetch.js +121 -0
  47. package/dist/memtree-fetch.js.map +1 -0
  48. package/dist/memtree-finder.d.ts +99 -0
  49. package/dist/memtree-finder.d.ts.map +1 -0
  50. package/dist/memtree-finder.js +235 -0
  51. package/dist/memtree-finder.js.map +1 -0
  52. package/dist/memtree-links.d.ts +16 -0
  53. package/dist/memtree-links.d.ts.map +1 -0
  54. package/dist/memtree-links.js +66 -0
  55. package/dist/memtree-links.js.map +1 -0
  56. package/dist/memtree-mcp-config.d.ts +28 -0
  57. package/dist/memtree-mcp-config.d.ts.map +1 -0
  58. package/dist/memtree-mcp-config.js +121 -0
  59. package/dist/memtree-mcp-config.js.map +1 -0
  60. package/dist/memtree-mcp.d.ts +265 -0
  61. package/dist/memtree-mcp.d.ts.map +1 -0
  62. package/dist/memtree-mcp.js +667 -0
  63. package/dist/memtree-mcp.js.map +1 -0
  64. package/dist/memtree-newest.d.ts +74 -0
  65. package/dist/memtree-newest.d.ts.map +1 -0
  66. package/dist/memtree-newest.js +217 -0
  67. package/dist/memtree-newest.js.map +1 -0
  68. package/dist/memtree-tools.d.ts +105 -0
  69. package/dist/memtree-tools.d.ts.map +1 -0
  70. package/dist/memtree-tools.js +408 -0
  71. package/dist/memtree-tools.js.map +1 -0
  72. package/dist/memtree.d.ts +430 -0
  73. package/dist/memtree.d.ts.map +1 -0
  74. package/dist/memtree.js +1286 -0
  75. package/dist/memtree.js.map +1 -0
  76. package/dist/notices.d.ts +177 -0
  77. package/dist/notices.d.ts.map +1 -0
  78. package/dist/notices.js +469 -0
  79. package/dist/notices.js.map +1 -0
  80. package/dist/payment-gate.d.ts +53 -0
  81. package/dist/payment-gate.d.ts.map +1 -0
  82. package/dist/payment-gate.js +97 -0
  83. package/dist/payment-gate.js.map +1 -0
  84. package/dist/project-meta.d.ts +15 -0
  85. package/dist/project-meta.d.ts.map +1 -0
  86. package/dist/project-meta.js +80 -0
  87. package/dist/project-meta.js.map +1 -0
  88. package/dist/prompt-accounting.d.ts +12 -0
  89. package/dist/prompt-accounting.d.ts.map +1 -0
  90. package/dist/prompt-accounting.js +70 -0
  91. package/dist/prompt-accounting.js.map +1 -0
  92. package/dist/proxy.d.ts +204 -0
  93. package/dist/proxy.d.ts.map +1 -0
  94. package/dist/proxy.js +4299 -0
  95. package/dist/proxy.js.map +1 -0
  96. package/dist/reqlog.d.ts +427 -0
  97. package/dist/reqlog.d.ts.map +1 -0
  98. package/dist/reqlog.js +146 -0
  99. package/dist/reqlog.js.map +1 -0
  100. package/dist/request-sizing.d.ts +74 -0
  101. package/dist/request-sizing.d.ts.map +1 -0
  102. package/dist/request-sizing.js +121 -0
  103. package/dist/request-sizing.js.map +1 -0
  104. package/dist/resume-repair-file.d.ts +17 -0
  105. package/dist/resume-repair-file.d.ts.map +1 -0
  106. package/dist/resume-repair-file.js +100 -0
  107. package/dist/resume-repair-file.js.map +1 -0
  108. package/dist/resume-repair.d.ts +27 -0
  109. package/dist/resume-repair.d.ts.map +1 -0
  110. package/dist/resume-repair.js +198 -0
  111. package/dist/resume-repair.js.map +1 -0
  112. package/dist/route-cache.d.ts +5 -0
  113. package/dist/route-cache.d.ts.map +1 -0
  114. package/dist/route-cache.js +63 -0
  115. package/dist/route-cache.js.map +1 -0
  116. package/dist/route-fallback.d.ts +67 -0
  117. package/dist/route-fallback.d.ts.map +1 -0
  118. package/dist/route-fallback.js +126 -0
  119. package/dist/route-fallback.js.map +1 -0
  120. package/dist/route-identity.d.ts +6 -0
  121. package/dist/route-identity.d.ts.map +1 -0
  122. package/dist/route-identity.js +100 -0
  123. package/dist/route-identity.js.map +1 -0
  124. package/dist/transcript-usage.d.ts +57 -0
  125. package/dist/transcript-usage.d.ts.map +1 -0
  126. package/dist/transcript-usage.js +570 -0
  127. package/dist/transcript-usage.js.map +1 -0
  128. package/dist/turns.d.ts +77 -0
  129. package/dist/turns.d.ts.map +1 -0
  130. package/dist/turns.js +330 -0
  131. package/dist/turns.js.map +1 -0
  132. package/dist/update-check.d.ts +38 -0
  133. package/dist/update-check.d.ts.map +1 -0
  134. package/dist/update-check.js +67 -0
  135. package/dist/update-check.js.map +1 -0
  136. package/package.json +6 -2
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Turn detection and message-shaping helpers, ported from the polychat server
3
+ * (memory/preserve_last_user_message.py, memory/v2/consume.py,
4
+ * llm_api/extract_text.py) per plans/2026-06-09_PLAN_local_proxy_app.md.
5
+ *
6
+ * Audit notes vs the server heuristic (plan "Turn detection nuances"):
7
+ * - A message containing ANY tool_result block is treated as a tool turn, even
8
+ * with trailing text blocks (Claude Code appends system-reminder text blocks
9
+ * after tool_results; the server's all-blocks-are-tool_results check counted
10
+ * those as user turns).
11
+ * - Text is checked after stripping <system-reminder> tags, so standalone
12
+ * system-reminder messages are not user turns.
13
+ * - The "user stepped away" recap prompt (plain text, no tag) intentionally
14
+ * counts as a real user turn for compression, but is separately recognized
15
+ * so no user-facing MemTree notice is queued for that hidden request.
16
+ */
17
+ export type Message = Record<string, any>;
18
+ /** Distinctive stable prefix of Claude Code's hidden away-summary prompt. */
19
+ export declare const AWAY_SUMMARY_PROMPT_PREFIX = "The user stepped away and is coming back. Recap in under 40 words";
20
+ export declare function stripSystemReminderText(text: string): string;
21
+ /** True only for Claude Code's user wrapper carrying one or more tool results. */
22
+ export declare function isToolResultUserMessage(message: Message | undefined | null): boolean;
23
+ /** True if this is a real user instruction (not a tool-result wrapper or synthetic reminder). */
24
+ export declare function isNonToolUserMessage(message: Message | undefined | null): boolean;
25
+ /** True only for Claude Code's hidden away-summary user request. */
26
+ export declare function isAwaySummaryUserMessage(message: Message | undefined | null): boolean;
27
+ /** Concatenate plain text fields from a user message for hook correlation. */
28
+ export declare function userMessageText(message: Message | undefined | null): string;
29
+ /**
30
+ * Claude Code may append ambient role=system context after the human message.
31
+ * Turn classification is based on the last conversation message, not that
32
+ * trailing metadata.
33
+ */
34
+ export declare function lastNonSystemMessage(messages: Message[]): Message | undefined;
35
+ /**
36
+ * True for Claude Code's local `!command` replay shape. These commands do not
37
+ * consistently emit UserPromptSubmit, but their stdout is followed by a real
38
+ * main-thread completion (and therefore can legitimately own a display-only
39
+ * MemTree notice). Keep the match strict so arbitrary unarmed API traffic does
40
+ * not acquire notice ownership.
41
+ */
42
+ export declare function isLocalBashCommandTurn(messages: Message[]): boolean;
43
+ /**
44
+ * True if any message before the effective last non-system message is a real
45
+ * user input. Distinguishes the
46
+ * first user turn (nothing indexed yet — don't block on compression) from
47
+ * followup user turns (plans/2026-07-05_PLAN_first_user_turn_nonblocking.md).
48
+ * Synthetic reminder messages and tool_result wrappers don't count, via the
49
+ * same audited isNonToolUserMessage heuristic.
50
+ */
51
+ export declare function hasEarlierNonToolUserMessage(messages: Message[]): boolean;
52
+ /**
53
+ * Remove Claude Code <system-reminder> snippets before sending messages to the
54
+ * indexing endpoint (mirrors server strip_cc_system_reminders — reminders churn
55
+ * on /resume and would cause indexing inconsistencies).
56
+ */
57
+ export declare function stripCcSystemReminders(messages: Message[]): Message[];
58
+ /**
59
+ * Build the message list sent to /v1/context_memory: the Anthropic top-level
60
+ * `system` param becomes a leading system-role message (mirrors cc_api.py).
61
+ */
62
+ export declare function messagesWithSystem(messages: Message[], system: string | any[] | undefined | null): Message[];
63
+ /** Whether the model accepts input + max_tokens over its window (4.5+ only).
64
+ * Exact allowlist after stripping a date and `[1m]`: unknown suffixes and
65
+ * unknown models are treated as older. */
66
+ export declare function acceptsContextOverflow(model: string | undefined): boolean;
67
+ export declare function contextLimitForModel(model: string | undefined, anthropicBeta?: string, nativeOneMillionContext?: boolean): number;
68
+ /**
69
+ * Model name to report to the MemTree server: re-attach the `[1m]` suffix
70
+ * when the session runs with 1M context but the wire model name is plain
71
+ * (either because Claude Code moved the suffix into the beta header or because
72
+ * the model is natively 1M). The server resolves `<model>[1m]` aliases and logs
73
+ * the requested model verbatim, so this keeps its budget telemetry
74
+ * self-explanatory about the context variant.
75
+ */
76
+ export declare function modelForMemtree(model: string | undefined, contextLimit: number): string | undefined;
77
+ //# sourceMappingURL=turns.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"turns.d.ts","sourceRoot":"","sources":["../src/turns.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAO1C,6EAA6E;AAC7E,eAAO,MAAM,0BAA0B,sEAC8B,CAAC;AAEtE,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE5D;AAkCD,kFAAkF;AAClF,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,OAAO,GAAG,SAAS,GAAG,IAAI,GAClC,OAAO,CAMT;AAED,iGAAiG;AACjG,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,SAAS,GAAG,IAAI,GAAG,OAAO,CAIjF;AAED,oEAAoE;AACpE,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,OAAO,GAAG,SAAS,GAAG,IAAI,GAClC,OAAO,CAeT;AAED,8EAA8E;AAC9E,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,CAU3E;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,GAAG,SAAS,CAK7E;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAuBnE;AAED;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CASzE;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,EAAE,CAmBrE;AAoCD;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,OAAO,EAAE,EACnB,MAAM,EAAE,MAAM,GAAG,GAAG,EAAE,GAAG,SAAS,GAAG,IAAI,GACxC,OAAO,EAAE,CAMX;AA8CD;;0CAE0C;AAC1C,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAEzE;AA4BD,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,aAAa,CAAC,EAAE,MAAM,EACtB,uBAAuB,UAAO,GAC7B,MAAM,CAOR;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,YAAY,EAAE,MAAM,GACnB,MAAM,GAAG,SAAS,CAIpB"}
package/dist/turns.js ADDED
@@ -0,0 +1,330 @@
1
+ /**
2
+ * Turn detection and message-shaping helpers, ported from the polychat server
3
+ * (memory/preserve_last_user_message.py, memory/v2/consume.py,
4
+ * llm_api/extract_text.py) per plans/2026-06-09_PLAN_local_proxy_app.md.
5
+ *
6
+ * Audit notes vs the server heuristic (plan "Turn detection nuances"):
7
+ * - A message containing ANY tool_result block is treated as a tool turn, even
8
+ * with trailing text blocks (Claude Code appends system-reminder text blocks
9
+ * after tool_results; the server's all-blocks-are-tool_results check counted
10
+ * those as user turns).
11
+ * - Text is checked after stripping <system-reminder> tags, so standalone
12
+ * system-reminder messages are not user turns.
13
+ * - The "user stepped away" recap prompt (plain text, no tag) intentionally
14
+ * counts as a real user turn for compression, but is separately recognized
15
+ * so no user-facing MemTree notice is queued for that hidden request.
16
+ */
17
+ const SYSTEM_REMINDER_RE = /<system-reminder>[\s\S]*?<\/system-reminder>/g;
18
+ const BASH_INPUT_RE = /^<bash-input>[\s\S]*<\/bash-input>$/;
19
+ const BASH_OUTPUT_RE = /^<bash-stdout>[\s\S]*<\/bash-stdout><bash-stderr>[\s\S]*<\/bash-stderr>$/;
20
+ /** Distinctive stable prefix of Claude Code's hidden away-summary prompt. */
21
+ export const AWAY_SUMMARY_PROMPT_PREFIX = "The user stepped away and is coming back. Recap in under 40 words";
22
+ export function stripSystemReminderText(text) {
23
+ return text.replace(SYSTEM_REMINDER_RE, "").trim();
24
+ }
25
+ function contentHasRealText(content) {
26
+ if (typeof content === "string") {
27
+ return stripSystemReminderText(content).length > 0;
28
+ }
29
+ if (Array.isArray(content)) {
30
+ for (const part of content) {
31
+ if (typeof part === "string" && stripSystemReminderText(part)) {
32
+ return true;
33
+ }
34
+ if (part &&
35
+ typeof part === "object" &&
36
+ part.type === "text" &&
37
+ typeof part.text === "string" &&
38
+ stripSystemReminderText(part.text)) {
39
+ return true;
40
+ }
41
+ }
42
+ }
43
+ return false;
44
+ }
45
+ function hasToolResultBlock(content) {
46
+ return (Array.isArray(content) &&
47
+ content.some((part) => part && typeof part === "object" && part.type === "tool_result"));
48
+ }
49
+ /** True only for Claude Code's user wrapper carrying one or more tool results. */
50
+ export function isToolResultUserMessage(message) {
51
+ return (!!message &&
52
+ message.role === "user" &&
53
+ hasToolResultBlock(message.content));
54
+ }
55
+ /** True if this is a real user instruction (not a tool-result wrapper or synthetic reminder). */
56
+ export function isNonToolUserMessage(message) {
57
+ if (!message || message.role !== "user")
58
+ return false;
59
+ if (hasToolResultBlock(message.content))
60
+ return false;
61
+ return contentHasRealText(message.content);
62
+ }
63
+ /** True only for Claude Code's hidden away-summary user request. */
64
+ export function isAwaySummaryUserMessage(message) {
65
+ if (!message || message.role !== "user")
66
+ return false;
67
+ const content = message.content;
68
+ if (typeof content === "string") {
69
+ return content.startsWith(AWAY_SUMMARY_PROMPT_PREFIX);
70
+ }
71
+ if (!Array.isArray(content))
72
+ return false;
73
+ const text = content
74
+ .map((part) => {
75
+ if (typeof part === "string")
76
+ return part;
77
+ if (part?.type === "text" && typeof part.text === "string")
78
+ return part.text;
79
+ return "";
80
+ })
81
+ .join("");
82
+ return text.startsWith(AWAY_SUMMARY_PROMPT_PREFIX);
83
+ }
84
+ /** Concatenate plain text fields from a user message for hook correlation. */
85
+ export function userMessageText(message) {
86
+ if (!message || message.role !== "user")
87
+ return "";
88
+ if (typeof message.content === "string")
89
+ return message.content;
90
+ if (!Array.isArray(message.content))
91
+ return "";
92
+ return message.content
93
+ .map((part) => {
94
+ if (typeof part === "string")
95
+ return part;
96
+ return part?.type === "text" && typeof part.text === "string" ? part.text : "";
97
+ })
98
+ .join("");
99
+ }
100
+ /**
101
+ * Claude Code may append ambient role=system context after the human message.
102
+ * Turn classification is based on the last conversation message, not that
103
+ * trailing metadata.
104
+ */
105
+ export function lastNonSystemMessage(messages) {
106
+ for (let i = messages.length - 1; i >= 0; i--) {
107
+ if (messages[i]?.role !== "system")
108
+ return messages[i];
109
+ }
110
+ return undefined;
111
+ }
112
+ /**
113
+ * True for Claude Code's local `!command` replay shape. These commands do not
114
+ * consistently emit UserPromptSubmit, but their stdout is followed by a real
115
+ * main-thread completion (and therefore can legitimately own a display-only
116
+ * MemTree notice). Keep the match strict so arbitrary unarmed API traffic does
117
+ * not acquire notice ownership.
118
+ */
119
+ export function isLocalBashCommandTurn(messages) {
120
+ let outputIndex = messages.length - 1;
121
+ while (outputIndex >= 0 && messages[outputIndex]?.role === "system") {
122
+ outputIndex--;
123
+ }
124
+ if (outputIndex < 1)
125
+ return false;
126
+ const output = messages[outputIndex];
127
+ if (output?.role !== "user" ||
128
+ !BASH_OUTPUT_RE.test(userMessageText(output))) {
129
+ return false;
130
+ }
131
+ let inputIndex = outputIndex - 1;
132
+ while (inputIndex >= 0 && messages[inputIndex]?.role === "system") {
133
+ inputIndex--;
134
+ }
135
+ const input = messages[inputIndex];
136
+ return (input?.role === "user" &&
137
+ BASH_INPUT_RE.test(userMessageText(input)));
138
+ }
139
+ /**
140
+ * True if any message before the effective last non-system message is a real
141
+ * user input. Distinguishes the
142
+ * first user turn (nothing indexed yet — don't block on compression) from
143
+ * followup user turns (plans/2026-07-05_PLAN_first_user_turn_nonblocking.md).
144
+ * Synthetic reminder messages and tool_result wrappers don't count, via the
145
+ * same audited isNonToolUserMessage heuristic.
146
+ */
147
+ export function hasEarlierNonToolUserMessage(messages) {
148
+ let currentIndex = messages.length - 1;
149
+ while (currentIndex >= 0 && messages[currentIndex]?.role === "system") {
150
+ currentIndex--;
151
+ }
152
+ for (let i = 0; i < currentIndex; i++) {
153
+ if (isNonToolUserMessage(messages[i]))
154
+ return true;
155
+ }
156
+ return false;
157
+ }
158
+ /**
159
+ * Remove Claude Code <system-reminder> snippets before sending messages to the
160
+ * indexing endpoint (mirrors server strip_cc_system_reminders — reminders churn
161
+ * on /resume and would cause indexing inconsistencies).
162
+ */
163
+ export function stripCcSystemReminders(messages) {
164
+ const result = [];
165
+ for (const msg of messages) {
166
+ const content = msg.content;
167
+ if (typeof content === "string") {
168
+ const cleaned = stripSystemReminderText(content);
169
+ if (cleaned)
170
+ result.push({ ...msg, content: cleaned });
171
+ }
172
+ else if (Array.isArray(content)) {
173
+ const cleanedParts = [];
174
+ for (const part of content) {
175
+ const cleaned = stripPart(part);
176
+ if (cleaned !== null)
177
+ cleanedParts.push(cleaned);
178
+ }
179
+ if (cleanedParts.length)
180
+ result.push({ ...msg, content: cleanedParts });
181
+ }
182
+ else {
183
+ result.push(msg);
184
+ }
185
+ }
186
+ return result;
187
+ }
188
+ function stripPart(part) {
189
+ if (typeof part === "string") {
190
+ const cleaned = stripSystemReminderText(part);
191
+ return cleaned ? cleaned : null;
192
+ }
193
+ if (part && typeof part === "object") {
194
+ if (part.type === "text" && typeof part.text === "string") {
195
+ const cleaned = stripSystemReminderText(part.text);
196
+ return cleaned ? { ...part, text: cleaned } : null;
197
+ }
198
+ if (part.type === "tool_result") {
199
+ const inner = part.content;
200
+ if (typeof inner === "string") {
201
+ const cleaned = stripSystemReminderText(inner);
202
+ return { ...part, content: cleaned };
203
+ }
204
+ if (Array.isArray(inner)) {
205
+ const cleanedInner = inner
206
+ .map((p) => stripPart(p))
207
+ .filter((p) => p !== null);
208
+ return { ...part, content: cleanedInner };
209
+ }
210
+ }
211
+ }
212
+ return part;
213
+ }
214
+ // The client-side flatten port (flattenToSingleUserMessage /
215
+ // extractTextForFlatten) was deleted per the 2026-08-09 consolidation
216
+ // decision: the flatten format is implemented ONCE, server-side, in
217
+ // polychat/memory/flatten_messages.py. The client requests it with
218
+ // `flatten: true` and forwards `flattened_messages` verbatim
219
+ // (serverFlattenedMessages in memtree.ts); it never re-derives the format.
220
+ /**
221
+ * Build the message list sent to /v1/context_memory: the Anthropic top-level
222
+ * `system` param becomes a leading system-role message (mirrors cc_api.py).
223
+ */
224
+ export function messagesWithSystem(messages, system) {
225
+ const msgs = messages.map((m) => ({ ...m }));
226
+ if (system != null && (typeof system === "string" ? system : system.length)) {
227
+ msgs.unshift({ role: "system", content: system });
228
+ }
229
+ return msgs;
230
+ }
231
+ /**
232
+ * Context-window budget for compression.
233
+ *
234
+ * 1M long context can be selected three ways and we must accept all three:
235
+ * - a `[1m]` model-name suffix (our CLI convention), or
236
+ * - an `anthropic-beta: context-1m-*` header — this is what Claude Code
237
+ * actually sends on the wire: it strips the `[1m]` suffix from the model
238
+ * field and translates it into the beta flag for extended-context models,
239
+ * - a current model whose API window is natively 1M. Native-1M requests use a
240
+ * plain model id and do not need the beta header.
241
+ */
242
+ const NATIVE_ONE_MILLION_MODELS = new Set([
243
+ "claude-opus-4-7",
244
+ "claude-opus-4-8",
245
+ "claude-opus-5",
246
+ "claude-opus-5-5",
247
+ "claude-sonnet-5",
248
+ "claude-fable-5",
249
+ "claude-fable-5-1",
250
+ "claude-mythos-5",
251
+ "claude-mythos-preview",
252
+ ]);
253
+ /**
254
+ * Claude 4.5 and newer: the API rejects a request only when its input alone
255
+ * exceeds the window; input + max_tokens over the window is accepted and
256
+ * generation stops with stop_reason "model_context_window_exceeded". Older
257
+ * models return a validation error instead (unless the request opts in with
258
+ * the model-context-window-exceeded-2025-08-26 beta header). See
259
+ * https://platform.claude.com/docs/en/build-with-claude/context-windows
260
+ * ("Context window overflow behavior").
261
+ */
262
+ const CONTEXT_OVERFLOW_MODELS = new Set([
263
+ ...NATIVE_ONE_MILLION_MODELS,
264
+ "claude-opus-4-5",
265
+ "claude-opus-4-6",
266
+ "claude-sonnet-4-5",
267
+ "claude-sonnet-4-6",
268
+ "claude-sonnet-5-5",
269
+ "claude-haiku-4-5",
270
+ "claude-haiku-5-5",
271
+ "claude-mythos-5-1",
272
+ ]);
273
+ /** Whether the model accepts input + max_tokens over its window (4.5+ only).
274
+ * Exact allowlist after stripping a date and `[1m]`: unknown suffixes and
275
+ * unknown models are treated as older. */
276
+ export function acceptsContextOverflow(model) {
277
+ return model !== undefined && CONTEXT_OVERFLOW_MODELS.has(normalizeModelId(model));
278
+ }
279
+ function isNativeOneMillionModel(model) {
280
+ return knownModelFamily(model, NATIVE_ONE_MILLION_MODELS);
281
+ }
282
+ function normalizeModelId(model) {
283
+ return model
284
+ .trim()
285
+ .toLowerCase()
286
+ .replace(/(?:\[1m\])+$/i, "")
287
+ .replace(/-\d{8}$/, "");
288
+ }
289
+ function knownModelFamily(model, family) {
290
+ if (!model)
291
+ return false;
292
+ const normalized = normalizeModelId(model);
293
+ if (family.has(normalized))
294
+ return true;
295
+ // Point releases / variants of a known model (e.g. "claude-fable-5-1"
296
+ // before it was listed, or a future "claude-opus-5-1") inherit its
297
+ // behavior, mirroring the server's "dated/variant id of a known model"
298
+ // rule. Without this the server clamps their 500k budget to a 200k window.
299
+ for (const base of family) {
300
+ if (normalized.startsWith(`${base}-`))
301
+ return true;
302
+ }
303
+ return false;
304
+ }
305
+ export function contextLimitForModel(model, anthropicBeta, nativeOneMillionContext = true) {
306
+ if (model && model.includes("[1m]"))
307
+ return 1_000_000;
308
+ if (anthropicBeta && anthropicBeta.includes("context-1m"))
309
+ return 1_000_000;
310
+ if (nativeOneMillionContext && isNativeOneMillionModel(model)) {
311
+ return 1_000_000;
312
+ }
313
+ return 200_000;
314
+ }
315
+ /**
316
+ * Model name to report to the MemTree server: re-attach the `[1m]` suffix
317
+ * when the session runs with 1M context but the wire model name is plain
318
+ * (either because Claude Code moved the suffix into the beta header or because
319
+ * the model is natively 1M). The server resolves `<model>[1m]` aliases and logs
320
+ * the requested model verbatim, so this keeps its budget telemetry
321
+ * self-explanatory about the context variant.
322
+ */
323
+ export function modelForMemtree(model, contextLimit) {
324
+ if (!model)
325
+ return undefined;
326
+ if (contextLimit >= 1_000_000 && !model.includes("[1m]"))
327
+ return `${model}[1m]`;
328
+ return model;
329
+ }
330
+ //# sourceMappingURL=turns.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"turns.js","sourceRoot":"","sources":["../src/turns.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Startup check for a newer claude-code-infinite release on npm.
3
+ *
4
+ * Detect-and-tell only: ccc is Claude Code's parent process, so a silent
5
+ * `npm -g` write mid-session is never acceptable. The result is surfaced
6
+ * inside Claude Code through the SessionStart banner (see notices.ts) — the
7
+ * pre-launch terminal is covered by the TUI within a second, so a line printed
8
+ * there is never read. Bounded by a short timeout and silent on every failure
9
+ * (registry down, offline, malformed JSON, timeout) so startup is never gated
10
+ * on the registry. `CCC_SKIP_UPDATE_CHECK=1` disables the fetch entirely.
11
+ */
12
+ export declare const PACKAGE_NAME = "claude-code-infinite";
13
+ export declare const NPM_LATEST_URL = "https://registry.npmjs.org/claude-code-infinite/latest";
14
+ export declare const SKIP_UPDATE_CHECK_ENV = "CCC_SKIP_UPDATE_CHECK";
15
+ export declare const UPGRADE_COMMAND = "npm install -g claude-code-infinite";
16
+ export interface UpdateAvailable {
17
+ /** Newest version on the registry's `latest` tag. */
18
+ latest: string;
19
+ /** The running client's version. */
20
+ current: string;
21
+ }
22
+ export interface UpdateCheckOptions {
23
+ currentVersion: string;
24
+ env?: NodeJS.ProcessEnv;
25
+ fetchImpl?: typeof fetch;
26
+ timeoutMs?: number;
27
+ url?: string;
28
+ }
29
+ /**
30
+ * Resolve to the newer version when the registry's `latest` is strictly ahead
31
+ * of `currentVersion`, else null. Never rejects.
32
+ */
33
+ export declare function checkForUpdate(opts: UpdateCheckOptions): Promise<UpdateAvailable | null>;
34
+ /** Parse `1.2.3` (optionally `v`-prefixed / suffixed) into numeric parts. */
35
+ export declare function parseVersion(version: string): [number, number, number] | null;
36
+ /** Numeric per-component compare: negative when a < b, positive when a > b. */
37
+ export declare function compareVersions(a: [number, number, number], b: [number, number, number]): number;
38
+ //# sourceMappingURL=update-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-check.d.ts","sourceRoot":"","sources":["../src/update-check.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,eAAO,MAAM,YAAY,yBAAyB,CAAC;AACnD,eAAO,MAAM,cAAc,2DAAsD,CAAC;AAClF,eAAO,MAAM,qBAAqB,0BAA0B,CAAC;AAC7D,eAAO,MAAM,eAAe,wCAAmC,CAAC;AAOhE,MAAM,WAAW,eAAe;IAC9B,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC;IACf,oCAAoC;IACpC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,cAAc,EAAE,MAAM,CAAC;IACvB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAsBjC;AAED,6EAA6E;AAC7E,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAI7E;AAED,+EAA+E;AAC/E,wBAAgB,eAAe,CAC7B,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAC3B,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAC1B,MAAM,CAKR"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Startup check for a newer claude-code-infinite release on npm.
3
+ *
4
+ * Detect-and-tell only: ccc is Claude Code's parent process, so a silent
5
+ * `npm -g` write mid-session is never acceptable. The result is surfaced
6
+ * inside Claude Code through the SessionStart banner (see notices.ts) — the
7
+ * pre-launch terminal is covered by the TUI within a second, so a line printed
8
+ * there is never read. Bounded by a short timeout and silent on every failure
9
+ * (registry down, offline, malformed JSON, timeout) so startup is never gated
10
+ * on the registry. `CCC_SKIP_UPDATE_CHECK=1` disables the fetch entirely.
11
+ */
12
+ export const PACKAGE_NAME = "claude-code-infinite";
13
+ export const NPM_LATEST_URL = `https://registry.npmjs.org/${PACKAGE_NAME}/latest`;
14
+ export const SKIP_UPDATE_CHECK_ENV = "CCC_SKIP_UPDATE_CHECK";
15
+ export const UPGRADE_COMMAND = `npm install -g ${PACKAGE_NAME}`;
16
+ const UPDATE_CHECK_TIMEOUT_MS = 2000;
17
+ // Dotted numeric core with an optional pre-release/build suffix, as npm
18
+ // publishes it. Anything else (a tag name, an error page) is ignored.
19
+ const VERSION_RE = /^v?(\d+)\.(\d+)\.(\d+)(?:[-+][0-9A-Za-z.-]{0,40})?$/;
20
+ /**
21
+ * Resolve to the newer version when the registry's `latest` is strictly ahead
22
+ * of `currentVersion`, else null. Never rejects.
23
+ */
24
+ export async function checkForUpdate(opts) {
25
+ const env = opts.env ?? process.env;
26
+ if (env[SKIP_UPDATE_CHECK_ENV] === "1")
27
+ return null;
28
+ const current = parseVersion(opts.currentVersion);
29
+ if (current === null)
30
+ return null;
31
+ try {
32
+ const fetchImpl = opts.fetchImpl ?? fetch;
33
+ const res = await fetchImpl(opts.url ?? NPM_LATEST_URL, {
34
+ headers: { accept: "application/json" },
35
+ signal: AbortSignal.timeout(opts.timeoutMs ?? UPDATE_CHECK_TIMEOUT_MS),
36
+ });
37
+ if (!res.ok)
38
+ return null;
39
+ const body = (await res.json());
40
+ const latestRaw = typeof body?.version === "string" ? body.version : "";
41
+ const latest = parseVersion(latestRaw);
42
+ if (latest === null || compareVersions(latest, current) <= 0)
43
+ return null;
44
+ return { latest: latestRaw, current: opts.currentVersion };
45
+ }
46
+ catch {
47
+ // Registry unreachable, timed out, or answered with something that is
48
+ // not a package document: no update is knowable, so say nothing.
49
+ return null;
50
+ }
51
+ }
52
+ /** Parse `1.2.3` (optionally `v`-prefixed / suffixed) into numeric parts. */
53
+ export function parseVersion(version) {
54
+ const match = VERSION_RE.exec(version.trim());
55
+ if (!match)
56
+ return null;
57
+ return [Number(match[1]), Number(match[2]), Number(match[3])];
58
+ }
59
+ /** Numeric per-component compare: negative when a < b, positive when a > b. */
60
+ export function compareVersions(a, b) {
61
+ for (let i = 0; i < 3; i++) {
62
+ if (a[i] !== b[i])
63
+ return a[i] - b[i];
64
+ }
65
+ return 0;
66
+ }
67
+ //# sourceMappingURL=update-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-check.js","sourceRoot":"","sources":["../src/update-check.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,CAAC,MAAM,YAAY,GAAG,sBAAsB,CAAC;AACnD,MAAM,CAAC,MAAM,cAAc,GAAG,8BAA8B,YAAY,SAAS,CAAC;AAClF,MAAM,CAAC,MAAM,qBAAqB,GAAG,uBAAuB,CAAC;AAC7D,MAAM,CAAC,MAAM,eAAe,GAAG,kBAAkB,YAAY,EAAE,CAAC;AAChE,MAAM,uBAAuB,GAAG,IAAI,CAAC;AAErC,wEAAwE;AACxE,sEAAsE;AACtE,MAAM,UAAU,GAAG,qDAAqD,CAAC;AAiBzE;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,IAAwB;IAExB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IACpC,IAAI,GAAG,CAAC,qBAAqB,CAAC,KAAK,GAAG;QAAE,OAAO,IAAI,CAAC;IACpD,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAClD,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAClC,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,KAAK,CAAC;QAC1C,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,GAAG,IAAI,cAAc,EAAE;YACtD,OAAO,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE;YACvC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,IAAI,uBAAuB,CAAC;SACvE,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,OAAO,IAAI,CAAC;QACzB,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAA0B,CAAC;QACzD,MAAM,SAAS,GAAG,OAAO,IAAI,EAAE,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QACxE,MAAM,MAAM,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;QACvC,IAAI,MAAM,KAAK,IAAI,IAAI,eAAe,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QAC1E,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC,cAAc,EAAE,CAAC;IAC7D,CAAC;IAAC,MAAM,CAAC;QACP,sEAAsE;QACtE,iEAAiE;QACjE,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,YAAY,CAAC,OAAe;IAC1C,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IAC9C,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAChE,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,eAAe,CAC7B,CAA2B,EAC3B,CAA2B;IAE3B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAAE,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACxC,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-code-infinite",
3
- "version": "1.0.11",
3
+ "version": "1.0.16",
4
4
  "description": "Wrapper for Claude Code CLI",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -12,9 +12,10 @@
12
12
  "dist"
13
13
  ],
14
14
  "scripts": {
15
- "build": "tsc",
15
+ "build": "tsc && chmod +x dist/cli.js",
16
16
  "dev": "tsc --watch",
17
17
  "start": "node dist/cli.js",
18
+ "test": "npm run build && node --test test/*.test.mjs",
18
19
  "prepublishOnly": "npm run build"
19
20
  },
20
21
  "keywords": [
@@ -35,5 +36,8 @@
35
36
  "@types/cross-spawn": "^6.0.6",
36
37
  "@types/node": "^25.0.0",
37
38
  "typescript": "^5.9.3"
39
+ },
40
+ "engines": {
41
+ "node": ">=20.3"
38
42
  }
39
43
  }