claude-code-infinite 1.0.24 → 1.0.26
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/README.md +36 -5
- package/dist/auto-update-runner.d.ts +13 -0
- package/dist/auto-update-runner.d.ts.map +1 -1
- package/dist/auto-update-runner.js +51 -7
- package/dist/auto-update-runner.js.map +1 -1
- package/dist/auto-update-setup.d.ts +19 -3
- package/dist/auto-update-setup.d.ts.map +1 -1
- package/dist/auto-update-setup.js +42 -16
- package/dist/auto-update-setup.js.map +1 -1
- package/dist/auto-update.d.ts +59 -6
- package/dist/auto-update.d.ts.map +1 -1
- package/dist/auto-update.js +207 -40
- package/dist/auto-update.js.map +1 -1
- package/dist/claude-auth.d.ts +47 -0
- package/dist/claude-auth.d.ts.map +1 -0
- package/dist/claude-auth.js +171 -0
- package/dist/claude-auth.js.map +1 -0
- package/dist/claude-locate.d.ts +62 -0
- package/dist/claude-locate.d.ts.map +1 -0
- package/dist/claude-locate.js +224 -0
- package/dist/claude-locate.js.map +1 -0
- package/dist/cli-main.js +103 -15
- package/dist/cli-main.js.map +1 -1
- package/dist/cli.js +7 -1
- package/dist/cli.js.map +1 -1
- package/dist/diagnostics-schema.d.ts +9 -1
- package/dist/diagnostics-schema.d.ts.map +1 -1
- package/dist/diagnostics-schema.js +26 -1
- package/dist/diagnostics-schema.js.map +1 -1
- package/dist/diagnostics.d.ts +5 -1
- package/dist/diagnostics.d.ts.map +1 -1
- package/dist/diagnostics.js +17 -1
- package/dist/diagnostics.js.map +1 -1
- package/dist/hooks.d.ts +6 -1
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +12 -0
- package/dist/hooks.js.map +1 -1
- package/dist/memtree-mcp.d.ts.map +1 -1
- package/dist/memtree-mcp.js +8 -5
- package/dist/memtree-mcp.js.map +1 -1
- package/dist/memtree.d.ts +9 -0
- package/dist/memtree.d.ts.map +1 -1
- package/dist/memtree.js +18 -0
- package/dist/memtree.js.map +1 -1
- package/dist/notices.d.ts.map +1 -1
- package/dist/notices.js +3 -2
- package/dist/notices.js.map +1 -1
- package/dist/payment-notice.d.ts +19 -1
- package/dist/payment-notice.d.ts.map +1 -1
- package/dist/payment-notice.js +25 -2
- package/dist/payment-notice.js.map +1 -1
- package/dist/proxy.d.ts.map +1 -1
- package/dist/proxy.js +116 -8
- package/dist/proxy.js.map +1 -1
- package/dist/reqlog.d.ts +9 -0
- package/dist/reqlog.d.ts.map +1 -1
- package/dist/reqlog.js.map +1 -1
- package/dist/resume-repair.d.ts +2 -0
- package/dist/resume-repair.d.ts.map +1 -1
- package/dist/resume-repair.js +7 -5
- package/dist/resume-repair.js.map +1 -1
- package/dist/route-fallback.d.ts +6 -0
- package/dist/route-fallback.d.ts.map +1 -1
- package/dist/route-fallback.js +9 -0
- package/dist/route-fallback.js.map +1 -1
- package/dist/update-check.d.ts +2 -0
- package/dist/update-check.d.ts.map +1 -1
- package/dist/update-check.js.map +1 -1
- package/dist/update-lock.js +3 -1
- package/dist/update-lock.js.map +1 -1
- package/dist/update-wait.d.ts +25 -0
- package/dist/update-wait.d.ts.map +1 -0
- package/dist/update-wait.js +63 -0
- package/dist/update-wait.js.map +1 -0
- package/package.json +1 -1
package/dist/proxy.js
CHANGED
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
*/
|
|
41
41
|
import { capCacheBreakpoints } from "./route-cache.js";
|
|
42
42
|
import { PromptAccounting } from "./prompt-accounting.js";
|
|
43
|
-
import { INDEX_WAIT_RETRY_AFTER_SECONDS, RouteFallbackFailures } from "./route-fallback.js";
|
|
43
|
+
import { INDEX_WAIT_RETRY_AFTER_SECONDS, RouteFallbackFailures, pausedRefusal } from "./route-fallback.js";
|
|
44
44
|
import { createCountTokensSession, CountTokensCooldowns, plausibleSample, } from "./count-tokens.js";
|
|
45
45
|
import { RequestSizing, estimateRequestTokens, fitsMeasured, fitsNative, outputReservation } from "./request-sizing.js";
|
|
46
46
|
import { routeMessageHash, stablePrefixMessageHash } from "./route-identity.js";
|
|
@@ -56,11 +56,12 @@ import { COMPRESSED_NOTICE, compressedTotalsText, DEGRADED_NOTICE, NOT_COMPRESSE
|
|
|
56
56
|
import { NoticeDeliveryQueue, MEMTREE_COMPACT_COMMAND, MEMTREE_HELP_COMMAND, TRAILER_LABEL, LINK_LABEL, linkLines, urlLine, terminalSupportsHyperlinks, isMemtreeViewCommand, sessionCommandArgs, parseNoticeHookInput, } from "./hooks.js";
|
|
57
57
|
import { USAGE_LABEL, USAGE_SIGN_IN_NOTE } from "./usage-link.js";
|
|
58
58
|
import { hyperlink } from "./payment-gate.js";
|
|
59
|
-
import { PaymentNoticeThrottle, paymentNoticeText } from "./payment-notice.js";
|
|
59
|
+
import { PaymentNoticeThrottle, pausedCompactionText, pausedRefusalMessage, paymentNoticeText, subscribeUrlFromDetail } from "./payment-notice.js";
|
|
60
60
|
import { MEMTREE_LINKS_MAX_SESSIONS } from "./memtree-links.js";
|
|
61
61
|
import { describeClaudeCodeRequest, inspectMonitorTranscript, knownSideRequestKind, transcriptWarning, isClaudeCodeSideRequest, memtreeClientMeta, sessionTag, } from "./cc-request.js";
|
|
62
62
|
import { isResumableSessionId } from "./resume-hint.js";
|
|
63
63
|
import { conservativeBodyTokens } from "./token-estimate.js";
|
|
64
|
+
import { claudeAuthFromHeaders, upstreamErrorCode } from "./claude-auth.js";
|
|
64
65
|
import { approxTokensFromBytes, mergeUsageFromJsonBody, mergeUsageFromSseEvent, } from "./reqlog.js";
|
|
65
66
|
const DEFAULT_UPSTREAM = "https://api.anthropic.com";
|
|
66
67
|
const HOOK_BODY_LIMIT = 64 * 1024;
|
|
@@ -303,7 +304,9 @@ export function startProxy(opts) {
|
|
|
303
304
|
const shutdownAbort = new AbortController();
|
|
304
305
|
const state = {
|
|
305
306
|
paymentNotice: new PaymentNoticeThrottle(opts.paymentNoticeIntervalMs),
|
|
307
|
+
pausedNearWindowWarned: new Set(),
|
|
306
308
|
unpaidDetail: () => opts.memtree.paymentRequiredDetail,
|
|
309
|
+
pausedDetail: () => opts.memtree.pausedDetail,
|
|
307
310
|
usageUrl: opts.memtree.usageDashboardUrl,
|
|
308
311
|
sessionStartNotice: opts.sessionStartNotice,
|
|
309
312
|
diagnostics: opts.diagnostics,
|
|
@@ -882,6 +885,7 @@ async function handleMessages(req, res, opts, upstream, state) {
|
|
|
882
885
|
kind: "messages",
|
|
883
886
|
turnType: "unparseable",
|
|
884
887
|
requestBytes: rawBody.length,
|
|
888
|
+
claudeAuth: claudeAuthFromHeaders(req.headers),
|
|
885
889
|
};
|
|
886
890
|
const logged = async (forward) => {
|
|
887
891
|
try {
|
|
@@ -1013,6 +1017,8 @@ async function handleMessages(req, res, opts, upstream, state) {
|
|
|
1013
1017
|
// strips the `[1m]` model suffix on the wire). Current native-1M models send
|
|
1014
1018
|
// neither, so contextLimitForModel also needs the launcher's native setting.
|
|
1015
1019
|
const modelContextLimit = contextLimitForModel(body.model, headerText(req.headers, "anthropic-beta"), opts.nativeOneMillionContext !== false);
|
|
1020
|
+
if (isMainRequest)
|
|
1021
|
+
rec.contextWindow = modelContextLimit;
|
|
1016
1022
|
// Before anything reads the size sample: replace an unknown or stale
|
|
1017
1023
|
// estimate with an exact count where it would decide the outcome.
|
|
1018
1024
|
const requestSessionKey = requestSessionId(req);
|
|
@@ -1717,11 +1723,20 @@ async function handleMessages(req, res, opts, upstream, state) {
|
|
|
1717
1723
|
capture(opts, "anthropic-request", forwardBody);
|
|
1718
1724
|
const paymentDetail = opts.memtree.paymentRequiredDetail;
|
|
1719
1725
|
const mayQueueNotice = displayForThisTurn && state.mainPromptGeneration === noticePromptGeneration;
|
|
1720
|
-
|
|
1721
|
-
|
|
1726
|
+
const overBudget = reachedBudget(rec.compaction);
|
|
1727
|
+
if (mayQueueNotice && paymentDetail !== null &&
|
|
1728
|
+
(state.paymentNotice.due() || (overBudget && !nearWindowWarned(state, sessionId)))) {
|
|
1729
|
+
// A paused refusal of this very request withdraws it (refuseWholeRequest),
|
|
1730
|
+
// and any later one withdraws its near-window line.
|
|
1731
|
+
const handle = state.notices.queueSuffix(paymentNoticeText(paymentDetail, recapLink(state, sessionId)?.link, { overBudget }), () => {
|
|
1722
1732
|
state.paymentNotice.markShown();
|
|
1733
|
+
if (overBudget && sessionId !== undefined)
|
|
1734
|
+
addNearWindowWarned(state, sessionId);
|
|
1723
1735
|
state.diagnostics?.record("paused_notice", { trigger: "turn" });
|
|
1724
1736
|
}, noticePromptId);
|
|
1737
|
+
pausedNotices.set(rec, handle);
|
|
1738
|
+
if (overBudget)
|
|
1739
|
+
state.nearWindowNotice = handle;
|
|
1725
1740
|
}
|
|
1726
1741
|
else if (mayQueueNotice && paymentDetail === null) {
|
|
1727
1742
|
state.notices.queueSuffix(DEGRADED_NOTICE, undefined, noticePromptId);
|
|
@@ -1976,10 +1991,15 @@ function joinNoticeLines(...parts) {
|
|
|
1976
1991
|
export const MEMTREE_COMPACT_MIN_TOKENS = 20_000;
|
|
1977
1992
|
/** The reply to a ccc slash command, or undefined for an ordinary prompt. */
|
|
1978
1993
|
function sessionCommandReply(state, sessionId, prompt) {
|
|
1994
|
+
const unpaid = state.unpaidDetail();
|
|
1995
|
+
// Paused, compaction needs the MemTree it cannot reach: say how to resume instead.
|
|
1996
|
+
const paused = unpaid === null ? undefined
|
|
1997
|
+
: pausedCompactionText(viewUrl(subscribeUrlFromDetail(unpaid)));
|
|
1979
1998
|
if (sessionCommandArgs(prompt, MEMTREE_HELP_COMMAND) !== undefined) {
|
|
1980
1999
|
return [
|
|
1981
2000
|
"• /memtree-view · show this session's MemTree page link",
|
|
1982
|
-
|
|
2001
|
+
paused !== undefined ? `• ${paused}`
|
|
2002
|
+
: `• /memtree-compact [tokens | off] · compact this session on your next message (default half the budget, at least ${MEMTREE_COMPACT_MIN_TOKENS / 1000}k)`,
|
|
1983
2003
|
usageLines(state),
|
|
1984
2004
|
].filter((line) => line !== undefined).join("\n");
|
|
1985
2005
|
}
|
|
@@ -2000,6 +2020,8 @@ function sessionCommandReply(state, sessionId, prompt) {
|
|
|
2000
2020
|
state.storedPrefixLookups.set(sessionId, null);
|
|
2001
2021
|
return `${TRAILER_LABEL} compaction off: the conversation is sent whole, and MemTree compresses only when it outgrows the model's budget.`;
|
|
2002
2022
|
}
|
|
2023
|
+
if (paused !== undefined)
|
|
2024
|
+
return `${TRAILER_LABEL} ${paused}`;
|
|
2003
2025
|
if (args === "") {
|
|
2004
2026
|
// Back to the automatic target (half the budget, or CCC_COMPACT_TARGET).
|
|
2005
2027
|
// Under CCC_COMPACT_TARGET=off the default is off, so pin the automatic
|
|
@@ -2082,7 +2104,9 @@ function viewUrl(url) {
|
|
|
2082
2104
|
*/
|
|
2083
2105
|
function sessionLink(state, sessionId, source) {
|
|
2084
2106
|
const newest = state.newestTrees?.peek(sessionId);
|
|
2085
|
-
|
|
2107
|
+
// The note suggests /memtree-compact, which cannot run while MemTree is paused.
|
|
2108
|
+
const note = source && !source.compressed && state.unpaidDetail() === null
|
|
2109
|
+
? { note: NOT_COMPRESSED_NOTE } : {};
|
|
2086
2110
|
if (newest)
|
|
2087
2111
|
return { key: newest.key, link: newest.url, ...note };
|
|
2088
2112
|
return source ? { key: source.index, link: source.url, ...note } : undefined;
|
|
@@ -2193,6 +2217,9 @@ function noteMemtreeHealth(state, compression) {
|
|
|
2193
2217
|
}
|
|
2194
2218
|
if (compression.liveHealth === "success") {
|
|
2195
2219
|
state.toolRecoveryCooldownUntil = 0;
|
|
2220
|
+
// Paid again: a later pause (next month's limit) warns near the window afresh.
|
|
2221
|
+
if (state.unpaidDetail() === null)
|
|
2222
|
+
state.pausedNearWindowWarned.clear();
|
|
2196
2223
|
}
|
|
2197
2224
|
}
|
|
2198
2225
|
/**
|
|
@@ -3915,6 +3942,7 @@ async function selectForwardCandidate(args) {
|
|
|
3915
3942
|
args.rec.overBudgetForward = { reason: measurement.source === "exact"
|
|
3916
3943
|
? "exact-count-fits-window" : measurement.source === "bytes"
|
|
3917
3944
|
? "bytes-fallback-fits-window" : "estimate-fits-window" };
|
|
3945
|
+
warnPausedNearWindow(args.state, args.rec, requestSessionId(args.req));
|
|
3918
3946
|
}
|
|
3919
3947
|
return changed ? candidate.body : intended;
|
|
3920
3948
|
}
|
|
@@ -3934,7 +3962,9 @@ async function wholeRequestRefused(sizing, candidate, limits) {
|
|
|
3934
3962
|
}
|
|
3935
3963
|
/** Write the bounded fallback refusal (route-fallback.ts); always false. */
|
|
3936
3964
|
function refuseWholeRequest(args, inputTokens, budgetTokens) {
|
|
3937
|
-
const
|
|
3965
|
+
const unpaid = args.state.pausedDetail();
|
|
3966
|
+
const failure = unpaid !== null ? pausedRefusal(pausedRefusalMessage(unpaid))
|
|
3967
|
+
: args.state.fallbackFailures.fail(args.routeKey, { awaitingIndex: args.rec.indexBehind === true });
|
|
3938
3968
|
args.rec.forwardedBytes = 0;
|
|
3939
3969
|
args.rec.approxInputTokens = 0;
|
|
3940
3970
|
args.state.diagnostics?.record("refusal", {
|
|
@@ -3946,14 +3976,89 @@ function refuseWholeRequest(args, inputTokens, budgetTokens) {
|
|
|
3946
3976
|
lane: args.routeKey, attempt: failure.attempt, status: failure.status,
|
|
3947
3977
|
inputTokens, outputTokens: args.body.max_tokens ?? 0,
|
|
3948
3978
|
outputReservation: bodyOutputReservation(args.body), indexBehind: args.rec.indexBehind === true,
|
|
3949
|
-
budgetTokens, modelContextLimit: args.modelContextLimit,
|
|
3979
|
+
budgetTokens, modelContextLimit: args.modelContextLimit, ...(unpaid !== null ? { paused: true } : {}),
|
|
3950
3980
|
};
|
|
3981
|
+
if (unpaid !== null)
|
|
3982
|
+
cancelPausedNotice(args.state, args.rec);
|
|
3951
3983
|
if (args.res.headersSent || args.res.destroyed)
|
|
3952
3984
|
return false;
|
|
3953
3985
|
args.res.writeHead(failure.status, { "content-type": "application/json", ...failure.headers });
|
|
3954
3986
|
args.res.end(JSON.stringify(failure.body));
|
|
3987
|
+
if (unpaid !== null) {
|
|
3988
|
+
notePausedRefusal(args.state, args.rec, args.routeKey, requestSessionId(args.req));
|
|
3989
|
+
}
|
|
3955
3990
|
return false;
|
|
3956
3991
|
}
|
|
3992
|
+
/**
|
|
3993
|
+
* The refusal text already says MemTree is paused and how to resume, so it
|
|
3994
|
+
* counts as the paused notice: the throttle restarts, and this request's
|
|
3995
|
+
* queued notice is withdrawn rather than shown a second time after it.
|
|
3996
|
+
*/
|
|
3997
|
+
function notePausedRefusal(state, rec, lane, sessionId) {
|
|
3998
|
+
// A subagent's or hidden away-summary's refusal is not on the user's screen.
|
|
3999
|
+
if (rec.routeLane === "main") {
|
|
4000
|
+
state.paymentNotice.markShown();
|
|
4001
|
+
// Past the window /compact no longer fits: withdraw an undelivered
|
|
4002
|
+
// near-window line and show none later.
|
|
4003
|
+
state.notices.cancel(state.nearWindowNotice);
|
|
4004
|
+
if (sessionId !== undefined)
|
|
4005
|
+
addNearWindowWarned(state, sessionId);
|
|
4006
|
+
}
|
|
4007
|
+
// A tool turn in the outage cooldown or its lane's growth backoff refuses on
|
|
4008
|
+
// the last 402 without asking. End both so the next request asks MemTree
|
|
4009
|
+
// again (a 402 answers fast) and paying takes effect with no restart. A
|
|
4010
|
+
// concurrent attempt still compressing (no backoff yet) keeps its slot.
|
|
4011
|
+
state.toolRecoveryCooldownUntil = 0;
|
|
4012
|
+
const attempt = state.toolRecoveryAttemptedLanes.get(lane);
|
|
4013
|
+
if (attempt && (!attempt.inFlight || attempt.retryAtTokens !== undefined)) {
|
|
4014
|
+
state.toolRecoveryAttemptedLanes.delete(lane);
|
|
4015
|
+
}
|
|
4016
|
+
}
|
|
4017
|
+
/** Withdraw the paused notice this request queued: its refusal says the same. */
|
|
4018
|
+
function cancelPausedNotice(state, rec) {
|
|
4019
|
+
state.notices.cancel(pausedNotices.get(rec));
|
|
4020
|
+
pausedNotices.delete(rec);
|
|
4021
|
+
}
|
|
4022
|
+
/**
|
|
4023
|
+
* A paused main-lane request over the budget, still fitting the window (often a
|
|
4024
|
+
* tool round): once per session, say /compact still works now. A turn that
|
|
4025
|
+
* already queued the paused notice carries the line itself.
|
|
4026
|
+
*/
|
|
4027
|
+
function warnPausedNearWindow(state, rec, sessionId) {
|
|
4028
|
+
const detail = state.unpaidDetail();
|
|
4029
|
+
// Paid again: a later pause (next month's limit) warns afresh.
|
|
4030
|
+
if (detail === null)
|
|
4031
|
+
state.pausedNearWindowWarned.clear();
|
|
4032
|
+
// Never replace another queued notice (or this one again): a later request tries.
|
|
4033
|
+
if (detail === null || rec.routeLane !== "main" || sessionId === undefined ||
|
|
4034
|
+
pausedNotices.has(rec) || nearWindowWarned(state, sessionId) ||
|
|
4035
|
+
state.notices.hasPending(state.mainPromptId))
|
|
4036
|
+
return;
|
|
4037
|
+
state.nearWindowNotice = state.notices.queueSuffix(paymentNoticeText(detail, undefined, { overBudget: true }), () => {
|
|
4038
|
+
state.paymentNotice.markShown();
|
|
4039
|
+
addNearWindowWarned(state, sessionId);
|
|
4040
|
+
state.diagnostics?.record("paused_notice", { trigger: "turn" });
|
|
4041
|
+
}, state.mainPromptId);
|
|
4042
|
+
}
|
|
4043
|
+
/** Remember a warned session, keeping the set bounded (oldest first out). */
|
|
4044
|
+
function addNearWindowWarned(state, sessionId) {
|
|
4045
|
+
state.pausedNearWindowWarned.delete(sessionId);
|
|
4046
|
+
state.pausedNearWindowWarned.add(sessionId);
|
|
4047
|
+
if (state.pausedNearWindowWarned.size > MEMTREE_LINKS_MAX_SESSIONS) {
|
|
4048
|
+
const oldest = state.pausedNearWindowWarned.values().next().value;
|
|
4049
|
+
if (oldest !== undefined)
|
|
4050
|
+
state.pausedNearWindowWarned.delete(oldest);
|
|
4051
|
+
}
|
|
4052
|
+
}
|
|
4053
|
+
function nearWindowWarned(state, sessionId) {
|
|
4054
|
+
return sessionId !== undefined && state.pausedNearWindowWarned.has(sessionId);
|
|
4055
|
+
}
|
|
4056
|
+
/** Whether this turn's own size estimate reached its whole-request budget. */
|
|
4057
|
+
function reachedBudget(compaction) {
|
|
4058
|
+
return compaction !== undefined && (compaction.estimatedTokens ?? 0) >= compaction.budgetTokens;
|
|
4059
|
+
}
|
|
4060
|
+
/** The paused notice a degraded request queued, until it is refused or settles. */
|
|
4061
|
+
const pausedNotices = new WeakMap();
|
|
3957
4062
|
const changedDeliveryRecords = new WeakSet();
|
|
3958
4063
|
const selectedCandidates = new WeakMap();
|
|
3959
4064
|
const candidateSizeOwners = new WeakMap();
|
|
@@ -4336,6 +4441,9 @@ function forwardAccepted(req, res, bodyBuffer, opts, upstream, shutdownSignal, r
|
|
|
4336
4441
|
observed = decodeForObservation(Buffer.concat(observedChunks), contentEncoding);
|
|
4337
4442
|
if (rec && observed && !isSse) {
|
|
4338
4443
|
mergeUsageFromJsonBody(observed, rec);
|
|
4444
|
+
if ((upstreamRes.statusCode ?? 0) >= 400) {
|
|
4445
|
+
rec.upstreamError = upstreamErrorCode(observed);
|
|
4446
|
+
}
|
|
4339
4447
|
}
|
|
4340
4448
|
}
|
|
4341
4449
|
if (isSse) {
|