@code-yeongyu/senpi-ai 2026.9.28-7 → 2026.9.29
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/dist/api/anthropic-messages.d.ts.map +1 -1
- package/dist/api/anthropic-messages.js +59 -10
- package/dist/api/anthropic-messages.js.map +1 -1
- package/dist/api/bedrock-converse-stream.js +6 -1
- package/dist/api/bedrock-converse-stream.js.map +1 -1
- package/dist/auth/types.d.ts +7 -0
- package/dist/auth/types.d.ts.map +1 -1
- package/dist/auth/types.js.map +1 -1
- package/dist/cursor/context-limit-store.d.ts.map +1 -1
- package/dist/cursor/context-limit-store.js +23 -18
- package/dist/cursor/context-limit-store.js.map +1 -1
- package/dist/models.d.ts.map +1 -1
- package/dist/models.js +3 -2
- package/dist/models.js.map +1 -1
- package/dist/providers/amazon-bedrock.js +13 -13
- package/dist/providers/amazon-bedrock.js.map +1 -1
- package/dist/providers/data/.manifest.json +1 -1
- package/dist/providers/data/amazon-bedrock.json +1 -1
- package/dist/providers/data/anthropic.json +1 -1
- package/dist/providers/data/cloudflare-ai-gateway.json +1 -1
- package/dist/providers/data/cloudflare-workers-ai.json +1 -1
- package/dist/providers/data/mistral.json +1 -1
- package/dist/providers/data/opencode.json +1 -1
- package/dist/providers/data/openrouter.json +1 -1
- package/dist/providers/data/together.json +1 -1
- package/dist/providers/data/venice.json +1 -1
- package/dist/providers/data/vercel-ai-gateway.json +1 -1
- package/dist/providers/google-vertex.d.ts.map +1 -1
- package/dist/providers/google-vertex.js +3 -5
- package/dist/providers/google-vertex.js.map +1 -1
- package/dist/session-resources.d.ts.map +1 -1
- package/dist/session-resources.js +2 -1
- package/dist/session-resources.js.map +1 -1
- package/dist/utils/block-symbols.d.ts +4 -0
- package/dist/utils/block-symbols.d.ts.map +1 -1
- package/dist/utils/block-symbols.js +10 -6
- package/dist/utils/block-symbols.js.map +1 -1
- package/dist/utils/claude-code-version-cache.d.ts +12 -0
- package/dist/utils/claude-code-version-cache.d.ts.map +1 -0
- package/dist/utils/claude-code-version-cache.js +60 -0
- package/dist/utils/claude-code-version-cache.js.map +1 -0
- package/dist/utils/claude-code-version.d.ts +78 -0
- package/dist/utils/claude-code-version.d.ts.map +1 -0
- package/dist/utils/claude-code-version.js +203 -0
- package/dist/utils/claude-code-version.js.map +1 -0
- package/dist/utils/cursor-context-limit.d.ts.map +1 -1
- package/dist/utils/cursor-context-limit.js +51 -45
- package/dist/utils/cursor-context-limit.js.map +1 -1
- package/dist/utils/overflow.d.ts.map +1 -1
- package/dist/utils/overflow.js +2 -0
- package/dist/utils/overflow.js.map +1 -1
- package/dist/utils/process-singleton.d.ts +10 -0
- package/dist/utils/process-singleton.d.ts.map +1 -0
- package/dist/utils/process-singleton.js +18 -0
- package/dist/utils/process-singleton.js.map +1 -0
- package/dist/utils/prompt-cache-ttl.d.ts.map +1 -1
- package/dist/utils/prompt-cache-ttl.js +3 -2
- package/dist/utils/prompt-cache-ttl.js.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"google-vertex.d.ts","sourceRoot":"","sources":["../../src/providers/google-vertex.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAEnE,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAIvE,eAAO,MAAM,kBAAkB,EAAE,cAAc,CAAC,eAAe,EAAE,mBAAmB,CAA8B,CAAC;AACnH,eAAO,MAAM,wBAAwB,EAAE,cAAc,CAAC,eAAe,EAAE,mBAAmB,CACzD,CAAC;
|
|
1
|
+
{"version":3,"file":"google-vertex.d.ts","sourceRoot":"","sources":["../../src/providers/google-vertex.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAEnE,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAIvE,eAAO,MAAM,kBAAkB,EAAE,cAAc,CAAC,eAAe,EAAE,mBAAmB,CAA8B,CAAC;AACnH,eAAO,MAAM,wBAAwB,EAAE,cAAc,CAAC,eAAe,EAAE,mBAAmB,CACzD,CAAC;AAsFlC,wBAAgB,oBAAoB,IAAI,QAAQ,CAAC,eAAe,CAAC,CAQhE"}
|
|
@@ -76,11 +76,9 @@ const vertexAuth = {
|
|
|
76
76
|
const project = credential?.env?.GOOGLE_CLOUD_PROJECT ?? (await env("GOOGLE_CLOUD_PROJECT")) ?? (await env("GCLOUD_PROJECT"));
|
|
77
77
|
const location = credential?.env?.GOOGLE_CLOUD_LOCATION ?? (await env("GOOGLE_CLOUD_LOCATION"));
|
|
78
78
|
if (hasCredentials && project && location) {
|
|
79
|
-
return
|
|
80
|
-
auth: {},
|
|
81
|
-
|
|
82
|
-
source: credential ? "stored credential" : "gcloud application default credentials",
|
|
83
|
-
};
|
|
79
|
+
return credential
|
|
80
|
+
? { auth: {}, env: credential.env, source: "stored credential" }
|
|
81
|
+
: { auth: {}, source: "gcloud application default credentials", ambient: true };
|
|
84
82
|
}
|
|
85
83
|
return undefined;
|
|
86
84
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"google-vertex.js","sourceRoot":"","sources":["../../src/providers/google-vertex.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"google-vertex.js","sourceRoot":"","sources":["../../src/providers/google-vertex.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAI/D,OAAO,EAAE,cAAc,EAAiB,MAAM,cAAc,CAAC;AAE7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAEjE,MAAM,mBAAmB,GAAG,eAAe,EAAE,CAAC;AAC9C,MAAM,CAAC,MAAM,kBAAkB,GAAyD,mBAAmB,CAAC,MAAM,CAAC;AACnH,MAAM,CAAC,MAAM,wBAAwB,GACpC,mBAAmB,CAAC,YAAY,CAAC;AAElC,MAAM,eAAe,GAAG,uDAAuD,CAAC;AAEhF;;;;GAIG;AACH,MAAM,UAAU,GAAe;IAC9B,IAAI,EAAE,0BAA0B;IAChC,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE;QAC5B,WAAW,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;QACpC,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,MAAM,CAAC;YACvC,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,gDAAgD;YACzD,OAAO,EAAE;gBACR,EAAE,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,sBAAsB,EAAE;gBAChD,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,iCAAiC,EAAE;gBACvD,EAAE,EAAE,EAAE,iBAAiB,EAAE,KAAK,EAAE,kCAAkC,EAAE;aACpE;SACD,CAAC,CAAC;QACH,WAAW,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;QACpC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YAC1B,OAAO;gBACN,IAAI,EAAE,SAAS;gBACf,GAAG,EAAE,MAAM,WAAW,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,4BAA4B,EAAE,CAAC;aACxF,CAAC;QACH,CAAC;QACD,IAAI,MAAM,KAAK,KAAK,IAAI,MAAM,KAAK,iBAAiB,EAAE,CAAC;YACtD,MAAM,IAAI,KAAK,CAAC,yCAAyC,MAAM,EAAE,CAAC,CAAC;QACpE,CAAC;QACD,WAAW,CAAC,MAAM,CAAC;YAClB,IAAI,EAAE,MAAM;YACZ,OAAO,EACN,MAAM,KAAK,KAAK;gBACf,CAAC,CAAC,qFAAqF;gBACvF,CAAC,CAAC,oEAAoE;YACxE,KAAK,EAAE;gBACN;oBACC,KAAK,EAAE,iCAAiC;oBACxC,GAAG,EAAE,sEAAsE;iBAC3E;aACD;SACD,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,+BAA+B,EAAE,CAAC,CAAC;QACrG,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,6BAA6B,EAAE,CAAC,CAAC;QACpG,MAAM,eAAe,GACpB,MAAM,KAAK,iBAAiB;YAC3B,CAAC,CAAC,MAAM,WAAW,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,6CAA6C,EAAE,CAAC;YACpG,CAAC,CAAC,SAAS,CAAC;QACd,OAAO;YACN,IAAI,EAAE,SAAS;YACf,GAAG,EAAE;gBACJ,oBAAoB,EAAE,OAAO;gBAC7B,qBAAqB,EAAE,QAAQ;gBAC/B,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,8BAA8B,EAAE,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC/E;SACD,CAAC;IACH,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE;QAC9C,MAAM,GAAG,GAAG,KAAK,EAAE,IAAY,EAAE,EAAE;YAClC,MAAM,CAAC,cAAc,EAAE,CAAC;YACxB,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAClC,MAAM,CAAC,cAAc,EAAE,CAAC;YACxB,OAAO,KAAK,CAAC;QACd,CAAC,CAAC;QACF,MAAM,GAAG,GAAG,UAAU,EAAE,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,sBAAsB,CAAC,CAAC,CAAC;QACnE,IAAI,GAAG;YAAE,OAAO,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,sBAAsB,EAAE,CAAC;QAElH,MAAM,OAAO,GAAG,UAAU,EAAE,GAAG,EAAE,8BAA8B,IAAI,CAAC,MAAM,GAAG,CAAC,gCAAgC,CAAC,CAAC,CAAC;QACjH,MAAM,CAAC,cAAc,EAAE,CAAC;QACxB,MAAM,cAAc,GAAG,MAAM,GAAG,CAAC,UAAU,CAAC,OAAO,IAAI,eAAe,CAAC,CAAC;QACxE,MAAM,CAAC,cAAc,EAAE,CAAC;QACxB,MAAM,OAAO,GACZ,UAAU,EAAE,GAAG,EAAE,oBAAoB,IAAI,CAAC,MAAM,GAAG,CAAC,sBAAsB,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC;QAC/G,MAAM,QAAQ,GAAG,UAAU,EAAE,GAAG,EAAE,qBAAqB,IAAI,CAAC,MAAM,GAAG,CAAC,uBAAuB,CAAC,CAAC,CAAC;QAChG,IAAI,cAAc,IAAI,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC3C,OAAO,UAAU;gBAChB,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,EAAE,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,mBAAmB,EAAE;gBAChE,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,wCAAwC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAClF,CAAC;QACD,OAAO,SAAS,CAAC;IAClB,CAAC;CACD,CAAC;AAEF,MAAM,UAAU,oBAAoB;IACnC,OAAO,cAAc,CAAC;QACrB,EAAE,EAAE,eAAe;QACnB,IAAI,EAAE,kBAAkB;QACxB,IAAI,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE;QAC5B,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,oBAAoB,CAAC;QAC3C,GAAG,EAAE,eAAe,EAAE;KACtB,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import { googleVertexApi } from \"../api/google-vertex.lazy.ts\";\n\nimport type { GoogleVertexOptions } from \"../api/google-vertex.ts\";\nimport type { ApiKeyAuth } from \"../auth/types.ts\";\nimport { createProvider, type Provider } from \"../models.ts\";\nimport type { SimpleStreamOptions, StreamFunction } from \"../types.ts\";\nimport { GOOGLE_VERTEX_MODELS } from \"./google-vertex.models.ts\";\n\nconst googleVertexStreams = googleVertexApi();\nexport const streamGoogleVertex: StreamFunction<\"google-vertex\", GoogleVertexOptions> = googleVertexStreams.stream;\nexport const streamSimpleGoogleVertex: StreamFunction<\"google-vertex\", SimpleStreamOptions> =\n\tgoogleVertexStreams.streamSimple;\n\nconst VERTEX_ADC_PATH = \"~/.config/gcloud/application_default_credentials.json\";\n\n/**\n * Vertex accepts an explicit API key or Application Default Credentials\n * (`gcloud auth application-default login`). ADC additionally requires\n * project and location env vars, which the implementation reads itself.\n */\nconst vertexAuth: ApiKeyAuth = {\n\tname: \"Google Cloud credentials\",\n\tlogin: async (interaction) => {\n\t\tinteraction.signal.throwIfAborted();\n\t\tconst method = await interaction.prompt({\n\t\t\ttype: \"select\",\n\t\t\tmessage: \"Select Google Vertex AI authentication method:\",\n\t\t\toptions: [\n\t\t\t\t{ id: \"api-key\", label: \"Google Cloud API key\" },\n\t\t\t\t{ id: \"adc\", label: \"Application Default Credentials\" },\n\t\t\t\t{ id: \"service-account\", label: \"Service account credentials file\" },\n\t\t\t],\n\t\t});\n\t\tinteraction.signal.throwIfAborted();\n\t\tif (method === \"api-key\") {\n\t\t\treturn {\n\t\t\t\ttype: \"api_key\",\n\t\t\t\tkey: await interaction.prompt({ type: \"secret\", message: \"Enter Google Cloud API key\" }),\n\t\t\t};\n\t\t}\n\t\tif (method !== \"adc\" && method !== \"service-account\") {\n\t\t\tthrow new Error(`Unknown Google Vertex AI auth method: ${method}`);\n\t\t}\n\t\tinteraction.notify({\n\t\t\ttype: \"info\",\n\t\t\tmessage:\n\t\t\t\tmethod === \"adc\"\n\t\t\t\t\t? \"Run `gcloud auth application-default login`, then provide the project and location.\"\n\t\t\t\t\t: \"Provide a service account credentials file, project, and location.\",\n\t\t\tlinks: [\n\t\t\t\t{\n\t\t\t\t\tlabel: \"Application Default Credentials\",\n\t\t\t\t\turl: \"https://cloud.google.com/docs/authentication/provide-credentials-adc\",\n\t\t\t\t},\n\t\t\t],\n\t\t});\n\t\tconst project = await interaction.prompt({ type: \"text\", message: \"Enter Google Cloud project ID\" });\n\t\tconst location = await interaction.prompt({ type: \"text\", message: \"Enter Google Cloud location\" });\n\t\tconst credentialsPath =\n\t\t\tmethod === \"service-account\"\n\t\t\t\t? await interaction.prompt({ type: \"text\", message: \"Enter service account credentials file path\" })\n\t\t\t\t: undefined;\n\t\treturn {\n\t\t\ttype: \"api_key\",\n\t\t\tenv: {\n\t\t\t\tGOOGLE_CLOUD_PROJECT: project,\n\t\t\t\tGOOGLE_CLOUD_LOCATION: location,\n\t\t\t\t...(credentialsPath ? { GOOGLE_APPLICATION_CREDENTIALS: credentialsPath } : {}),\n\t\t\t},\n\t\t};\n\t},\n\tresolve: async ({ ctx, credential, signal }) => {\n\t\tconst env = async (name: string) => {\n\t\t\tsignal.throwIfAborted();\n\t\t\tconst value = await ctx.env(name);\n\t\t\tsignal.throwIfAborted();\n\t\t\treturn value;\n\t\t};\n\t\tconst key = credential?.key ?? (await env(\"GOOGLE_CLOUD_API_KEY\"));\n\t\tif (key) return { auth: { apiKey: key }, source: credential?.key ? \"stored credential\" : \"GOOGLE_CLOUD_API_KEY\" };\n\n\t\tconst adcPath = credential?.env?.GOOGLE_APPLICATION_CREDENTIALS ?? (await env(\"GOOGLE_APPLICATION_CREDENTIALS\"));\n\t\tsignal.throwIfAborted();\n\t\tconst hasCredentials = await ctx.fileExists(adcPath ?? VERTEX_ADC_PATH);\n\t\tsignal.throwIfAborted();\n\t\tconst project =\n\t\t\tcredential?.env?.GOOGLE_CLOUD_PROJECT ?? (await env(\"GOOGLE_CLOUD_PROJECT\")) ?? (await env(\"GCLOUD_PROJECT\"));\n\t\tconst location = credential?.env?.GOOGLE_CLOUD_LOCATION ?? (await env(\"GOOGLE_CLOUD_LOCATION\"));\n\t\tif (hasCredentials && project && location) {\n\t\t\treturn credential\n\t\t\t\t? { auth: {}, env: credential.env, source: \"stored credential\" }\n\t\t\t\t: { auth: {}, source: \"gcloud application default credentials\", ambient: true };\n\t\t}\n\t\treturn undefined;\n\t},\n};\n\nexport function googleVertexProvider(): Provider<\"google-vertex\"> {\n\treturn createProvider({\n\t\tid: \"google-vertex\",\n\t\tname: \"Google Vertex AI\",\n\t\tauth: { apiKey: vertexAuth },\n\t\tmodels: Object.values(GOOGLE_VERTEX_MODELS),\n\t\tapi: googleVertexApi(),\n\t});\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-resources.d.ts","sourceRoot":"","sources":["../src/session-resources.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"session-resources.d.ts","sourceRoot":"","sources":["../src/session-resources.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,sBAAsB,GAAG,CAAC,SAAS,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;AAOlE,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,sBAAsB,GAAG,MAAM,IAAI,CAK1F;AAED,wBAAgB,uBAAuB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAYhE"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
import { processSingleton } from "./utils/process-singleton.js";
|
|
2
|
+
const sessionResourceCleanups = processSingleton("@earendil-works/pi-ai:session-resource-cleanups", () => new Set());
|
|
2
3
|
export function registerSessionResourceCleanup(cleanup) {
|
|
3
4
|
sessionResourceCleanups.add(cleanup);
|
|
4
5
|
return () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-resources.js","sourceRoot":"","sources":["../src/session-resources.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"session-resources.js","sourceRoot":"","sources":["../src/session-resources.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAIhE,MAAM,uBAAuB,GAAG,gBAAgB,CAC/C,iDAAiD,EACjD,GAAG,EAAE,CAAC,IAAI,GAAG,EAA0B,CACvC,CAAC;AAEF,MAAM,UAAU,8BAA8B,CAAC,OAA+B;IAC7E,uBAAuB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACrC,OAAO,GAAG,EAAE;QACX,uBAAuB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACzC,CAAC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,SAAkB;IACzD,MAAM,MAAM,GAAc,EAAE,CAAC;IAC7B,KAAK,MAAM,OAAO,IAAI,uBAAuB,EAAE,CAAC;QAC/C,IAAI,CAAC;YACJ,OAAO,CAAC,SAAS,CAAC,CAAC;QACpB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACpB,CAAC;IACF,CAAC;IACD,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,cAAc,CAAC,MAAM,EAAE,qCAAqC,CAAC,CAAC;IACzE,CAAC;AACF,CAAC","sourcesContent":["import { processSingleton } from \"./utils/process-singleton.ts\";\n\nexport type SessionResourceCleanup = (sessionId?: string) => void;\n\nconst sessionResourceCleanups = processSingleton(\n\t\"@earendil-works/pi-ai:session-resource-cleanups\",\n\t() => new Set<SessionResourceCleanup>(),\n);\n\nexport function registerSessionResourceCleanup(cleanup: SessionResourceCleanup): () => void {\n\tsessionResourceCleanups.add(cleanup);\n\treturn () => {\n\t\tsessionResourceCleanups.delete(cleanup);\n\t};\n}\n\nexport function cleanupSessionResources(sessionId?: string): void {\n\tconst errors: unknown[] = [];\n\tfor (const cleanup of sessionResourceCleanups) {\n\t\ttry {\n\t\t\tcleanup(sessionId);\n\t\t} catch (error) {\n\t\t\terrors.push(error);\n\t\t}\n\t}\n\tif (errors.length > 0) {\n\t\tthrow new AggregateError(errors, \"Failed to cleanup session resources\");\n\t}\n}\n"]}
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
* Symbol-keyed markers carried on streamed content blocks. Symbol keys never
|
|
3
3
|
* survive the JSONL persistence round-trip, so these are strictly in-memory
|
|
4
4
|
* coordination between a provider stream and the agent loop that consumes it.
|
|
5
|
+
*
|
|
6
|
+
* They are registry symbols (`Symbol.for`) because the stream and the loop can
|
|
7
|
+
* hold different copies of this module: the release bundle emits the Cursor
|
|
8
|
+
* provider as a self-contained chunk beside the main graph (#2334).
|
|
5
9
|
*/
|
|
6
10
|
/** Stores streamed tool-call argument JSON for live renderers and parser recovery. */
|
|
7
11
|
export declare const kStreamingPartialJson: unique symbol;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block-symbols.d.ts","sourceRoot":"","sources":["../../src/utils/block-symbols.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"block-symbols.d.ts","sourceRoot":"","sources":["../../src/utils/block-symbols.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,sFAAsF;AACtF,eAAO,MAAM,qBAAqB,eAA2C,CAAC;AAE9E,yFAAyF;AACzF,MAAM,MAAM,2BAA2B,GAAG,MAAM,GAAG;IAAE,CAAC,qBAAqB,CAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAExF,yFAAyF;AACzF,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,2BAA2B,GAAG,IAAI,CAElF;AAED,2FAA2F;AAC3F,eAAO,MAAM,oBAAoB,eAAqC,CAAC;AAEvE,0FAA0F;AAC1F,eAAO,MAAM,sBAAsB,eAA4C,CAAC;AAEhF;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,eAA0C,CAAC;AAE5E,2FAA2F;AAC3F,eAAO,MAAM,mBAAmB,eAAoC,CAAC;AAErE;;;;;;;;;;GAUG;AACH,eAAO,MAAM,mBAAmB,eAAkD,CAAC;AAEnF,4EAA4E;AAC5E,MAAM,MAAM,yBAAyB,GAAG,MAAM,GAAG;IAAE,CAAC,mBAAmB,CAAC,CAAC,EAAE,IAAI,CAAA;CAAE,CAAC;AAElF,gFAAgF;AAChF,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,yBAAyB,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAEjG;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,yBAAyB,EAAE,MAAM,EAAE,yBAAyB,GAAG,IAAI,CAEjH"}
|
|
@@ -2,18 +2,22 @@
|
|
|
2
2
|
* Symbol-keyed markers carried on streamed content blocks. Symbol keys never
|
|
3
3
|
* survive the JSONL persistence round-trip, so these are strictly in-memory
|
|
4
4
|
* coordination between a provider stream and the agent loop that consumes it.
|
|
5
|
+
*
|
|
6
|
+
* They are registry symbols (`Symbol.for`) because the stream and the loop can
|
|
7
|
+
* hold different copies of this module: the release bundle emits the Cursor
|
|
8
|
+
* provider as a self-contained chunk beside the main graph (#2334).
|
|
5
9
|
*/
|
|
6
10
|
/** Stores streamed tool-call argument JSON for live renderers and parser recovery. */
|
|
7
|
-
export const kStreamingPartialJson = Symbol("provider.block.partialJson");
|
|
11
|
+
export const kStreamingPartialJson = Symbol.for("provider.block.partialJson");
|
|
8
12
|
/** Clears streamed tool-call argument JSON without deleting or changing object shape. */
|
|
9
13
|
export function clearStreamingPartialJson(block) {
|
|
10
14
|
if (Object.hasOwn(block, kStreamingPartialJson))
|
|
11
15
|
block[kStreamingPartialJson] = undefined;
|
|
12
16
|
}
|
|
13
17
|
/** Stores a provider-local stream block index without exposing a string-keyed property. */
|
|
14
|
-
export const kStreamingBlockIndex = Symbol("provider.block.index");
|
|
18
|
+
export const kStreamingBlockIndex = Symbol.for("provider.block.index");
|
|
15
19
|
/** Stores the last parsed argument prefix length for throttled streaming JSON parsing. */
|
|
16
|
-
export const kStreamingLastParseLen = Symbol("provider.block.lastParseLen");
|
|
20
|
+
export const kStreamingLastParseLen = Symbol.for("provider.block.lastParseLen");
|
|
17
21
|
/**
|
|
18
22
|
* The Cursor interaction envelope's `call_id` for a streamed tool-call block.
|
|
19
23
|
*
|
|
@@ -24,9 +28,9 @@ export const kStreamingLastParseLen = Symbol("provider.block.lastParseLen");
|
|
|
24
28
|
* completions against the block id would mis-route every call whose args carry
|
|
25
29
|
* their own id.
|
|
26
30
|
*/
|
|
27
|
-
export const kStreamingEnvelopeId = Symbol("provider.block.envelopeId");
|
|
31
|
+
export const kStreamingEnvelopeId = Symbol.for("provider.block.envelopeId");
|
|
28
32
|
/** Classifies Cursor's in-flight tool-call kind without leaking provider-private state. */
|
|
29
|
-
export const kStreamingBlockKind = Symbol("provider.block.kind");
|
|
33
|
+
export const kStreamingBlockKind = Symbol.for("provider.block.kind");
|
|
30
34
|
/**
|
|
31
35
|
* Marks a `toolCall` content block that Cursor's exec channel already
|
|
32
36
|
* executed (via the coding-agent bridge) and whose result is buffered
|
|
@@ -38,7 +42,7 @@ export const kStreamingBlockKind = Symbol("provider.block.kind");
|
|
|
38
42
|
* so it never persists across the JSONL round-trip, where rebuild instead
|
|
39
43
|
* pairs the block with its already-persisted `toolResult` message by id.
|
|
40
44
|
*/
|
|
41
|
-
export const kCursorExecResolved = Symbol("provider.block.cursorExecResolved");
|
|
45
|
+
export const kCursorExecResolved = Symbol.for("provider.block.cursorExecResolved");
|
|
42
46
|
/** True when a toolCall block was already executed by Cursor's exec channel. */
|
|
43
47
|
export function isCursorExecResolved(block) {
|
|
44
48
|
return block?.[kCursorExecResolved] === true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block-symbols.js","sourceRoot":"","sources":["../../src/utils/block-symbols.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"block-symbols.js","sourceRoot":"","sources":["../../src/utils/block-symbols.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,sFAAsF;AACtF,MAAM,CAAC,MAAM,qBAAqB,GAAG,MAAM,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;AAK9E,yFAAyF;AACzF,MAAM,UAAU,yBAAyB,CAAC,KAAkC;IAC3E,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,qBAAqB,CAAC;QAAE,KAAK,CAAC,qBAAqB,CAAC,GAAG,SAAS,CAAC;AAC3F,CAAC;AAED,2FAA2F;AAC3F,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;AAEvE,0FAA0F;AAC1F,MAAM,CAAC,MAAM,sBAAsB,GAAG,MAAM,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;AAEhF;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;AAE5E,2FAA2F;AAC3F,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;AAErE;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;AAKnF,gFAAgF;AAChF,MAAM,UAAU,oBAAoB,CAAC,KAAmD;IACvF,OAAO,KAAK,EAAE,CAAC,mBAAmB,CAAC,KAAK,IAAI,CAAC;AAC9C,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,sBAAsB,CAAC,MAAiC,EAAE,MAAiC;IAC1G,IAAI,MAAM,CAAC,mBAAmB,CAAC,KAAK,IAAI;QAAE,MAAM,CAAC,mBAAmB,CAAC,GAAG,IAAI,CAAC;AAC9E,CAAC","sourcesContent":["/**\n * Symbol-keyed markers carried on streamed content blocks. Symbol keys never\n * survive the JSONL persistence round-trip, so these are strictly in-memory\n * coordination between a provider stream and the agent loop that consumes it.\n *\n * They are registry symbols (`Symbol.for`) because the stream and the loop can\n * hold different copies of this module: the release bundle emits the Cursor\n * provider as a self-contained chunk beside the main graph (#2334).\n */\n\n/** Stores streamed tool-call argument JSON for live renderers and parser recovery. */\nexport const kStreamingPartialJson = Symbol.for(\"provider.block.partialJson\");\n\n/** Carries streamed tool-call argument JSON without exposing a string-keyed property. */\nexport type StreamingPartialJsonCarrier = object & { [kStreamingPartialJson]?: string };\n\n/** Clears streamed tool-call argument JSON without deleting or changing object shape. */\nexport function clearStreamingPartialJson(block: StreamingPartialJsonCarrier): void {\n\tif (Object.hasOwn(block, kStreamingPartialJson)) block[kStreamingPartialJson] = undefined;\n}\n\n/** Stores a provider-local stream block index without exposing a string-keyed property. */\nexport const kStreamingBlockIndex = Symbol.for(\"provider.block.index\");\n\n/** Stores the last parsed argument prefix length for throttled streaming JSON parsing. */\nexport const kStreamingLastParseLen = Symbol.for(\"provider.block.lastParseLen\");\n\n/**\n * The Cursor interaction envelope's `call_id` for a streamed tool-call block.\n *\n * Tracked separately from the block's own `id` because they are NOT the same\n * key: MCP and Pi blocks are filed under the id inside the call's `args`, which\n * is what the exec channel pairs its result under, while every streamed\n * `ToolCall*Update` correlates on the envelope's `call_id`. Matching\n * completions against the block id would mis-route every call whose args carry\n * their own id.\n */\nexport const kStreamingEnvelopeId = Symbol.for(\"provider.block.envelopeId\");\n\n/** Classifies Cursor's in-flight tool-call kind without leaking provider-private state. */\nexport const kStreamingBlockKind = Symbol.for(\"provider.block.kind\");\n\n/**\n * Marks a `toolCall` content block that Cursor's exec channel already\n * executed (via the coding-agent bridge) and whose result is buffered\n * separately for emission alongside the assistant message.\n *\n * The agent loop MUST skip execution of blocks carrying this marker —\n * treating them as a fresh runnable tool call would run the same\n * side-effecting tool (bash, write, delete, …) a second time. Symbol-keyed\n * so it never persists across the JSONL round-trip, where rebuild instead\n * pairs the block with its already-persisted `toolResult` message by id.\n */\nexport const kCursorExecResolved = Symbol.for(\"provider.block.cursorExecResolved\");\n\n/** Carries the resolved marker without exposing a string-keyed property. */\nexport type CursorExecResolvedCarrier = object & { [kCursorExecResolved]?: true };\n\n/** True when a toolCall block was already executed by Cursor's exec channel. */\nexport function isCursorExecResolved(block: CursorExecResolvedCarrier | null | undefined): boolean {\n\treturn block?.[kCursorExecResolved] === true;\n}\n\n/**\n * Copy {@link kCursorExecResolved} onto a cloned/projected toolCall block.\n *\n * Stream projectors that rebuild toolCall objects field-by-field would\n * otherwise drop the marker and let the agent loop re-execute a call Cursor\n * already settled — duplicate toolResults and a second bash/write/delete.\n */\nexport function copyCursorExecResolved(target: CursorExecResolvedCarrier, source: CursorExecResolvedCarrier): void {\n\tif (source[kCursorExecResolved] === true) target[kCursorExecResolved] = true;\n}\n"]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type ClaudeCodeVersionStore } from "./claude-code-version.ts";
|
|
2
|
+
/** Same resolution as the other pi-ai stores: the agent directory the host configured, then the default one. */
|
|
3
|
+
export declare function resolveClaudeCodeVersionCachePath(env?: NodeJS.ProcessEnv): string;
|
|
4
|
+
export declare function createClaudeCodeVersionFileStore(path: string): ClaudeCodeVersionStore;
|
|
5
|
+
export interface InstallClaudeCodeVersionFileStoreOptions {
|
|
6
|
+
/** Cache file; defaults to `<agent dir>/claude-code-version.json`. */
|
|
7
|
+
readonly path?: string;
|
|
8
|
+
/** Serve the cache but never fetch (host offline mode); defaults to `PI_OFFLINE`. */
|
|
9
|
+
readonly offline?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare function installClaudeCodeVersionFileStore(options?: InstallClaudeCodeVersionFileStoreOptions): void;
|
|
12
|
+
//# sourceMappingURL=claude-code-version-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-code-version-cache.d.ts","sourceRoot":"","sources":["../../src/utils/claude-code-version-cache.ts"],"names":[],"mappings":"AASA,OAAO,EAEN,KAAK,sBAAsB,EAE3B,MAAM,0BAA0B,CAAC;AAIlC,gHAAgH;AAChH,wBAAgB,iCAAiC,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAI9F;AAWD,wBAAgB,gCAAgC,CAAC,IAAI,EAAE,MAAM,GAAG,sBAAsB,CA4BrF;AAED,MAAM,WAAW,wCAAwC;IACxD,sEAAsE;IACtE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,qFAAqF;IACrF,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,wBAAgB,iCAAiC,CAAC,OAAO,GAAE,wCAA6C,GAAG,IAAI,CAO9G"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node entry point for the Claude Code version cache.
|
|
3
|
+
*
|
|
4
|
+
* `claude-code-version.ts` is browser-safe and keeps no state on disk. Hosts with a filesystem
|
|
5
|
+
* call `installClaudeCodeVersionFileStore()` once at startup so the resolved version survives
|
|
6
|
+
* process restarts and one lookup per six hours serves every session on the machine.
|
|
7
|
+
*/
|
|
8
|
+
import { mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
9
|
+
import { dirname } from "node:path";
|
|
10
|
+
import { installClaudeCodeVersionStore, } from "./claude-code-version.js";
|
|
11
|
+
const CACHE_FILE = "claude-code-version.json";
|
|
12
|
+
/** Same resolution as the other pi-ai stores: the agent directory the host configured, then the default one. */
|
|
13
|
+
export function resolveClaudeCodeVersionCachePath(env = process.env) {
|
|
14
|
+
const agentDir = env.SENPI_CODING_AGENT_DIR ?? env.CODING_AGENT_DIR ?? `${(env.HOME ?? ".").replace(/\/$/, "")}/.senpi/agent`;
|
|
15
|
+
return `${agentDir.replace(/\/$/, "")}/${CACHE_FILE}`;
|
|
16
|
+
}
|
|
17
|
+
function isCachedVersion(value) {
|
|
18
|
+
return (typeof value === "object" &&
|
|
19
|
+
value !== null &&
|
|
20
|
+
typeof value.version === "string" &&
|
|
21
|
+
typeof value.checkedAt === "number");
|
|
22
|
+
}
|
|
23
|
+
export function createClaudeCodeVersionFileStore(path) {
|
|
24
|
+
let savingEnabled = true;
|
|
25
|
+
return {
|
|
26
|
+
load: () => {
|
|
27
|
+
let parsed;
|
|
28
|
+
try {
|
|
29
|
+
parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
// No file on first run, and a truncated or hand-edited one is the same situation
|
|
33
|
+
// for a cache: the bundled floor is the documented fallback.
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
return isCachedVersion(parsed) ? parsed : undefined;
|
|
37
|
+
},
|
|
38
|
+
save: (record) => {
|
|
39
|
+
if (!savingEnabled)
|
|
40
|
+
return;
|
|
41
|
+
try {
|
|
42
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
43
|
+
const temporaryPath = `${path}.${process.pid}.tmp`;
|
|
44
|
+
writeFileSync(temporaryPath, `${JSON.stringify(record)}\n`);
|
|
45
|
+
renameSync(temporaryPath, path);
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
// A read-only agent directory must not fail the live request, and one failure
|
|
49
|
+
// disables saving so a broken path cannot cost a write per refresh.
|
|
50
|
+
savingEnabled = false;
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
export function installClaudeCodeVersionFileStore(options = {}) {
|
|
56
|
+
const env = process.env;
|
|
57
|
+
const offline = options.offline ?? (env.PI_OFFLINE !== undefined && env.PI_OFFLINE !== "" && env.PI_OFFLINE !== "0");
|
|
58
|
+
installClaudeCodeVersionStore(createClaudeCodeVersionFileStore(options.path ?? resolveClaudeCodeVersionCachePath(env)), { offline });
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=claude-code-version-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-code-version-cache.js","sourceRoot":"","sources":["../../src/utils/claude-code-version-cache.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAGN,6BAA6B,GAC7B,MAAM,0BAA0B,CAAC;AAElC,MAAM,UAAU,GAAG,0BAA0B,CAAC;AAE9C,gHAAgH;AAChH,MAAM,UAAU,iCAAiC,CAAC,GAAG,GAAsB,OAAO,CAAC,GAAG;IACrF,MAAM,QAAQ,GACb,GAAG,CAAC,sBAAsB,IAAI,GAAG,CAAC,gBAAgB,IAAI,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,eAAe,CAAC;IAC9G,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,UAAU,EAAE,CAAC;AACvD,CAAC;AAED,SAAS,eAAe,CAAC,KAAc;IACtC,OAAO,CACN,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,OAAQ,KAA+B,CAAC,OAAO,KAAK,QAAQ;QAC5D,OAAQ,KAAiC,CAAC,SAAS,KAAK,QAAQ,CAChE,CAAC;AACH,CAAC;AAED,MAAM,UAAU,gCAAgC,CAAC,IAAY;IAC5D,IAAI,aAAa,GAAG,IAAI,CAAC;IACzB,OAAO;QACN,IAAI,EAAE,GAAG,EAAE;YACV,IAAI,MAAe,CAAC;YACpB,IAAI,CAAC;gBACJ,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;YACjD,CAAC;YAAC,MAAM,CAAC;gBACR,iFAAiF;gBACjF,6DAA6D;gBAC7D,OAAO,SAAS,CAAC;YAClB,CAAC;YACD,OAAO,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;QACrD,CAAC;QACD,IAAI,EAAE,CAAC,MAAM,EAAE,EAAE;YAChB,IAAI,CAAC,aAAa;gBAAE,OAAO;YAC3B,IAAI,CAAC;gBACJ,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC9C,MAAM,aAAa,GAAG,GAAG,IAAI,IAAI,OAAO,CAAC,GAAG,MAAM,CAAC;gBACnD,aAAa,CAAC,aAAa,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBAC5D,UAAU,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;YACjC,CAAC;YAAC,MAAM,CAAC;gBACR,8EAA8E;gBAC9E,oEAAoE;gBACpE,aAAa,GAAG,KAAK,CAAC;YACvB,CAAC;QACF,CAAC;KACD,CAAC;AACH,CAAC;AASD,MAAM,UAAU,iCAAiC,CAAC,OAAO,GAA6C,EAAE;IACvG,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IACxB,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,UAAU,KAAK,SAAS,IAAI,GAAG,CAAC,UAAU,KAAK,EAAE,IAAI,GAAG,CAAC,UAAU,KAAK,GAAG,CAAC,CAAC;IACrH,6BAA6B,CAC5B,gCAAgC,CAAC,OAAO,CAAC,IAAI,IAAI,iCAAiC,CAAC,GAAG,CAAC,CAAC,EACxF,EAAE,OAAO,EAAE,CACX,CAAC;AACH,CAAC","sourcesContent":["/**\n * Node entry point for the Claude Code version cache.\n *\n * `claude-code-version.ts` is browser-safe and keeps no state on disk. Hosts with a filesystem\n * call `installClaudeCodeVersionFileStore()` once at startup so the resolved version survives\n * process restarts and one lookup per six hours serves every session on the machine.\n */\nimport { mkdirSync, readFileSync, renameSync, writeFileSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport {\n\ttype CachedClaudeCodeVersion,\n\ttype ClaudeCodeVersionStore,\n\tinstallClaudeCodeVersionStore,\n} from \"./claude-code-version.ts\";\n\nconst CACHE_FILE = \"claude-code-version.json\";\n\n/** Same resolution as the other pi-ai stores: the agent directory the host configured, then the default one. */\nexport function resolveClaudeCodeVersionCachePath(env: NodeJS.ProcessEnv = process.env): string {\n\tconst agentDir =\n\t\tenv.SENPI_CODING_AGENT_DIR ?? env.CODING_AGENT_DIR ?? `${(env.HOME ?? \".\").replace(/\\/$/, \"\")}/.senpi/agent`;\n\treturn `${agentDir.replace(/\\/$/, \"\")}/${CACHE_FILE}`;\n}\n\nfunction isCachedVersion(value: unknown): value is CachedClaudeCodeVersion {\n\treturn (\n\t\ttypeof value === \"object\" &&\n\t\tvalue !== null &&\n\t\ttypeof (value as { version?: unknown }).version === \"string\" &&\n\t\ttypeof (value as { checkedAt?: unknown }).checkedAt === \"number\"\n\t);\n}\n\nexport function createClaudeCodeVersionFileStore(path: string): ClaudeCodeVersionStore {\n\tlet savingEnabled = true;\n\treturn {\n\t\tload: () => {\n\t\t\tlet parsed: unknown;\n\t\t\ttry {\n\t\t\t\tparsed = JSON.parse(readFileSync(path, \"utf8\"));\n\t\t\t} catch {\n\t\t\t\t// No file on first run, and a truncated or hand-edited one is the same situation\n\t\t\t\t// for a cache: the bundled floor is the documented fallback.\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\treturn isCachedVersion(parsed) ? parsed : undefined;\n\t\t},\n\t\tsave: (record) => {\n\t\t\tif (!savingEnabled) return;\n\t\t\ttry {\n\t\t\t\tmkdirSync(dirname(path), { recursive: true });\n\t\t\t\tconst temporaryPath = `${path}.${process.pid}.tmp`;\n\t\t\t\twriteFileSync(temporaryPath, `${JSON.stringify(record)}\\n`);\n\t\t\t\trenameSync(temporaryPath, path);\n\t\t\t} catch {\n\t\t\t\t// A read-only agent directory must not fail the live request, and one failure\n\t\t\t\t// disables saving so a broken path cannot cost a write per refresh.\n\t\t\t\tsavingEnabled = false;\n\t\t\t}\n\t\t},\n\t};\n}\n\nexport interface InstallClaudeCodeVersionFileStoreOptions {\n\t/** Cache file; defaults to `<agent dir>/claude-code-version.json`. */\n\treadonly path?: string;\n\t/** Serve the cache but never fetch (host offline mode); defaults to `PI_OFFLINE`. */\n\treadonly offline?: boolean;\n}\n\nexport function installClaudeCodeVersionFileStore(options: InstallClaudeCodeVersionFileStoreOptions = {}): void {\n\tconst env = process.env;\n\tconst offline = options.offline ?? (env.PI_OFFLINE !== undefined && env.PI_OFFLINE !== \"\" && env.PI_OFFLINE !== \"0\");\n\tinstallClaudeCodeVersionStore(\n\t\tcreateClaudeCodeVersionFileStore(options.path ?? resolveClaudeCodeVersionCachePath(env)),\n\t\t{ offline },\n\t);\n}\n"]}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code version the Anthropic OAuth `claude-cli/<version>` fingerprint advertises.
|
|
3
|
+
*
|
|
4
|
+
* Anthropic gates new models behind a minimum Claude Code version and answers an older
|
|
5
|
+
* fingerprint with HTTP 400 `claude_code_version_too_old`. A build-time constant goes stale
|
|
6
|
+
* between releases, so the fingerprint is the higher of the bundled floor and the latest
|
|
7
|
+
* published Claude Code release, resolved in the background and cached by the host through
|
|
8
|
+
* `ClaudeCodeVersionStore`. A request never waits on the lookup: it signs with whatever is
|
|
9
|
+
* known at that instant, and a too-old rejection raises the version at once.
|
|
10
|
+
*/
|
|
11
|
+
import type { ProviderEnv } from "../types.ts";
|
|
12
|
+
/** Exact `X.Y.Z` pins the fingerprint and skips the network lookup. */
|
|
13
|
+
export declare const CLAUDE_CODE_VERSION_PIN_ENV = "PI_CLAUDE_CODE_VERSION";
|
|
14
|
+
/**
|
|
15
|
+
* Anthropic's native-installer release channel. `stable` lags the npm package during a staged
|
|
16
|
+
* rollout, so `latest` is the channel that matches what a freshly updated Claude Code reports.
|
|
17
|
+
*/
|
|
18
|
+
export declare const CLAUDE_RELEASE_CHANNEL_URL = "https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases/latest";
|
|
19
|
+
export declare const CLAUDE_NPM_DIST_TAG_URL = "https://registry.npmjs.org/@anthropic-ai/claude-code/latest";
|
|
20
|
+
export interface CachedClaudeCodeVersion {
|
|
21
|
+
readonly version: string;
|
|
22
|
+
readonly checkedAt: number;
|
|
23
|
+
}
|
|
24
|
+
export interface ClaudeCodeVersionStore {
|
|
25
|
+
load(): CachedClaudeCodeVersion | undefined;
|
|
26
|
+
save(record: CachedClaudeCodeVersion): void;
|
|
27
|
+
}
|
|
28
|
+
export interface ClaudeCodeVersionResolverOptions {
|
|
29
|
+
readonly floor: string;
|
|
30
|
+
readonly pinned?: string | undefined;
|
|
31
|
+
/** `null` disables caching and network resolution: the resolver answers the floor or a raised version. */
|
|
32
|
+
readonly store: ClaudeCodeVersionStore | null;
|
|
33
|
+
/** Serve the cache but never fetch (host offline mode). */
|
|
34
|
+
readonly offline?: boolean;
|
|
35
|
+
readonly fetch?: typeof fetch;
|
|
36
|
+
readonly now?: () => number;
|
|
37
|
+
readonly refreshIntervalMs?: number;
|
|
38
|
+
}
|
|
39
|
+
export interface ClaudeCodeVersionResolver {
|
|
40
|
+
/** Current fingerprint; schedules one background refresh when the cache is stale. */
|
|
41
|
+
get(): string;
|
|
42
|
+
/** Refresh now (deduplicated); resolves with the fingerprint afterwards. */
|
|
43
|
+
refresh(): Promise<string>;
|
|
44
|
+
/** Adopt `version` at once when it is newer than the current fingerprint; returns the fingerprint. */
|
|
45
|
+
raise(version: string): string;
|
|
46
|
+
}
|
|
47
|
+
export declare function compareClaudeCodeVersions(a: string, b: string): number;
|
|
48
|
+
/**
|
|
49
|
+
* Latest published Claude Code version: the higher of the native-installer `latest` channel and
|
|
50
|
+
* the npm dist-tag, so one lagging or unavailable source cannot hold the fingerprint back.
|
|
51
|
+
*/
|
|
52
|
+
export declare function fetchLatestClaudeCodeVersion(fetchImpl?: typeof fetch): Promise<string | undefined>;
|
|
53
|
+
export declare function requiredClaudeCodeVersionFromError(message: string): string | undefined;
|
|
54
|
+
export declare function isClaudeCodeVersionTooOldError(error: unknown): error is Error & {
|
|
55
|
+
status: 400;
|
|
56
|
+
};
|
|
57
|
+
export declare function createClaudeCodeVersionResolver(options: ClaudeCodeVersionResolverOptions): ClaudeCodeVersionResolver;
|
|
58
|
+
/**
|
|
59
|
+
* Hosts with a filesystem install their cache here once at startup (see
|
|
60
|
+
* `utils/claude-code-version-cache.ts`); until then, and in browsers, the resolver answers
|
|
61
|
+
* the floor without touching the network.
|
|
62
|
+
*/
|
|
63
|
+
export declare function installClaudeCodeVersionStore(store: ClaudeCodeVersionStore | null, options?: {
|
|
64
|
+
readonly offline?: boolean;
|
|
65
|
+
}): void;
|
|
66
|
+
/**
|
|
67
|
+
* The version the next OAuth request signs with. `floor` is the bundled Claude Code version the
|
|
68
|
+
* caller declares (the `claudeCodeVersion` constant in `api/anthropic-messages.ts`).
|
|
69
|
+
*/
|
|
70
|
+
export declare function getClaudeCodeVersion(floor: string, env?: ProviderEnv): string;
|
|
71
|
+
/**
|
|
72
|
+
* After a `claude_code_version_too_old` rejection: adopt the version the error names, or the
|
|
73
|
+
* latest published one, and report the fingerprint to retry with; `undefined` when nothing
|
|
74
|
+
* newer is available (pinned, or already at the required version).
|
|
75
|
+
*/
|
|
76
|
+
export declare function recoverClaudeCodeVersion(error: Error, floor: string, advertised: string, env?: ProviderEnv): Promise<string | undefined>;
|
|
77
|
+
export declare function claudeCodeVersionTooOldHint(advertised: string): string;
|
|
78
|
+
//# sourceMappingURL=claude-code-version.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-code-version.d.ts","sourceRoot":"","sources":["../../src/utils/claude-code-version.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/C,uEAAuE;AACvE,eAAO,MAAM,2BAA2B,2BAA2B,CAAC;AAEpE;;;GAGG;AACH,eAAO,MAAM,0BAA0B,qHAC4E,CAAC;AACpH,eAAO,MAAM,uBAAuB,gEAAgE,CAAC;AAQrG,MAAM,WAAW,uBAAuB;IACvC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,sBAAsB;IACtC,IAAI,IAAI,uBAAuB,GAAG,SAAS,CAAC;IAC5C,IAAI,CAAC,MAAM,EAAE,uBAAuB,GAAG,IAAI,CAAC;CAC5C;AAED,MAAM,WAAW,gCAAgC;IAChD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,0GAA0G;IAC1G,QAAQ,CAAC,KAAK,EAAE,sBAAsB,GAAG,IAAI,CAAC;IAC9C,2DAA2D;IAC3D,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IAC9B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IAC5B,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CACpC;AAED,MAAM,WAAW,yBAAyB;IACzC,qFAAqF;IACrF,GAAG,IAAI,MAAM,CAAC;IACd,4EAA4E;IAC5E,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAC3B,sGAAsG;IACtG,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;CAC/B;AAED,wBAAgB,yBAAyB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAQtE;AA2CD;;;GAGG;AACH,wBAAsB,4BAA4B,CAAC,SAAS,GAAE,OAAO,KAAa,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAE/G;AAED,wBAAgB,kCAAkC,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAItF;AAED,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,KAAK,GAAG;IAAE,MAAM,EAAE,GAAG,CAAA;CAAE,CAE/F;AAED,wBAAgB,+BAA+B,CAAC,OAAO,EAAE,gCAAgC,GAAG,yBAAyB,CAuEpH;AAOD;;;;GAIG;AACH,wBAAgB,6BAA6B,CAC5C,KAAK,EAAE,sBAAsB,GAAG,IAAI,EACpC,OAAO,GAAE;IAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAO,GAC1C,IAAI,CAIN;AAeD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,WAAW,GAAG,MAAM,CAE7E;AAED;;;;GAIG;AACH,wBAAsB,wBAAwB,CAC7C,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,EAClB,GAAG,CAAC,EAAE,WAAW,GACf,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAK7B;AAED,wBAAgB,2BAA2B,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEtE"}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { getProviderEnvValue } from "./provider-env.js";
|
|
2
|
+
/** Exact `X.Y.Z` pins the fingerprint and skips the network lookup. */
|
|
3
|
+
export const CLAUDE_CODE_VERSION_PIN_ENV = "PI_CLAUDE_CODE_VERSION";
|
|
4
|
+
/**
|
|
5
|
+
* Anthropic's native-installer release channel. `stable` lags the npm package during a staged
|
|
6
|
+
* rollout, so `latest` is the channel that matches what a freshly updated Claude Code reports.
|
|
7
|
+
*/
|
|
8
|
+
export const CLAUDE_RELEASE_CHANNEL_URL = "https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases/latest";
|
|
9
|
+
export const CLAUDE_NPM_DIST_TAG_URL = "https://registry.npmjs.org/@anthropic-ai/claude-code/latest";
|
|
10
|
+
const REFRESH_INTERVAL_MS = 6 * 60 * 60 * 1000;
|
|
11
|
+
const FETCH_TIMEOUT_MS = 5_000;
|
|
12
|
+
const EXACT_SEMVER = /^(\d+)\.(\d+)\.(\d+)$/;
|
|
13
|
+
const EMBEDDED_SEMVER = /(\d+\.\d+\.\d+)/;
|
|
14
|
+
const TOO_OLD_REJECTION = /claude_code_version_too_old|does not support this model; version (\d+\.\d+\.\d+) or newer/i;
|
|
15
|
+
export function compareClaudeCodeVersions(a, b) {
|
|
16
|
+
const left = a.split(".").map(Number);
|
|
17
|
+
const right = b.split(".").map(Number);
|
|
18
|
+
for (let i = 0; i < 3; i++) {
|
|
19
|
+
const diff = (left[i] ?? 0) - (right[i] ?? 0);
|
|
20
|
+
if (diff !== 0)
|
|
21
|
+
return diff;
|
|
22
|
+
}
|
|
23
|
+
return 0;
|
|
24
|
+
}
|
|
25
|
+
function isExactSemver(value) {
|
|
26
|
+
return typeof value === "string" && EXACT_SEMVER.test(value);
|
|
27
|
+
}
|
|
28
|
+
function highest(candidates) {
|
|
29
|
+
let best;
|
|
30
|
+
for (const candidate of candidates) {
|
|
31
|
+
if (!isExactSemver(candidate))
|
|
32
|
+
continue;
|
|
33
|
+
if (best === undefined || compareClaudeCodeVersions(candidate, best) > 0)
|
|
34
|
+
best = candidate;
|
|
35
|
+
}
|
|
36
|
+
return best;
|
|
37
|
+
}
|
|
38
|
+
async function fetchText(fetchImpl, url) {
|
|
39
|
+
try {
|
|
40
|
+
const response = await fetchImpl(url, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS) });
|
|
41
|
+
return response.ok ? await response.text() : undefined;
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// Offline, DNS failure, or timeout: the caller keeps the floor or the cached value.
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
async function fetchReleaseChannel(fetchImpl) {
|
|
49
|
+
const text = await fetchText(fetchImpl, CLAUDE_RELEASE_CHANNEL_URL);
|
|
50
|
+
return text === undefined ? undefined : EMBEDDED_SEMVER.exec(text.trim())?.[1];
|
|
51
|
+
}
|
|
52
|
+
async function fetchNpmDistTag(fetchImpl) {
|
|
53
|
+
const text = await fetchText(fetchImpl, CLAUDE_NPM_DIST_TAG_URL);
|
|
54
|
+
if (text === undefined)
|
|
55
|
+
return undefined;
|
|
56
|
+
try {
|
|
57
|
+
const data = JSON.parse(text);
|
|
58
|
+
const version = typeof data === "object" && data !== null && "version" in data ? data.version : undefined;
|
|
59
|
+
return typeof version === "string" ? EMBEDDED_SEMVER.exec(version)?.[1] : undefined;
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
// A registry error page is not a dist-tag document.
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Latest published Claude Code version: the higher of the native-installer `latest` channel and
|
|
68
|
+
* the npm dist-tag, so one lagging or unavailable source cannot hold the fingerprint back.
|
|
69
|
+
*/
|
|
70
|
+
export async function fetchLatestClaudeCodeVersion(fetchImpl = fetch) {
|
|
71
|
+
return highest(await Promise.all([fetchReleaseChannel(fetchImpl), fetchNpmDistTag(fetchImpl)]));
|
|
72
|
+
}
|
|
73
|
+
export function requiredClaudeCodeVersionFromError(message) {
|
|
74
|
+
const match = TOO_OLD_REJECTION.exec(message);
|
|
75
|
+
if (!match)
|
|
76
|
+
return undefined;
|
|
77
|
+
return match[1] ?? /version (\d+\.\d+\.\d+) or newer/i.exec(message)?.[1];
|
|
78
|
+
}
|
|
79
|
+
export function isClaudeCodeVersionTooOldError(error) {
|
|
80
|
+
return error instanceof Error && "status" in error && error.status === 400 && TOO_OLD_REJECTION.test(error.message);
|
|
81
|
+
}
|
|
82
|
+
export function createClaudeCodeVersionResolver(options) {
|
|
83
|
+
const { floor, store } = options;
|
|
84
|
+
const offline = options.offline === true;
|
|
85
|
+
const fetchImpl = options.fetch ?? fetch;
|
|
86
|
+
const now = options.now ?? Date.now;
|
|
87
|
+
const refreshIntervalMs = options.refreshIntervalMs ?? REFRESH_INTERVAL_MS;
|
|
88
|
+
const pinned = isExactSemver(options.pinned) ? options.pinned : undefined;
|
|
89
|
+
let loaded = false;
|
|
90
|
+
let resolved;
|
|
91
|
+
let checkedAt = 0;
|
|
92
|
+
let inflight;
|
|
93
|
+
const current = () => resolved !== undefined && compareClaudeCodeVersions(resolved, floor) > 0 ? resolved : floor;
|
|
94
|
+
const loadCache = () => {
|
|
95
|
+
if (loaded || store === null)
|
|
96
|
+
return;
|
|
97
|
+
loaded = true;
|
|
98
|
+
const record = store.load();
|
|
99
|
+
if (record && isExactSemver(record.version) && Number.isFinite(record.checkedAt)) {
|
|
100
|
+
resolved = record.version;
|
|
101
|
+
checkedAt = record.checkedAt;
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
const persist = () => {
|
|
105
|
+
if (store !== null && resolved !== undefined)
|
|
106
|
+
store.save({ version: resolved, checkedAt });
|
|
107
|
+
};
|
|
108
|
+
const refresh = () => {
|
|
109
|
+
if (pinned !== undefined || store === null)
|
|
110
|
+
return Promise.resolve(pinned ?? current());
|
|
111
|
+
loadCache();
|
|
112
|
+
if (offline)
|
|
113
|
+
return Promise.resolve(current());
|
|
114
|
+
inflight ??= (async () => {
|
|
115
|
+
try {
|
|
116
|
+
const latest = await fetchLatestClaudeCodeVersion(fetchImpl);
|
|
117
|
+
// A failed lookup still counts as a check: an offline host waits a full interval
|
|
118
|
+
// before trying again instead of retrying on every request.
|
|
119
|
+
checkedAt = now();
|
|
120
|
+
if (latest !== undefined && (resolved === undefined || compareClaudeCodeVersions(latest, resolved) > 0)) {
|
|
121
|
+
resolved = latest;
|
|
122
|
+
}
|
|
123
|
+
persist();
|
|
124
|
+
}
|
|
125
|
+
finally {
|
|
126
|
+
inflight = undefined;
|
|
127
|
+
}
|
|
128
|
+
return current();
|
|
129
|
+
})();
|
|
130
|
+
return inflight;
|
|
131
|
+
};
|
|
132
|
+
return {
|
|
133
|
+
get() {
|
|
134
|
+
if (pinned !== undefined)
|
|
135
|
+
return pinned;
|
|
136
|
+
if (store === null)
|
|
137
|
+
return current();
|
|
138
|
+
loadCache();
|
|
139
|
+
if (!offline && inflight === undefined && now() - checkedAt >= refreshIntervalMs)
|
|
140
|
+
void refresh();
|
|
141
|
+
return current();
|
|
142
|
+
},
|
|
143
|
+
refresh,
|
|
144
|
+
raise(version) {
|
|
145
|
+
if (pinned !== undefined)
|
|
146
|
+
return pinned;
|
|
147
|
+
loadCache();
|
|
148
|
+
if (isExactSemver(version) && compareClaudeCodeVersions(version, current()) > 0) {
|
|
149
|
+
resolved = version;
|
|
150
|
+
persist();
|
|
151
|
+
}
|
|
152
|
+
return current();
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
let installedStore = null;
|
|
157
|
+
let installedOffline = false;
|
|
158
|
+
let defaultResolver;
|
|
159
|
+
let defaultFloor;
|
|
160
|
+
/**
|
|
161
|
+
* Hosts with a filesystem install their cache here once at startup (see
|
|
162
|
+
* `utils/claude-code-version-cache.ts`); until then, and in browsers, the resolver answers
|
|
163
|
+
* the floor without touching the network.
|
|
164
|
+
*/
|
|
165
|
+
export function installClaudeCodeVersionStore(store, options = {}) {
|
|
166
|
+
installedStore = store;
|
|
167
|
+
installedOffline = options.offline === true;
|
|
168
|
+
defaultResolver = undefined;
|
|
169
|
+
}
|
|
170
|
+
function resolver(floor) {
|
|
171
|
+
if (defaultResolver === undefined || defaultFloor !== floor) {
|
|
172
|
+
defaultFloor = floor;
|
|
173
|
+
defaultResolver = createClaudeCodeVersionResolver({ floor, store: installedStore, offline: installedOffline });
|
|
174
|
+
}
|
|
175
|
+
return defaultResolver;
|
|
176
|
+
}
|
|
177
|
+
function pinnedClaudeCodeVersion(env) {
|
|
178
|
+
const pin = getProviderEnvValue(CLAUDE_CODE_VERSION_PIN_ENV, env)?.trim();
|
|
179
|
+
return isExactSemver(pin) ? pin : undefined;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* The version the next OAuth request signs with. `floor` is the bundled Claude Code version the
|
|
183
|
+
* caller declares (the `claudeCodeVersion` constant in `api/anthropic-messages.ts`).
|
|
184
|
+
*/
|
|
185
|
+
export function getClaudeCodeVersion(floor, env) {
|
|
186
|
+
return pinnedClaudeCodeVersion(env) ?? resolver(floor).get();
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* After a `claude_code_version_too_old` rejection: adopt the version the error names, or the
|
|
190
|
+
* latest published one, and report the fingerprint to retry with; `undefined` when nothing
|
|
191
|
+
* newer is available (pinned, or already at the required version).
|
|
192
|
+
*/
|
|
193
|
+
export async function recoverClaudeCodeVersion(error, floor, advertised, env) {
|
|
194
|
+
if (pinnedClaudeCodeVersion(env) !== undefined)
|
|
195
|
+
return undefined;
|
|
196
|
+
const required = requiredClaudeCodeVersionFromError(error.message);
|
|
197
|
+
const next = required === undefined ? await resolver(floor).refresh() : resolver(floor).raise(required);
|
|
198
|
+
return compareClaudeCodeVersions(next, advertised) > 0 ? next : undefined;
|
|
199
|
+
}
|
|
200
|
+
export function claudeCodeVersionTooOldHint(advertised) {
|
|
201
|
+
return `senpi advertised claude-cli/${advertised}; Anthropic requires a newer Claude Code for this model. senpi refreshes the version automatically when online; set ${CLAUDE_CODE_VERSION_PIN_ENV}=X.Y.Z to advertise a specific one.`;
|
|
202
|
+
}
|
|
203
|
+
//# sourceMappingURL=claude-code-version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-code-version.js","sourceRoot":"","sources":["../../src/utils/claude-code-version.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Claude Code version the Anthropic OAuth `claude-cli/<version>` fingerprint advertises.\n *\n * Anthropic gates new models behind a minimum Claude Code version and answers an older\n * fingerprint with HTTP 400 `claude_code_version_too_old`. A build-time constant goes stale\n * between releases, so the fingerprint is the higher of the bundled floor and the latest\n * published Claude Code release, resolved in the background and cached by the host through\n * `ClaudeCodeVersionStore`. A request never waits on the lookup: it signs with whatever is\n * known at that instant, and a too-old rejection raises the version at once.\n */\nimport type { ProviderEnv } from \"../types.ts\";\nimport { getProviderEnvValue } from \"./provider-env.ts\";\n\n/** Exact `X.Y.Z` pins the fingerprint and skips the network lookup. */\nexport const CLAUDE_CODE_VERSION_PIN_ENV = \"PI_CLAUDE_CODE_VERSION\";\n\n/**\n * Anthropic's native-installer release channel. `stable` lags the npm package during a staged\n * rollout, so `latest` is the channel that matches what a freshly updated Claude Code reports.\n */\nexport const CLAUDE_RELEASE_CHANNEL_URL =\n\t\"https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases/latest\";\nexport const CLAUDE_NPM_DIST_TAG_URL = \"https://registry.npmjs.org/@anthropic-ai/claude-code/latest\";\n\nconst REFRESH_INTERVAL_MS = 6 * 60 * 60 * 1000;\nconst FETCH_TIMEOUT_MS = 5_000;\nconst EXACT_SEMVER = /^(\\d+)\\.(\\d+)\\.(\\d+)$/;\nconst EMBEDDED_SEMVER = /(\\d+\\.\\d+\\.\\d+)/;\nconst TOO_OLD_REJECTION = /claude_code_version_too_old|does not support this model; version (\\d+\\.\\d+\\.\\d+) or newer/i;\n\nexport interface CachedClaudeCodeVersion {\n\treadonly version: string;\n\treadonly checkedAt: number;\n}\n\nexport interface ClaudeCodeVersionStore {\n\tload(): CachedClaudeCodeVersion | undefined;\n\tsave(record: CachedClaudeCodeVersion): void;\n}\n\nexport interface ClaudeCodeVersionResolverOptions {\n\treadonly floor: string;\n\treadonly pinned?: string | undefined;\n\t/** `null` disables caching and network resolution: the resolver answers the floor or a raised version. */\n\treadonly store: ClaudeCodeVersionStore | null;\n\t/** Serve the cache but never fetch (host offline mode). */\n\treadonly offline?: boolean;\n\treadonly fetch?: typeof fetch;\n\treadonly now?: () => number;\n\treadonly refreshIntervalMs?: number;\n}\n\nexport interface ClaudeCodeVersionResolver {\n\t/** Current fingerprint; schedules one background refresh when the cache is stale. */\n\tget(): string;\n\t/** Refresh now (deduplicated); resolves with the fingerprint afterwards. */\n\trefresh(): Promise<string>;\n\t/** Adopt `version` at once when it is newer than the current fingerprint; returns the fingerprint. */\n\traise(version: string): string;\n}\n\nexport function compareClaudeCodeVersions(a: string, b: string): number {\n\tconst left = a.split(\".\").map(Number);\n\tconst right = b.split(\".\").map(Number);\n\tfor (let i = 0; i < 3; i++) {\n\t\tconst diff = (left[i] ?? 0) - (right[i] ?? 0);\n\t\tif (diff !== 0) return diff;\n\t}\n\treturn 0;\n}\n\nfunction isExactSemver(value: unknown): value is string {\n\treturn typeof value === \"string\" && EXACT_SEMVER.test(value);\n}\n\nfunction highest(candidates: ReadonlyArray<string | undefined>): string | undefined {\n\tlet best: string | undefined;\n\tfor (const candidate of candidates) {\n\t\tif (!isExactSemver(candidate)) continue;\n\t\tif (best === undefined || compareClaudeCodeVersions(candidate, best) > 0) best = candidate;\n\t}\n\treturn best;\n}\n\nasync function fetchText(fetchImpl: typeof fetch, url: string): Promise<string | undefined> {\n\ttry {\n\t\tconst response = await fetchImpl(url, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS) });\n\t\treturn response.ok ? await response.text() : undefined;\n\t} catch {\n\t\t// Offline, DNS failure, or timeout: the caller keeps the floor or the cached value.\n\t\treturn undefined;\n\t}\n}\n\nasync function fetchReleaseChannel(fetchImpl: typeof fetch): Promise<string | undefined> {\n\tconst text = await fetchText(fetchImpl, CLAUDE_RELEASE_CHANNEL_URL);\n\treturn text === undefined ? undefined : EMBEDDED_SEMVER.exec(text.trim())?.[1];\n}\n\nasync function fetchNpmDistTag(fetchImpl: typeof fetch): Promise<string | undefined> {\n\tconst text = await fetchText(fetchImpl, CLAUDE_NPM_DIST_TAG_URL);\n\tif (text === undefined) return undefined;\n\ttry {\n\t\tconst data: unknown = JSON.parse(text);\n\t\tconst version = typeof data === \"object\" && data !== null && \"version\" in data ? data.version : undefined;\n\t\treturn typeof version === \"string\" ? EMBEDDED_SEMVER.exec(version)?.[1] : undefined;\n\t} catch {\n\t\t// A registry error page is not a dist-tag document.\n\t\treturn undefined;\n\t}\n}\n\n/**\n * Latest published Claude Code version: the higher of the native-installer `latest` channel and\n * the npm dist-tag, so one lagging or unavailable source cannot hold the fingerprint back.\n */\nexport async function fetchLatestClaudeCodeVersion(fetchImpl: typeof fetch = fetch): Promise<string | undefined> {\n\treturn highest(await Promise.all([fetchReleaseChannel(fetchImpl), fetchNpmDistTag(fetchImpl)]));\n}\n\nexport function requiredClaudeCodeVersionFromError(message: string): string | undefined {\n\tconst match = TOO_OLD_REJECTION.exec(message);\n\tif (!match) return undefined;\n\treturn match[1] ?? /version (\\d+\\.\\d+\\.\\d+) or newer/i.exec(message)?.[1];\n}\n\nexport function isClaudeCodeVersionTooOldError(error: unknown): error is Error & { status: 400 } {\n\treturn error instanceof Error && \"status\" in error && error.status === 400 && TOO_OLD_REJECTION.test(error.message);\n}\n\nexport function createClaudeCodeVersionResolver(options: ClaudeCodeVersionResolverOptions): ClaudeCodeVersionResolver {\n\tconst { floor, store } = options;\n\tconst offline = options.offline === true;\n\tconst fetchImpl = options.fetch ?? fetch;\n\tconst now = options.now ?? Date.now;\n\tconst refreshIntervalMs = options.refreshIntervalMs ?? REFRESH_INTERVAL_MS;\n\tconst pinned = isExactSemver(options.pinned) ? options.pinned : undefined;\n\n\tlet loaded = false;\n\tlet resolved: string | undefined;\n\tlet checkedAt = 0;\n\tlet inflight: Promise<string> | undefined;\n\n\tconst current = (): string =>\n\t\tresolved !== undefined && compareClaudeCodeVersions(resolved, floor) > 0 ? resolved : floor;\n\n\tconst loadCache = (): void => {\n\t\tif (loaded || store === null) return;\n\t\tloaded = true;\n\t\tconst record = store.load();\n\t\tif (record && isExactSemver(record.version) && Number.isFinite(record.checkedAt)) {\n\t\t\tresolved = record.version;\n\t\t\tcheckedAt = record.checkedAt;\n\t\t}\n\t};\n\n\tconst persist = (): void => {\n\t\tif (store !== null && resolved !== undefined) store.save({ version: resolved, checkedAt });\n\t};\n\n\tconst refresh = (): Promise<string> => {\n\t\tif (pinned !== undefined || store === null) return Promise.resolve(pinned ?? current());\n\t\tloadCache();\n\t\tif (offline) return Promise.resolve(current());\n\t\tinflight ??= (async () => {\n\t\t\ttry {\n\t\t\t\tconst latest = await fetchLatestClaudeCodeVersion(fetchImpl);\n\t\t\t\t// A failed lookup still counts as a check: an offline host waits a full interval\n\t\t\t\t// before trying again instead of retrying on every request.\n\t\t\t\tcheckedAt = now();\n\t\t\t\tif (latest !== undefined && (resolved === undefined || compareClaudeCodeVersions(latest, resolved) > 0)) {\n\t\t\t\t\tresolved = latest;\n\t\t\t\t}\n\t\t\t\tpersist();\n\t\t\t} finally {\n\t\t\t\tinflight = undefined;\n\t\t\t}\n\t\t\treturn current();\n\t\t})();\n\t\treturn inflight;\n\t};\n\n\treturn {\n\t\tget() {\n\t\t\tif (pinned !== undefined) return pinned;\n\t\t\tif (store === null) return current();\n\t\t\tloadCache();\n\t\t\tif (!offline && inflight === undefined && now() - checkedAt >= refreshIntervalMs) void refresh();\n\t\t\treturn current();\n\t\t},\n\t\trefresh,\n\t\traise(version) {\n\t\t\tif (pinned !== undefined) return pinned;\n\t\t\tloadCache();\n\t\t\tif (isExactSemver(version) && compareClaudeCodeVersions(version, current()) > 0) {\n\t\t\t\tresolved = version;\n\t\t\t\tpersist();\n\t\t\t}\n\t\t\treturn current();\n\t\t},\n\t};\n}\n\nlet installedStore: ClaudeCodeVersionStore | null = null;\nlet installedOffline = false;\nlet defaultResolver: ClaudeCodeVersionResolver | undefined;\nlet defaultFloor: string | undefined;\n\n/**\n * Hosts with a filesystem install their cache here once at startup (see\n * `utils/claude-code-version-cache.ts`); until then, and in browsers, the resolver answers\n * the floor without touching the network.\n */\nexport function installClaudeCodeVersionStore(\n\tstore: ClaudeCodeVersionStore | null,\n\toptions: { readonly offline?: boolean } = {},\n): void {\n\tinstalledStore = store;\n\tinstalledOffline = options.offline === true;\n\tdefaultResolver = undefined;\n}\n\nfunction resolver(floor: string): ClaudeCodeVersionResolver {\n\tif (defaultResolver === undefined || defaultFloor !== floor) {\n\t\tdefaultFloor = floor;\n\t\tdefaultResolver = createClaudeCodeVersionResolver({ floor, store: installedStore, offline: installedOffline });\n\t}\n\treturn defaultResolver;\n}\n\nfunction pinnedClaudeCodeVersion(env?: ProviderEnv): string | undefined {\n\tconst pin = getProviderEnvValue(CLAUDE_CODE_VERSION_PIN_ENV, env)?.trim();\n\treturn isExactSemver(pin) ? pin : undefined;\n}\n\n/**\n * The version the next OAuth request signs with. `floor` is the bundled Claude Code version the\n * caller declares (the `claudeCodeVersion` constant in `api/anthropic-messages.ts`).\n */\nexport function getClaudeCodeVersion(floor: string, env?: ProviderEnv): string {\n\treturn pinnedClaudeCodeVersion(env) ?? resolver(floor).get();\n}\n\n/**\n * After a `claude_code_version_too_old` rejection: adopt the version the error names, or the\n * latest published one, and report the fingerprint to retry with; `undefined` when nothing\n * newer is available (pinned, or already at the required version).\n */\nexport async function recoverClaudeCodeVersion(\n\terror: Error,\n\tfloor: string,\n\tadvertised: string,\n\tenv?: ProviderEnv,\n): Promise<string | undefined> {\n\tif (pinnedClaudeCodeVersion(env) !== undefined) return undefined;\n\tconst required = requiredClaudeCodeVersionFromError(error.message);\n\tconst next = required === undefined ? await resolver(floor).refresh() : resolver(floor).raise(required);\n\treturn compareClaudeCodeVersions(next, advertised) > 0 ? next : undefined;\n}\n\nexport function claudeCodeVersionTooOldHint(advertised: string): string {\n\treturn `senpi advertised claude-cli/${advertised}; Anthropic requires a newer Claude Code for this model. senpi refreshes the version automatically when online; set ${CLAUDE_CODE_VERSION_PIN_ENV}=X.Y.Z to advertise a specific one.`;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cursor-context-limit.d.ts","sourceRoot":"","sources":["../../src/utils/cursor-context-limit.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cursor-context-limit.d.ts","sourceRoot":"","sources":["../../src/utils/cursor-context-limit.ts"],"names":[],"mappings":"AAsBA;;;GAGG;AACH,wBAAgB,kCAAkC,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAO/F;AAsDD,sFAAsF;AACtF,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAG7F;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGzE;AAED,qFAAqF;AACrF,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAGzF;AAED,wBAAgB,mCAAmC,IAAI,IAAI,CAG1D"}
|