vibe-coding-master 0.4.33 → 0.4.34

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.
@@ -24,8 +24,9 @@ export function createLarkRegistrationClient(deps = {}) {
24
24
  return {
25
25
  async init(domain) {
26
26
  const payload = await postRegistration(domain, { action: "init" });
27
- const methods = Array.isArray(payload.supported_auth_methods)
28
- ? payload.supported_auth_methods.filter((value) => typeof value === "string")
27
+ const data = responseData(payload);
28
+ const methods = Array.isArray(data.supported_auth_methods)
29
+ ? data.supported_auth_methods.filter((value) => typeof value === "string")
29
30
  : [];
30
31
  if (!methods.includes("client_secret")) {
31
32
  throw new Error(`Lark QR setup does not support client_secret auth. Supported methods: ${methods.join(", ") || "none"}.`);
@@ -38,11 +39,12 @@ export function createLarkRegistrationClient(deps = {}) {
38
39
  auth_method: "client_secret",
39
40
  request_user_info: "open_id"
40
41
  });
41
- const deviceCode = stringOrNull(payload.device_code);
42
+ const data = responseData(payload);
43
+ const deviceCode = stringOrNull(data.device_code);
42
44
  if (!deviceCode) {
43
45
  throw new Error("Lark QR setup did not return a device_code.");
44
46
  }
45
- const qrUrl = appendQrTrackingParams(stringOrNull(payload.verification_uri_complete) ?? "");
47
+ const qrUrl = appendQrTrackingParams(stringOrNull(data.verification_uri_complete) ?? "");
46
48
  if (!qrUrl) {
47
49
  throw new Error("Lark QR setup did not return a QR URL.");
48
50
  }
@@ -50,9 +52,9 @@ export function createLarkRegistrationClient(deps = {}) {
50
52
  domain,
51
53
  deviceCode,
52
54
  qrUrl,
53
- userCode: stringOrNull(payload.user_code),
54
- intervalSeconds: positiveNumberOr(payload.interval, 5),
55
- expiresInSeconds: positiveNumberOr(payload.expire_in, 600)
55
+ userCode: stringOrNull(data.user_code),
56
+ intervalSeconds: positiveNumberOr(data.interval, 5),
57
+ expiresInSeconds: positiveNumberOr(data.expire_in, 600)
56
58
  };
57
59
  },
58
60
  async poll(input) {
@@ -61,11 +63,12 @@ export function createLarkRegistrationClient(deps = {}) {
61
63
  device_code: input.deviceCode,
62
64
  tp: "ob_app"
63
65
  });
64
- const userInfo = isObject(payload.user_info) ? payload.user_info : {};
66
+ const data = responseData(payload);
67
+ const userInfo = isObject(data.user_info) ? data.user_info : {};
65
68
  const tenantBrand = stringOrNull(userInfo.tenant_brand);
66
69
  const domain = tenantBrand === "lark" ? "lark" : input.domain;
67
- const appId = stringOrNull(payload.client_id);
68
- const appSecret = stringOrNull(payload.client_secret);
70
+ const appId = stringOrNull(data.client_id);
71
+ const appSecret = stringOrNull(data.client_secret);
69
72
  if (appId && appSecret) {
70
73
  const bot = await probeBot(fetchImpl, {
71
74
  appId,
@@ -82,20 +85,31 @@ export function createLarkRegistrationClient(deps = {}) {
82
85
  botOpenId: bot.botOpenId
83
86
  };
84
87
  }
85
- const error = stringOrNull(payload.error);
88
+ const error = stringOrNull(data.error) ?? stringOrNull(payload.error);
86
89
  if (error === "expired_token") {
87
90
  return { status: "expired", message: "Lark QR setup expired. Start a new setup." };
88
91
  }
89
92
  if (error === "access_denied") {
90
93
  return { status: "failed", message: "Lark QR setup was denied." };
91
94
  }
95
+ const errorDescription = stringOrNull(data.error_description)
96
+ ?? stringOrNull(payload.error_description)
97
+ ?? stringOrNull(data.message)
98
+ ?? stringOrNull(payload.message)
99
+ ?? stringOrNull(data.msg)
100
+ ?? stringOrNull(payload.msg);
92
101
  return {
93
102
  status: "wait",
94
- message: error && error !== "authorization_pending" ? error : undefined
103
+ message: error && error !== "authorization_pending"
104
+ ? [error, errorDescription].filter(Boolean).join(": ")
105
+ : undefined
95
106
  };
96
107
  }
97
108
  };
98
109
  }
110
+ function responseData(payload) {
111
+ return isObject(payload.data) ? payload.data : payload;
112
+ }
99
113
  async function probeBot(fetchImpl, input) {
100
114
  try {
101
115
  const tokenPayload = await fetchJson(fetchImpl, `${OPEN_BASE_URLS[input.domain]}/open-apis/auth/v3/tenant_access_token/internal`, {
@@ -155,7 +169,7 @@ async function fetchJson(fetchImpl, url, init = {}) {
155
169
  throw new Error("Lark setup response was not a JSON object.");
156
170
  }
157
171
  if (!response.ok && !payload.error) {
158
- throw new Error(`${response.status} ${response.statusText}`);
172
+ throw new Error(`Lark QR setup request failed: ${response.status} ${response.statusText}${formatPayloadError(payload)}`);
159
173
  }
160
174
  return payload;
161
175
  }
@@ -169,18 +183,30 @@ async function fetchJson(fetchImpl, url, init = {}) {
169
183
  clearTimeout(timeout);
170
184
  }
171
185
  }
186
+ function formatPayloadError(payload) {
187
+ const data = responseData(payload);
188
+ const message = [
189
+ stringOrNull(data.error) ?? stringOrNull(payload.error),
190
+ stringOrNull(data.error_description) ?? stringOrNull(payload.error_description),
191
+ stringOrNull(data.message) ?? stringOrNull(payload.message),
192
+ stringOrNull(data.msg) ?? stringOrNull(payload.msg),
193
+ typeof data.code === "number" || typeof data.code === "string" ? `code ${data.code}` : null,
194
+ typeof payload.code === "number" || typeof payload.code === "string" ? `code ${payload.code}` : null
195
+ ].filter(Boolean).join(": ");
196
+ return message ? ` (${message})` : "";
197
+ }
172
198
  function appendQrTrackingParams(value) {
173
199
  if (!value) {
174
200
  return "";
175
201
  }
176
202
  try {
177
203
  const url = new URL(value);
178
- url.searchParams.set("from", "vcm");
179
- url.searchParams.set("tp", "vcm");
204
+ url.searchParams.set("from", "hermes");
205
+ url.searchParams.set("tp", "hermes");
180
206
  return url.toString();
181
207
  }
182
208
  catch {
183
- return `${value}${value.includes("?") ? "&" : "?"}from=vcm&tp=vcm`;
209
+ return `${value}${value.includes("?") ? "&" : "?"}from=hermes&tp=hermes`;
184
210
  }
185
211
  }
186
212
  function positiveNumberOr(input, fallback) {
@@ -14,6 +14,7 @@ const POLL_ERROR_BACKOFF_MS = 2_000;
14
14
  const POLL_LONG_BACKOFF_MS = 30_000;
15
15
  const MAX_FAILURES_BEFORE_LONG_BACKOFF = 3;
16
16
  const DEFAULT_POLL_TIMEOUT_MS = 35_000;
17
+ const LARK_REGISTRATION_CONFIRM_TIMEOUT_MS = 15_000;
17
18
  const MAX_LATEST_PM_REPLY_CHARS = 8_000;
18
19
  const GATEWAY_TRANSLATION_FAILURE_TEXT = "PM 回复已收到,但翻译失败。\n发送 /retry 重新翻译。";
19
20
  const COMMANDS_ALLOWED_WHEN_DISABLED = new Set([
@@ -938,17 +939,25 @@ export function createGatewayService(deps) {
938
939
  message: "Lark QR setup expired. Start a new setup."
939
940
  };
940
941
  }
941
- const result = await larkRegistration.poll({
942
+ const confirmDeadline = Date.now() + LARK_REGISTRATION_CONFIRM_TIMEOUT_MS;
943
+ let result = await larkRegistration.poll({
942
944
  domain: larkRegistrationState.domain,
943
945
  deviceCode: larkRegistrationState.deviceCode
944
946
  });
947
+ while (result.status === "wait" && Date.now() < confirmDeadline) {
948
+ await sleep(Math.min(larkRegistrationState.intervalSeconds * 1000, 3_000), new AbortController().signal);
949
+ result = await larkRegistration.poll({
950
+ domain: larkRegistrationState.domain,
951
+ deviceCode: larkRegistrationState.deviceCode
952
+ });
953
+ }
945
954
  if (result.status !== "confirmed") {
946
955
  if (result.status === "expired" || result.status === "failed") {
947
956
  larkRegistrationState = null;
948
957
  }
949
958
  return {
950
959
  status: result.status,
951
- message: result.message
960
+ message: result.message ?? (result.status === "wait" ? "Lark has not returned app credentials yet. Confirm again in a moment." : undefined)
952
961
  };
953
962
  }
954
963
  if (!result.appId || !result.appSecret || !result.domain) {
@@ -1339,7 +1348,10 @@ function normalizeBaseUrl(input, fallback) {
1339
1348
  if (!trimmed) {
1340
1349
  return fallback;
1341
1350
  }
1342
- if (trimmed.startsWith("http://") || trimmed.startsWith("https://")) {
1351
+ if (/^https:\/\/lark:\/\//i.test(trimmed)) {
1352
+ return trimmed.replace(/^https:\/\//i, "").replace(/\/+$/, "");
1353
+ }
1354
+ if (/^[a-z][a-z0-9+.-]*:\/\//i.test(trimmed)) {
1343
1355
  return trimmed.replace(/\/+$/, "");
1344
1356
  }
1345
1357
  return `https://${trimmed.replace(/\/+$/, "")}`;
@@ -289,7 +289,10 @@ function normalizeBaseUrl(input, fallback = DEFAULT_BASE_URL) {
289
289
  if (!raw) {
290
290
  return fallback;
291
291
  }
292
- if (raw.startsWith("http://") || raw.startsWith("https://")) {
292
+ if (/^https:\/\/lark:\/\//i.test(raw)) {
293
+ return raw.replace(/^https:\/\//i, "").replace(/\/+$/, "");
294
+ }
295
+ if (/^[a-z][a-z0-9+.-]*:\/\//i.test(raw)) {
293
296
  return raw.replace(/\/+$/, "");
294
297
  }
295
298
  return `https://${raw.replace(/\/+$/, "")}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibe-coding-master",
3
- "version": "0.4.33",
3
+ "version": "0.4.34",
4
4
  "description": "Local GUI session cockpit for Claude Code role sessions.",
5
5
  "type": "module",
6
6
  "files": [