@lyogvce/dsh-codex-subscription 0.2.5 → 0.2.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.
- package/README.md +2 -2
- package/lib/index.d.ts +3 -2
- package/lib/index.js +36 -15
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
- 每次请求前检查 `access_token` 的 JWT `exp`:距离过期不足 5 分钟时自动通过单飞锁(Single-flight)向 `https://auth.openai.com/oauth/token` 刷新,并通过 `realpathSync` + 临时文件 `rename` 原子写回 `auth.json`,保证与 Codex CLI 永不互踢下线。
|
|
14
14
|
2. **零网络轮询的本地模型目录发现、防降级保护与可观测性日志**
|
|
15
15
|
- 直接读取 `~/.codex/models_cache.json`(每次按文件 `mtime` 与大小做微秒级 `stat` 校验,仅在文件变化时重读解析),提取 `visibility === "list"` 的模型及其 `context_window`、`supported_reasoning_levels`(自动将 `ultra` 映射为 DSH 的 `max` 档位)与 `default_verbosity`。
|
|
16
|
-
- **防旧版客户端降级污染**:自动将高版本 `models_cache.json` 备份至 `~/.codex
|
|
17
|
-
- **可观测性日志**:自动在 `~/.codex/dsh-codex-subscription.log`(带 512KB
|
|
16
|
+
- **防旧版客户端降级污染**:自动将高版本 `models_cache.json` 备份至 `~/.codex/cache/dsh-codex-subscription/models-cache-backup.json`;当外部旧版进程(如 `dsh-subagent-codex` 内置的 `0.153.4`)将 `models_cache.json` 降级覆写为不含新模型的旧缓存时,自动拦截降级并保留高版本模型目录。
|
|
17
|
+
- **可观测性日志**:自动在 `~/.codex/cache/dsh-codex-subscription/plugin.log`(带 512KB 自动滚动截断,忽略纯 `fetched_at` 心跳刷新)记录目录加载(`catalog.load` / `catalog.snapshot`)、降级拦截(`catalog.downgrade_rejected`)、备份恢复(`catalog.backup_restored`)与凭证续期(`auth.refreshed` / `auth.refresh_failed`)事件。
|
|
18
18
|
3. **支持按配置屏蔽模型(`disabledModels`)与自定义上下文窗口(`contextWindows`)**
|
|
19
19
|
- 在插件配置中通过 `disabledModels` 屏蔽指定模型 `slug`,保持模型选择器干净清爽。
|
|
20
20
|
- 通过 `contextWindows` 按模型 `slug` 自定义向 DSH 会话与自动压缩器暴露的预算窗口(例如设为 `400000`);未配置时默认使用模型物理上限 `max_context_window`(`872000`)。同时底层 `PiCodexModel.contextWindow` 始终保持物理上限 `872000`,彻底防止 `dsh-llm-pi-ai` 在预算窗口与物理上限之间误判 `CONTEXT_WINDOW_EXCEEDED`。
|
package/lib/index.d.ts
CHANGED
|
@@ -59,7 +59,8 @@ declare function createAuthManager(options: AuthManagerOptions): {
|
|
|
59
59
|
};
|
|
60
60
|
//#endregion
|
|
61
61
|
//#region src/catalog.d.ts
|
|
62
|
-
export declare const
|
|
62
|
+
export declare const PLUGIN_CACHE_DIR_NAME = "cache/dsh-codex-subscription";
|
|
63
|
+
export declare const BACKUP_CACHE_FILE_NAME = "models-cache-backup.json";
|
|
63
64
|
interface RawReasoningLevel {
|
|
64
65
|
effort?: string;
|
|
65
66
|
description?: string;
|
|
@@ -143,7 +144,7 @@ declare function createUsageFetcher(options: UsageFetcherOptions): {
|
|
|
143
144
|
//#region src/index.d.ts
|
|
144
145
|
export declare const name = "codex-subscription";
|
|
145
146
|
export declare const inject: string[];
|
|
146
|
-
export declare const LOG_FILE_NAME = "
|
|
147
|
+
export declare const LOG_FILE_NAME = "plugin.log";
|
|
147
148
|
export declare const Config: any;
|
|
148
149
|
export declare function apply(ctx: PluginContextLike, config?: Record<string, unknown>): void;
|
|
149
150
|
export declare const __test: Readonly<{
|
package/lib/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { appendFileSync, chmodSync, readFileSync, realpathSync, renameSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
1
|
+
import { appendFileSync, chmodSync, mkdirSync, readFileSync, realpathSync, renameSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { basename, dirname, join, resolve } from "node:path";
|
|
3
3
|
import z from "@deepseek-ai/schemastery";
|
|
4
4
|
import { LlmError, resolveImageAttachmentAccess, resolveRetryPolicy } from "@deepseek-ai/dsh-llm";
|
|
@@ -13,7 +13,8 @@ const PROVIDER = "openai-codex";
|
|
|
13
13
|
const DISPLAY_NAME = "Codex";
|
|
14
14
|
const DEFAULT_CLIENT_VERSION = "0.163.0";
|
|
15
15
|
const DEFAULT_CONTEXT_WINDOW = 872e3;
|
|
16
|
-
const
|
|
16
|
+
const PLUGIN_CACHE_DIR_NAME = "cache/dsh-codex-subscription";
|
|
17
|
+
const BACKUP_CACHE_FILE_NAME = "models-cache-backup.json";
|
|
17
18
|
const THINKING_LEVELS = [
|
|
18
19
|
"off",
|
|
19
20
|
"minimal",
|
|
@@ -35,6 +36,12 @@ function parseRawModelsCache(rawText) {
|
|
|
35
36
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) throw new SyntaxError("models_cache.json root must be a JSON object");
|
|
36
37
|
return parsed;
|
|
37
38
|
}
|
|
39
|
+
function isSameModelsCatalogPayload(a, b) {
|
|
40
|
+
if (!a || !b) return false;
|
|
41
|
+
const { fetched_at: _fa, ...restA } = a;
|
|
42
|
+
const { fetched_at: _fb, ...restB } = b;
|
|
43
|
+
return JSON.stringify(restA) === JSON.stringify(restB);
|
|
44
|
+
}
|
|
38
45
|
function compareClientVersions(a, b) {
|
|
39
46
|
const parseParts = (ver) => typeof ver === "string" && ver.trim() !== "" ? ver.trim().split(/[^0-9]+/u).filter(Boolean).map((n) => Number.parseInt(n, 10)) : [];
|
|
40
47
|
const pa = parseParts(a);
|
|
@@ -380,6 +387,10 @@ function resolveRealTargetPath(filePath) {
|
|
|
380
387
|
}
|
|
381
388
|
}
|
|
382
389
|
function writeFileAtomicSync(filePath, content) {
|
|
390
|
+
mkdirSync(dirname(filePath), {
|
|
391
|
+
recursive: true,
|
|
392
|
+
mode: 448
|
|
393
|
+
});
|
|
383
394
|
const targetPath = resolveRealTargetPath(filePath);
|
|
384
395
|
const tempPath = join(dirname(targetPath), `.${basename(targetPath)}.tmp-${process.pid}-${randomUUID()}`);
|
|
385
396
|
try {
|
|
@@ -552,12 +563,15 @@ function createAuthManager(options) {
|
|
|
552
563
|
//#region src/index.ts
|
|
553
564
|
const name = "codex-subscription";
|
|
554
565
|
const inject = ["llm"];
|
|
555
|
-
const LOG_FILE_NAME = "
|
|
566
|
+
const LOG_FILE_NAME = "plugin.log";
|
|
556
567
|
const STREAM_IDLE_TIMEOUT_MS = 3e5;
|
|
557
568
|
const MAX_REQUEST_IMAGE_BYTES = 20971520;
|
|
558
569
|
const REQUEST_IMAGE_PIXEL_BUDGET = 4194304;
|
|
559
570
|
const REQUEST_IMAGE_MAX_BYTES = 1048576;
|
|
560
571
|
const MAX_LOG_FILE_BYTES = 524288;
|
|
572
|
+
function resolvePluginCacheDir(codexHome) {
|
|
573
|
+
return join(codexHome, PLUGIN_CACHE_DIR_NAME);
|
|
574
|
+
}
|
|
561
575
|
function appendPluginLog(codexHome, ctx, level, event, detail) {
|
|
562
576
|
const line = `[${new Date().toISOString()}] [${level}] ${event} ${JSON.stringify(detail)}\n`;
|
|
563
577
|
if (level === "ERROR") {
|
|
@@ -567,7 +581,12 @@ function appendPluginLog(codexHome, ctx, level, event, detail) {
|
|
|
567
581
|
if (typeof ctx.logger?.warn === "function") ctx.logger.warn(`[dsh-codex-subscription] ${event}: ${JSON.stringify(detail)}`);
|
|
568
582
|
}
|
|
569
583
|
try {
|
|
570
|
-
const
|
|
584
|
+
const cacheDir = resolvePluginCacheDir(codexHome);
|
|
585
|
+
mkdirSync(cacheDir, {
|
|
586
|
+
recursive: true,
|
|
587
|
+
mode: 448
|
|
588
|
+
});
|
|
589
|
+
const logPath = join(cacheDir, LOG_FILE_NAME);
|
|
571
590
|
try {
|
|
572
591
|
if (statSync(logPath).size > MAX_LOG_FILE_BYTES) {
|
|
573
592
|
const buf = readFileSync(logPath);
|
|
@@ -584,14 +603,14 @@ function appendPluginLog(codexHome, ctx, level, event, detail) {
|
|
|
584
603
|
}
|
|
585
604
|
function readBackupCache(codexHome) {
|
|
586
605
|
try {
|
|
587
|
-
return parseRawModelsCache(readFileSync(join(codexHome, BACKUP_CACHE_FILE_NAME), "utf8"));
|
|
606
|
+
return parseRawModelsCache(readFileSync(join(resolvePluginCacheDir(codexHome), BACKUP_CACHE_FILE_NAME), "utf8"));
|
|
588
607
|
} catch {
|
|
589
608
|
return;
|
|
590
609
|
}
|
|
591
610
|
}
|
|
592
611
|
function writeBackupCache(codexHome, raw) {
|
|
593
612
|
try {
|
|
594
|
-
writeFileAtomicSync(join(codexHome, BACKUP_CACHE_FILE_NAME), `${JSON.stringify(raw, null, 2)}\n`);
|
|
613
|
+
writeFileAtomicSync(join(resolvePluginCacheDir(codexHome), BACKUP_CACHE_FILE_NAME), `${JSON.stringify(raw, null, 2)}\n`);
|
|
595
614
|
} catch {}
|
|
596
615
|
}
|
|
597
616
|
const Config = z.object({
|
|
@@ -749,14 +768,16 @@ function apply(ctx, config = {}) {
|
|
|
749
768
|
incomingFetchedAt: incomingRaw.fetched_at ?? null
|
|
750
769
|
});
|
|
751
770
|
else if (cachedRaw !== void 0 || !tryRestoreFromBackup({ diskVersion: incomingRaw.client_version ?? "unknown" }, incomingRaw.client_version)) {
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
771
|
+
if (!isSameModelsCatalogPayload(cachedRaw, incomingRaw)) {
|
|
772
|
+
setActiveRaw(incomingRaw);
|
|
773
|
+
writeBackupCache(codexHome, incomingRaw);
|
|
774
|
+
appendPluginLog(codexHome, ctx, "INFO", "catalog.load", {
|
|
775
|
+
cachePath,
|
|
776
|
+
clientVersion: incomingRaw.client_version ?? "0.163.0",
|
|
777
|
+
fetchedAt: incomingRaw.fetched_at ?? null,
|
|
778
|
+
rawModelCount: Array.isArray(incomingRaw.models) ? incomingRaw.models.length : 0
|
|
779
|
+
});
|
|
780
|
+
}
|
|
760
781
|
}
|
|
761
782
|
} catch (error) {
|
|
762
783
|
handleReadError(error);
|
|
@@ -879,4 +900,4 @@ const __test = Object.freeze({
|
|
|
879
900
|
createUsageFetcher
|
|
880
901
|
});
|
|
881
902
|
//#endregion
|
|
882
|
-
export { BACKUP_CACHE_FILE_NAME, Config, LOG_FILE_NAME, __test, apply, inject, name };
|
|
903
|
+
export { BACKUP_CACHE_FILE_NAME, Config, LOG_FILE_NAME, PLUGIN_CACHE_DIR_NAME, __test, apply, inject, name };
|