@wu529778790/open-im 1.9.3-beta.1 → 1.9.3-beta.10
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/adapters/claude-sdk-adapter.d.ts +5 -0
- package/dist/adapters/claude-sdk-adapter.js +164 -8
- package/dist/config-web-page-i18n.d.ts +76 -4
- package/dist/config-web-page-i18n.js +76 -4
- package/dist/config-web-page-script.js +146 -20
- package/dist/config-web-page-template.js +273 -29
- package/dist/config-web.js +20 -9
- package/dist/config.js +40 -9
- package/dist/feishu/message-sender.js +21 -0
- package/dist/index.js +1 -1
- package/dist/qq/client.js +2 -0
- package/dist/qq/message-sender.js +4 -4
- package/dist/session/session-manager.js +62 -41
- package/dist/telegram/message-sender.js +1 -3
- package/dist/wework/event-handler.js +78 -80
- package/dist/wework/message-sender.d.ts +1 -2
- package/dist/wework/message-sender.js +6 -13
- package/dist/workbuddy/centrifuge-client.d.ts +6 -1
- package/dist/workbuddy/centrifuge-client.js +51 -24
- package/dist/workbuddy/client.js +18 -0
- package/dist/workbuddy/event-handler.js +12 -9
- package/package.json +1 -1
|
@@ -15,5 +15,10 @@ export declare class ClaudeSDKAdapter implements ToolAdapter {
|
|
|
15
15
|
* 清理所有活跃的 SDK 会话和流
|
|
16
16
|
*/
|
|
17
17
|
static destroy(): void;
|
|
18
|
+
/**
|
|
19
|
+
* Remove a specific session from the in-memory cache and close it.
|
|
20
|
+
* Useful when the caller knows a session is corrupted.
|
|
21
|
+
*/
|
|
22
|
+
static removeSession(sessionId: string): void;
|
|
18
23
|
run(prompt: string, sessionId: string | undefined, workDir: string, callbacks: RunCallbacks, options?: RunOptions): RunHandle;
|
|
19
24
|
}
|
|
@@ -16,6 +16,52 @@ const log = createLogger('ClaudeSDK');
|
|
|
16
16
|
const activeSessions = new Map();
|
|
17
17
|
// 存储正在进行的流式迭代器,用于中断
|
|
18
18
|
const activeStreams = new Set();
|
|
19
|
+
// 空闲会话清理:跟踪最后使用时间,定期清除超时会话
|
|
20
|
+
const sessionLastUsed = new Map();
|
|
21
|
+
const SESSION_IDLE_TTL_MS = 30 * 60 * 1000; // 30 分钟未使用则清理
|
|
22
|
+
const CLEANUP_INTERVAL_MS = 5 * 60 * 1000; // 每 5 分钟检查一次
|
|
23
|
+
const cleanupInterval = setInterval(() => {
|
|
24
|
+
const now = Date.now();
|
|
25
|
+
for (const [id, lastUsed] of sessionLastUsed) {
|
|
26
|
+
if (now - lastUsed > SESSION_IDLE_TTL_MS) {
|
|
27
|
+
const session = activeSessions.get(id);
|
|
28
|
+
if (session) {
|
|
29
|
+
try {
|
|
30
|
+
session.close();
|
|
31
|
+
}
|
|
32
|
+
catch { /* ignore */ }
|
|
33
|
+
activeSessions.delete(id);
|
|
34
|
+
}
|
|
35
|
+
sessionLastUsed.delete(id);
|
|
36
|
+
log.info(`Cleaned up idle session (unused ${Math.round((now - lastUsed) / 60000)}min): ${id}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}, CLEANUP_INTERVAL_MS);
|
|
40
|
+
cleanupInterval.unref(); // 不阻止进程退出
|
|
41
|
+
// Lazy cleanup: check idle sessions periodically during getOrCreateSession calls
|
|
42
|
+
let lazyCleanupCounter = 0;
|
|
43
|
+
const LAZY_CLEANUP_INTERVAL = 10;
|
|
44
|
+
let sessionSeq = 0;
|
|
45
|
+
function lazyCleanupIdleSessions() {
|
|
46
|
+
lazyCleanupCounter++;
|
|
47
|
+
if (lazyCleanupCounter % LAZY_CLEANUP_INTERVAL !== 0)
|
|
48
|
+
return;
|
|
49
|
+
const now = Date.now();
|
|
50
|
+
for (const [id, lastUsed] of sessionLastUsed) {
|
|
51
|
+
if (now - lastUsed > SESSION_IDLE_TTL_MS) {
|
|
52
|
+
const s = activeSessions.get(id);
|
|
53
|
+
if (s) {
|
|
54
|
+
try {
|
|
55
|
+
s.close();
|
|
56
|
+
}
|
|
57
|
+
catch { /* ignore */ }
|
|
58
|
+
activeSessions.delete(id);
|
|
59
|
+
}
|
|
60
|
+
sessionLastUsed.delete(id);
|
|
61
|
+
log.info(`Lazy cleanup: idle session ${id} (unused ${Math.round((now - lastUsed) / 60000)}min)`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
19
65
|
// Mutex to serialize process.chdir() calls across concurrent users
|
|
20
66
|
let chdirMutex = Promise.resolve();
|
|
21
67
|
function withChdirMutex(fn) {
|
|
@@ -44,6 +90,9 @@ function isAssistant(msg) {
|
|
|
44
90
|
function isResult(msg) {
|
|
45
91
|
return msg.type === 'result';
|
|
46
92
|
}
|
|
93
|
+
function isSessionCorruptionError(msg) {
|
|
94
|
+
return /session\s*(not found|expired|corrupt)|no\s*conversation\s*found/i.test(msg);
|
|
95
|
+
}
|
|
47
96
|
/**
|
|
48
97
|
* 获取或创建 SDKSession
|
|
49
98
|
* @param sessionId 已有的 sessionId,如果为 undefined 则创建新会话
|
|
@@ -53,6 +102,7 @@ function isResult(msg) {
|
|
|
53
102
|
* @returns SDKSession 对象和实际的 sessionId
|
|
54
103
|
*/
|
|
55
104
|
async function getOrCreateSession(sessionId, workDir, model, permissionMode) {
|
|
105
|
+
lazyCleanupIdleSessions();
|
|
56
106
|
const resolvedModel = model?.trim() || 'claude-opus-4-5';
|
|
57
107
|
const sessionOptions = {
|
|
58
108
|
model: resolvedModel,
|
|
@@ -60,7 +110,9 @@ async function getOrCreateSession(sessionId, workDir, model, permissionMode) {
|
|
|
60
110
|
};
|
|
61
111
|
const baseUrl = process.env.ANTHROPIC_BASE_URL ?? '(default)';
|
|
62
112
|
log.info(`[V2] getOrCreateSession model param=${String(model ?? '')} resolved=${resolvedModel} baseUrl=${baseUrl} workDir=${workDir}`);
|
|
63
|
-
//
|
|
113
|
+
// NOTE: process.chdir() 是进程级全局副作用,在并发服务器中不理想。
|
|
114
|
+
// 但 SDK 的 createSession/resumeSession 不接受 cwd 参数,且这些调用是同步的,
|
|
115
|
+
// 所以 mutex + try/finally 已是最优方案。如果 SDK 未来支持 cwd 选项,应移除 chdir。
|
|
64
116
|
return withChdirMutex(() => {
|
|
65
117
|
let session;
|
|
66
118
|
const originalCwd = process.cwd();
|
|
@@ -69,11 +121,19 @@ async function getOrCreateSession(sessionId, workDir, model, permissionMode) {
|
|
|
69
121
|
process.chdir(workDir);
|
|
70
122
|
}
|
|
71
123
|
if (sessionId) {
|
|
72
|
-
//
|
|
124
|
+
// 优先复用内存中已有的 SDKSession,避免每次都启动新进程
|
|
125
|
+
const existing = activeSessions.get(sessionId);
|
|
126
|
+
if (existing) {
|
|
127
|
+
log.info(`Reusing existing in-memory session: ${sessionId}`);
|
|
128
|
+
sessionLastUsed.set(sessionId, Date.now());
|
|
129
|
+
return { session: existing, sessionId };
|
|
130
|
+
}
|
|
131
|
+
// 内存中没有,尝试通过 resume 恢复(会启动新 CLI 进程)
|
|
73
132
|
try {
|
|
74
133
|
log.info(`Attempting to resume session: ${sessionId}`);
|
|
75
134
|
session = unstable_v2_resumeSession(sessionId, sessionOptions);
|
|
76
135
|
activeSessions.set(sessionId, session);
|
|
136
|
+
sessionLastUsed.set(sessionId, Date.now());
|
|
77
137
|
log.info(`Successfully resumed session: ${sessionId}`);
|
|
78
138
|
return { session, sessionId };
|
|
79
139
|
}
|
|
@@ -86,8 +146,9 @@ async function getOrCreateSession(sessionId, workDir, model, permissionMode) {
|
|
|
86
146
|
session = unstable_v2_createSession(sessionOptions);
|
|
87
147
|
// 新会话的 sessionId 需要从第一个消息中获取
|
|
88
148
|
// 暂时返回 undefined,稍后在 init 消息中获取
|
|
89
|
-
const tempId = `pending-${
|
|
149
|
+
const tempId = `pending-${++sessionSeq}`;
|
|
90
150
|
activeSessions.set(tempId, session);
|
|
151
|
+
sessionLastUsed.set(tempId, Date.now());
|
|
91
152
|
log.info(`Created new session (tempId: ${tempId})`);
|
|
92
153
|
return { session, sessionId: tempId };
|
|
93
154
|
}
|
|
@@ -104,6 +165,7 @@ export class ClaudeSDKAdapter {
|
|
|
104
165
|
* 清理所有活跃的 SDK 会话和流
|
|
105
166
|
*/
|
|
106
167
|
static destroy() {
|
|
168
|
+
clearInterval(cleanupInterval);
|
|
107
169
|
for (const stream of activeStreams) {
|
|
108
170
|
try {
|
|
109
171
|
if (stream && typeof stream.return === 'function') {
|
|
@@ -124,6 +186,23 @@ export class ClaudeSDKAdapter {
|
|
|
124
186
|
}
|
|
125
187
|
}
|
|
126
188
|
activeSessions.clear();
|
|
189
|
+
sessionLastUsed.clear();
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Remove a specific session from the in-memory cache and close it.
|
|
193
|
+
* Useful when the caller knows a session is corrupted.
|
|
194
|
+
*/
|
|
195
|
+
static removeSession(sessionId) {
|
|
196
|
+
const session = activeSessions.get(sessionId);
|
|
197
|
+
if (session) {
|
|
198
|
+
try {
|
|
199
|
+
session.close();
|
|
200
|
+
}
|
|
201
|
+
catch { /* ignore */ }
|
|
202
|
+
activeSessions.delete(sessionId);
|
|
203
|
+
sessionLastUsed.delete(sessionId);
|
|
204
|
+
log.info(`Explicitly removed session: ${sessionId}`);
|
|
205
|
+
}
|
|
127
206
|
}
|
|
128
207
|
run(prompt, sessionId, workDir, callbacks, options) {
|
|
129
208
|
log.info(`[V2] run() entry model=${String(options?.model ?? '')} baseUrl=${process.env.ANTHROPIC_BASE_URL ?? '(default)'}`);
|
|
@@ -132,6 +211,8 @@ export class ClaudeSDKAdapter {
|
|
|
132
211
|
let actualSessionId;
|
|
133
212
|
let pendingTempId; // 记录临时 ID,用于 abort 时清理
|
|
134
213
|
let runSettled = false;
|
|
214
|
+
let currentStream; // 用于 abort 时立即中断 stream
|
|
215
|
+
let timeoutHandle;
|
|
135
216
|
const permissionMode = options?.skipPermissions
|
|
136
217
|
? 'bypassPermissions'
|
|
137
218
|
: options?.permissionMode === 'acceptEdits'
|
|
@@ -158,6 +239,7 @@ export class ClaudeSDKAdapter {
|
|
|
158
239
|
await session.send(prompt);
|
|
159
240
|
// 获取响应流
|
|
160
241
|
const stream = session.stream();
|
|
242
|
+
currentStream = stream;
|
|
161
243
|
activeStreams.add(stream);
|
|
162
244
|
let accumulated = '';
|
|
163
245
|
let accumulatedThinking = '';
|
|
@@ -173,10 +255,15 @@ export class ClaudeSDKAdapter {
|
|
|
173
255
|
const newSessionId = msg.session_id;
|
|
174
256
|
if (newSessionId && newSessionId !== actualSessionId) {
|
|
175
257
|
// 更新 sessionId 映射
|
|
176
|
-
|
|
177
|
-
|
|
258
|
+
// 清理 pending 临时 ID(actualSessionId 尚未赋值时用 pendingTempId)
|
|
259
|
+
const idToClean = actualSessionId ?? pendingTempId;
|
|
260
|
+
if (idToClean?.startsWith('pending-')) {
|
|
261
|
+
activeSessions.delete(idToClean);
|
|
178
262
|
}
|
|
179
263
|
activeSessions.set(newSessionId, session);
|
|
264
|
+
sessionLastUsed.set(newSessionId, Date.now());
|
|
265
|
+
if (idToClean)
|
|
266
|
+
sessionLastUsed.delete(idToClean);
|
|
180
267
|
actualSessionId = newSessionId;
|
|
181
268
|
log.info(`[V2] Got actual sessionId: ${newSessionId}`);
|
|
182
269
|
callbacks.onSessionId?.(newSessionId);
|
|
@@ -218,10 +305,20 @@ export class ClaudeSDKAdapter {
|
|
|
218
305
|
log.info(`[V2] Result: subtype=${m.subtype}, num_turns=${m.num_turns}, sessionId=${actualSessionId ?? 'unknown'}`);
|
|
219
306
|
// 检查会话错误
|
|
220
307
|
if (!success) {
|
|
308
|
+
if (timeoutHandle)
|
|
309
|
+
clearTimeout(timeoutHandle);
|
|
221
310
|
runSettled = true;
|
|
222
311
|
const noConvErr = errs.find((e) => e.includes('No conversation found') || e.includes('session not found'));
|
|
223
312
|
if (noConvErr) {
|
|
224
|
-
log.warn(`Session ${actualSessionId} not found,
|
|
313
|
+
log.warn(`Session ${actualSessionId} not found, removing from active sessions`);
|
|
314
|
+
if (actualSessionId) {
|
|
315
|
+
activeSessions.delete(actualSessionId);
|
|
316
|
+
sessionLastUsed.delete(actualSessionId);
|
|
317
|
+
try {
|
|
318
|
+
session.close();
|
|
319
|
+
}
|
|
320
|
+
catch { /* ignore */ }
|
|
321
|
+
}
|
|
225
322
|
callbacks.onSessionInvalid?.();
|
|
226
323
|
}
|
|
227
324
|
const errMsg = errs[0] || '未知错误';
|
|
@@ -246,6 +343,8 @@ export class ClaudeSDKAdapter {
|
|
|
246
343
|
result.result = accumulated;
|
|
247
344
|
}
|
|
248
345
|
runSettled = true;
|
|
346
|
+
if (timeoutHandle)
|
|
347
|
+
clearTimeout(timeoutHandle);
|
|
249
348
|
callbacks.onComplete(result);
|
|
250
349
|
return;
|
|
251
350
|
}
|
|
@@ -254,6 +353,8 @@ export class ClaudeSDKAdapter {
|
|
|
254
353
|
if (!streamClosed) {
|
|
255
354
|
if (accumulated) {
|
|
256
355
|
log.info('Stream ended without result message, using accumulated text');
|
|
356
|
+
if (timeoutHandle)
|
|
357
|
+
clearTimeout(timeoutHandle);
|
|
257
358
|
runSettled = true;
|
|
258
359
|
callbacks.onComplete({
|
|
259
360
|
success: true,
|
|
@@ -268,6 +369,8 @@ export class ClaudeSDKAdapter {
|
|
|
268
369
|
else {
|
|
269
370
|
// 流结束但无 result 也无 accumulated:必须触发回调,否则 Promise 永远挂起
|
|
270
371
|
log.warn('Stream ended with no result and no accumulated text, calling onError to prevent stuck state');
|
|
372
|
+
if (timeoutHandle)
|
|
373
|
+
clearTimeout(timeoutHandle);
|
|
271
374
|
runSettled = true;
|
|
272
375
|
callbacks.onError('AI 响应异常结束(无输出),请重试');
|
|
273
376
|
}
|
|
@@ -290,6 +393,8 @@ export class ClaudeSDKAdapter {
|
|
|
290
393
|
return;
|
|
291
394
|
}
|
|
292
395
|
runSettled = true;
|
|
396
|
+
if (timeoutHandle)
|
|
397
|
+
clearTimeout(timeoutHandle);
|
|
293
398
|
const errorObj = err;
|
|
294
399
|
const msg = errorObj.message || String(err);
|
|
295
400
|
log.error(`Claude SDK V2 error: ${msg}`);
|
|
@@ -302,15 +407,66 @@ export class ClaudeSDKAdapter {
|
|
|
302
407
|
activeSessions.delete(errIdToClean);
|
|
303
408
|
log.info(`Cleaned up pending session after error: ${errIdToClean}`);
|
|
304
409
|
}
|
|
410
|
+
// If error suggests a corrupted session, remove it from cache to prevent reuse
|
|
411
|
+
if (actualSessionId && isSessionCorruptionError(msg)) {
|
|
412
|
+
const corrupted = activeSessions.get(actualSessionId);
|
|
413
|
+
activeSessions.delete(actualSessionId);
|
|
414
|
+
sessionLastUsed.delete(actualSessionId);
|
|
415
|
+
if (corrupted) {
|
|
416
|
+
try {
|
|
417
|
+
corrupted.close();
|
|
418
|
+
}
|
|
419
|
+
catch { /* ignore */ }
|
|
420
|
+
}
|
|
421
|
+
log.warn(`Removed corrupted session ${actualSessionId} after error: ${msg}`);
|
|
422
|
+
callbacks.onSessionInvalid?.();
|
|
423
|
+
}
|
|
305
424
|
callbacks.onError(msg);
|
|
306
425
|
}
|
|
307
426
|
};
|
|
308
|
-
//
|
|
309
|
-
runSession()
|
|
427
|
+
// 启动会话(不等待),catch 兜底防止 unhandledRejection 导致用户请求挂起
|
|
428
|
+
runSession().catch((err) => {
|
|
429
|
+
if (!runSettled) {
|
|
430
|
+
runSettled = true;
|
|
431
|
+
if (timeoutHandle)
|
|
432
|
+
clearTimeout(timeoutHandle);
|
|
433
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
434
|
+
log.error(`Unhandled runSession error: ${msg}`);
|
|
435
|
+
callbacks.onError(msg);
|
|
436
|
+
}
|
|
437
|
+
});
|
|
438
|
+
// 强制执行超时
|
|
439
|
+
if (options?.timeoutMs && options.timeoutMs > 0) {
|
|
440
|
+
timeoutHandle = setTimeout(() => {
|
|
441
|
+
if (!runSettled) {
|
|
442
|
+
log.warn(`Session timed out after ${options.timeoutMs}ms, aborting`);
|
|
443
|
+
abortController.abort();
|
|
444
|
+
// 立即中断 stream,不等下一条消息
|
|
445
|
+
if (currentStream) {
|
|
446
|
+
try {
|
|
447
|
+
currentStream.return?.();
|
|
448
|
+
}
|
|
449
|
+
catch { /* ignore */ }
|
|
450
|
+
}
|
|
451
|
+
runSettled = true;
|
|
452
|
+
callbacks.onError(`AI 响应超时(${Math.round(options.timeoutMs / 1000)}s),请重试`);
|
|
453
|
+
}
|
|
454
|
+
}, options.timeoutMs);
|
|
455
|
+
timeoutHandle.unref();
|
|
456
|
+
}
|
|
310
457
|
return {
|
|
311
458
|
abort: () => {
|
|
312
459
|
log.info('Aborting session run');
|
|
313
460
|
abortController.abort();
|
|
461
|
+
if (timeoutHandle)
|
|
462
|
+
clearTimeout(timeoutHandle);
|
|
463
|
+
// 立即中断 stream,不等下一条消息
|
|
464
|
+
if (currentStream) {
|
|
465
|
+
try {
|
|
466
|
+
currentStream.return?.();
|
|
467
|
+
}
|
|
468
|
+
catch { /* ignore */ }
|
|
469
|
+
}
|
|
314
470
|
},
|
|
315
471
|
};
|
|
316
472
|
}
|
|
@@ -40,7 +40,13 @@ export declare const PAGE_TEXTS: {
|
|
|
40
40
|
readonly serviceIdleMeta: "Bridge has not been started yet";
|
|
41
41
|
readonly listSeparator: ", ";
|
|
42
42
|
readonly platformsTitle: "Platforms";
|
|
43
|
-
readonly
|
|
43
|
+
readonly navConfigFiles: "Config files";
|
|
44
|
+
readonly configFilesTitle: "Config files (JSON)";
|
|
45
|
+
readonly configFilesHint: "Edit the files on disk directly. Each card has its own Save. Platform / AI forms and Service → Save config still apply.";
|
|
46
|
+
readonly openImConfigCardHint: "Full open-im configuration. Use Format, then Save. Invalid JSON is rejected.";
|
|
47
|
+
readonly claudeSettingsCardHint: "Claude SDK environment (ANTHROPIC_API_KEY, ANTHROPIC_BASE_URL, ANTHROPIC_MODEL, etc.). Set API access here without shell exports.";
|
|
48
|
+
readonly claudeJsonShortcutHint: "Edit ~/.claude/settings.json in the sidebar «Config files» section below.";
|
|
49
|
+
readonly platformsHint: "Follow the setup checklist on Overview first. Disabled platforms still keep saved values.";
|
|
44
50
|
readonly enabled: "Enabled";
|
|
45
51
|
readonly readyState: "Ready";
|
|
46
52
|
readonly setupRequired: "Setup required";
|
|
@@ -81,7 +87,7 @@ export declare const PAGE_TEXTS: {
|
|
|
81
87
|
readonly optional: "Optional";
|
|
82
88
|
readonly commaSeparatedIds: "Comma-separated IDs";
|
|
83
89
|
readonly aiTitle: "AI Tooling";
|
|
84
|
-
readonly aiHint: "";
|
|
90
|
+
readonly aiHint: "Pick the default tool first. Claude SDK keys: sidebar Config files → ~/.claude/settings.json. Codex / CodeBuddy need a CLI path here.";
|
|
85
91
|
readonly claudeNote: "Claude credentials are still read from environment variables or ~/.claude/settings.json. This page manages local bridge config, not Claude account auth.";
|
|
86
92
|
readonly aiCommonTitle: "Shared defaults";
|
|
87
93
|
readonly aiCommonHint: "Choose the default AI tool first. Tool-specific fields are shown below.";
|
|
@@ -134,6 +140,36 @@ export declare const PAGE_TEXTS: {
|
|
|
134
140
|
readonly saveBtn: "Save";
|
|
135
141
|
readonly jsonValid: "Valid JSON";
|
|
136
142
|
readonly jsonInvalid: "Invalid JSON: {error}";
|
|
143
|
+
readonly wizardTitle: "First-time setup";
|
|
144
|
+
readonly wizardStep1Title: "Connect an IM channel";
|
|
145
|
+
readonly wizardStep1Desc: "Enable at least one platform below and fill every required field. Use Check config when available.";
|
|
146
|
+
readonly wizardStep2Title: "Set the default AI tool";
|
|
147
|
+
readonly wizardStep2Desc: "Claude SDK: edit ~/.claude/settings.json under sidebar Config files. Codex / CodeBuddy: set the CLI path in the AI section.";
|
|
148
|
+
readonly wizardStep3Title: "Validate and save";
|
|
149
|
+
readonly wizardStep3Desc: "Click Validate, then Save config. Fix any errors shown in the banner above.";
|
|
150
|
+
readonly wizardStep4Title: "Start the bridge";
|
|
151
|
+
readonly wizardStep4Desc: "Open Service and click Start bridge. If it exits, read ~/.open-im/logs.";
|
|
152
|
+
readonly wizardStatusDone: "Done";
|
|
153
|
+
readonly wizardStatusTodo: "To do";
|
|
154
|
+
readonly wizardJumpPlatforms: "Open Platforms";
|
|
155
|
+
readonly wizardJumpAi: "Open AI";
|
|
156
|
+
readonly wizardJumpService: "Open Service";
|
|
157
|
+
readonly validationNoPlatformEnabled: "Enable at least one IM platform and fill its required credentials before saving.";
|
|
158
|
+
readonly validationPlatformIncomplete: "Platform \"{platform}\" is enabled but these required fields are empty: {fields}";
|
|
159
|
+
readonly validationAiCodexNoCli: "Default AI is Codex but Codex CLI path is empty. Set it under AI Tooling or change the default tool.";
|
|
160
|
+
readonly validationAiCodebuddyNoCli: "Default AI is CodeBuddy but CodeBuddy CLI path is empty. Set it under AI Tooling or change the default tool.";
|
|
161
|
+
readonly onboardingTitle: "Welcome to open-im";
|
|
162
|
+
readonly onboardingDismiss: "Got it";
|
|
163
|
+
readonly onboardingReadme: "README (setup)";
|
|
164
|
+
readonly onboardingBody: "<p><strong>open-im</strong> bridges Telegram, Feishu, QQ, WeWork, DingTalk, and WorkBuddy to Claude / Codex / CodeBuddy on your machine.</p><ol style=\"margin:12px 0 12px 18px;line-height:1.65\"><li>Pick <strong>one</strong> chat app in <strong>Platforms</strong> and paste credentials (see hints under each field).</li><li>Set the <strong>default AI</strong> under AI Tooling; for Claude SDK, put API keys in sidebar <strong>Config files</strong> → <strong>~/.claude/settings.json</strong>.</li><li>Edit <strong>~/.open-im/config.json</strong> in the same <strong>Config files</strong> section when you need raw JSON.</li><li>Use <strong>Validate</strong> then <strong>Save config</strong>, then <strong>Start bridge</strong> under Service.</li><li>CLI alternative: run <code style=\"background:var(--bg-tertiary);padding:2px 6px;border-radius:4px\">open-im init</code> in a terminal.</li></ol>";
|
|
165
|
+
readonly tipTelegramToken: "From Telegram, open <a href=\"https://t.me/BotFather\" target=\"_blank\" rel=\"noopener\">@BotFather</a> → /newbot → copy the token.";
|
|
166
|
+
readonly tipFeishuAppId: "Feishu Open Platform → your app → Credentials → App ID.";
|
|
167
|
+
readonly tipFeishuSecret: "Same page → App Secret (click show / reset if needed).";
|
|
168
|
+
readonly tipQqAppId: "<a href=\"https://bot.q.qq.com\" target=\"_blank\" rel=\"noopener\">QQ bot console</a> → your bot → App ID.";
|
|
169
|
+
readonly tipQqSecret: "Same console → App Secret.";
|
|
170
|
+
readonly tipWeworkCorp: "WeCom admin → app → view Corp ID (or smart-bot Bot ID) and Secret.";
|
|
171
|
+
readonly tipDingtalkClient: "<a href=\"https://open-dev.dingtalk.com\" target=\"_blank\" rel=\"noopener\">DingTalk Open Platform</a> → internal app → App Key & App Secret.";
|
|
172
|
+
readonly tipWorkbuddyToken: "Use terminal <code>open-im init</code> for WorkBuddy OAuth, or paste tokens from CodeBuddy login.";
|
|
137
173
|
};
|
|
138
174
|
readonly zh: {
|
|
139
175
|
readonly pageTitle: "open-im 本地控制台";
|
|
@@ -174,7 +210,13 @@ export declare const PAGE_TEXTS: {
|
|
|
174
210
|
readonly serviceIdleMeta: "桥接服务尚未启动";
|
|
175
211
|
readonly listSeparator: "、";
|
|
176
212
|
readonly platformsTitle: "平台配置";
|
|
177
|
-
readonly
|
|
213
|
+
readonly navConfigFiles: "配置文件";
|
|
214
|
+
readonly configFilesTitle: "配置文件(JSON)";
|
|
215
|
+
readonly configFilesHint: "直接编辑磁盘上的文件,每张卡片有独立保存按钮。平台 / AI 表单与服务区的「保存配置」仍然有效。";
|
|
216
|
+
readonly openImConfigCardHint: "open-im 完整配置。先格式化再保存;JSON 不合法时无法写入。";
|
|
217
|
+
readonly claudeSettingsCardHint: "Claude SDK 环境变量(ANTHROPIC_API_KEY、ANTHROPIC_BASE_URL、ANTHROPIC_MODEL 等)。在此配置 API,无需在终端 export。";
|
|
218
|
+
readonly claudeJsonShortcutHint: "提示:请在左侧栏「配置文件」分区编辑 ~/.claude/settings.json。";
|
|
219
|
+
readonly platformsHint: "建议先在概览页按引导步骤操作。禁用的平台仍保留已保存的值。";
|
|
178
220
|
readonly enabled: "启用";
|
|
179
221
|
readonly readyState: "已就绪";
|
|
180
222
|
readonly setupRequired: "需要完成配置";
|
|
@@ -214,7 +256,7 @@ export declare const PAGE_TEXTS: {
|
|
|
214
256
|
readonly optional: "可选";
|
|
215
257
|
readonly commaSeparatedIds: "多个 ID 用逗号分隔";
|
|
216
258
|
readonly aiTitle: "AI 工具配置";
|
|
217
|
-
readonly aiHint: "";
|
|
259
|
+
readonly aiHint: "先选默认 AI。Claude SDK:左侧栏「配置文件」→ ~/.claude/settings.json。Codex / CodeBuddy 在此填 CLI 路径。";
|
|
218
260
|
readonly claudeNote: "Claude 凭证仍然从环境变量或 ~/.claude/settings.json 读取。这个页面只管理本地桥接配置,不负责 Claude 账号登录。";
|
|
219
261
|
readonly aiCommonTitle: "公共默认配置";
|
|
220
262
|
readonly aiCommonHint: "先选择默认 AI 工具,下方再显示对应的工具专属配置。";
|
|
@@ -264,5 +306,35 @@ export declare const PAGE_TEXTS: {
|
|
|
264
306
|
readonly saveBtn: "保存";
|
|
265
307
|
readonly jsonValid: "JSON 有效";
|
|
266
308
|
readonly jsonInvalid: "JSON 无效:{error}";
|
|
309
|
+
readonly wizardTitle: "首次使用引导";
|
|
310
|
+
readonly wizardStep1Title: "接入一个 IM 渠道";
|
|
311
|
+
readonly wizardStep1Desc: "在下方启用至少一个平台,并填写所有必填项。有条件时用「校验配置」测试凭证。";
|
|
312
|
+
readonly wizardStep2Title: "设置默认 AI 工具";
|
|
313
|
+
readonly wizardStep2Desc: "Claude SDK:在左侧栏「配置文件」编辑 ~/.claude/settings.json。Codex / CodeBuddy:在 AI 区填 CLI 路径。";
|
|
314
|
+
readonly wizardStep3Title: "校验并保存";
|
|
315
|
+
readonly wizardStep3Desc: "先点「校验」,再点「保存配置」。按顶部提示修复错误。";
|
|
316
|
+
readonly wizardStep4Title: "启动桥接";
|
|
317
|
+
readonly wizardStep4Desc: "到「服务」区点「启动桥接」。若马上退出,查 ~/.open-im/logs 日志。";
|
|
318
|
+
readonly wizardStatusDone: "已完成";
|
|
319
|
+
readonly wizardStatusTodo: "待完成";
|
|
320
|
+
readonly wizardJumpPlatforms: "打开平台配置";
|
|
321
|
+
readonly wizardJumpAi: "打开 AI 配置";
|
|
322
|
+
readonly wizardJumpService: "打开服务控制";
|
|
323
|
+
readonly validationNoPlatformEnabled: "保存前请至少启用一个 IM 平台,并填完必填凭证。";
|
|
324
|
+
readonly validationPlatformIncomplete: "平台「{platform}」已启用,但以下必填项为空:{fields}";
|
|
325
|
+
readonly validationAiCodexNoCli: "默认 AI 为 Codex,但 Codex CLI 路径为空。请在 AI 区填写,或改默认工具。";
|
|
326
|
+
readonly validationAiCodebuddyNoCli: "默认 AI 为 CodeBuddy,但 CodeBuddy CLI 路径为空。请在 AI 区填写,或改默认工具。";
|
|
327
|
+
readonly onboardingTitle: "欢迎使用 open-im";
|
|
328
|
+
readonly onboardingDismiss: "知道了";
|
|
329
|
+
readonly onboardingReadme: "README(部署说明)";
|
|
330
|
+
readonly onboardingBody: "<p><strong>open-im</strong> 在本机把 Telegram、飞书、QQ、企微、钉钉、WorkBuddy 等渠道连到 Claude / Codex / CodeBuddy。</p><ol style=\"margin:12px 0 12px 18px;line-height:1.65\"><li>在<strong>平台配置</strong>选一个聊天应用,按字段下方提示填凭证。</li><li>在<strong>AI 工具配置</strong>设默认 AI;用 Claude SDK 时在左侧<strong>配置文件</strong>分区编辑<strong>~/.claude/settings.json</strong>。</li><li>同一<strong>配置文件</strong>分区可编辑<strong>~/.open-im/config.json</strong>。</li><li>先<strong>校验</strong>再<strong>保存配置</strong>,然后到<strong>服务</strong>启动桥接。</li><li>也可在终端运行 <code style=\"background:var(--bg-tertiary);padding:2px 6px;border-radius:4px\">open-im init</code> 交互配置。</li></ol>";
|
|
331
|
+
readonly tipTelegramToken: "在 Telegram 搜 <a href=\"https://t.me/BotFather\" target=\"_blank\" rel=\"noopener\">@BotFather</a>,发 /newbot 创建机器人后复制 Token。";
|
|
332
|
+
readonly tipFeishuAppId: "飞书开放平台 → 应用 → 凭证与基础信息 → App ID。";
|
|
333
|
+
readonly tipFeishuSecret: "同一页 App Secret(可重置后查看)。";
|
|
334
|
+
readonly tipQqAppId: "<a href=\"https://bot.q.qq.com\" target=\"_blank\" rel=\"noopener\">QQ 开放平台</a> → 机器人 → App ID。";
|
|
335
|
+
readonly tipQqSecret: "同一处获取 App Secret。";
|
|
336
|
+
readonly tipWeworkCorp: "企业微信管理后台 → 应用 → 查省 Corp ID / 智能机器人 Bot ID 与 Secret。";
|
|
337
|
+
readonly tipDingtalkClient: "<a href=\"https://open-dev.dingtalk.com\" target=\"_blank\" rel=\"noopener\">钉钉开放平台</a> → 企业内部应用 → AppKey / AppSecret。";
|
|
338
|
+
readonly tipWorkbuddyToken: "建议在终端运行 <code>open-im init</code> 完成 WorkBuddy 授权;或粘贴 CodeBuddy 登录后的 Token。";
|
|
267
339
|
};
|
|
268
340
|
};
|
|
@@ -40,7 +40,13 @@ export const PAGE_TEXTS = {
|
|
|
40
40
|
serviceIdleMeta: "Bridge has not been started yet",
|
|
41
41
|
listSeparator: ", ",
|
|
42
42
|
platformsTitle: "Platforms",
|
|
43
|
-
|
|
43
|
+
navConfigFiles: "Config files",
|
|
44
|
+
configFilesTitle: "Config files (JSON)",
|
|
45
|
+
configFilesHint: "Edit the files on disk directly. Each card has its own Save. Platform / AI forms and Service → Save config still apply.",
|
|
46
|
+
openImConfigCardHint: "Full open-im configuration. Use Format, then Save. Invalid JSON is rejected.",
|
|
47
|
+
claudeSettingsCardHint: "Claude SDK environment (ANTHROPIC_API_KEY, ANTHROPIC_BASE_URL, ANTHROPIC_MODEL, etc.). Set API access here without shell exports.",
|
|
48
|
+
claudeJsonShortcutHint: "Edit ~/.claude/settings.json in the sidebar «Config files» section below.",
|
|
49
|
+
platformsHint: "Follow the setup checklist on Overview first. Disabled platforms still keep saved values.",
|
|
44
50
|
enabled: "Enabled",
|
|
45
51
|
readyState: "Ready",
|
|
46
52
|
setupRequired: "Setup required",
|
|
@@ -81,7 +87,7 @@ export const PAGE_TEXTS = {
|
|
|
81
87
|
optional: "Optional",
|
|
82
88
|
commaSeparatedIds: "Comma-separated IDs",
|
|
83
89
|
aiTitle: "AI Tooling",
|
|
84
|
-
aiHint: "",
|
|
90
|
+
aiHint: "Pick the default tool first. Claude SDK keys: sidebar Config files → ~/.claude/settings.json. Codex / CodeBuddy need a CLI path here.",
|
|
85
91
|
claudeNote: "Claude credentials are still read from environment variables or ~/.claude/settings.json. This page manages local bridge config, not Claude account auth.",
|
|
86
92
|
aiCommonTitle: "Shared defaults",
|
|
87
93
|
aiCommonHint: "Choose the default AI tool first. Tool-specific fields are shown below.",
|
|
@@ -134,6 +140,36 @@ export const PAGE_TEXTS = {
|
|
|
134
140
|
saveBtn: "Save",
|
|
135
141
|
jsonValid: "Valid JSON",
|
|
136
142
|
jsonInvalid: "Invalid JSON: {error}",
|
|
143
|
+
wizardTitle: "First-time setup",
|
|
144
|
+
wizardStep1Title: "Connect an IM channel",
|
|
145
|
+
wizardStep1Desc: "Enable at least one platform below and fill every required field. Use Check config when available.",
|
|
146
|
+
wizardStep2Title: "Set the default AI tool",
|
|
147
|
+
wizardStep2Desc: "Claude SDK: edit ~/.claude/settings.json under sidebar Config files. Codex / CodeBuddy: set the CLI path in the AI section.",
|
|
148
|
+
wizardStep3Title: "Validate and save",
|
|
149
|
+
wizardStep3Desc: "Click Validate, then Save config. Fix any errors shown in the banner above.",
|
|
150
|
+
wizardStep4Title: "Start the bridge",
|
|
151
|
+
wizardStep4Desc: "Open Service and click Start bridge. If it exits, read ~/.open-im/logs.",
|
|
152
|
+
wizardStatusDone: "Done",
|
|
153
|
+
wizardStatusTodo: "To do",
|
|
154
|
+
wizardJumpPlatforms: "Open Platforms",
|
|
155
|
+
wizardJumpAi: "Open AI",
|
|
156
|
+
wizardJumpService: "Open Service",
|
|
157
|
+
validationNoPlatformEnabled: "Enable at least one IM platform and fill its required credentials before saving.",
|
|
158
|
+
validationPlatformIncomplete: "Platform \"{platform}\" is enabled but these required fields are empty: {fields}",
|
|
159
|
+
validationAiCodexNoCli: "Default AI is Codex but Codex CLI path is empty. Set it under AI Tooling or change the default tool.",
|
|
160
|
+
validationAiCodebuddyNoCli: "Default AI is CodeBuddy but CodeBuddy CLI path is empty. Set it under AI Tooling or change the default tool.",
|
|
161
|
+
onboardingTitle: "Welcome to open-im",
|
|
162
|
+
onboardingDismiss: "Got it",
|
|
163
|
+
onboardingReadme: "README (setup)",
|
|
164
|
+
onboardingBody: "<p><strong>open-im</strong> bridges Telegram, Feishu, QQ, WeWork, DingTalk, and WorkBuddy to Claude / Codex / CodeBuddy on your machine.</p><ol style=\"margin:12px 0 12px 18px;line-height:1.65\"><li>Pick <strong>one</strong> chat app in <strong>Platforms</strong> and paste credentials (see hints under each field).</li><li>Set the <strong>default AI</strong> under AI Tooling; for Claude SDK, put API keys in sidebar <strong>Config files</strong> → <strong>~/.claude/settings.json</strong>.</li><li>Edit <strong>~/.open-im/config.json</strong> in the same <strong>Config files</strong> section when you need raw JSON.</li><li>Use <strong>Validate</strong> then <strong>Save config</strong>, then <strong>Start bridge</strong> under Service.</li><li>CLI alternative: run <code style=\"background:var(--bg-tertiary);padding:2px 6px;border-radius:4px\">open-im init</code> in a terminal.</li></ol>",
|
|
165
|
+
tipTelegramToken: 'From Telegram, open <a href="https://t.me/BotFather" target="_blank" rel="noopener">@BotFather</a> → /newbot → copy the token.',
|
|
166
|
+
tipFeishuAppId: "Feishu Open Platform → your app → Credentials → App ID.",
|
|
167
|
+
tipFeishuSecret: "Same page → App Secret (click show / reset if needed).",
|
|
168
|
+
tipQqAppId: '<a href="https://bot.q.qq.com" target="_blank" rel="noopener">QQ bot console</a> → your bot → App ID.',
|
|
169
|
+
tipQqSecret: "Same console → App Secret.",
|
|
170
|
+
tipWeworkCorp: "WeCom admin → app → view Corp ID (or smart-bot Bot ID) and Secret.",
|
|
171
|
+
tipDingtalkClient: '<a href="https://open-dev.dingtalk.com" target="_blank" rel="noopener">DingTalk Open Platform</a> → internal app → App Key & App Secret.',
|
|
172
|
+
tipWorkbuddyToken: 'Use terminal <code>open-im init</code> for WorkBuddy OAuth, or paste tokens from CodeBuddy login.',
|
|
137
173
|
},
|
|
138
174
|
zh: {
|
|
139
175
|
pageTitle: "open-im \u672c\u5730\u63a7\u5236\u53f0",
|
|
@@ -174,7 +210,13 @@ export const PAGE_TEXTS = {
|
|
|
174
210
|
serviceIdleMeta: "\u6865\u63a5\u670d\u52a1\u5c1a\u672a\u542f\u52a8",
|
|
175
211
|
listSeparator: "\u3001",
|
|
176
212
|
platformsTitle: "\u5e73\u53f0\u914d\u7f6e",
|
|
177
|
-
|
|
213
|
+
navConfigFiles: "\u914d\u7f6e\u6587\u4ef6",
|
|
214
|
+
configFilesTitle: "\u914d\u7f6e\u6587\u4ef6\uff08JSON\uff09",
|
|
215
|
+
configFilesHint: "\u76f4\u63a5\u7f16\u8f91\u78c1\u76d8\u4e0a\u7684\u6587\u4ef6\uff0c\u6bcf\u5f20\u5361\u7247\u6709\u72ec\u7acb\u4fdd\u5b58\u6309\u94ae\u3002\u5e73\u53f0 / AI \u8868\u5355\u4e0e\u670d\u52a1\u533a\u7684\u300c\u4fdd\u5b58\u914d\u7f6e\u300d\u4ecd\u7136\u6709\u6548\u3002",
|
|
216
|
+
openImConfigCardHint: "open-im \u5b8c\u6574\u914d\u7f6e\u3002\u5148\u683c\u5f0f\u5316\u518d\u4fdd\u5b58\uff1bJSON \u4e0d\u5408\u6cd5\u65f6\u65e0\u6cd5\u5199\u5165\u3002",
|
|
217
|
+
claudeSettingsCardHint: "Claude SDK \u73af\u5883\u53d8\u91cf\uff08ANTHROPIC_API_KEY\u3001ANTHROPIC_BASE_URL\u3001ANTHROPIC_MODEL \u7b49\uff09\u3002\u5728\u6b64\u914d\u7f6e API\uff0c\u65e0\u9700\u5728\u7ec8\u7aef export\u3002",
|
|
218
|
+
claudeJsonShortcutHint: "\u63d0\u793a\uff1a\u8bf7\u5728\u5de6\u4fa7\u680f\u300c\u914d\u7f6e\u6587\u4ef6\u300d\u5206\u533a\u7f16\u8f91 ~/.claude/settings.json\u3002",
|
|
219
|
+
platformsHint: "\u5efa\u8bae\u5148\u5728\u6982\u89c8\u9875\u6309\u5f15\u5bfc\u6b65\u9aa4\u64cd\u4f5c\u3002\u7981\u7528\u7684\u5e73\u53f0\u4ecd\u4fdd\u7559\u5df2\u4fdd\u5b58\u7684\u503c\u3002",
|
|
178
220
|
enabled: "\u542f\u7528",
|
|
179
221
|
readyState: "\u5df2\u5c31\u7eea",
|
|
180
222
|
setupRequired: "\u9700\u8981\u5b8c\u6210\u914d\u7f6e",
|
|
@@ -214,7 +256,7 @@ export const PAGE_TEXTS = {
|
|
|
214
256
|
optional: "\u53ef\u9009",
|
|
215
257
|
commaSeparatedIds: "\u591a\u4e2a ID \u7528\u9017\u53f7\u5206\u9694",
|
|
216
258
|
aiTitle: "AI \u5de5\u5177\u914d\u7f6e",
|
|
217
|
-
aiHint: "",
|
|
259
|
+
aiHint: "\u5148\u9009\u9ed8\u8ba4 AI\u3002Claude SDK\uff1a\u5de6\u4fa7\u680f\u300c\u914d\u7f6e\u6587\u4ef6\u300d\u2192 ~/.claude/settings.json\u3002Codex / CodeBuddy \u5728\u6b64\u586b CLI \u8def\u5f84\u3002",
|
|
218
260
|
claudeNote: "Claude \u51ed\u8bc1\u4ecd\u7136\u4ece\u73af\u5883\u53d8\u91cf\u6216 ~/.claude/settings.json \u8bfb\u53d6\u3002\u8fd9\u4e2a\u9875\u9762\u53ea\u7ba1\u7406\u672c\u5730\u6865\u63a5\u914d\u7f6e\uff0c\u4e0d\u8d1f\u8d23 Claude \u8d26\u53f7\u767b\u5f55\u3002",
|
|
219
261
|
aiCommonTitle: "\u516c\u5171\u9ed8\u8ba4\u914d\u7f6e",
|
|
220
262
|
aiCommonHint: "\u5148\u9009\u62e9\u9ed8\u8ba4 AI \u5de5\u5177\uff0c\u4e0b\u65b9\u518d\u663e\u793a\u5bf9\u5e94\u7684\u5de5\u5177\u4e13\u5c5e\u914d\u7f6e\u3002",
|
|
@@ -264,5 +306,35 @@ export const PAGE_TEXTS = {
|
|
|
264
306
|
saveBtn: "\u4fdd\u5b58",
|
|
265
307
|
jsonValid: "JSON \u6709\u6548",
|
|
266
308
|
jsonInvalid: "JSON \u65e0\u6548\uff1a{error}",
|
|
309
|
+
wizardTitle: "\u9996\u6b21\u4f7f\u7528\u5f15\u5bfc",
|
|
310
|
+
wizardStep1Title: "\u63a5\u5165\u4e00\u4e2a IM \u6e20\u9053",
|
|
311
|
+
wizardStep1Desc: "\u5728\u4e0b\u65b9\u542f\u7528\u81f3\u5c11\u4e00\u4e2a\u5e73\u53f0\uff0c\u5e76\u586b\u5199\u6240\u6709\u5fc5\u586b\u9879\u3002\u6709\u6761\u4ef6\u65f6\u7528\u300c\u6821\u9a8c\u914d\u7f6e\u300d\u6d4b\u8bd5\u51ed\u8bc1\u3002",
|
|
312
|
+
wizardStep2Title: "\u8bbe\u7f6e\u9ed8\u8ba4 AI \u5de5\u5177",
|
|
313
|
+
wizardStep2Desc: "Claude SDK\uff1a\u5728\u5de6\u4fa7\u680f\u300c\u914d\u7f6e\u6587\u4ef6\u300d\u7f16\u8f91 ~/.claude/settings.json\u3002Codex / CodeBuddy\uff1a\u5728 AI \u533a\u586b CLI \u8def\u5f84\u3002",
|
|
314
|
+
wizardStep3Title: "\u6821\u9a8c\u5e76\u4fdd\u5b58",
|
|
315
|
+
wizardStep3Desc: "\u5148\u70b9\u300c\u6821\u9a8c\u300d\uff0c\u518d\u70b9\u300c\u4fdd\u5b58\u914d\u7f6e\u300d\u3002\u6309\u9876\u90e8\u63d0\u793a\u4fee\u590d\u9519\u8bef\u3002",
|
|
316
|
+
wizardStep4Title: "\u542f\u52a8\u6865\u63a5",
|
|
317
|
+
wizardStep4Desc: "\u5230\u300c\u670d\u52a1\u300d\u533a\u70b9\u300c\u542f\u52a8\u6865\u63a5\u300d\u3002\u82e5\u9a6c\u4e0a\u9000\u51fa\uff0c\u67e5 ~/.open-im/logs \u65e5\u5fd7\u3002",
|
|
318
|
+
wizardStatusDone: "\u5df2\u5b8c\u6210",
|
|
319
|
+
wizardStatusTodo: "\u5f85\u5b8c\u6210",
|
|
320
|
+
wizardJumpPlatforms: "\u6253\u5f00\u5e73\u53f0\u914d\u7f6e",
|
|
321
|
+
wizardJumpAi: "\u6253\u5f00 AI \u914d\u7f6e",
|
|
322
|
+
wizardJumpService: "\u6253\u5f00\u670d\u52a1\u63a7\u5236",
|
|
323
|
+
validationNoPlatformEnabled: "\u4fdd\u5b58\u524d\u8bf7\u81f3\u5c11\u542f\u7528\u4e00\u4e2a IM \u5e73\u53f0\uff0c\u5e76\u586b\u5b8c\u5fc5\u586b\u51ed\u8bc1\u3002",
|
|
324
|
+
validationPlatformIncomplete: "\u5e73\u53f0\u300c{platform}\u300d\u5df2\u542f\u7528\uff0c\u4f46\u4ee5\u4e0b\u5fc5\u586b\u9879\u4e3a\u7a7a\uff1a{fields}",
|
|
325
|
+
validationAiCodexNoCli: "\u9ed8\u8ba4 AI \u4e3a Codex\uff0c\u4f46 Codex CLI \u8def\u5f84\u4e3a\u7a7a\u3002\u8bf7\u5728 AI \u533a\u586b\u5199\uff0c\u6216\u6539\u9ed8\u8ba4\u5de5\u5177\u3002",
|
|
326
|
+
validationAiCodebuddyNoCli: "\u9ed8\u8ba4 AI \u4e3a CodeBuddy\uff0c\u4f46 CodeBuddy CLI \u8def\u5f84\u4e3a\u7a7a\u3002\u8bf7\u5728 AI \u533a\u586b\u5199\uff0c\u6216\u6539\u9ed8\u8ba4\u5de5\u5177\u3002",
|
|
327
|
+
onboardingTitle: "\u6b22\u8fce\u4f7f\u7528 open-im",
|
|
328
|
+
onboardingDismiss: "\u77e5\u9053\u4e86",
|
|
329
|
+
onboardingReadme: "README\uff08\u90e8\u7f72\u8bf4\u660e\uff09",
|
|
330
|
+
onboardingBody: "<p><strong>open-im</strong> \u5728\u672c\u673a\u628a Telegram\u3001\u98de\u4e66\u3001QQ\u3001\u4f01\u5fae\u3001\u9489\u9489\u3001WorkBuddy \u7b49\u6e20\u9053\u8fde\u5230 Claude / Codex / CodeBuddy\u3002</p><ol style=\"margin:12px 0 12px 18px;line-height:1.65\"><li>\u5728<strong>\u5e73\u53f0\u914d\u7f6e</strong>\u9009\u4e00\u4e2a\u804a\u5929\u5e94\u7528\uff0c\u6309\u5b57\u6bb5\u4e0b\u65b9\u63d0\u793a\u586b\u51ed\u8bc1\u3002</li><li>\u5728<strong>AI \u5de5\u5177\u914d\u7f6e</strong>\u8bbe\u9ed8\u8ba4 AI\uff1b\u7528 Claude SDK \u65f6\u5728\u5de6\u4fa7<strong>\u914d\u7f6e\u6587\u4ef6</strong>\u5206\u533a\u7f16\u8f91<strong>~/.claude/settings.json</strong>\u3002</li><li>\u540c\u4e00<strong>\u914d\u7f6e\u6587\u4ef6</strong>\u5206\u533a\u53ef\u7f16\u8f91<strong>~/.open-im/config.json</strong>\u3002</li><li>\u5148<strong>\u6821\u9a8c</strong>\u518d<strong>\u4fdd\u5b58\u914d\u7f6e</strong>\uff0c\u7136\u540e\u5230<strong>\u670d\u52a1</strong>\u542f\u52a8\u6865\u63a5\u3002</li><li>\u4e5f\u53ef\u5728\u7ec8\u7aef\u8fd0\u884c <code style=\"background:var(--bg-tertiary);padding:2px 6px;border-radius:4px\">open-im init</code> \u4ea4\u4e92\u914d\u7f6e\u3002</li></ol>",
|
|
331
|
+
tipTelegramToken: '\u5728 Telegram \u641c <a href="https://t.me/BotFather" target="_blank" rel="noopener">@BotFather</a>\uff0c\u53d1 /newbot \u521b\u5efa\u673a\u5668\u4eba\u540e\u590d\u5236 Token\u3002',
|
|
332
|
+
tipFeishuAppId: "\u98de\u4e66\u5f00\u653e\u5e73\u53f0 \u2192 \u5e94\u7528 \u2192 \u51ed\u8bc1\u4e0e\u57fa\u7840\u4fe1\u606f \u2192 App ID\u3002",
|
|
333
|
+
tipFeishuSecret: "\u540c\u4e00\u9875 App Secret\uff08\u53ef\u91cd\u7f6e\u540e\u67e5\u770b\uff09\u3002",
|
|
334
|
+
tipQqAppId: '<a href="https://bot.q.qq.com" target="_blank" rel="noopener">QQ \u5f00\u653e\u5e73\u53f0</a> \u2192 \u673a\u5668\u4eba \u2192 App ID\u3002',
|
|
335
|
+
tipQqSecret: "\u540c\u4e00\u5904\u83b7\u53d6 App Secret\u3002",
|
|
336
|
+
tipWeworkCorp: "\u4f01\u4e1a\u5fae\u4fe1\u7ba1\u7406\u540e\u53f0 \u2192 \u5e94\u7528 \u2192 \u67e5\u7701 Corp ID / \u667a\u80fd\u673a\u5668\u4eba Bot ID \u4e0e Secret\u3002",
|
|
337
|
+
tipDingtalkClient: '<a href="https://open-dev.dingtalk.com" target="_blank" rel="noopener">\u9489\u9489\u5f00\u653e\u5e73\u53f0</a> \u2192 \u4f01\u4e1a\u5185\u90e8\u5e94\u7528 \u2192 AppKey / AppSecret\u3002',
|
|
338
|
+
tipWorkbuddyToken: "\u5efa\u8bae\u5728\u7ec8\u7aef\u8fd0\u884c <code>open-im init</code> \u5b8c\u6210 WorkBuddy \u6388\u6743\uff1b\u6216\u7c98\u8d34 CodeBuddy \u767b\u5f55\u540e\u7684 Token\u3002",
|
|
267
339
|
}
|
|
268
340
|
};
|