pi-kimi-keepalive 0.3.2 → 0.3.4
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 +1 -1
- package/src/index.ts +38 -16
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-kimi-keepalive",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
4
4
|
"description": "Prompt-cache keepalive for Kimi (kimi-coding) sessions in the Pi coding agent. Replays the last real provider request while idle so the automatic prefix cache never expires.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
package/src/index.ts
CHANGED
|
@@ -51,7 +51,10 @@ import {
|
|
|
51
51
|
|
|
52
52
|
const STATE_DIR = join(homedir(), ".pi", "cache-keepalive");
|
|
53
53
|
const STATE_FILE = join(STATE_DIR, "state.json");
|
|
54
|
-
|
|
54
|
+
/** Live OAuth state; resolved lazily so tests can redirect it via PI_AGENT_DIR. */
|
|
55
|
+
function authFile(): string {
|
|
56
|
+
return join(process.env.PI_AGENT_DIR ?? join(homedir(), ".pi", "agent"), "auth.json");
|
|
57
|
+
}
|
|
55
58
|
|
|
56
59
|
interface PersistedConfig {
|
|
57
60
|
enabled: boolean;
|
|
@@ -473,22 +476,26 @@ export default function (pi: ExtensionAPI) {
|
|
|
473
476
|
*/
|
|
474
477
|
function probeHeaders(): Record<string, string> | null {
|
|
475
478
|
if (!capture) return null;
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
debug(`auth.json unavailable: ${error instanceof Error ? error.message : String(error)}`);
|
|
479
|
+
// Prefer the live token from auth.json: pi refreshes it there on real
|
|
480
|
+
// requests, while captured request headers freeze the token from capture
|
|
481
|
+
// time — hours later that Bearer can already be expired (HTTP 401).
|
|
482
|
+
// Fall back to the captured headers when auth.json is unavailable.
|
|
483
|
+
try {
|
|
484
|
+
const raw = JSON.parse(readFileSync(authFile(), "utf8")) as Record<string, unknown>;
|
|
485
|
+
const entry = (raw["kimi-coding"] ?? null) as { access?: unknown } | null;
|
|
486
|
+
if (entry && typeof entry.access === "string" && entry.access.length > 0) {
|
|
487
|
+
const headers = buildProbeHeaders(capture.headers);
|
|
488
|
+
headers.authorization = `Bearer ${entry.access}`;
|
|
489
|
+
return headers;
|
|
488
490
|
}
|
|
491
|
+
debug(`no kimi-coding access token in ${authFile()}`);
|
|
492
|
+
} catch (error) {
|
|
493
|
+
debug(
|
|
494
|
+
`auth.json unavailable (${error instanceof Error ? error.message : String(error)}) — falling back to captured headers`,
|
|
495
|
+
);
|
|
489
496
|
}
|
|
490
|
-
|
|
491
|
-
return headers;
|
|
497
|
+
const headers = buildProbeHeaders(capture.headers);
|
|
498
|
+
return headers.authorization ? headers : null;
|
|
492
499
|
}
|
|
493
500
|
|
|
494
501
|
async function runProbe(): Promise<boolean> {
|
|
@@ -952,8 +959,23 @@ export default function (pi: ExtensionAPI) {
|
|
|
952
959
|
const raw = payload as Record<string, unknown>;
|
|
953
960
|
if (!Array.isArray(raw.messages) || raw.messages.length === 0) return;
|
|
954
961
|
if (raw.system !== undefined && !Array.isArray(raw.system) && typeof raw.system !== "string") return;
|
|
962
|
+
let clonedPayload: Record<string, unknown>;
|
|
963
|
+
try {
|
|
964
|
+
clonedPayload = structuredClone(raw);
|
|
965
|
+
} catch {
|
|
966
|
+
// DataCloneError: the payload carries non-cloneable values (BigInt,
|
|
967
|
+
// symbols, functions). Fall back to a JSON round-trip; probing never
|
|
968
|
+
// mutates the captured payload, so a by-reference capture is the last
|
|
969
|
+
// resort rather than failing the real request.
|
|
970
|
+
try {
|
|
971
|
+
clonedPayload = JSON.parse(JSON.stringify(raw)) as Record<string, unknown>;
|
|
972
|
+
} catch {
|
|
973
|
+
debug("payload not cloneable — capturing by reference");
|
|
974
|
+
clonedPayload = raw;
|
|
975
|
+
}
|
|
976
|
+
}
|
|
955
977
|
capture = {
|
|
956
|
-
payload:
|
|
978
|
+
payload: clonedPayload,
|
|
957
979
|
headers: capturedHeaders,
|
|
958
980
|
provider: model.provider,
|
|
959
981
|
api: (model as { api?: string }).api,
|