@vibe-lark/larkpal 0.1.86 → 0.1.87
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/account-id-BM1T6029-BzQ_cMoi.mjs +1 -0
- package/dist/activation-context--5yu1dPF-XV0Y0pTy.mjs +1 -0
- package/dist/anthropic-CFZUCb1w.mjs +39 -0
- package/dist/assistant-visible-text-DuFWokAt-BOJV_zwc.mjs +9 -0
- package/dist/azure-openai-responses-BEuiMaF-.mjs +1 -0
- package/dist/boundary-file-read-BSd9MXPy-gnNVhPKT.mjs +1 -0
- package/dist/browser-lifecycle-cleanup-BdNsMhMD-BM97qA_M.mjs +1 -0
- package/dist/build-Bkj0hOS2.mjs +3 -0
- package/dist/bundled-compat-BpaDaAAu-DJtrIX6i.mjs +27 -0
- package/dist/bundled-dir-U738ay4K-BxbzrJOo.mjs +1 -0
- package/dist/call-DimWbpgJ-B4pv55RH.mjs +20 -0
- package/dist/channel-bootstrap.runtime-BVclcGv1-CEZ0-JP9.mjs +1 -0
- package/dist/channel-bootstrap.runtime-Cwcr38m2-Dt6QlQkX.mjs +1 -0
- package/dist/chunk-DHbaKqs-.mjs +1 -0
- package/dist/cli.mjs +7 -92
- package/dist/command-format-LSnUCVVF-Dn4h9IOh.mjs +16 -0
- package/dist/config-Bim2pi8a-03N-28sw.mjs +1 -0
- package/dist/delivery-context.shared-j5hC5qb1-BSLQG47q.mjs +1 -0
- package/dist/diagnostic-ClMwNnUA-BMKvPQJT.mjs +1 -0
- package/dist/dist-J5UB83Ws.mjs +601 -0
- package/dist/dist-coestTs9.mjs +5 -0
- package/dist/env-api-keys-Cuz5irWW.mjs +1 -0
- package/dist/event-stream-B7Ei41Bu.mjs +1 -0
- package/dist/facade-loader-DFzIYYt_-4bzFvy-b.mjs +1 -0
- package/dist/from-Ba69_5cR.mjs +14 -0
- package/dist/gateway-method-policy-C7rf0SeV-CTJcMQCE.mjs +1 -0
- package/dist/github-copilot-headers-BfhryVuU.mjs +1 -0
- package/dist/google-ABo-1guT.mjs +1 -0
- package/dist/google-gemini-cli-CGlN1zUA.mjs +2 -0
- package/dist/google-shared-C60sNhwd.mjs +301 -0
- package/dist/google-vertex-De0nAItu.mjs +1 -0
- package/dist/hash-Dw-N8Y9l.mjs +1 -0
- package/dist/headers-Bpsp70B9.mjs +1 -0
- package/dist/home-dir-C44RaPME-B5iLWwCq.mjs +1 -0
- package/dist/ids-BPsM98Uu-CJBJAeVC.mjs +1 -0
- package/dist/image-2w3cApg7-CrpUMCvm.mjs +3 -0
- package/dist/interactive-init-C5MFL5MW.mjs +8 -0
- package/dist/io-CH2g3vsv-JJtUIa_U.mjs +10 -0
- package/dist/jiti-loader-cache-Bat69wam-DNIteTtO.mjs +9 -0
- package/dist/json-file-BQRNuxmK-hRjIgOXI.mjs +1 -0
- package/dist/json-parse-BESd8UAM.mjs +3 -0
- package/dist/jws-YaZ38F_i.mjs +12 -0
- package/dist/lark-cli-provider-BLMxH6CN.mjs +4 -0
- package/dist/lark-logger-xpMKNNtY.mjs +1 -0
- package/dist/live-smoke-DpURW676.mjs +33 -0
- package/dist/load-context-mb7uvLSn-3xYwSnOZ.mjs +1 -0
- package/dist/loader-708jrx4Y-BbJRXNlQ.mjs +4 -0
- package/dist/main.mjs +153 -74571
- package/dist/manifest-registry-_hxKCS2K-OL8KK_o4.mjs +15 -0
- package/dist/mcp-server.mjs +4 -527
- package/dist/message-channel-Bk_YHfQg-n2Hw2Y0L.mjs +1 -0
- package/dist/message-channel-core-DTA--Gjh-CIh10vfo.mjs +1 -0
- package/dist/message.config.runtime-K-k4XOyq-F_h0Cgkl.mjs +1 -0
- package/dist/message.gateway.runtime-DqHOHRTQ-ge4c5p4s.mjs +1 -0
- package/dist/mistral-DyL3Zo1b.mjs +7 -0
- package/dist/model-auth-env-oyg2Hexc-DJbt9J3o.mjs +1 -0
- package/dist/models-config-BmpSQJQF-BL6S5qAo.mjs +1 -0
- package/dist/models-config.runtime-SOhLEw-f.mjs +1 -0
- package/dist/multipart-parser-B9dwXBqu.mjs +2 -0
- package/dist/oauth-25y2wc7K.mjs +75 -0
- package/dist/openai-C-rgGb7X.mjs +16 -0
- package/dist/openai-codex-responses-BbyAPsP1.mjs +7 -0
- package/dist/openai-completions-Bu5qvQzb.mjs +5 -0
- package/dist/openai-responses-pIdwQBc4.mjs +1 -0
- package/dist/openai-responses-shared-DqW1JSux.mjs +10 -0
- package/dist/paths-D6msg0S1-BO4XgM1u.mjs +1 -0
- package/dist/paths-D92DjaZ--DdtJ-zYp.mjs +1 -0
- package/dist/pi-model-discovery-Bd0TWzo8-DvSM0eWu.mjs +1 -0
- package/dist/pi-model-discovery-runtime-PrjWOmsV.mjs +1 -0
- package/dist/pi-tools.before-tool-call.runtime-Bn7uqKie-WPxU5oNX.mjs +2 -0
- package/dist/plugin-auto-enable-DdH3n9V8-Dr_bUXkG.mjs +1 -0
- package/dist/process-scoped-map-B2cWkYET-Co-i-MXA.mjs +1 -0
- package/dist/provider-discovery.runtime-DY0VWQ81.mjs +1 -0
- package/dist/provider-model-compat-CFqcq0it-BUwZENrz.mjs +1 -0
- package/dist/provider-runtime-C8rljsNs-BDvu6FW3.mjs +1 -0
- package/dist/provider-runtime-CT50mNIX-DImw7ZZu.mjs +79 -0
- package/dist/provider-stream-COLujAAo-Dpq1DSIk.mjs +248 -0
- package/dist/providers.runtime-Ba7tOlq7-B4t6ywCr.mjs +1 -0
- package/dist/public-surface-loader-BVl0NQAE-TfJ3izj1.mjs +1 -0
- package/dist/resolve-C33B7eeu-DZM_z6Wr.mjs +1 -0
- package/dist/runtime-Cym-fqI8-1GOIuRRQ.mjs +1 -0
- package/dist/runtime-channel-state-CohMybAh-BBzhl07Q.mjs +1 -0
- package/dist/runtime-snapshot-C54O1-gI-DxusscPf.mjs +1 -0
- package/dist/runtime-state-IBOIXKOx-Cw1GA1td.mjs +1 -0
- package/dist/runtime-web-tools-fallback.runtime-Ca-qn1mj-BsYE2gOd.mjs +1 -0
- package/dist/runtime-web-tools-manifest.runtime-BgxQTjmq-P6MKP9gQ.mjs +1 -0
- package/dist/runtime-web-tools-public-artifacts.runtime-D9qcoWIX-5VoyjouO.mjs +1 -0
- package/dist/session-archive.runtime-B52_5vs4-cU2tYbBz.mjs +1 -0
- package/dist/session-key-Cn2QoOyX-QZeYmbxd.mjs +1 -0
- package/dist/session-transcript-files.fs-DEeFXruQ-CXIAFSsr.mjs +1 -0
- package/dist/src-CCDx_C-U.mjs +3 -0
- package/dist/src-DACmA9V6.mjs +5 -0
- package/dist/subagent-announce-L5WsQatW--rMn240x.mjs +2 -0
- package/dist/subagent-announce.registry.runtime-DiqZyeTs-DNfNHsls.mjs +1 -0
- package/dist/subagent-registry-steer-runtime-DFgZFC0j-XYS1_qwl.mjs +1 -0
- package/dist/subagent-system-prompt-C1qnN--K-CsU4f97T.mjs +23 -0
- package/dist/target-parsing-loaded-DKkb6jJY-B830OA1a.mjs +12 -0
- package/dist/task-registry-delivery-runtime-Dd1CUkZF-B2Hj2k8C.mjs +16 -0
- package/dist/task-registry-delivery-runtime-ragbeVx5-Bdvo2Q5u.mjs +1 -0
- package/dist/thinking-Bh-7MqXz-uApNUe6g.mjs +1 -0
- package/dist/transcript-E_-ISOkD-VTwb782D.mjs +5 -0
- package/dist/transcript.runtime-BqhvZZdl-B4E0TiX5.mjs +1 -0
- package/dist/transform-messages-BTA3xbAI.mjs +1 -0
- package/dist/web-provider-public-artifacts-BlpRwIUS-DbVhDOrY.mjs +1 -0
- package/dist/web-search-providers.runtime--0aUtC3b-Bjh4Bmrz.mjs +1 -0
- package/package.json +2 -3
- package/dist/account-id-BM1T6029-DYjVxojW.mjs +0 -46
- package/dist/activation-context--5yu1dPF-Bwsn3moT.mjs +0 -172
- package/dist/anthropic-TH8ERTXK.mjs +0 -5962
- package/dist/assistant-visible-text-DuFWokAt-CsbII5KS.mjs +0 -596
- package/dist/azure-openai-responses-Bt_Ag9Er.mjs +0 -166
- package/dist/boundary-file-read-BSd9MXPy--KThL5e6.mjs +0 -594
- package/dist/browser-lifecycle-cleanup-BdNsMhMD-O3tnAM4i.mjs +0 -60
- package/dist/build-DgTrEpge.mjs +0 -3333
- package/dist/bundled-compat-BpaDaAAu-D7oazKjD.mjs +0 -5216
- package/dist/bundled-dir-U738ay4K-DXK0q_TV.mjs +0 -258
- package/dist/call-DimWbpgJ-ColD4W-y.mjs +0 -9993
- package/dist/channel-bootstrap.runtime-BVclcGv1-DJv_Z-Kr.mjs +0 -2
- package/dist/channel-bootstrap.runtime-Cwcr38m2-VRfVCR-i.mjs +0 -33
- package/dist/chunk-D6SyT4dJ.mjs +0 -36
- package/dist/command-format-LSnUCVVF-BQ2SMKka.mjs +0 -685
- package/dist/config-Bim2pi8a-BQUdfiEi.mjs +0 -9
- package/dist/delivery-context.shared-j5hC5qb1-CI83RXXZ.mjs +0 -72
- package/dist/diagnostic-ClMwNnUA-D6nUtLnb.mjs +0 -140
- package/dist/dist-CEGw8-2W.mjs +0 -429
- package/dist/dist-DD2aJ2UL.mjs +0 -125135
- package/dist/env-api-keys-BVvSg7T2.mjs +0 -68
- package/dist/event-stream-xaQWmyas.mjs +0 -15226
- package/dist/facade-loader-DFzIYYt_-CIr4HKtE.mjs +0 -194
- package/dist/from-DF7cl2wz.mjs +0 -3842
- package/dist/gateway-method-policy-C7rf0SeV-CJQMEYIE.mjs +0 -28
- package/dist/github-copilot-headers-DjqWtUoP.mjs +0 -22
- package/dist/google-C2pVrgBZ.mjs +0 -336
- package/dist/google-gemini-cli-BBxgS5Ho.mjs +0 -623
- package/dist/google-shared-BsWgwEk1.mjs +0 -22791
- package/dist/google-vertex-BsVLJrrC.mjs +0 -358
- package/dist/hash-DAFtW_W7.mjs +0 -16
- package/dist/headers-R3HdCbAE.mjs +0 -8
- package/dist/home-dir-C44RaPME-CBRS4HLP.mjs +0 -93
- package/dist/ids-BPsM98Uu-CwuxvUai.mjs +0 -77
- package/dist/image-2w3cApg7-CxpHvoB5.mjs +0 -207
- package/dist/interactive-init-BXQBalNr.mjs +0 -450
- package/dist/io-CH2g3vsv-BOGlLlB8.mjs +0 -26218
- package/dist/jiti-loader-cache-Bat69wam-D6hCxboy.mjs +0 -5049
- package/dist/json-file-BQRNuxmK-DhJM5NsG.mjs +0 -108
- package/dist/json-parse-v_HIJjjI.mjs +0 -381
- package/dist/jws-GFcTvvVT.mjs +0 -2291
- package/dist/lark-cli-provider-BARgbbmo.mjs +0 -554
- package/dist/lark-logger-D7_pEVQc.mjs +0 -143
- package/dist/live-smoke-BhkBOcH9.mjs +0 -7135
- package/dist/load-context-mb7uvLSn-B10MAi3I.mjs +0 -29
- package/dist/loader-708jrx4Y-BOswuvpe.mjs +0 -5053
- package/dist/manifest-registry-_hxKCS2K-CZdeyN0f.mjs +0 -3512
- package/dist/message-channel-Bk_YHfQg-AeNrPPpp.mjs +0 -50
- package/dist/message-channel-core-DTA--Gjh-CY4Tkb7N.mjs +0 -29
- package/dist/message.config.runtime-K-k4XOyq-DZTmXomP.mjs +0 -2
- package/dist/message.gateway.runtime-DqHOHRTQ-DH4ml0YF.mjs +0 -2
- package/dist/mistral-CaR4DiLu.mjs +0 -28657
- package/dist/model-auth-env-oyg2Hexc-DU_rOUU5.mjs +0 -1306
- package/dist/models-config-BmpSQJQF-Gfvh1n3A.mjs +0 -1282
- package/dist/models-config.runtime-BsU_22xk.mjs +0 -2
- package/dist/multipart-parser-DedmaB5g.mjs +0 -294
- package/dist/oauth-DOJeGfcE.mjs +0 -6392
- package/dist/openai-BDtIh3Ja.mjs +0 -6693
- package/dist/openai-codex-responses-C5EORu31.mjs +0 -664
- package/dist/openai-completions-CR_cS6gX.mjs +0 -669
- package/dist/openai-responses-oGxwZyuC.mjs +0 -184
- package/dist/openai-responses-shared-BixMSDZE.mjs +0 -398
- package/dist/paths-D6msg0S1-C2lYuisN.mjs +0 -189
- package/dist/paths-D92DjaZ--CTOESW2b.mjs +0 -192
- package/dist/pi-model-discovery-Bd0TWzo8-BFsJmeMb.mjs +0 -227
- package/dist/pi-model-discovery-runtime-CCCZxkd8.mjs +0 -2
- package/dist/pi-tools.before-tool-call.runtime-Bn7uqKie-C5ewk8kK.mjs +0 -399
- package/dist/plugin-auto-enable-DdH3n9V8-DsA1isaF.mjs +0 -1456
- package/dist/process-scoped-map-B2cWkYET-CXwUZ8CZ.mjs +0 -61
- package/dist/provider-discovery.runtime-BPzz1PFj.mjs +0 -58
- package/dist/provider-model-compat-CFqcq0it-BDDuBI3A.mjs +0 -118
- package/dist/provider-runtime-C8rljsNs-CIT93zoy.mjs +0 -2
- package/dist/provider-runtime-CT50mNIX-BwEV6GyO.mjs +0 -573
- package/dist/provider-stream-COLujAAo-CbJPDngm.mjs +0 -35449
- package/dist/providers.runtime-Ba7tOlq7-CXkhkzU9.mjs +0 -219
- package/dist/public-surface-loader-BVl0NQAE-C0piXtsT.mjs +0 -117
- package/dist/resolve-C33B7eeu-BNvYTl6k.mjs +0 -1041
- package/dist/runtime-Cym-fqI8-DaSDMH-a.mjs +0 -120
- package/dist/runtime-channel-state-CohMybAh-hXR6y5Gx.mjs +0 -19
- package/dist/runtime-snapshot-C54O1-gI-40cbyi7P.mjs +0 -677
- package/dist/runtime-state-IBOIXKOx-Bf9tcLvc.mjs +0 -10
- package/dist/runtime-web-tools-fallback.runtime-Ca-qn1mj-BCVImm7a.mjs +0 -39
- package/dist/runtime-web-tools-manifest.runtime-BgxQTjmq-Cb4nJkRT.mjs +0 -2
- package/dist/runtime-web-tools-public-artifacts.runtime-D9qcoWIX-BrQdXzOQ.mjs +0 -2
- package/dist/session-archive.runtime-B52_5vs4-BG-_IwNJ.mjs +0 -2
- package/dist/session-key-Cn2QoOyX-CuHbJMgR.mjs +0 -82
- package/dist/session-transcript-files.fs-DEeFXruQ-B1PF6nLy.mjs +0 -147
- package/dist/src-BgCX0MLG.mjs +0 -813
- package/dist/src-DYbqlAqf.mjs +0 -1177
- package/dist/subagent-announce-L5WsQatW-CQWI9GMd.mjs +0 -344
- package/dist/subagent-announce.registry.runtime-DiqZyeTs-BKuniyi3.mjs +0 -28
- package/dist/subagent-registry-steer-runtime-DFgZFC0j-BhBz0roy.mjs +0 -211
- package/dist/subagent-system-prompt-C1qnN--K-DpnTFP47.mjs +0 -3061
- package/dist/target-parsing-loaded-DKkb6jJY-BMD4CkpS.mjs +0 -1002
- package/dist/task-registry-delivery-runtime-Dd1CUkZF-C8U40a3O.mjs +0 -2950
- package/dist/task-registry-delivery-runtime-ragbeVx5-CNbFAkjD.mjs +0 -2
- package/dist/thinking-Bh-7MqXz-D3woGbO7.mjs +0 -2
- package/dist/transcript-E_-ISOkD-DWCfZP2p.mjs +0 -2019
- package/dist/transcript.runtime-BqhvZZdl-BPy42vBP.mjs +0 -2
- package/dist/transform-messages-DbhIzTxq.mjs +0 -207
- package/dist/web-provider-public-artifacts-BlpRwIUS-CGPSV4W2.mjs +0 -295
- package/dist/web-search-providers.runtime--0aUtC3b-DyuhC95V.mjs +0 -200
|
@@ -1,207 +0,0 @@
|
|
|
1
|
-
import { d as resolveProviderRequestCapabilities } from "./io-CH2g3vsv-BOGlLlB8.mjs";
|
|
2
|
-
import { n as requireApiKey, r as normalizeModelRef, t as ensureOpenClawModelsJson } from "./models-config-BmpSQJQF-Gfvh1n3A.mjs";
|
|
3
|
-
import { s as complete } from "./oauth-DOJeGfcE.mjs";
|
|
4
|
-
import { a as minimaxUnderstandImage, c as getApiKeyForModel, i as isMinimaxVlmModel, l as resolveApiKeyForProvider, n as coerceImageAssistantText, r as hasImageReasoningOnlyResponse, t as registerProviderStreamForModel } from "./provider-stream-COLujAAo-CbJPDngm.mjs";
|
|
5
|
-
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/image-2w3cApg7.js
|
|
6
|
-
let piModelDiscoveryRuntimePromise = null;
|
|
7
|
-
function loadPiModelDiscoveryRuntime() {
|
|
8
|
-
piModelDiscoveryRuntimePromise ??= import("./pi-model-discovery-runtime-CCCZxkd8.mjs");
|
|
9
|
-
return piModelDiscoveryRuntimePromise;
|
|
10
|
-
}
|
|
11
|
-
function resolveImageToolMaxTokens(modelMaxTokens, requestedMaxTokens = 4096) {
|
|
12
|
-
if (typeof modelMaxTokens !== "number" || !Number.isFinite(modelMaxTokens) || modelMaxTokens <= 0) return requestedMaxTokens;
|
|
13
|
-
return Math.min(requestedMaxTokens, modelMaxTokens);
|
|
14
|
-
}
|
|
15
|
-
function isRecord(value) {
|
|
16
|
-
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
17
|
-
}
|
|
18
|
-
function isNativeResponsesReasoningPayload(model) {
|
|
19
|
-
if (model.api !== "openai-responses" && model.api !== "azure-openai-responses" && model.api !== "openai-codex-responses") return false;
|
|
20
|
-
return resolveProviderRequestCapabilities({
|
|
21
|
-
provider: model.provider,
|
|
22
|
-
api: model.api,
|
|
23
|
-
baseUrl: model.baseUrl,
|
|
24
|
-
capability: "image",
|
|
25
|
-
transport: "media-understanding"
|
|
26
|
-
}).usesKnownNativeOpenAIRoute;
|
|
27
|
-
}
|
|
28
|
-
function removeReasoningInclude(value) {
|
|
29
|
-
if (!Array.isArray(value)) return value;
|
|
30
|
-
const next = value.filter((entry) => entry !== "reasoning.encrypted_content");
|
|
31
|
-
return next.length > 0 ? next : void 0;
|
|
32
|
-
}
|
|
33
|
-
function disableReasoningForImageRetryPayload(payload, model) {
|
|
34
|
-
if (!isRecord(payload)) return;
|
|
35
|
-
const next = { ...payload };
|
|
36
|
-
delete next.reasoning;
|
|
37
|
-
delete next.reasoning_effort;
|
|
38
|
-
const include = removeReasoningInclude(next.include);
|
|
39
|
-
if (include === void 0) delete next.include;
|
|
40
|
-
else next.include = include;
|
|
41
|
-
if (isNativeResponsesReasoningPayload(model)) next.reasoning = { effort: "none" };
|
|
42
|
-
return next;
|
|
43
|
-
}
|
|
44
|
-
function isImageModelNoTextError(err) {
|
|
45
|
-
return err instanceof Error && /^Image model returned no text\b/.test(err.message);
|
|
46
|
-
}
|
|
47
|
-
async function resolveImageRuntime(params) {
|
|
48
|
-
await ensureOpenClawModelsJson(params.cfg, params.agentDir);
|
|
49
|
-
const { discoverAuthStorage, discoverModels } = await loadPiModelDiscoveryRuntime();
|
|
50
|
-
const authStorage = discoverAuthStorage(params.agentDir);
|
|
51
|
-
const modelRegistry = discoverModels(authStorage, params.agentDir);
|
|
52
|
-
const resolvedRef = normalizeModelRef(params.provider, params.model);
|
|
53
|
-
const model = modelRegistry.find(resolvedRef.provider, resolvedRef.model);
|
|
54
|
-
if (!model) throw new Error(`Unknown model: ${resolvedRef.provider}/${resolvedRef.model}`);
|
|
55
|
-
if (!model.input?.includes("image")) throw new Error(`Model does not support images: ${params.provider}/${params.model}`);
|
|
56
|
-
const apiKey = requireApiKey(await getApiKeyForModel({
|
|
57
|
-
model,
|
|
58
|
-
cfg: params.cfg,
|
|
59
|
-
agentDir: params.agentDir,
|
|
60
|
-
profileId: params.profile,
|
|
61
|
-
preferredProfile: params.preferredProfile,
|
|
62
|
-
store: params.authStore
|
|
63
|
-
}), model.provider);
|
|
64
|
-
authStorage.setRuntimeApiKey(model.provider, apiKey);
|
|
65
|
-
return {
|
|
66
|
-
apiKey,
|
|
67
|
-
model
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
function buildImageContext(prompt, images) {
|
|
71
|
-
return {
|
|
72
|
-
systemPrompt: prompt,
|
|
73
|
-
messages: [{
|
|
74
|
-
role: "user",
|
|
75
|
-
content: images.map((image) => ({
|
|
76
|
-
type: "image",
|
|
77
|
-
data: image.buffer.toString("base64"),
|
|
78
|
-
mimeType: image.mime ?? "image/jpeg"
|
|
79
|
-
})),
|
|
80
|
-
timestamp: Date.now()
|
|
81
|
-
}]
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
async function describeImagesWithMinimax(params) {
|
|
85
|
-
const responses = [];
|
|
86
|
-
for (const [index, image] of params.images.entries()) {
|
|
87
|
-
const prompt = params.images.length > 1 ? `${params.prompt}\n\nDescribe image ${index + 1} of ${params.images.length} independently.` : params.prompt;
|
|
88
|
-
const text = await minimaxUnderstandImage({
|
|
89
|
-
apiKey: params.apiKey,
|
|
90
|
-
prompt,
|
|
91
|
-
imageDataUrl: `data:${image.mime ?? "image/jpeg"};base64,${image.buffer.toString("base64")}`,
|
|
92
|
-
modelBaseUrl: params.modelBaseUrl
|
|
93
|
-
});
|
|
94
|
-
responses.push(params.images.length > 1 ? `Image ${index + 1}:\n${text.trim()}` : text.trim());
|
|
95
|
-
}
|
|
96
|
-
return {
|
|
97
|
-
text: responses.join("\n\n").trim(),
|
|
98
|
-
model: params.modelId
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
function isUnknownModelError(err) {
|
|
102
|
-
return err instanceof Error && /^Unknown model:/i.test(err.message);
|
|
103
|
-
}
|
|
104
|
-
function resolveConfiguredProviderBaseUrl(cfg, provider) {
|
|
105
|
-
const direct = cfg.models?.providers?.[provider];
|
|
106
|
-
if (typeof direct?.baseUrl === "string" && direct.baseUrl.trim()) return direct.baseUrl.trim();
|
|
107
|
-
}
|
|
108
|
-
async function resolveMinimaxVlmFallbackRuntime(params) {
|
|
109
|
-
return {
|
|
110
|
-
apiKey: requireApiKey(await resolveApiKeyForProvider({
|
|
111
|
-
provider: params.provider,
|
|
112
|
-
cfg: params.cfg,
|
|
113
|
-
profileId: params.profile,
|
|
114
|
-
preferredProfile: params.preferredProfile,
|
|
115
|
-
agentDir: params.agentDir
|
|
116
|
-
}), params.provider),
|
|
117
|
-
modelBaseUrl: resolveConfiguredProviderBaseUrl(params.cfg, params.provider)
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
async function describeImagesWithModel(params) {
|
|
121
|
-
const prompt = params.prompt ?? "Describe the image.";
|
|
122
|
-
let apiKey;
|
|
123
|
-
let model;
|
|
124
|
-
try {
|
|
125
|
-
const resolved = await resolveImageRuntime(params);
|
|
126
|
-
apiKey = resolved.apiKey;
|
|
127
|
-
model = resolved.model;
|
|
128
|
-
} catch (err) {
|
|
129
|
-
if (!isMinimaxVlmModel(params.provider, params.model) || !isUnknownModelError(err)) throw err;
|
|
130
|
-
const fallback = await resolveMinimaxVlmFallbackRuntime(params);
|
|
131
|
-
return await describeImagesWithMinimax({
|
|
132
|
-
apiKey: fallback.apiKey,
|
|
133
|
-
modelId: params.model,
|
|
134
|
-
modelBaseUrl: fallback.modelBaseUrl,
|
|
135
|
-
prompt,
|
|
136
|
-
images: params.images
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
if (isMinimaxVlmModel(model.provider, model.id)) return await describeImagesWithMinimax({
|
|
140
|
-
apiKey,
|
|
141
|
-
modelId: model.id,
|
|
142
|
-
modelBaseUrl: model.baseUrl,
|
|
143
|
-
prompt,
|
|
144
|
-
images: params.images
|
|
145
|
-
});
|
|
146
|
-
registerProviderStreamForModel({
|
|
147
|
-
model,
|
|
148
|
-
cfg: params.cfg,
|
|
149
|
-
agentDir: params.agentDir
|
|
150
|
-
});
|
|
151
|
-
const context = buildImageContext(prompt, params.images);
|
|
152
|
-
const controller = new AbortController();
|
|
153
|
-
const timeout = typeof params.timeoutMs === "number" && Number.isFinite(params.timeoutMs) && params.timeoutMs > 0 ? setTimeout(() => controller.abort(), params.timeoutMs) : void 0;
|
|
154
|
-
const maxTokens = resolveImageToolMaxTokens(model.maxTokens, params.maxTokens ?? 512);
|
|
155
|
-
const completeImage = async (onPayload) => await complete(model, context, {
|
|
156
|
-
apiKey,
|
|
157
|
-
maxTokens,
|
|
158
|
-
signal: controller.signal,
|
|
159
|
-
...onPayload ? { onPayload } : {}
|
|
160
|
-
});
|
|
161
|
-
try {
|
|
162
|
-
const message = await completeImage();
|
|
163
|
-
try {
|
|
164
|
-
return {
|
|
165
|
-
text: coerceImageAssistantText({
|
|
166
|
-
message,
|
|
167
|
-
provider: model.provider,
|
|
168
|
-
model: model.id
|
|
169
|
-
}),
|
|
170
|
-
model: model.id
|
|
171
|
-
};
|
|
172
|
-
} catch (err) {
|
|
173
|
-
if (!isImageModelNoTextError(err) || !hasImageReasoningOnlyResponse(message)) throw err;
|
|
174
|
-
}
|
|
175
|
-
return {
|
|
176
|
-
text: coerceImageAssistantText({
|
|
177
|
-
message: await completeImage(disableReasoningForImageRetryPayload),
|
|
178
|
-
provider: model.provider,
|
|
179
|
-
model: model.id
|
|
180
|
-
}),
|
|
181
|
-
model: model.id
|
|
182
|
-
};
|
|
183
|
-
} finally {
|
|
184
|
-
clearTimeout(timeout);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
async function describeImageWithModel(params) {
|
|
188
|
-
return await describeImagesWithModel({
|
|
189
|
-
images: [{
|
|
190
|
-
buffer: params.buffer,
|
|
191
|
-
fileName: params.fileName,
|
|
192
|
-
mime: params.mime
|
|
193
|
-
}],
|
|
194
|
-
model: params.model,
|
|
195
|
-
provider: params.provider,
|
|
196
|
-
prompt: params.prompt,
|
|
197
|
-
maxTokens: params.maxTokens,
|
|
198
|
-
timeoutMs: params.timeoutMs,
|
|
199
|
-
profile: params.profile,
|
|
200
|
-
preferredProfile: params.preferredProfile,
|
|
201
|
-
authStore: params.authStore,
|
|
202
|
-
agentDir: params.agentDir,
|
|
203
|
-
cfg: params.cfg
|
|
204
|
-
});
|
|
205
|
-
}
|
|
206
|
-
//#endregion
|
|
207
|
-
export { describeImageWithModel, describeImagesWithModel };
|
|
@@ -1,450 +0,0 @@
|
|
|
1
|
-
import { t as larkLogger } from "./lark-logger-D7_pEVQc.mjs";
|
|
2
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
|
-
import { join } from "node:path";
|
|
4
|
-
import { homedir } from "node:os";
|
|
5
|
-
import { execSync, spawn } from "node:child_process";
|
|
6
|
-
import { createInterface } from "node:readline";
|
|
7
|
-
import * as Lark from "@larksuiteoapi/node-sdk";
|
|
8
|
-
import qrcodeTerminal from "qrcode-terminal";
|
|
9
|
-
//#region src/credentials/app-registration.ts
|
|
10
|
-
async function registerFeishuAppCredentials(options) {
|
|
11
|
-
const result = await (options.registerApp ?? defaultRegisterApp)({
|
|
12
|
-
source: options.source ?? "larkpal",
|
|
13
|
-
signal: options.signal,
|
|
14
|
-
onQRCodeReady: options.onQRCodeReady,
|
|
15
|
-
onStatusChange: options.onStatusChange
|
|
16
|
-
});
|
|
17
|
-
if (!result.client_id || !result.client_secret) throw new Error("飞书应用创建完成但未返回 App ID 或 App Secret");
|
|
18
|
-
await options.saveCredentials({
|
|
19
|
-
appId: result.client_id,
|
|
20
|
-
appSecret: result.client_secret
|
|
21
|
-
});
|
|
22
|
-
return {
|
|
23
|
-
appId: result.client_id,
|
|
24
|
-
appSecret: result.client_secret,
|
|
25
|
-
creatorOpenId: result.user_info?.open_id,
|
|
26
|
-
tenantBrand: result.user_info?.tenant_brand
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
async function defaultRegisterApp(options) {
|
|
30
|
-
return Lark.registerApp(options);
|
|
31
|
-
}
|
|
32
|
-
//#endregion
|
|
33
|
-
//#region src/init/landing-presentation.ts
|
|
34
|
-
function renderFeishuAppCreationQRCode(input) {
|
|
35
|
-
return [
|
|
36
|
-
" 请扫码创建飞书智能体应用,或打开下面的链接:",
|
|
37
|
-
"",
|
|
38
|
-
renderQRCodeOrFallback(input.url, input.createQRCode ?? createQRCode),
|
|
39
|
-
` ${input.url}`,
|
|
40
|
-
` 链接有效期 ${input.expireIn} 秒。`
|
|
41
|
-
].join("\n");
|
|
42
|
-
}
|
|
43
|
-
function formatRuntimeSelectionSummary(runtimeName) {
|
|
44
|
-
switch (runtimeName) {
|
|
45
|
-
case "codex-app-server": return [
|
|
46
|
-
"已选择 Codex app-server 作为 agent runtime。",
|
|
47
|
-
"启动前请确保 Codex CLI 可用:codex",
|
|
48
|
-
"启动配置:LARKPAL_RUNTIME=codex-app-server"
|
|
49
|
-
].join("\n");
|
|
50
|
-
case "larkpal-agent": return [
|
|
51
|
-
"已选择 larkpal-agent 作为 agent runtime。",
|
|
52
|
-
"启动前请配置 larkpal-agent 所需的 LLM 和 scenario provider 环境变量。",
|
|
53
|
-
"启动配置:LARKPAL_RUNTIME=larkpal-agent"
|
|
54
|
-
].join("\n");
|
|
55
|
-
case "claude-code": return [
|
|
56
|
-
"已选择 Claude Code 作为 agent runtime。",
|
|
57
|
-
"启动前请确保 Claude Code CLI 可用:claude",
|
|
58
|
-
"启动配置:LARKPAL_RUNTIME=claude-code"
|
|
59
|
-
].join("\n");
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
function renderRuntimeSelectionPrompt(currentRuntime) {
|
|
63
|
-
return [
|
|
64
|
-
"Agent runtime 选择",
|
|
65
|
-
"",
|
|
66
|
-
` [1] Claude Code (claude-code)${currentRuntime === "claude-code" ? "(当前)" : ""}`,
|
|
67
|
-
` [2] Codex app-server (codex-app-server)${currentRuntime === "codex-app-server" ? "(当前)" : ""}`,
|
|
68
|
-
` [3] larkpal-agent${currentRuntime === "larkpal-agent" ? "(当前)" : ""}`
|
|
69
|
-
].join("\n");
|
|
70
|
-
}
|
|
71
|
-
function resolveRuntimeSelection(choice, currentRuntime) {
|
|
72
|
-
const normalized = choice.trim().toLowerCase();
|
|
73
|
-
if (!normalized) return currentRuntime;
|
|
74
|
-
if (normalized === "1" || normalized === "claude" || normalized === "claude-code") return "claude-code";
|
|
75
|
-
if (normalized === "2" || normalized === "codex" || normalized === "codex-app-server") return "codex-app-server";
|
|
76
|
-
if (normalized === "3" || normalized === "larkpal-agent") return "larkpal-agent";
|
|
77
|
-
return currentRuntime;
|
|
78
|
-
}
|
|
79
|
-
function createQRCode(url) {
|
|
80
|
-
let qrCode = "";
|
|
81
|
-
qrcodeTerminal.setErrorLevel("L");
|
|
82
|
-
qrcodeTerminal.generate(url, { small: true }, (code) => {
|
|
83
|
-
qrCode = code;
|
|
84
|
-
});
|
|
85
|
-
return qrCode.trimEnd();
|
|
86
|
-
}
|
|
87
|
-
function renderQRCodeOrFallback(url, renderer) {
|
|
88
|
-
try {
|
|
89
|
-
return renderer(url).trimEnd() || " [二维码渲染失败,请使用下方链接]";
|
|
90
|
-
} catch {
|
|
91
|
-
return " [二维码渲染失败,请使用下方链接]";
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
//#endregion
|
|
95
|
-
//#region src/init/prerequisites.ts
|
|
96
|
-
function assessInitPrerequisites(deps) {
|
|
97
|
-
const larkCli = deps.detectCli("lark-cli");
|
|
98
|
-
const runtimeCliName = resolveRuntimeCliName(deps.runtimeName);
|
|
99
|
-
const runtimeCli = runtimeCliName ? deps.detectCli(runtimeCliName) : { installed: true };
|
|
100
|
-
const warnings = [];
|
|
101
|
-
if (runtimeCliName && !runtimeCli.installed) warnings.push(runtimeCliName === "codex" ? "OpenAI Codex CLI is not installed. Feishu app credentials can still be configured now, but service startup with LARKPAL_RUNTIME=codex-app-server will require codex later." : "Claude Code is not installed. Feishu app credentials can still be configured now, but service startup with the default runtime will require Claude Code later.");
|
|
102
|
-
if (!larkCli.installed) warnings.push("lark-cli is not installed. Basic Feishu bot chat can be configured with app credentials, but execution-layer tools for documents, calendars, mail, tasks, and personal data will require lark-cli later.");
|
|
103
|
-
return {
|
|
104
|
-
canConfigureFeishuCredentials: true,
|
|
105
|
-
larkCli: {
|
|
106
|
-
...larkCli,
|
|
107
|
-
ready: larkCli.installed,
|
|
108
|
-
requiredForBasicChat: false
|
|
109
|
-
},
|
|
110
|
-
runtime: {
|
|
111
|
-
...runtimeCli,
|
|
112
|
-
ready: runtimeCli.installed,
|
|
113
|
-
name: deps.runtimeName,
|
|
114
|
-
cliName: runtimeCliName ?? deps.runtimeName
|
|
115
|
-
},
|
|
116
|
-
warnings
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
function resolveRuntimeCliName(runtimeName) {
|
|
120
|
-
if (runtimeName === "codex-app-server") return "codex";
|
|
121
|
-
if (runtimeName === "larkpal-agent") return void 0;
|
|
122
|
-
return "claude";
|
|
123
|
-
}
|
|
124
|
-
//#endregion
|
|
125
|
-
//#region src/init/interactive-init.ts
|
|
126
|
-
/**
|
|
127
|
-
* 交互式初始化流程
|
|
128
|
-
*
|
|
129
|
-
* 引导用户完成 LarkPal 首次配置:
|
|
130
|
-
* Step 1: 检查前置依赖(claude、lark-cli)
|
|
131
|
-
* Step 2: 配置飞书应用凭证(lark-cli config init + 补充 App Secret)
|
|
132
|
-
* Step 3: 打印成功信息
|
|
133
|
-
*
|
|
134
|
-
* 仅使用 Node.js 内置模块,不依赖第三方包。
|
|
135
|
-
*/
|
|
136
|
-
const log = larkLogger("init");
|
|
137
|
-
const CYAN = "\x1B[36m";
|
|
138
|
-
const GREEN = "\x1B[32m";
|
|
139
|
-
const YELLOW = "\x1B[33m";
|
|
140
|
-
const RED = "\x1B[31m";
|
|
141
|
-
const BOLD = "\x1B[1m";
|
|
142
|
-
const DIM = "\x1B[2m";
|
|
143
|
-
const RESET = "\x1B[0m";
|
|
144
|
-
/** LarkPal 自身配置目录 */
|
|
145
|
-
const LARKPAL_CONFIG_DIR = join(homedir(), ".larkpal");
|
|
146
|
-
/** LarkPal 凭证文件(存储 appId + appSecret) */
|
|
147
|
-
const LARKPAL_CREDENTIALS_PATH = join(LARKPAL_CONFIG_DIR, "credentials.json");
|
|
148
|
-
/** readline 问答封装 */
|
|
149
|
-
function ask(rl, question) {
|
|
150
|
-
return new Promise((resolve) => {
|
|
151
|
-
rl.question(question, (answer) => resolve(answer.trim()));
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
/** 检测 CLI 工具是否已安装 */
|
|
155
|
-
function isCliInstalled(name) {
|
|
156
|
-
try {
|
|
157
|
-
return !!execSync(`which ${name}`, {
|
|
158
|
-
encoding: "utf-8",
|
|
159
|
-
timeout: 5e3
|
|
160
|
-
}).trim();
|
|
161
|
-
} catch {
|
|
162
|
-
return false;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
/** 通过 lark-cli config show 获取当前配置的 appId */
|
|
166
|
-
function getAppIdFromLarkCli() {
|
|
167
|
-
try {
|
|
168
|
-
const jsonMatch = execSync("lark-cli config show", {
|
|
169
|
-
encoding: "utf-8",
|
|
170
|
-
timeout: 1e4,
|
|
171
|
-
stdio: [
|
|
172
|
-
"pipe",
|
|
173
|
-
"pipe",
|
|
174
|
-
"pipe"
|
|
175
|
-
]
|
|
176
|
-
}).match(/\{[\s\S]*\}/);
|
|
177
|
-
if (jsonMatch) return JSON.parse(jsonMatch[0]).appId || null;
|
|
178
|
-
} catch {}
|
|
179
|
-
return null;
|
|
180
|
-
}
|
|
181
|
-
/** 写入凭证到 LarkPal 配置文件 */
|
|
182
|
-
function writeCredentials(appId, appSecret) {
|
|
183
|
-
try {
|
|
184
|
-
if (!existsSync(LARKPAL_CONFIG_DIR)) {
|
|
185
|
-
mkdirSync(LARKPAL_CONFIG_DIR, { recursive: true });
|
|
186
|
-
log.info("创建 LarkPal 配置目录", { path: LARKPAL_CONFIG_DIR });
|
|
187
|
-
}
|
|
188
|
-
writeFileSync(LARKPAL_CREDENTIALS_PATH, JSON.stringify({
|
|
189
|
-
app_id: appId,
|
|
190
|
-
app_secret: appSecret
|
|
191
|
-
}, null, 2) + "\n", {
|
|
192
|
-
encoding: "utf-8",
|
|
193
|
-
mode: 384
|
|
194
|
-
});
|
|
195
|
-
log.info("凭证已写入", {
|
|
196
|
-
path: LARKPAL_CREDENTIALS_PATH,
|
|
197
|
-
appId
|
|
198
|
-
});
|
|
199
|
-
return true;
|
|
200
|
-
} catch (err) {
|
|
201
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
202
|
-
log.error("写入凭证文件失败", {
|
|
203
|
-
path: LARKPAL_CREDENTIALS_PATH,
|
|
204
|
-
error: msg
|
|
205
|
-
});
|
|
206
|
-
return false;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
async function saveCredentialsOrThrow(credentials) {
|
|
210
|
-
if (!writeCredentials(credentials.appId, credentials.appSecret)) throw new Error("凭证保存失败");
|
|
211
|
-
}
|
|
212
|
-
/** 检查 LarkPal 凭证文件是否已有有效凭证 */
|
|
213
|
-
function hasLarkPalCredentials() {
|
|
214
|
-
if (!existsSync(LARKPAL_CREDENTIALS_PATH)) return null;
|
|
215
|
-
try {
|
|
216
|
-
const raw = readFileSync(LARKPAL_CREDENTIALS_PATH, "utf-8");
|
|
217
|
-
const creds = JSON.parse(raw);
|
|
218
|
-
if (creds.app_id && creds.app_secret) return {
|
|
219
|
-
appId: creds.app_id,
|
|
220
|
-
appSecret: creds.app_secret
|
|
221
|
-
};
|
|
222
|
-
} catch {}
|
|
223
|
-
return null;
|
|
224
|
-
}
|
|
225
|
-
function checkPrerequisites(runtimeName) {
|
|
226
|
-
console.log(`\n${BOLD}🔍 检查前置依赖${RESET}\n`);
|
|
227
|
-
const assessment = assessInitPrerequisites({
|
|
228
|
-
runtimeName,
|
|
229
|
-
detectCli: (name) => ({ installed: isCliInstalled(name) })
|
|
230
|
-
});
|
|
231
|
-
if (assessment.runtime.ready) console.log(` ${GREEN}✅ ${assessment.runtime.cliName} 已安装${RESET}`);
|
|
232
|
-
else console.log(` ${YELLOW}⚠️ ${assessment.runtime.cliName} 未安装${RESET}`);
|
|
233
|
-
if (assessment.larkCli.ready) console.log(` ${GREEN}✅ lark-cli 已安装${RESET}`);
|
|
234
|
-
else console.log(` ${YELLOW}⚠️ lark-cli 未安装(基础飞书连接不阻塞)${RESET}`);
|
|
235
|
-
for (const warning of assessment.warnings) console.log(` ${DIM}${warning}${RESET}`);
|
|
236
|
-
console.log();
|
|
237
|
-
}
|
|
238
|
-
async function configureRuntime(rl) {
|
|
239
|
-
const currentRuntime = resolveConfiguredRuntime(process.env.LARKPAL_RUNTIME);
|
|
240
|
-
console.log(`\n${BOLD}🤖 Agent runtime 配置${RESET}\n`);
|
|
241
|
-
console.log(renderRuntimeSelectionPrompt(currentRuntime));
|
|
242
|
-
console.log();
|
|
243
|
-
const selectedRuntime = resolveRuntimeSelection(await ask(rl, ` 请选择 [1/2/3](默认当前): `), currentRuntime);
|
|
244
|
-
process.env.LARKPAL_RUNTIME = selectedRuntime;
|
|
245
|
-
console.log(`\n${formatRuntimeSelectionSummary(selectedRuntime)}\n`);
|
|
246
|
-
log.info("用户选择 agent runtime", { runtimeName: selectedRuntime });
|
|
247
|
-
return selectedRuntime;
|
|
248
|
-
}
|
|
249
|
-
/**
|
|
250
|
-
* 通过 lark-cli config init 子进程配置凭证。
|
|
251
|
-
* 返回解析到的 appId(成功)或 null(失败)。
|
|
252
|
-
*/
|
|
253
|
-
function runLarkCliConfigInit() {
|
|
254
|
-
return new Promise((resolve) => {
|
|
255
|
-
console.log(`\n${DIM}正在启动 lark-cli config init ...${RESET}\n`);
|
|
256
|
-
log.info("启动子进程: lark-cli config init");
|
|
257
|
-
let capturedOutput = "";
|
|
258
|
-
const child = spawn("lark-cli", ["config", "init"], { stdio: [
|
|
259
|
-
"inherit",
|
|
260
|
-
"pipe",
|
|
261
|
-
"pipe"
|
|
262
|
-
] });
|
|
263
|
-
child.stdout?.on("data", (chunk) => {
|
|
264
|
-
const text = chunk.toString();
|
|
265
|
-
capturedOutput += text;
|
|
266
|
-
process.stdout.write(text);
|
|
267
|
-
});
|
|
268
|
-
child.stderr?.on("data", (chunk) => {
|
|
269
|
-
const text = chunk.toString();
|
|
270
|
-
capturedOutput += text;
|
|
271
|
-
process.stderr.write(text);
|
|
272
|
-
});
|
|
273
|
-
child.on("error", (err) => {
|
|
274
|
-
log.error("lark-cli config init 启动失败", { error: err.message });
|
|
275
|
-
console.log(`\n${RED}启动 lark-cli config init 失败: ${err.message}${RESET}`);
|
|
276
|
-
resolve(null);
|
|
277
|
-
});
|
|
278
|
-
child.on("close", (code) => {
|
|
279
|
-
log.info("lark-cli config init 执行完毕", {
|
|
280
|
-
exitCode: code,
|
|
281
|
-
output: capturedOutput.substring(0, 500)
|
|
282
|
-
});
|
|
283
|
-
if (code === 0) {
|
|
284
|
-
let appId = capturedOutput.match(/App\s*ID:\s*(\S+)/i)?.[1] || null;
|
|
285
|
-
if (!appId) appId = getAppIdFromLarkCli();
|
|
286
|
-
if (appId) {
|
|
287
|
-
log.info("lark-cli config init 成功", { appId });
|
|
288
|
-
console.log(`\n${GREEN}✅ 飞书应用创建成功${RESET} ${DIM}(App ID: ${appId})${RESET}`);
|
|
289
|
-
} else console.log(`\n${GREEN}✅ lark-cli config init 完成${RESET}`);
|
|
290
|
-
resolve(appId);
|
|
291
|
-
} else {
|
|
292
|
-
console.log(`\n${YELLOW}⚠️ lark-cli config init 退出码: ${code}${RESET}`);
|
|
293
|
-
resolve(null);
|
|
294
|
-
}
|
|
295
|
-
});
|
|
296
|
-
});
|
|
297
|
-
}
|
|
298
|
-
/**
|
|
299
|
-
* 提示用户输入 App Secret 并保存到 LarkPal 凭证文件。
|
|
300
|
-
*
|
|
301
|
-
* lark-cli 新版使用 master key 加密存储 secret,LarkPal 无法直接读取。
|
|
302
|
-
* 需要用户从飞书开放平台复制 App Secret 并输入。
|
|
303
|
-
*/
|
|
304
|
-
async function promptAppSecret(rl, appId) {
|
|
305
|
-
console.log(`\n${BOLD}🔑 输入 App Secret${RESET}\n`);
|
|
306
|
-
console.log(` ${DIM}lark-cli 已完成应用配置,但 LarkPal 还需要 App Secret 来启动服务。${RESET}`);
|
|
307
|
-
console.log(` ${DIM}请在飞书开放平台的应用管理页面(凭证与基础信息)中复制 App Secret:${RESET}\n`);
|
|
308
|
-
console.log(` ${CYAN}https://open.feishu.cn/app/${appId}${RESET}\n`);
|
|
309
|
-
const appSecret = await ask(rl, ` App Secret: `);
|
|
310
|
-
if (!appSecret) {
|
|
311
|
-
console.log(`\n${RED}App Secret 不能为空${RESET}`);
|
|
312
|
-
return false;
|
|
313
|
-
}
|
|
314
|
-
if (writeCredentials(appId, appSecret)) {
|
|
315
|
-
console.log(`\n${GREEN}✅ 凭证已保存${RESET} ${DIM}(${LARKPAL_CREDENTIALS_PATH})${RESET}`);
|
|
316
|
-
return true;
|
|
317
|
-
}
|
|
318
|
-
console.log(`\n${RED}凭证保存失败${RESET}`);
|
|
319
|
-
return false;
|
|
320
|
-
}
|
|
321
|
-
/** 手动输入完整凭证(App ID + App Secret) */
|
|
322
|
-
async function manualCredentialInput(rl) {
|
|
323
|
-
console.log(`\n${BOLD}📝 手动输入飞书应用凭证${RESET}\n`);
|
|
324
|
-
console.log(` ${DIM}你可以在飞书开放平台 (https://open.feishu.cn) 的应用管理页面找到这些信息。${RESET}\n`);
|
|
325
|
-
const appId = await ask(rl, ` App ID: `);
|
|
326
|
-
if (!appId) {
|
|
327
|
-
console.log(`\n${RED}App ID 不能为空${RESET}`);
|
|
328
|
-
return false;
|
|
329
|
-
}
|
|
330
|
-
const appSecret = await ask(rl, ` App Secret: `);
|
|
331
|
-
if (!appSecret) {
|
|
332
|
-
console.log(`\n${RED}App Secret 不能为空${RESET}`);
|
|
333
|
-
return false;
|
|
334
|
-
}
|
|
335
|
-
if (writeCredentials(appId, appSecret)) {
|
|
336
|
-
console.log(`\n${GREEN}✅ 凭证已保存${RESET} ${DIM}(${LARKPAL_CREDENTIALS_PATH})${RESET}`);
|
|
337
|
-
return true;
|
|
338
|
-
}
|
|
339
|
-
console.log(`\n${RED}凭证保存失败${RESET}`);
|
|
340
|
-
return false;
|
|
341
|
-
}
|
|
342
|
-
async function scanCreateAppCredentials() {
|
|
343
|
-
console.log(`\n${BOLD}📱 扫码创建飞书智能体应用${RESET}\n`);
|
|
344
|
-
console.log(` LarkPal 会通过飞书官方一键创建应用能力获取 App ID 和 App Secret。`);
|
|
345
|
-
console.log(` ${DIM}这一步只配置应用凭据;个人日历、文档、邮件等能力后续通过 lark-cli auth login 授权。${RESET}\n`);
|
|
346
|
-
try {
|
|
347
|
-
const result = await registerFeishuAppCredentials({
|
|
348
|
-
saveCredentials: saveCredentialsOrThrow,
|
|
349
|
-
onQRCodeReady: ({ url, expireIn }) => {
|
|
350
|
-
console.log(renderFeishuAppCreationQRCode({
|
|
351
|
-
url,
|
|
352
|
-
expireIn
|
|
353
|
-
}));
|
|
354
|
-
console.log();
|
|
355
|
-
},
|
|
356
|
-
onStatusChange: ({ status }) => {
|
|
357
|
-
if (status === "polling") console.log(` ${DIM}等待飞书确认中...${RESET}`);
|
|
358
|
-
else if (status === "slow_down") console.log(` ${DIM}飞书要求降低轮询频率,继续等待...${RESET}`);
|
|
359
|
-
else if (status === "domain_switched") console.log(` ${DIM}已根据租户切换认证域名,继续等待...${RESET}`);
|
|
360
|
-
},
|
|
361
|
-
source: "larkpal-init"
|
|
362
|
-
});
|
|
363
|
-
console.log(`\n${GREEN}✅ 飞书应用创建并保存成功${RESET} ${DIM}(App ID: ${result.appId})${RESET}`);
|
|
364
|
-
return true;
|
|
365
|
-
} catch (err) {
|
|
366
|
-
console.log(`\n${RED}扫码创建飞书应用失败: ${err instanceof Error ? err.message : String(err)}${RESET}`);
|
|
367
|
-
return false;
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
async function configureCredentials(rl) {
|
|
371
|
-
if (process.env.LARK_APP_ID && process.env.LARK_APP_SECRET) {
|
|
372
|
-
console.log(`${GREEN}✅ 飞书应用凭证已通过环境变量配置${RESET}`);
|
|
373
|
-
log.info("凭证已通过环境变量配置");
|
|
374
|
-
return true;
|
|
375
|
-
}
|
|
376
|
-
const existing = hasLarkPalCredentials();
|
|
377
|
-
if (existing) {
|
|
378
|
-
console.log(`${GREEN}✅ 飞书应用凭证已配置${RESET} ${DIM}(App ID: ${existing.appId})${RESET}`);
|
|
379
|
-
log.info("LarkPal 凭证文件已存在", { appId: existing.appId });
|
|
380
|
-
return true;
|
|
381
|
-
}
|
|
382
|
-
const existingAppId = getAppIdFromLarkCli();
|
|
383
|
-
if (existingAppId) {
|
|
384
|
-
console.log(`${GREEN}✅ 飞书应用已配置${RESET} ${DIM}(App ID: ${existingAppId})${RESET}`);
|
|
385
|
-
console.log(`\n ${YELLOW}但 LarkPal 还需要 App Secret 才能启动。${RESET}`);
|
|
386
|
-
return promptAppSecret(rl, existingAppId);
|
|
387
|
-
}
|
|
388
|
-
console.log(`${BOLD}📋 飞书应用配置${RESET}\n`);
|
|
389
|
-
console.log(` LarkPal 需要飞书应用凭据才能进入飞书会话。推荐使用飞书官方扫码创建应用能力:\n`);
|
|
390
|
-
console.log(` ${DIM}[1] 扫码创建飞书智能体应用(推荐)${RESET}`);
|
|
391
|
-
console.log(` ${DIM}[2] 手动输入 App ID 和 App Secret${RESET}`);
|
|
392
|
-
console.log(` ${DIM}[3] 使用 lark-cli config init(兼容旧流程)${RESET}\n`);
|
|
393
|
-
const choice = await ask(rl, ` 请选择 [1/2/3](默认 1): `);
|
|
394
|
-
const option = choice === "2" ? 2 : choice === "3" ? 3 : 1;
|
|
395
|
-
log.info("用户选择凭证配置方式", { option });
|
|
396
|
-
if (option === 1) {
|
|
397
|
-
if (await scanCreateAppCredentials()) return true;
|
|
398
|
-
console.log(`\n ${YELLOW}扫码创建未完成,是否手动输入凭证?${RESET}`);
|
|
399
|
-
if ((await ask(rl, ` 手动输入? [y/N]: `)).toLowerCase() === "y") return manualCredentialInput(rl);
|
|
400
|
-
return false;
|
|
401
|
-
}
|
|
402
|
-
if (option === 3) {
|
|
403
|
-
const appId = await runLarkCliConfigInit();
|
|
404
|
-
if (appId) return promptAppSecret(rl, appId);
|
|
405
|
-
console.log(`\n ${YELLOW}lark-cli 配置未成功,是否手动输入凭证?${RESET}`);
|
|
406
|
-
if ((await ask(rl, ` 手动输入? [y/N]: `)).toLowerCase() === "y") return manualCredentialInput(rl);
|
|
407
|
-
return false;
|
|
408
|
-
}
|
|
409
|
-
return manualCredentialInput(rl);
|
|
410
|
-
}
|
|
411
|
-
/**
|
|
412
|
-
* 执行交互式初始化流程。
|
|
413
|
-
*
|
|
414
|
-
* @returns 0 成功,1 失败
|
|
415
|
-
*/
|
|
416
|
-
async function runInteractiveInit() {
|
|
417
|
-
console.log(`\n${BOLD}${CYAN}╔══════════════════════════════════════╗${RESET}`);
|
|
418
|
-
console.log(`${BOLD}${CYAN}║ LarkPal 初始化向导 ║${RESET}`);
|
|
419
|
-
console.log(`${BOLD}${CYAN}╚══════════════════════════════════════╝${RESET}\n`);
|
|
420
|
-
log.info("开始交互式初始化流程");
|
|
421
|
-
const rl = createInterface({
|
|
422
|
-
input: process.stdin,
|
|
423
|
-
output: process.stdout
|
|
424
|
-
});
|
|
425
|
-
let credentialsOk;
|
|
426
|
-
let selectedRuntime;
|
|
427
|
-
try {
|
|
428
|
-
selectedRuntime = await configureRuntime(rl);
|
|
429
|
-
checkPrerequisites(selectedRuntime);
|
|
430
|
-
credentialsOk = await configureCredentials(rl);
|
|
431
|
-
} finally {
|
|
432
|
-
rl.close();
|
|
433
|
-
}
|
|
434
|
-
if (!credentialsOk) {
|
|
435
|
-
console.log(`\n${RED}凭证配置未完成。你可以稍后运行 ${CYAN}larkpal init${RED} 重新配置。${RESET}\n`);
|
|
436
|
-
return 1;
|
|
437
|
-
}
|
|
438
|
-
console.log(`\n${BOLD}${GREEN}🎉 初始化完成!${RESET}\n`);
|
|
439
|
-
console.log(` ${DIM}下一步:${RESET}`);
|
|
440
|
-
console.log(` ${formatRuntimeSelectionSummary(selectedRuntime)}`);
|
|
441
|
-
console.log(` 运行 ${CYAN}larkpal${RESET} 启动服务\n`);
|
|
442
|
-
log.info("交互式初始化流程完成");
|
|
443
|
-
return 0;
|
|
444
|
-
}
|
|
445
|
-
function resolveConfiguredRuntime(value) {
|
|
446
|
-
if (value === "codex-app-server" || value === "larkpal-agent" || value === "claude-code") return value;
|
|
447
|
-
return "claude-code";
|
|
448
|
-
}
|
|
449
|
-
//#endregion
|
|
450
|
-
export { runInteractiveInit };
|