dsh-schedule-ilife 0.3.8 → 0.3.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/client.js CHANGED
@@ -33,7 +33,7 @@ window.__ModuleLoader__.load({
33
33
  const PLUGIN = "dsh-schedule-ilife";
34
34
  //#endregion
35
35
  //#region src/settings.ts
36
- /** 常用项:改了就影响「库与产物落在哪」,放页面上。 */
36
+ /** 常用项:#764 起是「可改 1 + 只读 2」(高级组已空,见下)。 */
37
37
  const COMMON = [
38
38
  {
39
39
  key: "db.dir",
@@ -48,30 +48,23 @@ window.__ModuleLoader__.load({
48
48
  title: "库文件名",
49
49
  tier: "common",
50
50
  control: "text",
51
- hint: "数据目录下的数据库文件名。改名=换库,旧记录不会被读入。"
51
+ readonly: true,
52
+ resolveFrom: "dbFile",
53
+ hint: "数据目录下的库文件。只读,要改请编辑配置文件。"
52
54
  },
53
55
  {
54
56
  key: "html.dir",
55
- title: "HTML 产物目录名",
57
+ title: "HELP 产物目录",
56
58
  tier: "common",
57
59
  control: "text",
58
- hint: "数据目录下存放 HELP 页面的子目录名。"
60
+ readonly: true,
61
+ resolveFrom: "htmlDir",
62
+ hint: "HELP 页面的存放目录。只读,要改请编辑配置文件。"
59
63
  }
60
64
  ];
61
- /** 高级项:默认收起。改错了多半只是自己撞上麻烦,不确定就别动。 */
62
- const ADVANCED = [{
63
- key: "files.help",
64
- title: "产物文件名主体 · HELP",
65
- tier: "advanced",
66
- control: "text",
67
- hint: "HELP 文件名前缀,后面自动加时间戳。"
68
- }, {
69
- key: "lark.cliPath",
70
- title: "飞书 CLI 路径",
71
- tier: "advanced",
72
- control: "text",
73
- hint: "飞书 CLI 的完整路径。留空=自动探测。"
74
- }];
65
+ /** 高级项:#764 起已空(`files.help`/`lark.cliPath` 出配置表)——组还在,行没有。
66
+ * 空组不渲染(见 client.ts),行表长度即 3。 */
67
+ const ADVANCED = [];
75
68
  /** 设置页的行表,顺序即页面顺序。 */
76
69
  const CONFIG_ITEMS = [...COMMON, ...ADVANCED];
77
70
  /** 常用项行数(页面上直接画出来的那些)。 */
@@ -116,6 +109,11 @@ window.__ModuleLoader__.load({
116
109
  const RPC_ENDPOINT_CONFIG_GET = "config.get";
117
110
  const RPC_ENDPOINT_CONFIG_SAVE = "config.save";
118
111
  const RPC_ENDPOINT_CONFIG_RESET = "config.reset";
112
+ /** #706 配置体检端点:只读一次,回一份报告(判据由技能侧出,本包只透传,不重写一个字)。
113
+ *
114
+ * 端点名与技能侧那条只读命令同名(`<技能>.config.check`);报告形状的唯一真相在技能侧
115
+ * `packages/skill-<技能>/src/health.ts`,面板侧镜像在 `packages/plugin-manager/src/health-contract.ts`。 */
116
+ const RPC_ENDPOINT_CONFIG_CHECK = "config.check";
119
117
  /** 信封守卫:供 client 拆包前校验(port 拥有信封定义,守卫住 port)。 */
120
118
  function isRpcResult(raw) {
121
119
  if (typeof raw !== "object" || raw === null) return false;
@@ -1185,24 +1183,121 @@ window.__ModuleLoader__.load({
1185
1183
  function resetConfigSurface(call) {
1186
1184
  return configRpc(call, RPC_ENDPOINT_CONFIG_RESET, {});
1187
1185
  }
1188
- /** 把配置取值铺成「行键 → 输入框文本」(页面表单态;值缺项即空串,不返空留白)。
1189
- *
1190
- * `prefill` 是**落点回执**(配置面那几格解析出来的绝对路径):标了 `prefillFrom` 的行在取值空着时
1191
- * 直接显示那条绝对路径——用户不必自己拼路径(#743),显示的就是技能真会用的那个目录(逐字相同)。 */
1186
+ /** 读一次配置体检(只读;判据由技能侧出,本包只透传,不重写一个字)。 */
1187
+ function fetchHealthSurface(call) {
1188
+ return configRpc(call, RPC_ENDPOINT_CONFIG_CHECK, {});
1189
+ }
1190
+ /** 从体检报告里挑出 `lark.cli` 那一项;形状不对回 null(不抛)。 */
1191
+ function larkItemOf(report) {
1192
+ if (typeof report !== "object" || report === null) return null;
1193
+ const items = report.items;
1194
+ if (!Array.isArray(items)) return null;
1195
+ for (const it of items) {
1196
+ if (typeof it !== "object" || it === null) continue;
1197
+ const rec = it;
1198
+ if (rec["id"] !== "lark.cli") continue;
1199
+ if (typeof rec["id"] !== "string" || typeof rec["status"] !== "string" || typeof rec["message"] !== "string") return null;
1200
+ return {
1201
+ id: rec["id"],
1202
+ status: rec["status"],
1203
+ message: rec["message"],
1204
+ action: typeof rec["action"] === "string" ? rec["action"] : ""
1205
+ };
1206
+ }
1207
+ return null;
1208
+ }
1209
+ /** 飞书 CLI 官网(面板状态行与安装 prompt 里的同一地址,唯一定义地是这里)。 */
1210
+ const LARK_OFFICIAL_URL = "https://www.feishu.cn/feishu-cli";
1211
+ /** 状态行上逐字显示的那一行(三档都在、显示成文字、可点击跳转,不改写、不加话)。 */
1212
+ const LARK_OFFICIAL_LINE = "飞书CLI官网为:https://www.feishu.cn/feishu-cli";
1213
+ /** 「复制 prompt」按钮复制的内容(定稿住 #759 最新一条评论 v5 的逐字全文,两家的实施票都引它,
1214
+ * 不在本票里另写一份;官网指南 shape 变化时改 #759 那一条,这里跟着换)。 */
1215
+ const LARK_PROMPT_V5 = `在这台机器上安装并配置飞书 CLI(lark-cli)。你来推进,做完为止。
1216
+
1217
+ 必须满足的终态(每条都要真跑,把命令原文和输出贴回来):
1218
+ 1) lark-cli --version >= 1.0.82(更低的版本没有我们要用的 --no-wait)
1219
+ 2) where lark-cli(Windows)或 which lark-cli(macOS/Linux)能命中;Windows 上还要确认 %APPDATA%\\npm\\lark-cli.cmd 这个文件存在
1220
+ 3) lark-cli auth status 的输出里有 identities.user.openId
1221
+ 4) lark-cli auth check --scope task 退出码 0(连退出码一起贴)—— 备忘录要用任务域
1222
+ 5) lark-cli calendar +agenda 退出码 0(连退出码一起贴)—— 作息管家要读你的主日历
1223
+ 6) 技能侧也能用:跑一次作息管家的「飞书探测」(=一条不落地的同步探测),不报「缺 CLI/未登录/日历不可达」
1224
+
1225
+ 怎么做:
1226
+ 7) Node.js/npm 不可用就先装。
1227
+ 8) 安装:npm install -g @larksuite/cli。只装这个官方包(bin 名 lark-cli);不要装 npm 上的 lark-cli。
1228
+ 9) 官方指南里的第二件事也照做:npx -y skills add https://open.feishu.cn --skill -y
1229
+ 10) 配置与登录照这两条走(都是 CLI 自己在 --help 里写给 AI agent 的写法,别改写成别的):
1230
+ 先初始化:lark-cli config init --new
1231
+ 它会阻塞等你完成浏览器授权,所以起在后台、从它的输出里把验证链接捞出来
1232
+ (CLI 原文:Run it in the background and retrieve the verification URL from its output);
1233
+ 链接给我,我批准后你继续。
1234
+ 如果它报 Inside an Agent context 之类被拒,照它的提示改用 lark-cli config bind。
1235
+ 再授权:lark-cli auth login --no-wait --json --domain calendar,task
1236
+ 它会立刻返回一个验证链接(或二维码);把链接给我,我批准后你再用
1237
+ lark-cli auth login --device-code <拿到的 device code> 收尾。
1238
+ 官方指南:https://open.feishu.cn/document/no_class/mcp-archive/feishu-cli-installation-guide.md
1239
+ 子命令以 lark-cli auth --help / config --help 和官方文档为准,不要凭猜;做完要能过第 3、4、5 条。
1240
+ 11) npm 全局目录如果不在系统 PATH 上,把它加进系统 PATH(不是只在当前终端 export)。
1241
+
1242
+ 怎么推进:
1243
+ 12) 除第 13 条那三类,其余你自己一口气做完,不要逐步问我确认:安装、改 PATH、重试、修报错都自己做完。
1244
+ 13) 只有这三类必须我介入;遇到就用 /wizard 生成脚本带我走,走完你接着自动往下做:
1245
+ ① 浏览器里的初始化授权 / 登录(把验证链接或二维码给我);
1246
+ ② 系统权限提示(管理员/sudo);
1247
+ ③ Node.js 需要我先定怎么装。
1248
+ 14) 任何一步失败:自己按报错修;修不动再一次性告诉我「卡在哪、报错原文、需要我做什么」。
1249
+
1250
+ 参考官网:https://www.feishu.cn/feishu-cli`;
1251
+ /** 复制一段文本:先剪贴板,不成再走兜底(永不抛,回是否成功)。 */
1252
+ async function copyText(text, deps = {}) {
1253
+ if (deps.clipboard !== void 0) try {
1254
+ await deps.clipboard.writeText(text);
1255
+ return true;
1256
+ } catch {}
1257
+ if (deps.execCopy !== void 0) try {
1258
+ return deps.execCopy(text);
1259
+ } catch {
1260
+ return false;
1261
+ }
1262
+ return false;
1263
+ }
1264
+ /** 当刻环境的剪贴板(经 `globalThis` 懒取:顶层不碰 DOM,loader 沙箱与 node 单测都不炸;拿不到回 null)。 */
1265
+ function clipboardOf() {
1266
+ try {
1267
+ return globalThis.navigator?.clipboard ?? null;
1268
+ } catch {
1269
+ return null;
1270
+ }
1271
+ }
1272
+ /** 只读行显示什么:标了 `resolveFrom` ⇒ 回执 `resolved` 组那一格;没标 ⇒ 配置文件里那个值本身
1273
+ * (数字类只读项走这一档:显示的是生效数字,见 #749 补注二的甲档)。 */
1274
+ function readonlyTextOf(item, raw, prefill) {
1275
+ if (item.resolveFrom === void 0) return raw;
1276
+ const shown = prefill.resolved?.[item.resolveFrom];
1277
+ return typeof shown === "string" ? shown : "";
1278
+ }
1192
1279
  function toDraft(values, prefill = {}) {
1193
1280
  const draft = {};
1194
1281
  for (const item of CONFIG_ITEMS) {
1195
1282
  const v = readPath(values, item.key);
1196
1283
  const raw = v === void 0 || v === null ? "" : String(v);
1284
+ if (item.readonly === true) {
1285
+ draft[item.key] = readonlyTextOf(item, raw, prefill);
1286
+ continue;
1287
+ }
1197
1288
  const fallback = item.prefillFrom === void 0 ? void 0 : prefill[item.prefillFrom];
1198
1289
  draft[item.key] = raw === "" && typeof fallback === "string" && fallback !== "" ? fallback : raw;
1199
1290
  }
1200
1291
  return draft;
1201
1292
  }
1202
- /** 表单态 → 配置取值(按控件种类还原类型;空串对文本项照收,语义由「未配」承担)。 */
1293
+ /** 表单态 → 配置取值(按控件种类还原类型;空串对文本项照收,语义由「按默认落点」承担)。
1294
+ *
1295
+ * **只读行不收**(#764,照 #749 样板):它们显示的是技能算好的绝对路径,写回配置就是把「显示的路径」
1296
+ * 当成「配置值」——保存只提交真能改的那些行(本家=`db.dir` 一行),其余键由技能侧做组内合并保留现值。 */
1203
1297
  function fromDraft(draft) {
1204
1298
  const values = {};
1205
1299
  for (const item of CONFIG_ITEMS) {
1300
+ if (item.readonly === true) continue;
1206
1301
  const raw = draft[item.key] ?? "";
1207
1302
  const value = item.control === "number" ? Number(raw) : item.control === "switch" ? raw === "true" : raw;
1208
1303
  writePath(values, item.key, item.control === "number" && !Number.isFinite(value) ? 0 : value);
@@ -1261,31 +1356,38 @@ window.__ModuleLoader__.load({
1261
1356
  /** 一行输入(四种控件对齐受限 YAML 子集:文本/数字/布尔/目录)。
1262
1357
  *
1263
1358
  * 目录档=文本框 + 一枚唤起系统文件夹选择器的按钮;`onBrowse` 缺席(命名空间拿不到、
1264
- * 或这条路已被拒)时不画按钮,文本框照旧——那是该缝自己的契约(供不了就收起入口,不是失败)。 */
1359
+ * 或这条路已被拒)时不画按钮,文本框照旧——那是该缝自己的契约(供不了就收起入口,不是失败)。
1360
+ *
1361
+ * **只读行(#764,照 #749 样板)**:`item.readonly` 为真时控件一律 `disabled`(值只经技能侧解析后显示、
1362
+ * 不给改),目录行的浏览按钮**保留但不可点击**(#747 定稿:入口不作废,只是不能改)。控件文案**不出现省略号**
1363
+ * (#746 处置 9)——按钮就写「选择文件夹」/「浏览」两个字面。 */
1265
1364
  function Row(props) {
1266
1365
  const { item } = props;
1267
- const onChange = (e) => props.onChange(item.key, e.target.value);
1366
+ const readonly = item.readonly === true;
1367
+ const disabled = props.disabled || readonly;
1368
+ const onChange = readonly ? void 0 : (e) => props.onChange(item.key, e.target.value);
1268
1369
  const control = item.control === "switch" ? react.createElement("input", {
1269
1370
  type: "checkbox",
1270
1371
  checked: props.value === "true",
1271
- disabled: props.disabled,
1272
- onChange: (e) => props.onChange(item.key, e.target.checked ? "true" : "false")
1372
+ disabled,
1373
+ onChange: readonly ? void 0 : (e) => props.onChange(item.key, e.target.checked ? "true" : "false")
1273
1374
  }) : react.createElement("input", {
1274
1375
  style: S.input,
1275
1376
  type: item.control === "number" ? "number" : "text",
1276
1377
  value: props.value,
1277
- disabled: props.disabled,
1378
+ disabled,
1278
1379
  spellCheck: false,
1279
1380
  onChange
1280
1381
  });
1281
- /** 三态入口:供不了(`none`/缺席)就不画,不摆一个点了没反应的死按钮。 */
1382
+ /** 三态入口:供不了(`none`/缺席)就不画,不摆一个点了没反应的死按钮。
1383
+ * 只读行照画(按钮保留),但 `disabled` ⇒ 点不动。 */
1282
1384
  const entry = props.browser ?? null;
1283
1385
  const browse = item.control === "directory" && entry !== null && entry.mode !== "none" ? react.createElement("button", {
1284
1386
  style: S.btnPick,
1285
1387
  type: "button",
1286
- disabled: props.disabled,
1388
+ disabled,
1287
1389
  onClick: () => entry.onOpen(item.key)
1288
- }, entry.mode === "native" ? "选择文件夹…" : "浏览…") : null;
1390
+ }, entry.mode === "native" ? "选择文件夹" : "浏览") : null;
1289
1391
  return react.createElement("div", { style: S.row }, react.createElement("div", { style: S.label }, item.title), react.createElement("div", { style: S.hint }, item.hint), browse === null ? control : react.createElement("div", { style: S.pickRow }, control, browse));
1290
1392
  }
1291
1393
  /** 技能设置页:承载作息管家自己的全部可配置项(只配置,不干活)。 */
@@ -1297,6 +1399,10 @@ window.__ModuleLoader__.load({
1297
1399
  const [busy, setBusy] = react.useState(false);
1298
1400
  const [notice, setNotice] = react.useState(null);
1299
1401
  const [error, setError] = react.useState(null);
1402
+ /** 飞书 CLI 状态行(三档读数由技能侧体检出,面板只显示;`null` 以外的三态见下)。 */
1403
+ const [lark, setLark] = react.useState({ kind: "loading" });
1404
+ /** 复制 prompt 那枚按钮的回执(idle=没点过)。 */
1405
+ const [copied, setCopied] = react.useState("idle");
1300
1406
  const apply = react.useCallback((surface) => {
1301
1407
  setState({
1302
1408
  kind: "ready",
@@ -1304,6 +1410,25 @@ window.__ModuleLoader__.load({
1304
1410
  });
1305
1411
  setDraft(toDraft(surface.values, surface));
1306
1412
  }, []);
1413
+ const loadHealth = react.useCallback(async () => {
1414
+ setLark({ kind: "loading" });
1415
+ const r = await fetchHealthSurface(props.getCall());
1416
+ if (!r.ok) {
1417
+ setLark({
1418
+ kind: "failed",
1419
+ message: r.message
1420
+ });
1421
+ return;
1422
+ }
1423
+ const item = larkItemOf(r.surface);
1424
+ setLark(item === null ? {
1425
+ kind: "failed",
1426
+ message: "体检回执里没有飞书 CLI 那一项"
1427
+ } : {
1428
+ kind: "ready",
1429
+ item
1430
+ });
1431
+ }, [props.getCall]);
1307
1432
  const load = react.useCallback(async () => {
1308
1433
  setNotice(null);
1309
1434
  setError(null);
@@ -1313,7 +1438,12 @@ window.__ModuleLoader__.load({
1313
1438
  kind: "failed",
1314
1439
  message: r.message
1315
1440
  });
1316
- }, [apply, props.getCall]);
1441
+ await loadHealth();
1442
+ }, [
1443
+ apply,
1444
+ loadHealth,
1445
+ props.getCall
1446
+ ]);
1317
1447
  react.useEffect(() => {
1318
1448
  let alive = true;
1319
1449
  (async () => {
@@ -1324,6 +1454,22 @@ window.__ModuleLoader__.load({
1324
1454
  kind: "failed",
1325
1455
  message: r.message
1326
1456
  });
1457
+ const h = await fetchHealthSurface(props.getCall());
1458
+ if (!alive) return;
1459
+ if (!h.ok) setLark({
1460
+ kind: "failed",
1461
+ message: h.message
1462
+ });
1463
+ else {
1464
+ const item = larkItemOf(h.surface);
1465
+ setLark(item === null ? {
1466
+ kind: "failed",
1467
+ message: "体检回执里没有飞书 CLI 那一项"
1468
+ } : {
1469
+ kind: "ready",
1470
+ item
1471
+ });
1472
+ }
1327
1473
  })();
1328
1474
  return () => {
1329
1475
  alive = false;
@@ -1388,7 +1534,10 @@ window.__ModuleLoader__.load({
1388
1534
  onOpen: onOpenRow
1389
1535
  };
1390
1536
  const surface = state.kind === "ready" ? state.surface : null;
1391
- const dirty = surface !== null && CONFIG_ITEMS.some((i) => (draft[i.key] ?? "") !== (toDraft(surface.values, surface)[i.key] ?? ""));
1537
+ /** 脏值只看**可改行**(#764,照 #749 样板):只读行显示的是技能算好的绝对路径,
1538
+ * 拿它当「改动」会让打开面板就变「未保存」。 */
1539
+ const editableItems = CONFIG_ITEMS.filter((i) => i.readonly !== true);
1540
+ const dirty = surface !== null && editableItems.some((i) => (draft[i.key] ?? "") !== (toDraft(surface.values, surface)[i.key] ?? ""));
1392
1541
  /** 写完之后重新读一份:写回执只有 {path, values},头部那两行要的是读整面。 */
1393
1542
  const writeThenReload = react.useCallback(async (done) => {
1394
1543
  setBusy(true);
@@ -1426,8 +1575,8 @@ window.__ModuleLoader__.load({
1426
1575
  if (r.ok) await writeThenReload("已重置为默认(原配置已另存一份 .bak)");
1427
1576
  else setError(r.message);
1428
1577
  }, [props.getCall, writeThenReload]);
1429
- const head = react.createElement("div", null, react.createElement("div", { style: S.title }, `${SLOT_TITLE} · 配置`), surface !== null ? react.createElement("div", null, react.createElement("div", { style: S.info }, `配置文件 ${surface.path}`), react.createElement("div", { style: S.info }, `数据目录 ${surface.dataDir}`), surface.created ? react.createElement("div", { style: S.muted }, "(配置文件刚按默认值生成)") : null) : null);
1430
- if (state.kind === "loading") return react.createElement("div", { style: S.card }, head, react.createElement("div", { style: S.muted }, "配置读取中…"));
1578
+ const head = react.createElement("div", null, react.createElement("div", { style: S.title }, `${SLOT_TITLE} · 配置`), surface !== null ? react.createElement("div", null, react.createElement("div", { style: S.info }, `配置文件 ${surface.path}`), react.createElement("div", { style: S.info }, `数据目录 ${surface.resolved?.dbDir ?? surface.dataDir}`), surface.created ? react.createElement("div", { style: S.muted }, "(配置文件刚按默认值生成)") : null) : null);
1579
+ if (state.kind === "loading") return react.createElement("div", { style: S.card }, head, react.createElement("div", { style: S.muted }, "配置读取中"));
1431
1580
  if (state.kind === "failed") return react.createElement("div", { style: S.card }, react.createElement("div", { style: S.title }, `${SLOT_TITLE} · 配置`), react.createElement("div", { style: S.error }, state.message), react.createElement("div", { style: S.bar }, react.createElement("button", {
1432
1581
  style: S.btn,
1433
1582
  type: "button",
@@ -1447,12 +1596,42 @@ window.__ModuleLoader__.load({
1447
1596
  onChange,
1448
1597
  browser: rowEntry
1449
1598
  });
1450
- return react.createElement("div", { style: S.card }, head, react.createElement("div", { style: S.rows }, common.map(renderRow)), react.createElement("details", { style: S.advanced }, react.createElement("summary", { style: S.summary }, ADVANCED_GROUP_TITLE), react.createElement("div", { style: S.muted }, ADVANCED_GROUP_NOTE), advanced.map(renderRow)), react.createElement("div", { style: S.bar }, react.createElement("button", {
1599
+ /** 「复制 prompt」:剪贴板不在就报失败,不抛(按钮三档都在,见 #761 定稿)。 */
1600
+ const onCopyPrompt = react.useCallback(async () => {
1601
+ const ok = await copyText(LARK_PROMPT_V5, { clipboard: clipboardOf() ?? void 0 });
1602
+ setCopied(ok ? "done" : "failed");
1603
+ }, []);
1604
+ /** 「飞书 CLI」状态行(#764,定稿 #761):不是配置项——三档读数由技能侧体检出,面板只显示;
1605
+ * 三档都有「复制 prompt」按钮与官网那一行(逐字、可点击)。 */
1606
+ const renderLark = () => {
1607
+ if (lark.kind === "loading") return react.createElement("div", { style: S.rows }, react.createElement("div", { style: S.label }, "飞书 CLI"), react.createElement("div", { style: S.muted }, "飞书 CLI 检测中"));
1608
+ if (lark.kind === "failed") return react.createElement("div", { style: S.rows }, react.createElement("div", { style: S.label }, "飞书 CLI"), react.createElement("div", { style: S.error }, lark.message), react.createElement("div", { style: S.bar }, react.createElement("button", {
1609
+ style: S.btn,
1610
+ type: "button",
1611
+ onClick: () => void loadHealth()
1612
+ }, "重新检测")));
1613
+ const item = lark.item;
1614
+ const tone = item.status === "green" ? S.okText : item.status === "red" ? S.error : S.muted;
1615
+ return react.createElement("div", { style: S.rows }, react.createElement("div", { style: S.label }, "飞书 CLI"), react.createElement("div", { style: tone }, item.message), item.action === "" ? null : react.createElement("div", { style: S.hint }, item.action), react.createElement("div", { style: S.bar }, react.createElement("button", {
1616
+ style: S.btn,
1617
+ type: "button",
1618
+ onClick: () => void onCopyPrompt()
1619
+ }, "复制 prompt"), react.createElement("button", {
1620
+ style: S.btn,
1621
+ type: "button",
1622
+ onClick: () => void loadHealth()
1623
+ }, "重新检测")), copied === "done" ? react.createElement("div", { style: S.okText }, "已复制安装指引") : copied === "failed" ? react.createElement("div", { style: S.error }, "复制失败:剪贴板不可用,请手动复制对话框里的安装指引") : null, react.createElement("div", { style: S.info }, react.createElement("a", {
1624
+ href: LARK_OFFICIAL_URL,
1625
+ target: "_blank",
1626
+ rel: "noreferrer"
1627
+ }, LARK_OFFICIAL_LINE)));
1628
+ };
1629
+ return react.createElement("div", { style: S.card }, head, react.createElement("div", { style: S.rows }, common.map(renderRow)), advanced.length === 0 ? null : react.createElement("details", { style: S.advanced }, react.createElement("summary", { style: S.summary }, ADVANCED_GROUP_TITLE), react.createElement("div", { style: S.muted }, ADVANCED_GROUP_NOTE), advanced.map(renderRow)), renderLark(), react.createElement("div", { style: S.bar }, react.createElement("button", {
1451
1630
  style: dirty ? S.btnPrimary : S.btn,
1452
1631
  type: "button",
1453
1632
  disabled: busy || !dirty,
1454
1633
  onClick: () => void onSave()
1455
- }, busy ? "处理中…" : "保存"), react.createElement("button", {
1634
+ }, busy ? "处理中" : "保存"), react.createElement("button", {
1456
1635
  style: S.btn,
1457
1636
  type: "button",
1458
1637
  disabled: busy,
@@ -1473,7 +1652,7 @@ window.__ModuleLoader__.load({
1473
1652
  go: "转到",
1474
1653
  showHidden: (n) => "显示隐藏目录(" + n + ")",
1475
1654
  empty: "这个目录里没有子目录。",
1476
- loading: "正在读取…",
1655
+ loading: "正在读取",
1477
1656
  newFolder: "新建文件夹",
1478
1657
  createConfirm: "创建",
1479
1658
  createCancel: "取消",
@@ -1506,16 +1685,23 @@ window.__ModuleLoader__.load({
1506
1685
  })));
1507
1686
  }
1508
1687
  //#endregion
1688
+ exports.LARK_OFFICIAL_LINE = LARK_OFFICIAL_LINE;
1689
+ exports.LARK_OFFICIAL_URL = LARK_OFFICIAL_URL;
1690
+ exports.LARK_PROMPT_V5 = LARK_PROMPT_V5;
1509
1691
  exports.READ_TIMEOUT_MS = READ_TIMEOUT_MS;
1510
1692
  exports.Row = Row;
1511
1693
  exports.apply = apply;
1694
+ exports.clipboardOf = clipboardOf;
1695
+ exports.copyText = copyText;
1512
1696
  exports.createBrowseHandler = createBrowseHandler;
1513
1697
  exports.directoryEntryMode = directoryEntryMode;
1514
1698
  exports.fetchConfigSurface = fetchConfigSurface;
1699
+ exports.fetchHealthSurface = fetchHealthSurface;
1515
1700
  exports.fromDraft = fromDraft;
1516
1701
  exports.humanizeConfigFailure = humanizeConfigFailure;
1517
1702
  exports.inject = inject;
1518
1703
  exports.isDirectoryPicker = isDirectoryPicker;
1704
+ exports.larkItemOf = larkItemOf;
1519
1705
  exports.openRowBrowser = openRowBrowser;
1520
1706
  exports.pickDirectory = pickDirectory;
1521
1707
  exports.pickerModeOf = pickerModeOf;