mslxdff 0.1.136 → 0.1.140
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 +2 -2
- package/src/chat/gateway.js +1 -1
- package/src/chat/prompt.js +1 -1
- package/src/chat/terminal.js +1 -1
- package/src/chooser.js +31 -12
- package/src/cli/commands/model/list-live.js +22 -0
- package/src/cli/commands/model/list-providers.js +1 -1
- package/src/cli/commands/model/list-render.js +2 -2
- package/src/cli/commands/model/list.js +2 -0
- package/src/cli/commands/model/live-models.js +24 -0
- package/src/cli/commands/provider/add.js +2 -1
- package/src/cli/commands/provider/bench-via.js +1 -1
- package/src/cli/commands/provider/cline-free.js +94 -0
- package/src/cli/commands/provider/cline-login.js +20 -15
- package/src/cli/commands/provider/codearts-login.js +45 -0
- package/src/cli/commands/provider/index.js +34 -0
- package/src/cli/commands/provider/keys.js +13 -2
- package/src/cli/commands/provider/models.js +13 -1
- package/src/cli/commands/provider/qoder-checkin.js +81 -0
- package/src/cli/commands/provider/qoder-login.js +103 -0
- package/src/cli/commands/provider/traework-login.js +202 -0
- package/src/cli/commands/provider/workbuddy-login.js +1 -1
- package/src/cli/commands/workbuddy.js +14 -21
- package/src/cli/index.js +3 -0
- package/src/cli/interactive.js +41 -4
- package/src/cli/provider-row.js +1 -1
- package/src/compat.js +23 -5
- package/src/model-capabilities/merge.js +2 -2
- package/src/providers/classify.js +1 -1
- package/src/providers/cline/auth.js +1 -1
- package/src/providers/cline/chat.js +14 -11
- package/src/providers/cline/free-catalog.js +71 -0
- package/src/providers/cline/index.js +2 -16
- package/src/providers/cline/models.js +28 -51
- package/src/providers/codearts/auth-pool.js +148 -0
- package/src/providers/codearts/chat.js +176 -0
- package/src/providers/codearts/const.js +60 -0
- package/src/providers/codearts/dpop.js +95 -0
- package/src/providers/codearts/index.js +160 -0
- package/src/providers/codearts/login.js +214 -0
- package/src/providers/codearts/models.js +182 -0
- package/src/providers/codearts/sign.js +96 -0
- package/src/providers/codearts/sse.js +204 -0
- package/src/providers/codearts/stream.js +209 -0
- package/src/providers/codearts/sts.js +124 -0
- package/src/providers/codearts.js +1 -0
- package/src/providers/model-id.js +4 -4
- package/src/providers/qoder/account-store.js +107 -0
- package/src/providers/qoder/aggregate.js +51 -0
- package/src/providers/qoder/baseprompt.json +592 -0
- package/src/providers/qoder/chat.js +72 -0
- package/src/providers/qoder/checkin.js +160 -0
- package/src/providers/qoder/constants.js +45 -0
- package/src/providers/qoder/encode.js +42 -0
- package/src/providers/qoder/fingerprint.js +39 -0
- package/src/providers/qoder/index.js +106 -0
- package/src/providers/qoder/models.js +62 -0
- package/src/providers/qoder/oauth.js +85 -0
- package/src/providers/qoder/payload.js +156 -0
- package/src/providers/qoder/request.js +26 -0
- package/src/providers/qoder/session.js +135 -0
- package/src/providers/qoder/sse.js +46 -0
- package/src/providers/qoder/stream.js +81 -0
- package/src/providers/qoder.js +2 -0
- package/src/providers/registry.js +16 -1
- package/src/providers/share-keys.js +7 -2
- package/src/providers/traework/account-store.js +149 -0
- package/src/providers/traework/chat.js +211 -0
- package/src/providers/traework/checkin.js +35 -0
- package/src/providers/traework/constants.js +21 -0
- package/src/providers/traework/errors.js +52 -0
- package/src/providers/traework/headers.js +47 -0
- package/src/providers/traework/index.js +122 -0
- package/src/providers/traework/models.js +97 -0
- package/src/providers/traework/payload.js +86 -0
- package/src/providers/traework/sse.js +184 -0
- package/src/providers/traework/token.js +52 -0
- package/src/providers/traework.js +2 -0
- package/src/providers/workbuddy/account-store.js +73 -7
- package/src/providers/workbuddy/chat.js +1 -1
- package/src/providers/workbuddy/index.js +10 -20
- package/src/readline-compat.js +9 -10
- package/src/routes/models-route.js +19 -1
- package/src/runtime/bootstrap.js +10 -0
- package/src/runtime/provider-gate.js +30 -0
- package/src/runtime/providers-setup.js +18 -3
- package/src/runtime/qoder-checkin.js +93 -0
- package/src/runtime/server-lifecycle.js +2 -2
- package/src/runtime/traework-checkin.js +104 -0
- package/src/state/migrations/cline-unify.js +94 -0
- package/src/state/migrations.js +33 -0
- package/src/state/schemas/token.js +6 -2
- package/src/state/schemas/use-group.js +4 -4
- package/src/sync-workbuddy.js +1 -1
- package/src/upstream-engine/index.js +1 -1
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// qoder 账号落盘单一源:auths/qoder-<uid>.json(0600 tmp+rename)+ state.json providerConfigs.qoder keys/auths 按 uid 去重。
|
|
2
|
+
// 凭证形状对齐 qoder2api:secret = {"device_token":"dt-xxx","refresh_token":"drt-xxx"},region 进 auth 行。
|
|
3
|
+
import { writeFileSync, mkdirSync, existsSync, renameSync, unlinkSync, readdirSync, readFileSync, chmodSync } from "node:fs";
|
|
4
|
+
import { join, dirname } from "node:path";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
import { isTestEnv, defaultStateFile } from "../../state/store.js";
|
|
7
|
+
import { normalizeRegion } from "./constants.js";
|
|
8
|
+
|
|
9
|
+
export function authDirFor({ explicit = "", testEnv = false, stateFile } = {}) {
|
|
10
|
+
if (explicit) return explicit;
|
|
11
|
+
if (testEnv) return join(tmpdir(), "mslxdff-test-auths");
|
|
12
|
+
return join(dirname(stateFile), "auths");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function resolveAuthDir() {
|
|
16
|
+
return authDirFor({
|
|
17
|
+
explicit: process.env.QODER_AUTH_DIR || "",
|
|
18
|
+
testEnv: isTestEnv(),
|
|
19
|
+
stateFile: defaultStateFile(),
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function resolveAuthDirs() {
|
|
24
|
+
const primary = resolveAuthDir();
|
|
25
|
+
const cwdDir = join(process.cwd(), "auths");
|
|
26
|
+
return primary === cwdDir ? [primary] : [primary, cwdDir];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function listAccountDocs({ dirs } = {}) {
|
|
30
|
+
const out = [];
|
|
31
|
+
const seen = new Set();
|
|
32
|
+
for (const dir of dirs || resolveAuthDirs()) {
|
|
33
|
+
let files = [];
|
|
34
|
+
try {
|
|
35
|
+
if (!existsSync(dir)) continue;
|
|
36
|
+
files = readdirSync(dir).filter((f) => f.startsWith("qoder-") && f.endsWith(".json"));
|
|
37
|
+
} catch { continue; }
|
|
38
|
+
for (const f of files) {
|
|
39
|
+
try {
|
|
40
|
+
const doc = JSON.parse(readFileSync(join(dir, f), "utf8"));
|
|
41
|
+
const uid = doc?.account?.uid;
|
|
42
|
+
if (!uid || !doc?.auth?.deviceToken) continue;
|
|
43
|
+
if (seen.has(String(uid))) continue;
|
|
44
|
+
seen.add(String(uid));
|
|
45
|
+
out.push({ uid: String(uid), file: join(dir, f), dir, doc });
|
|
46
|
+
} catch {}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return out;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function writeAccountFile({ uid, deviceToken, refreshToken = "", region = "global", name = "", email = "", userType = "personal_standard", organizationId = "", organizationName = "" }) {
|
|
53
|
+
const authDir = resolveAuthDir();
|
|
54
|
+
mkdirSync(authDir, { recursive: true });
|
|
55
|
+
const doc = {
|
|
56
|
+
account: { uid, name, email, userType, organizationId, organizationName },
|
|
57
|
+
auth: { deviceToken, refreshToken, region: normalizeRegion(region) },
|
|
58
|
+
};
|
|
59
|
+
const fp = join(authDir, `qoder-${uid}.json`);
|
|
60
|
+
const tmp = `${fp}.tmp`;
|
|
61
|
+
writeFileSync(tmp, JSON.stringify(doc, null, 2), { mode: 0o600 });
|
|
62
|
+
try {
|
|
63
|
+
if (existsSync(fp)) { try { chmodSync(fp, 0o600); } catch {} unlinkSync(fp); }
|
|
64
|
+
renameSync(tmp, fp);
|
|
65
|
+
} catch {
|
|
66
|
+
writeFileSync(fp, JSON.stringify(doc, null, 2), { mode: 0o600 });
|
|
67
|
+
try { unlinkSync(tmp); } catch {}
|
|
68
|
+
}
|
|
69
|
+
try { chmodSync(fp, 0o600); } catch {}
|
|
70
|
+
return fp;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// state 落盘:key 存 JSON blob(对齐 qoder2api ParseOAuthSecret 形状),auths 存 uid 索引行。
|
|
74
|
+
async function persistAccounts(accounts, file) {
|
|
75
|
+
const { loadProviderConfigs, saveProviderConfig } = await import("../../state.js");
|
|
76
|
+
const cfg = (loadProviderConfigs(file ? { file } : {})?.qoder) || {};
|
|
77
|
+
const keys = [...(Array.isArray(cfg.keys) ? cfg.keys : [])];
|
|
78
|
+
const auths = [...(Array.isArray(cfg.auths) ? cfg.auths : [])];
|
|
79
|
+
let updated = 0;
|
|
80
|
+
for (const acc of accounts) {
|
|
81
|
+
if (!acc?.uid || !acc?.deviceToken) continue;
|
|
82
|
+
const blob = JSON.stringify({ device_token: acc.deviceToken, refresh_token: acc.refreshToken || "" });
|
|
83
|
+
const row = { uid: acc.uid, domain: acc.domain || "qoder.com", region: normalizeRegion(acc.region), name: acc.name || "", refreshToken: acc.refreshToken || "" };
|
|
84
|
+
const idx = auths.findIndex((a) => a?.uid === acc.uid);
|
|
85
|
+
if (idx >= 0) { keys[idx] = blob; auths[idx] = row; updated += 1; }
|
|
86
|
+
else { keys.push(blob); auths.push(row); }
|
|
87
|
+
}
|
|
88
|
+
saveProviderConfig("qoder", { baseUrl: cfg.baseUrl || "", keys, auths }, file ? { file } : {});
|
|
89
|
+
return { keys, auths, updated };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export async function saveQoderAccount({ uid, deviceToken, refreshToken = "", region = "global", name = "", email = "", userType = "personal_standard", organizationId = "", organizationName = "", domain = "qoder.com", file } = {}) {
|
|
93
|
+
if (!uid || !deviceToken) throw new Error("saveQoderAccount: 缺少 uid/deviceToken");
|
|
94
|
+
const fp = writeAccountFile({ uid, deviceToken, refreshToken, region, name, email, userType, organizationId, organizationName });
|
|
95
|
+
const st = await persistAccounts([{ uid, deviceToken, refreshToken, region, name, domain }], file);
|
|
96
|
+
return { file: fp, accounts: st.keys.length, updated: st.updated > 0 };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// 重建 provider 的行级 auth:由 keys[i] blob + auths[i] 还原 deviceToken。
|
|
100
|
+
export function accountFromBlob(blob) {
|
|
101
|
+
try {
|
|
102
|
+
const j = JSON.parse(String(blob || "{}"));
|
|
103
|
+
return { deviceToken: String(j.device_token || ""), refreshToken: String(j.refresh_token || "") };
|
|
104
|
+
} catch {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// qoder 非流式聚合:上游 SSE 全读完 → chat.completion JSON。
|
|
2
|
+
// 真流式走 stream.js;本模块只服务 stream:false(行为与旧 callQoder 聚合同)。
|
|
3
|
+
import { extractDelta } from "./sse.js";
|
|
4
|
+
|
|
5
|
+
export async function aggregateQoderStream(upstreamRes) {
|
|
6
|
+
const reader = upstreamRes.body.getReader();
|
|
7
|
+
const dec = new TextDecoder();
|
|
8
|
+
let buf = "";
|
|
9
|
+
let usage = null;
|
|
10
|
+
let content = "";
|
|
11
|
+
let reasoning = "";
|
|
12
|
+
const toolCalls = [];
|
|
13
|
+
let sawContent = false;
|
|
14
|
+
for (;;) {
|
|
15
|
+
const { done, value } = await reader.read();
|
|
16
|
+
if (value) buf += dec.decode(value, { stream: !done });
|
|
17
|
+
const lines = buf.split("\n");
|
|
18
|
+
buf = lines.pop();
|
|
19
|
+
for (const raw of lines) {
|
|
20
|
+
const line = raw.replace(/\r$/, "");
|
|
21
|
+
if (!line.startsWith("data:")) continue;
|
|
22
|
+
const payload = line.slice(5).trim();
|
|
23
|
+
if (!payload || payload === "[DONE]") continue;
|
|
24
|
+
const d = extractDelta(payload);
|
|
25
|
+
if (d.err) throw d.err;
|
|
26
|
+
if (d.usageIn > 0 || d.usageOut > 0) {
|
|
27
|
+
usage = { prompt_tokens: d.usageIn, completion_tokens: d.usageOut, total_tokens: d.usageIn + d.usageOut };
|
|
28
|
+
}
|
|
29
|
+
if (d.content) { content += d.content; sawContent = true; }
|
|
30
|
+
if (d.reasoning) { reasoning += d.reasoning; sawContent = true; }
|
|
31
|
+
if (d.toolCalls) { toolCalls.push(...d.toolCalls); sawContent = true; }
|
|
32
|
+
}
|
|
33
|
+
if (done) break;
|
|
34
|
+
}
|
|
35
|
+
if (!sawContent && !usage) throw { kind: "upstream", status: 502, detail: "empty upstream stream" };
|
|
36
|
+
return { usage, content, reasoning, toolCalls };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function toCompletionJson({ model, chatId, content, reasoning, toolCalls, usage }) {
|
|
40
|
+
const msg = { role: "assistant", content: content || (toolCalls.length ? null : "") };
|
|
41
|
+
if (reasoning) msg.reasoning_content = reasoning;
|
|
42
|
+
if (toolCalls.length) msg.tool_calls = toolCalls;
|
|
43
|
+
return {
|
|
44
|
+
id: chatId,
|
|
45
|
+
object: "chat.completion",
|
|
46
|
+
created: Math.floor(Date.now() / 1000),
|
|
47
|
+
model,
|
|
48
|
+
choices: [{ index: 0, message: msg, finish_reason: toolCalls.length ? "tool_calls" : "stop" }],
|
|
49
|
+
usage: usage || { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 },
|
|
50
|
+
};
|
|
51
|
+
}
|