ck-pi-zen-session 0.1.4 → 0.1.6

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 (3) hide show
  1. package/README.md +1 -1
  2. package/package.json +1 -1
  3. package/src/index.ts +21 -22
package/README.md CHANGED
@@ -24,7 +24,7 @@ OpenCode Zen 免费模型同步、请求头伪装与 Session 会话自动维护
24
24
  - 若用户处于纯文本或无工具模式,自动补齐官方完整的 6 大核心工具(`bash`, `edit`, `glob`, `grep`, `read`, `write`)与 `tool_choice: "auto"`,彻底根除 403 拦截;
25
25
  - 若请求已有工具,严格按照官方客户端规约(`localeCompare`)按函数名升序重排;
26
26
  - 自动对齐流式用量元数据 `stream_options: { include_usage: true }`。
27
- - 🌐 **独立供应商隔离命名空间**:注册为独立供应商 `opencode-zen-free`,彻底避开并兼容用户自带的官方登录 `opencode` / `opencode-zen` 套餐,互不干扰、平稳共存。
27
+ - 🌐 **独立供应商隔离与零干扰保障 (`isZenModelTarget`)**:严格将生命周期守卫、请求头与请求体拦截限制在 `opencode-zen-free` 命名空间内,对 `relayhub`、`deepseek`、`anthropic`、`openai`、`onerouter`、`apmix` 等其他任何模型及 Claude Code(`pi-cc-extensions`)插件 100% 保持完全静默放行,零副作用、零冲突。
28
28
  - 🧠 **精准上下文与思维链适配**:严格对齐免费模型的 `contextWindow`、`maxTokens` 与 `thinkingLevelMap`(涵盖小米 MiMo、英伟达 Nemotron、Meta Muse Spark、Ling、Jev 等)。
29
29
  - 🔌 **全自动多端持久化同步**:自动双写 Pi 本地配置(`~/.pi/agent/models.json` 和 `~/.pi/agent/auth.json`),若检测到 CC-Switch 亦无缝同步其 SQLite 数据库。
30
30
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ck-pi-zen-session",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "OpenCode Zen session auto-refresh and free-tier model catalog synchronization for the Pi coding agent.",
5
5
  "keywords": [
6
6
  "pi-package",
package/src/index.ts CHANGED
@@ -68,6 +68,20 @@ export function registerZenProviderToPi(
68
68
  }
69
69
  }
70
70
 
71
+ export function isZenModelTarget(model?: { provider?: string; id?: string }): boolean {
72
+ if (!model) return false;
73
+ // 严格隔离:仅处理 opencode-zen-free 或明确属于 opencode 官方的免费模型
74
+ // 绝不干涉 relayhub、deepseek、anthropic、openai 等其他任何供应商或 CC 插件
75
+ if (model.provider === ZEN_PROVIDER_ID) return true;
76
+ if (
77
+ model.provider === "opencode" &&
78
+ (model.id?.includes("-free") || model.id === "big-pickle")
79
+ ) {
80
+ return true;
81
+ }
82
+ return false;
83
+ }
84
+
71
85
  export default function piZenSession(pi: ExtensionAPI): void {
72
86
  // 1. 若本地已配置 Key,启动时即刻注册独立供应商 opencode-zen-free
73
87
  // 独立命名空间,彻底避开并兼容用户自带的官方登录 opencode / opencode-zen 套餐
@@ -78,13 +92,7 @@ export default function piZenSession(pi: ExtensionAPI): void {
78
92
 
79
93
  // 2. 核心请求头拦截钩子:在每一次请求发往 Provider 前注入完整官方客户端对齐请求头
80
94
  pi.on("before_provider_headers", (event, ctx) => {
81
- const model = ctx.model;
82
- const isZenModel =
83
- model?.provider === ZEN_PROVIDER_ID ||
84
- model?.id?.includes("-free") ||
85
- model?.id === "big-pickle";
86
-
87
- if (isZenModel) {
95
+ if (isZenModelTarget(ctx.model)) {
88
96
  // 检查 x-opencode-session 是否过期 (>30分钟) 或缺失
89
97
  let currentSession = event.headers["x-opencode-session"];
90
98
  if (
@@ -111,13 +119,7 @@ export default function piZenSession(pi: ExtensionAPI): void {
111
119
 
112
120
  // 3. 核心请求体守卫钩子:深度对齐 OpenCode 官方请求体结构与工具集
113
121
  pi.on("before_provider_request", (event, ctx) => {
114
- const model = ctx.model;
115
- const isZenModel =
116
- model?.provider === ZEN_PROVIDER_ID ||
117
- model?.id?.includes("-free") ||
118
- model?.id === "big-pickle";
119
-
120
- if (isZenModel && event.payload && typeof event.payload === "object") {
122
+ if (isZenModelTarget(ctx.model) && event.payload && typeof event.payload === "object") {
121
123
  const payload = event.payload as Record<string, unknown>;
122
124
  const tools = payload.tools;
123
125
  let modified = false;
@@ -151,13 +153,7 @@ export default function piZenSession(pi: ExtensionAPI): void {
151
153
 
152
154
  // 4. 网关响应守卫:遇 401/403 会话受限或过期时,立即自愈换新 Session ID
153
155
  pi.on("after_provider_response", (event, ctx) => {
154
- const model = ctx.model;
155
- const isZenModel =
156
- model?.provider === ZEN_PROVIDER_ID ||
157
- model?.id?.includes("-free") ||
158
- model?.id === "big-pickle";
159
-
160
- if (isZenModel && (event.status === 401 || event.status === 403)) {
156
+ if (isZenModelTarget(ctx.model) && (event.status === 401 || event.status === 403)) {
161
157
  // 自动异步刷新 Session
162
158
  syncZenConfiguration({ forceSession: true }).catch(() => {});
163
159
  if (ctx.hasUI) {
@@ -170,8 +166,11 @@ export default function piZenSession(pi: ExtensionAPI): void {
170
166
  });
171
167
 
172
168
  // 5. 常驻生命周期守卫:在每次 Agent 循环执行前,自动检测 Session 有效性并无感续期
173
- pi.on("before_agent_start", async () => {
169
+ pi.on("before_agent_start", async (_event, ctx) => {
174
170
  try {
171
+ // 严格隔离:仅在当前激活/选择的是 Zen 模型时才触发轮换检测,绝不干扰其他模型或 CC 插件
172
+ if (!isZenModelTarget(ctx.model)) return;
173
+
175
174
  const currentSession = getStoredZenSessionId();
176
175
  // 若当前会话不存在或已使用超过 30 分钟,后台自动续期
177
176
  if (!currentSession || isZenSessionExpired(currentSession, DEFAULT_SESSION_MAX_AGE_MS)) {