dsh-mishu 0.5.1 → 0.6.2

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/lib/client.js CHANGED
@@ -33,7 +33,7 @@ __export(index_exports, {
33
33
  module.exports = __toCommonJS(index_exports);
34
34
 
35
35
  // src/client/Board.tsx
36
- var import_react3 = require("react");
36
+ var import_react4 = require("react");
37
37
 
38
38
  // src/client/api.ts
39
39
  async function post(path, body) {
@@ -60,12 +60,19 @@ var mishuApi = {
60
60
  add: (lang, item) => post("/add", { lang, item }),
61
61
  ask: (lang, ask) => post("/ask", { lang, ask })
62
62
  };
63
+ var restartApi = {
64
+ info: (lang) => post("/restart/info", { lang }),
65
+ restart: (lang) => post("/restart", { lang })
66
+ };
63
67
  var settingsApi = {
64
68
  load: (lang) => post("/settings", { lang }),
65
69
  save: (lang, settings) => post("/settings/save", { lang, settings }),
66
70
  testGithub: (lang) => post("/github/test", { lang }),
67
71
  saveToken: (lang, token) => post("/github/token/save", { lang, token }),
68
72
  deleteToken: (lang) => post("/github/token/delete", { lang }),
73
+ deviceStart: (lang) => post("/github/device/start", { lang }),
74
+ deviceStatus: (lang) => post("/github/device/status", { lang }),
75
+ deviceCancel: (lang) => post("/github/device/cancel", { lang }),
69
76
  saveMail: (lang, account, password) => post("/mail/save", { lang, account, password }),
70
77
  testMail: (lang, account, password) => post("/mail/test", { lang, account, password }),
71
78
  deleteMail: (lang, id) => post("/mail/delete", { lang, id }),
@@ -134,6 +141,13 @@ var zh = {
134
141
  resize: "\u62D6\u52A8\u8C03\u6574\u5BBD\u5EA6\uFF0C\u53CC\u51FB\u6062\u590D\u7B49\u5BBD",
135
142
  tabBoard: "\u770B\u677F",
136
143
  tabSettings: "\u8BBE\u7F6E",
144
+ restart: "\u91CD\u542F DSH",
145
+ restartTip: "\u91CD\u88C5\u6216\u5347\u7EA7\u63D2\u4EF6\u540E\uFF0C\u53EF\u4EE5\u7528\u8FD9\u4E2A\u6309\u952E\u91CD\u542F\u672C DSH",
146
+ restartConfirm: "\u91CD\u542F DSH\uFF1F\u5B89\u88C5\u63D2\u4EF6\u6216\u8005\u63D2\u4EF6\u66F4\u65B0\u540E\u9700\u8981\u91CD\u542F DSH\u3002",
147
+ restarting: "\u6B63\u5728\u91CD\u542F\u2026\u7A97\u53E3\u4F1A\u5173\u6389\u518D\u81EA\u52A8\u6253\u5F00",
148
+ restartingWeb: "\u6B63\u5728\u91CD\u542F\u2026\u9875\u9762\u4F1A\u65AD\u5F00\u4E00\u4F1A\u513F\uFF0C\u8FDE\u4E0A\u540E\u81EA\u52A8\u5237\u65B0",
149
+ restartReloading: "\u5DF2\u7ECF\u91CD\u542F\u597D\u4E86\uFF0C\u6B63\u5728\u5237\u65B0\u9875\u9762\u2026",
150
+ restartSlow: "\u4E24\u5206\u949F\u4E86\u8FD8\u6CA1\u8FDE\u4E0A\uFF0C\u8BF7\u624B\u52A8\u5237\u65B0\u9875\u9762\u770B\u770B\u3002",
137
151
  all: "\u5168\u90E8",
138
152
  sourceGithub: "GitHub",
139
153
  sourceMail: "\u90AE\u4EF6",
@@ -151,6 +165,19 @@ var zh = {
151
165
  sTokenGh: "\u7528 GitHub CLI\uFF08gh\uFF09\u767B\u5F55\u7684\u8D26\u53F7\uFF0Ctoken \u5728\u7CFB\u7EDF\u94A5\u5319\u4E32\u91CC",
152
166
  sTokenKeychain: "\u4F60\u5728\u8FD9\u91CC\u586B\u7684 token\uFF0C\u5B58\u5728\u7CFB\u7EDF\u94A5\u5319\u4E32\u91CC",
153
167
  sTokenPaste: "\u586B\u4E00\u4E2A GitHub token",
168
+ gLogin: "\u7528 GitHub \u767B\u5F55",
169
+ gPasteInstead: "\u6216\u8005\u7C98\u8D34\u4E00\u4E2A token",
170
+ gStarting: "\u6B63\u5728\u5411 GitHub \u8981\u767B\u5F55\u7801\u2026",
171
+ gStep1: "1. \u590D\u5236\u8FD9\u4E2A\u767B\u5F55\u7801",
172
+ gCopy: "\u590D\u5236",
173
+ gCopied: "\u5DF2\u590D\u5236",
174
+ gStep2: "2. \u6253\u5F00 GitHub\uFF0C\u7C98\u8D34\u767B\u5F55\u7801\uFF0C\u70B9 Authorize\u3002\u7528\u624B\u673A\u6216\u522B\u7684\u7535\u8111\u6253\u5F00\u4E5F\u884C\u3002",
175
+ gOpen: "\u6253\u5F00 GitHub",
176
+ gWaiting: "\u7B49\u4F60\u5728 GitHub \u4E0A\u6388\u6743\u2026",
177
+ gScopes: "\u4F1A\u8BF7\u6C42\u4E24\u9879\u6743\u9650\uFF1A\u8BFB\u901A\u77E5\uFF08notifications\uFF09\u548C\u4ED3\u5E93\uFF08repo\uFF0C\u67E5\u79C1\u6709\u4ED3\u5E93\u7684 CI\u3001PR \u8981\u7528\uFF1BGitHub \u6CA1\u6709\u53EA\u8BFB\u7684\u7248\u672C\uFF0C\u5C0F\u79D8\u4E66\u53EA\u8BFB\u4E0D\u5199\uFF09\u3002\u62FF\u5230\u7684 token \u53EA\u5B58\u5728\u8FD9\u53F0\u7535\u8111\u4E0A\u3002",
178
+ gDone: (login) => `\u767B\u5F55\u597D\u4E86\uFF0C\u8D26\u53F7 ${login}`,
179
+ gRetry: "\u518D\u8BD5\u4E00\u6B21",
180
+ gClose: "\u5173\u95ED",
154
181
  sTokenHow: "\u7528 classic token\uFF0C\u52FE\u9009 notifications\uFF1B\u8981\u770B\u79C1\u6709\u4ED3\u5E93\u518D\u52FE repo\u3002GitHub \u7684\u901A\u77E5\u63A5\u53E3\u4E0D\u8BA4 fine-grained token\u3002token \u53EA\u5B58\u8FDB\u7CFB\u7EDF\u94A5\u5319\u4E32\uFF0C\u4E0D\u5199\u8FDB\u4EFB\u4F55\u6587\u4EF6\u3002",
155
182
  sTokenNew: "\u53BB GitHub \u751F\u6210\uFF08\u6743\u9650\u5DF2\u52FE\u597D\uFF09",
156
183
  sTokenSave: "\u68C0\u67E5\u5E76\u4FDD\u5B58",
@@ -172,6 +199,7 @@ var zh = {
172
199
  sMail: "\u90AE\u7BB1",
173
200
  sMailPrivacy: "\u53EA\u8BFB\uFF1A\u5C0F\u79D8\u4E66\u7528\u53EA\u8BFB\u65B9\u5F0F\u6253\u5F00\u6536\u4EF6\u7BB1\uFF0C\u53EA\u770B\u53D1\u4EF6\u4EBA\u3001\u6536\u4EF6\u4EBA\u3001\u6807\u9898\u548C\u51E0\u4E2A\u90AE\u4EF6\u5934\uFF0C\u4E0D\u8BFB\u6B63\u6587\uFF0C\u4E5F\u4E0D\u4F1A\u628A\u90AE\u4EF6\u6807\u6210\u5DF2\u8BFB\u3002",
174
201
  sSecretsAt: (kind) => `\u5BC6\u7801\u4FDD\u5B58\u5728\uFF1A${kind}\uFF08\u52A0\u5BC6\u4FDD\u5B58\uFF0C\u4E0D\u5199\u8FDB\u4EFB\u4F55\u6587\u4EF6\uFF09`,
202
+ sSecretsFile: (path, why) => `\u8FD9\u53F0\u7535\u8111\u6CA1\u6709\u53EF\u7528\u7684\u7CFB\u7EDF\u94A5\u5319\u4E32\uFF08${why}\uFF09\uFF0C\u6240\u4EE5\u5BC6\u7801\u548C token \u5B58\u5728 ${path}\u3002\u8FD9\u4E2A\u6587\u4EF6\u53EA\u6709\u4F60\u7684\u7CFB\u7EDF\u8D26\u53F7\u80FD\u8BFB\uFF08\u6743\u9650 600\uFF09\uFF0C\u4F46\u6CA1\u6709\u52A0\u5BC6\uFF1A\u80FD\u767B\u5F55\u4F60\u8FD9\u4E2A\u8D26\u53F7\u7684\u4EBA\u90FD\u80FD\u770B\u5230\u3002`,
175
203
  sSecretsNone: (why) => `\u8FD9\u53F0\u7535\u8111\u4E0A\u6CA1\u6709\u53EF\u7528\u7684\u7CFB\u7EDF\u94A5\u5319\u4E32\uFF1A${why}\u3002\u5BC6\u7801\u4E0D\u4F1A\u88AB\u4FDD\u5B58\uFF1B\u8D26\u6237\u7167\u6837\u80FD\u4FDD\u5B58\uFF0C\u5BC6\u7801\u7528\u73AF\u5883\u53D8\u91CF\u63D0\u4F9B\uFF0C\u53D8\u91CF\u540D\u5199\u5728\u6BCF\u4E2A\u8D26\u6237\u4E0B\u9762\u3002`,
176
204
  sPasswordTestOnly: "\u6CA1\u6709\u94A5\u5319\u4E32\uFF1A\u8FD9\u91CC\u586B\u7684\u53EA\u7528\u6765\u6D4B\u8BD5\u8FDE\u63A5\uFF0C\u4E0D\u4F1A\u4FDD\u5B58",
177
205
  secretKinds: { macos: "macOS \u94A5\u5319\u4E32", windows: "Windows \u51ED\u636E\u7BA1\u7406\u5668", linux: "Linux \u5BC6\u94A5\u73AF\uFF08Secret Service\uFF09", memory: "\u5185\u5B58\uFF08\u6D4B\u8BD5\u7528\uFF09" },
@@ -195,6 +223,15 @@ var zh = {
195
223
  sMailOk: (n) => `\u8FDE\u4E0A\u4E86\uFF0C\u6700\u8FD1\u6709 ${n} \u5C01\u672A\u8BFB\u90AE\u4EF6`,
196
224
  sEnvHint: (name) => `\u6CA1\u6709\u627E\u5230\u5BC6\u7801\u3002\u70B9\u300C\u7F16\u8F91\u300D\u91CD\u65B0\u586B\u4E00\u6B21\uFF1B\u8FD9\u53F0\u7535\u8111\u6CA1\u6709\u94A5\u5319\u4E32\u7684\u8BDD\uFF0C\u5728\u542F\u52A8 DSH \u7684\u73AF\u5883\u91CC\u8BBE\u7F6E ${name}=\u6388\u6743\u7801\uFF0C\u518D\u91CD\u542F DSH\u3002`,
197
225
  sNeverChecked: "\u8FD8\u6CA1\u6536\u8FC7",
226
+ sNoPassword: "\u8FD8\u6CA1\u6709\u8FD9\u4E2A\u90AE\u7BB1\u7684\u5BC6\u7801\uFF08\u6388\u6743\u7801\uFF09\u3002\u70B9\u300C\u7F16\u8F91\u300D\u586B\u4E00\u6B21\u3002",
227
+ mTitleAdd: "\u6DFB\u52A0\u90AE\u7BB1",
228
+ mTitleEdit: "\u7F16\u8F91\u90AE\u7BB1",
229
+ mStepsHelp: "\u7167\u7740\u505A\u8FD8\u662F\u5361\u4F4F\u4E86\uFF1F",
230
+ mTestSave: "\u6D4B\u8BD5\u5E76\u4FDD\u5B58",
231
+ mSaveAnyway: "\u4E0D\u6D4B\u8BD5\uFF0C\u76F4\u63A5\u4FDD\u5B58",
232
+ mMore: "\u66F4\u591A\u8BBE\u7F6E",
233
+ mLength: (label, want, got) => `${label}${/[A-Za-z]$/.test(label) ? " " : ""}\u7684\u6388\u6743\u7801\uFF08\u5E94\u7528\u4E13\u7528\u5BC6\u7801\uFF09\u662F ${want} \u4F4D\uFF0C\u4F60\u586B\u7684\u662F ${got} \u4F4D\uFF0C\u53EF\u80FD\u586B\u6210\u4E86\u767B\u5F55\u5BC6\u7801\u3002`,
234
+ mSavedUnread: (n) => `\u5DF2\u4FDD\u5B58\u3002\u8FDE\u4E0A\u4E86\uFF0C\u6700\u8FD1\u6709 ${n} \u5C01\u672A\u8BFB\u90AE\u4EF6\u3002`,
198
235
  sFeishu: "\u98DE\u4E66",
199
236
  sComing: "\u5373\u5C06\u63A5\u5165",
200
237
  ai: "+AI",
@@ -258,6 +295,13 @@ var en = {
258
295
  resize: "Drag to resize; double-click to make them equal",
259
296
  tabBoard: "Board",
260
297
  tabSettings: "Settings",
298
+ restart: "Restart DSH",
299
+ restartTip: "After reinstalling or upgrading plugins, use this to restart DSH",
300
+ restartConfirm: "Restart DSH? DSH needs a restart after you install or update plugins.",
301
+ restarting: "Restarting\u2026 the window closes and opens again",
302
+ restartingWeb: "Restarting\u2026 the page loses its connection for a moment and reloads once DSH is back",
303
+ restartReloading: "DSH is back; reloading the page\u2026",
304
+ restartSlow: "Still not back after two minutes; reload the page yourself.",
261
305
  all: "All",
262
306
  sourceGithub: "GitHub",
263
307
  sourceMail: "Mail",
@@ -275,6 +319,19 @@ var en = {
275
319
  sTokenGh: "The account the GitHub CLI (gh) is signed in to; the token stays in the system keychain",
276
320
  sTokenKeychain: "The token you pasted here, kept in the system keychain",
277
321
  sTokenPaste: "Paste a GitHub token",
322
+ gLogin: "Sign in with GitHub",
323
+ gPasteInstead: "Or paste a token",
324
+ gStarting: "Asking GitHub for a sign-in code\u2026",
325
+ gStep1: "1. Copy this code",
326
+ gCopy: "Copy",
327
+ gCopied: "Copied",
328
+ gStep2: "2. Open GitHub, paste the code and click Authorize. A phone or another computer works too.",
329
+ gOpen: "Open GitHub",
330
+ gWaiting: "Waiting for you to authorize on GitHub\u2026",
331
+ gScopes: "It asks for two permissions: notifications, and repo (needed for CI runs and pull requests of private repositories; GitHub has no read-only version, and the secretary only reads). The token stays on this computer.",
332
+ gDone: (login) => `Signed in as ${login}`,
333
+ gRetry: "Try again",
334
+ gClose: "Close",
278
335
  sTokenHow: "Use a classic token with the notifications scope, plus repo for private repositories. GitHub's notifications API does not take fine-grained tokens. The token goes to the system keychain only, never to a file.",
279
336
  sTokenNew: "Create one on GitHub (scopes pre-ticked)",
280
337
  sTokenSave: "Check and save",
@@ -296,6 +353,7 @@ var en = {
296
353
  sMail: "Mail",
297
354
  sMailPrivacy: "Read-only: the secretary opens your inbox read-only and looks at sender, recipients, subject and a few headers only. It never reads bodies and never marks mail read.",
298
355
  sSecretsAt: (kind) => `Passwords are kept in: ${kind} (encrypted, never written to a file)`,
356
+ sSecretsFile: (path, why) => `No usable system keychain on this computer (${why}), so passwords and tokens are kept in ${path}. Only your system account can read that file (mode 600), but it is not encrypted: anyone who can sign in as you can read it.`,
299
357
  sSecretsNone: (why) => `No usable system keychain on this computer: ${why}. Passwords are not saved; you can still save accounts and give each password through the environment variable shown under it.`,
300
358
  sPasswordTestOnly: "No keychain: used only to test the connection, not saved",
301
359
  secretKinds: { macos: "the macOS Keychain", windows: "Windows Credential Manager", linux: "the Linux keyring (Secret Service)", memory: "memory (tests)" },
@@ -319,6 +377,15 @@ var en = {
319
377
  sMailOk: (n) => `Connected; ${n} unread messages recently`,
320
378
  sEnvHint: (name) => `No password found. Click Edit and enter it again; if this computer has no keychain, set ${name}=<app password> in the environment DSH starts from, then restart DSH.`,
321
379
  sNeverChecked: "Not checked yet",
380
+ sNoPassword: "No password (app password) for this account yet. Click Edit and enter it.",
381
+ mTitleAdd: "Add a mail account",
382
+ mTitleEdit: "Edit mail account",
383
+ mStepsHelp: "Stuck on a step?",
384
+ mTestSave: "Test and save",
385
+ mSaveAnyway: "Save without testing",
386
+ mMore: "More settings",
387
+ mLength: (label, want, got) => `A ${label} app password is ${want} characters; this one is ${got}. It may be your sign-in password instead.`,
388
+ mSavedUnread: (n) => `Saved. Connected; ${n} unread messages recently.`,
322
389
  sFeishu: "Feishu / Lark",
323
390
  sComing: "Coming soon",
324
391
  ai: "+AI",
@@ -379,19 +446,47 @@ function AskAI({ topic, lang, locale, openChat: openChat2, compact = false }) {
379
446
  }
380
447
 
381
448
  // src/client/Settings.tsx
449
+ var import_react3 = require("react");
450
+
451
+ // src/client/Modal.tsx
382
452
  var import_react2 = require("react");
453
+ var import_react_dom = require("react-dom");
383
454
  var import_jsx_runtime2 = require("react/jsx-runtime");
455
+ function Modal({ title, onClose, children }) {
456
+ (0, import_react2.useEffect)(() => {
457
+ const key = (event) => {
458
+ if (event.key === "Escape") onClose();
459
+ };
460
+ window.addEventListener("keydown", key);
461
+ return () => window.removeEventListener("keydown", key);
462
+ }, [onClose]);
463
+ return (0, import_react_dom.createPortal)(
464
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "mishu-modal-backdrop", onMouseDown: (event) => {
465
+ if (event.target === event.currentTarget) onClose();
466
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mishu-modal", role: "dialog", "aria-modal": "true", "aria-label": title, children: [
467
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mishu-modal-head", children: [
468
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h2", { children: title }),
469
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: "mishu-btn mishu-btn-quiet", "aria-label": "\xD7", onClick: onClose, children: "\xD7" })
470
+ ] }),
471
+ children
472
+ ] }) }),
473
+ document.body
474
+ );
475
+ }
476
+
477
+ // src/client/Settings.tsx
478
+ var import_jsx_runtime3 = require("react/jsx-runtime");
384
479
  var CATEGORIES = ["document", "bill", "birthday", "renewal", "other"];
385
480
  function MishuSettings({ lang, locale, openChat: openChat2 }) {
386
481
  const t = TEXT[lang];
387
- const [view, setView] = (0, import_react2.useState)();
388
- const [error, setError] = (0, import_react2.useState)();
389
- const [note, setNote] = (0, import_react2.useState)();
390
- const [lead, setLead] = (0, import_react2.useState)({});
391
- const [githubTest, setGithubTest] = (0, import_react2.useState)();
392
- const [confirmOn, setConfirmOn] = (0, import_react2.useState)(false);
393
- const [pasting, setPasting] = (0, import_react2.useState)(false);
394
- const [editing, setEditing] = (0, import_react2.useState)();
482
+ const [view, setView] = (0, import_react3.useState)();
483
+ const [error, setError] = (0, import_react3.useState)();
484
+ const [note, setNote] = (0, import_react3.useState)();
485
+ const [lead, setLead] = (0, import_react3.useState)({});
486
+ const [githubTest, setGithubTest] = (0, import_react3.useState)();
487
+ const [confirmOn, setConfirmOn] = (0, import_react3.useState)(false);
488
+ const [pasting, setPasting] = (0, import_react3.useState)(false);
489
+ const [editing, setEditing] = (0, import_react3.useState)();
395
490
  const take = (result, saved) => {
396
491
  if (result.ok) {
397
492
  setView(result.view);
@@ -402,11 +497,11 @@ function MishuSettings({ lang, locale, openChat: openChat2 }) {
402
497
  setError(result.message);
403
498
  }
404
499
  };
405
- (0, import_react2.useEffect)(() => {
500
+ (0, import_react3.useEffect)(() => {
406
501
  void settingsApi.load(locale()).then((r) => take(r));
407
502
  }, [locale]);
408
503
  if (view === void 0) {
409
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "mishu-settings", children: error === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "mishu-empty", children: t.loading }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mishu-error", children: [
504
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mishu-settings", children: error === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mishu-empty", children: t.loading }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-error", children: [
410
505
  t.failed,
411
506
  error
412
507
  ] }) });
@@ -414,95 +509,96 @@ function MishuSettings({ lang, locale, openChat: openChat2 }) {
414
509
  const save = async (settings) => take(await settingsApi.save(locale(), settings), t.sSaved);
415
510
  const token = view.github.token;
416
511
  const secretKind = t.secretKinds[view.secrets.kind] ?? view.secrets.kind;
417
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mishu-settings", children: [
418
- error === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mishu-error", children: [
512
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-settings", children: [
513
+ error === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-error", children: [
419
514
  t.failed,
420
515
  error
421
516
  ] }),
422
- note === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "mishu-ok", children: note }),
423
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("section", { className: "mishu-panel", children: [
424
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h2", { children: t.sGeneral }),
425
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: "mishu-field", children: [
517
+ note === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mishu-ok", children: note }),
518
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("section", { className: "mishu-panel", children: [
519
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { children: t.sGeneral }),
520
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "mishu-field", children: [
426
521
  t.sLanguage,
427
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("select", { value: view.settings.language, onChange: (e) => {
522
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("select", { value: view.settings.language, onChange: (e) => {
428
523
  void save({ language: e.target.value });
429
524
  }, children: [
430
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "auto", children: t.sLanguageAuto }),
431
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "zh", children: "\u4E2D\u6587" }),
432
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "en", children: "English" })
525
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "auto", children: t.sLanguageAuto }),
526
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "zh", children: "\u4E2D\u6587" }),
527
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "en", children: "English" })
433
528
  ] })
434
529
  ] }),
435
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "mishu-field", children: t.sLead }),
436
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "mishu-grid5", children: CATEGORIES.map((c) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: "mishu-field", children: [
530
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mishu-field", children: t.sLead }),
531
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mishu-grid5", children: CATEGORIES.map((c) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "mishu-field", children: [
437
532
  t.categories[c],
438
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { type: "number", min: 0, max: 366, value: lead[c] ?? 0, onChange: (e) => setLead({ ...lead, [c]: Number(e.target.value) }) })
533
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { type: "number", min: 0, max: 366, value: lead[c] ?? 0, onChange: (e) => setLead({ ...lead, [c]: Number(e.target.value) }) })
439
534
  ] }, c)) }),
440
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: "mishu-btn primary", onClick: () => {
535
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "mishu-btn primary", onClick: () => {
441
536
  void save({ leadDays: lead });
442
537
  }, children: t.sSave })
443
538
  ] }),
444
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("section", { className: "mishu-panel", children: [
445
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h2", { children: t.sGithub }),
446
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: "mishu-check", children: [
447
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { type: "checkbox", checked: view.settings.githubEnabled, onChange: (e) => {
539
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("section", { className: "mishu-panel", children: [
540
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { children: t.sGithub }),
541
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "mishu-check", children: [
542
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { type: "checkbox", checked: view.settings.githubEnabled, onChange: (e) => {
448
543
  void save({ githubEnabled: e.target.checked });
449
544
  } }),
450
545
  t.sGithubOn
451
546
  ] }),
452
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mishu-row-explain", children: [
453
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "mishu-row-label", children: t.sToken }),
454
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: token.found ? "" : "mishu-danger", children: token.found ? token.from === "env" ? t.sTokenEnv(view.github.tokenEnv) : token.from === "keychain" ? t.sTokenKeychain : t.sTokenGh : token.text })
547
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-row-explain", children: [
548
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "mishu-row-label", children: t.sToken }),
549
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: token.found ? "" : "mishu-danger", children: token.found ? token.from === "env" ? t.sTokenEnv(view.github.tokenEnv) : token.from === "keychain" ? t.sTokenKeychain : t.sTokenGh : token.text })
455
550
  ] }),
456
- token.found ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mishu-actions", children: [
457
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: "mishu-btn", onClick: () => {
551
+ token.found ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-actions", children: [
552
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "mishu-btn", onClick: () => {
458
553
  setGithubTest(t.sTesting);
459
554
  void settingsApi.testGithub(locale()).then((r) => setGithubTest(r.ok ? t.sGithubOk(r.login) : `${t.failed}${r.message}`));
460
555
  }, children: t.sTest }),
461
- token.from === "env" || pasting ? null : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: "mishu-btn", onClick: () => setPasting(true), children: t.sTokenReplace }),
462
- token.from === "keychain" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: "mishu-btn mishu-btn-quiet", onClick: () => {
556
+ token.from === "env" || pasting ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "mishu-btn", onClick: () => setPasting(true), children: t.sTokenReplace }),
557
+ token.from === "keychain" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "mishu-btn mishu-btn-quiet", onClick: () => {
463
558
  if (window.confirm(t.sTokenRemoveConfirm)) void settingsApi.deleteToken(locale()).then((r) => {
464
559
  setGithubTest(void 0);
465
560
  take(r);
466
561
  });
467
562
  }, children: t.sTokenRemove }) : null,
468
- githubTest === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "mishu-hint", children: githubTest })
563
+ githubTest === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "mishu-hint", children: githubTest })
469
564
  ] }) : null,
470
- !token.found || pasting ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(TokenForm, { view, lang, locale, onSaved: (next, login) => {
565
+ !token.found || pasting ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(GithubConnect, { view, lang, locale, onSaved: (next, login) => {
471
566
  setPasting(false);
472
567
  setGithubTest(t.sTokenSaved(login));
473
568
  take({ ok: true, view: next });
474
569
  }, onCancel: token.found ? () => setPasting(false) : void 0 }) : null,
475
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: "mishu-field", children: [
570
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "mishu-field", children: [
476
571
  t.sMarkRead,
477
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("select", { value: view.settings.markRead, onChange: (e) => {
572
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("select", { value: view.settings.markRead, onChange: (e) => {
478
573
  const value = e.target.value;
479
574
  if (value === "on") setConfirmOn(true);
480
575
  else void save({ markRead: value });
481
576
  }, children: [
482
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "off", children: t.sMarkOff }),
483
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "shadow", children: t.sMarkShadow }),
484
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "on", children: t.sMarkOn })
577
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "off", children: t.sMarkOff }),
578
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "shadow", children: t.sMarkShadow }),
579
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "on", children: t.sMarkOn })
485
580
  ] })
486
581
  ] }),
487
- confirmOn ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mishu-banner", children: [
488
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { children: t.sMarkConfirm }),
489
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mishu-actions", children: [
490
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: "mishu-btn primary", onClick: () => {
582
+ confirmOn ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-banner", children: [
583
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { children: t.sMarkConfirm }),
584
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-actions", children: [
585
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "mishu-btn primary", onClick: () => {
491
586
  setConfirmOn(false);
492
587
  void save({ markRead: "on" });
493
588
  }, children: t.sConfirm }),
494
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: "mishu-btn", onClick: () => setConfirmOn(false), children: t.sCancel })
589
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "mishu-btn", onClick: () => setConfirmOn(false), children: t.sCancel })
495
590
  ] })
496
591
  ] }) : null
497
592
  ] }),
498
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("section", { className: "mishu-panel", children: [
499
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h2", { children: t.sMail }),
500
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "mishu-hint", children: t.sMailPrivacy }),
501
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: view.secrets.available ? "mishu-hint" : "mishu-hint mishu-warn", children: view.secrets.available ? t.sSecretsAt(secretKind) : t.sSecretsNone(view.secrets.why ?? secretKind) }),
502
- view.accounts.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "mishu-empty", children: t.sNoAccounts }) : view.accounts.map((account) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
593
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("section", { className: "mishu-panel", children: [
594
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { children: t.sMail }),
595
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mishu-hint", children: t.sMailPrivacy }),
596
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: view.secrets.available && view.secrets.file === void 0 ? "mishu-hint" : "mishu-hint mishu-warn", children: !view.secrets.available ? t.sSecretsNone(view.secrets.why ?? secretKind) : view.secrets.file !== void 0 ? t.sSecretsFile(view.secrets.file.path, view.secrets.file.why) : t.sSecretsAt(secretKind) }),
597
+ view.accounts.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mishu-empty", children: t.sNoAccounts }) : view.accounts.map((account) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
503
598
  AccountRow,
504
599
  {
505
600
  account,
601
+ secretsOk: view.secrets.available,
506
602
  lang,
507
603
  locale,
508
604
  openChat: openChat2,
@@ -511,24 +607,133 @@ function MishuSettings({ lang, locale, openChat: openChat2 }) {
511
607
  },
512
608
  account.id
513
609
  )),
514
- editing === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: "mishu-btn mishu-add-toggle", onClick: () => setEditing({ preset: "qq", sinceDays: 14, enabled: true }), children: t.sAddAccount }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(AccountForm, { draft: editing, view, lang, locale, openChat: openChat2, onDone: (next) => {
515
- setEditing(void 0);
516
- if (next !== void 0) take({ ok: true, view: next }, t.sSaved);
517
- } })
610
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "mishu-btn mishu-add-toggle", onClick: () => setEditing({ preset: "custom", sinceDays: 14, enabled: true }), children: t.sAddAccount }),
611
+ editing === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
612
+ MailDialog,
613
+ {
614
+ draft: editing,
615
+ view,
616
+ lang,
617
+ locale,
618
+ openChat: openChat2,
619
+ onDone: (next, note2) => {
620
+ setEditing(void 0);
621
+ if (next !== void 0) take({ ok: true, view: next }, note2 ?? t.sSaved);
622
+ }
623
+ }
624
+ )
518
625
  ] }),
519
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("section", { className: "mishu-panel", children: [
520
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h2", { children: t.sFeishu }),
521
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "mishu-hint", children: t.sComing })
626
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("section", { className: "mishu-panel", children: [
627
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { children: t.sFeishu }),
628
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mishu-hint", children: t.sComing })
522
629
  ] })
523
630
  ] });
524
631
  }
632
+ function GithubConnect({ view, lang, locale, onSaved, onCancel }) {
633
+ const t = TEXT[lang];
634
+ const [signingIn, setSigningIn] = (0, import_react3.useState)(false);
635
+ const [paste, setPaste] = (0, import_react3.useState)(!view.github.deviceLogin);
636
+ if (!view.github.deviceLogin) return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(TokenForm, { view, lang, locale, onSaved, onCancel });
637
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
638
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-actions", children: [
639
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "mishu-btn primary", onClick: () => setSigningIn(true), children: t.gLogin }),
640
+ paste ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "mishu-btn mishu-btn-quiet", onClick: () => setPaste(true), children: t.gPasteInstead }),
641
+ onCancel === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "mishu-btn", onClick: onCancel, children: t.sCancel })
642
+ ] }),
643
+ paste ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(TokenForm, { view, lang, locale, onSaved, onCancel: void 0 }) : null,
644
+ signingIn ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(GithubLoginDialog, { lang, locale, onClose: () => setSigningIn(false), onSaved: (next, login) => {
645
+ setSigningIn(false);
646
+ onSaved(next, login);
647
+ } }) : null
648
+ ] });
649
+ }
650
+ function GithubLoginDialog({ lang, locale, onClose, onSaved }) {
651
+ const t = TEXT[lang];
652
+ const [login, setLogin] = (0, import_react3.useState)();
653
+ const [error, setError] = (0, import_react3.useState)();
654
+ const [copied, setCopied] = (0, import_react3.useState)(false);
655
+ const [attempt, setAttempt] = (0, import_react3.useState)(0);
656
+ const saved = (0, import_react3.useRef)(void 0);
657
+ (0, import_react3.useEffect)(() => {
658
+ let alive = true;
659
+ let timer;
660
+ setLogin(void 0);
661
+ setError(void 0);
662
+ const poll = async () => {
663
+ const r = await settingsApi.deviceStatus(locale());
664
+ if (!alive) return;
665
+ if (!r.ok) {
666
+ setError(r.message);
667
+ return;
668
+ }
669
+ setLogin(r.login);
670
+ if (r.login.state === "done" && r.view !== void 0) saved.current = { view: r.view, login: r.login.login };
671
+ else if (r.login.state === "waiting") timer = setTimeout(() => {
672
+ void poll();
673
+ }, 2e3);
674
+ };
675
+ void settingsApi.deviceStart(locale()).then((r) => {
676
+ if (!alive) return;
677
+ if (!r.ok) {
678
+ setError(r.message);
679
+ return;
680
+ }
681
+ setLogin(r.login);
682
+ timer = setTimeout(() => {
683
+ void poll();
684
+ }, 2e3);
685
+ });
686
+ return () => {
687
+ alive = false;
688
+ if (timer !== void 0) clearTimeout(timer);
689
+ };
690
+ }, [attempt, locale]);
691
+ const close = () => {
692
+ if (saved.current !== void 0) onSaved(saved.current.view, saved.current.login);
693
+ else {
694
+ void settingsApi.deviceCancel(locale());
695
+ onClose();
696
+ }
697
+ };
698
+ const copy2 = (code) => {
699
+ void navigator.clipboard?.writeText(code).then(() => setCopied(true), () => setCopied(false));
700
+ };
701
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Modal, { title: t.gLogin, onClose: close, children: error !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
702
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mishu-preview mishu-danger", children: error }),
703
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mishu-actions", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "mishu-btn", onClick: close, children: t.gClose }) })
704
+ ] }) : login === void 0 || login.state === "idle" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mishu-hint", children: t.gStarting }) : login.state === "waiting" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
705
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mishu-field", children: t.gStep1 }),
706
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-code-row", children: [
707
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("code", { className: "mishu-code", children: login.userCode }),
708
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "mishu-btn", onClick: () => copy2(login.userCode), children: copied ? t.gCopied : t.gCopy })
709
+ ] }),
710
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mishu-field", children: t.gStep2 }),
711
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-actions", children: [
712
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "mishu-btn primary", onClick: () => window.open(login.verificationUri, "_blank", "noopener"), children: t.gOpen }),
713
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "mishu-hint", children: t.gWaiting })
714
+ ] }),
715
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mishu-hint", children: t.gScopes })
716
+ ] }) : login.state === "done" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
717
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mishu-ok", children: t.gDone(login.login) }),
718
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mishu-actions", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "mishu-btn primary", onClick: close, children: t.gClose }) })
719
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
720
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mishu-preview mishu-danger", children: login.message }),
721
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-actions", children: [
722
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "mishu-btn primary", onClick: () => {
723
+ setCopied(false);
724
+ setAttempt(attempt + 1);
725
+ }, children: t.gRetry }),
726
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "mishu-btn", onClick: close, children: t.gClose })
727
+ ] })
728
+ ] }) });
729
+ }
525
730
  function TokenForm({ view, lang, locale, onSaved, onCancel }) {
526
731
  const t = TEXT[lang];
527
- const [token, setToken] = (0, import_react2.useState)("");
528
- const [busy, setBusy] = (0, import_react2.useState)(false);
529
- const [message, setMessage] = (0, import_react2.useState)();
732
+ const [token, setToken] = (0, import_react3.useState)("");
733
+ const [busy, setBusy] = (0, import_react3.useState)(false);
734
+ const [message, setMessage] = (0, import_react3.useState)();
530
735
  if (!view.secrets.available) {
531
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "mishu-hint mishu-warn", children: t.sTokenNoKeychain(view.github.tokenEnv, view.secrets.why ?? "") });
736
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mishu-hint mishu-warn", children: t.sTokenNoKeychain(view.github.tokenEnv, view.secrets.why ?? "") });
532
737
  }
533
738
  const save = async () => {
534
739
  setBusy(true);
@@ -542,162 +747,191 @@ function TokenForm({ view, lang, locale, onSaved, onCancel }) {
542
747
  setMessage(r.message);
543
748
  }
544
749
  };
545
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mishu-add", children: [
546
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: "mishu-field", children: [
750
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-add", children: [
751
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "mishu-field", children: [
547
752
  t.sTokenPaste,
548
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { type: "password", value: token, autoComplete: "off", spellCheck: false, placeholder: "ghp_\u2026", onChange: (e) => {
753
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { type: "password", value: token, autoComplete: "off", spellCheck: false, placeholder: "ghp_\u2026", onChange: (e) => {
549
754
  setToken(e.target.value);
550
755
  setMessage(void 0);
551
756
  } })
552
757
  ] }),
553
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "mishu-hint", children: t.sTokenHow }),
554
- message === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "mishu-preview mishu-danger", children: message }),
555
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mishu-actions", children: [
556
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: "mishu-btn", onClick: () => window.open(view.github.newTokenUrl, "_blank", "noopener"), children: t.sTokenNew }),
557
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: "mishu-btn primary", disabled: busy || token.trim() === "", onClick: () => {
758
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mishu-hint", children: t.sTokenHow }),
759
+ message === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mishu-preview mishu-danger", children: message }),
760
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-actions", children: [
761
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "mishu-btn", onClick: () => window.open(view.github.newTokenUrl, "_blank", "noopener"), children: t.sTokenNew }),
762
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "mishu-btn primary", disabled: busy || token.trim() === "", onClick: () => {
558
763
  void save();
559
764
  }, children: busy ? t.sTesting : t.sTokenSave }),
560
- onCancel === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: "mishu-btn", onClick: onCancel, children: t.sCancel })
765
+ onCancel === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "mishu-btn", onClick: onCancel, children: t.sCancel })
561
766
  ] })
562
767
  ] });
563
768
  }
564
- function AccountRow({ account, lang, locale, openChat: openChat2, onEdit, onView }) {
769
+ function AccountRow({ account, secretsOk, lang, locale, openChat: openChat2, onEdit, onView }) {
565
770
  const t = TEXT[lang];
566
- const [busy, setBusy] = (0, import_react2.useState)(false);
771
+ const [busy, setBusy] = (0, import_react3.useState)(false);
567
772
  const report = account.report;
568
- const status = report === null ? t.sNeverChecked : report.error !== void 0 ? report.error[lang] : lang === "zh" ? `${new Date(report.at).toLocaleString()} \u6536\u4FE1\uFF0C${report.messages} \u5C01\u672A\u8BFB` : `checked ${new Date(report.at).toLocaleString()}, ${report.messages} unread`;
569
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mishu-card", children: [
570
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mishu-card-title", children: [
773
+ const status = !account.hasPassword ? secretsOk ? t.sNoPassword : t.sEnvHint(account.envName) : report === null ? t.sNeverChecked : report.error !== void 0 ? report.error[lang] : lang === "zh" ? `${new Date(report.at).toLocaleString()} \u6536\u4FE1\uFF0C${report.messages} \u5C01\u672A\u8BFB` : `checked ${new Date(report.at).toLocaleString()}, ${report.messages} unread`;
774
+ const failed = !account.hasPassword || report?.error !== void 0;
775
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-card", children: [
776
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-card-title", children: [
571
777
  account.label,
572
778
  account.enabled ? "" : ` (${lang === "zh" ? "\u5DF2\u505C\u7528" : "disabled"})`
573
779
  ] }),
574
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mishu-card-meta", children: [
780
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-card-meta", children: [
575
781
  account.address,
576
782
  " \xB7 ",
577
783
  account.host,
578
784
  ":",
579
785
  account.port
580
786
  ] }),
581
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: `mishu-card-note ${report?.error === void 0 ? "" : "mishu-danger"}`, children: [
787
+ account.mismatch === null ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mishu-card-note mishu-warn", children: account.mismatch }),
788
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: `mishu-card-note ${failed ? "mishu-danger" : ""}`, children: [
582
789
  status,
583
- report?.error === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(AskAI, { topic: { kind: "mail-error", accountId: account.id }, lang, locale, openChat: openChat2, compact: true })
790
+ account.hasPassword && report?.error !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(AskAI, { topic: { kind: "mail-error", accountId: account.id }, lang, locale, openChat: openChat2, compact: true }) : null
584
791
  ] }),
585
- account.hasPassword ? null : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "mishu-card-note mishu-warn", children: t.sEnvHint(account.envName) }),
586
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mishu-actions", children: [
587
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: "mishu-btn", disabled: busy, onClick: () => {
792
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-actions", children: [
793
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "mishu-btn", disabled: busy || !account.hasPassword, onClick: () => {
588
794
  setBusy(true);
589
795
  void settingsApi.syncMail(locale(), account.id).then((r) => {
590
796
  setBusy(false);
591
797
  onView(r);
592
798
  });
593
799
  }, children: busy ? t.sTesting : t.sCheckNow }),
594
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: "mishu-btn", onClick: onEdit, children: t.sEdit }),
595
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: "mishu-btn mishu-btn-quiet", onClick: () => {
800
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: account.hasPassword && account.mismatch === null ? "mishu-btn" : "mishu-btn primary", onClick: onEdit, children: t.sEdit }),
801
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "mishu-btn mishu-btn-quiet", onClick: () => {
596
802
  if (window.confirm(t.sDeleteConfirm)) void settingsApi.deleteMail(locale(), account.id).then(onView);
597
803
  }, children: t.sDelete })
598
804
  ] })
599
805
  ] });
600
806
  }
601
- function AccountForm({ draft, view, lang, locale, openChat: openChat2, onDone }) {
807
+ function MailDialog({ draft, view, lang, locale, openChat: openChat2, onDone }) {
602
808
  const t = TEXT[lang];
603
- const [account, setAccount] = (0, import_react2.useState)(draft);
604
- const [password, setPassword] = (0, import_react2.useState)("");
605
- const [message, setMessage] = (0, import_react2.useState)();
606
- const [busy, setBusy] = (0, import_react2.useState)(false);
809
+ const existing = draft.id !== void 0;
810
+ const [account, setAccount] = (0, import_react3.useState)(draft);
811
+ const [picked, setPicked] = (0, import_react3.useState)(existing);
812
+ const [password, setPassword] = (0, import_react3.useState)("");
813
+ const [message, setMessage] = (0, import_react3.useState)();
814
+ const [failedTest, setFailedTest] = (0, import_react3.useState)(false);
815
+ const [busy, setBusy] = (0, import_react3.useState)(false);
607
816
  const preset = view.presets.find((p) => p.id === account.preset) ?? view.presets[view.presets.length - 1];
608
817
  const custom = preset.id === "custom";
609
- const existing = draft.id !== void 0;
610
818
  const set = (patch) => {
611
819
  setAccount({ ...account, ...patch });
612
820
  setMessage(void 0);
821
+ setFailedTest(false);
613
822
  };
614
- const test = async () => {
615
- setBusy(true);
616
- setMessage({ ok: true, text: t.sTesting });
617
- const r = await settingsApi.testMail(locale(), account, password);
618
- setBusy(false);
619
- setMessage(r.ok ? { ok: true, text: t.sMailOk(r.unread) } : { ok: false, text: r.message });
823
+ const setAddress = (address) => {
824
+ const domain = address.trim().toLowerCase().split("@")[1] ?? "";
825
+ const known = view.presets.find((p) => p.domains.includes(domain));
826
+ set({ address, ...picked ? {} : known !== void 0 ? { preset: known.id } : domain.includes(".") ? { preset: "custom" } : {} });
620
827
  };
621
- const save = async () => {
622
- setBusy(true);
828
+ const typed = password.replace(/\s+/g, "");
829
+ const lengthOff = preset.passwordLength !== null && typed !== "" && typed.length !== preset.passwordLength;
830
+ const save = async (unread) => {
623
831
  const r = await settingsApi.saveMail(locale(), account, password);
624
832
  setBusy(false);
833
+ if (r.ok) onDone(r.view, unread === void 0 ? void 0 : t.mSavedUnread(unread));
834
+ else setMessage({ ok: false, text: r.message });
835
+ };
836
+ const testAndSave = async () => {
837
+ setBusy(true);
838
+ setMessage({ ok: true, text: t.sTesting });
839
+ const r = await settingsApi.testMail(locale(), account, password);
625
840
  if (r.ok) {
626
- setPassword("");
627
- onDone(r.view);
841
+ await save(r.unread);
628
842
  } else {
843
+ setBusy(false);
844
+ setFailedTest(true);
629
845
  setMessage({ ok: false, text: r.message });
630
846
  }
631
847
  };
632
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mishu-add", children: [
633
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: "mishu-field", children: [
634
- t.sProvider,
635
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("select", { value: account.preset, onChange: (e) => set({ preset: e.target.value }), children: view.presets.map((p) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: p.id, children: p.label }, p.id)) })
636
- ] }),
637
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: preset.supported ? "mishu-hint" : "mishu-hint mishu-danger", children: [
638
- preset.howTo,
639
- preset.supported ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(AskAI, { topic: { kind: "mail-setup", preset: preset.id }, lang, locale, openChat: openChat2, compact: true }) : null
640
- ] }),
641
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: "mishu-field", children: [
848
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Modal, { title: existing ? t.mTitleEdit : t.mTitleAdd, onClose: () => onDone(), children: [
849
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "mishu-field", children: [
642
850
  t.sAddress,
643
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { type: "email", value: account.address ?? "", autoComplete: "off", onChange: (e) => set({ address: e.target.value }) })
851
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { type: "email", value: account.address ?? "", autoComplete: "off", autoFocus: !existing, onChange: (e) => setAddress(e.target.value) })
644
852
  ] }),
645
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mishu-row", children: [
646
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: "mishu-field", children: [
647
- t.sLabel,
648
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { value: account.label ?? "", onChange: (e) => set({ label: e.target.value }) })
649
- ] }),
650
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: "mishu-field", children: [
651
- t.sUser,
652
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { value: account.user ?? "", placeholder: account.address ?? "", autoComplete: "off", onChange: (e) => set({ user: e.target.value }) })
653
- ] })
853
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "mishu-field", children: [
854
+ t.sProvider,
855
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("select", { value: account.preset, onChange: (e) => {
856
+ setPicked(true);
857
+ set({ preset: e.target.value });
858
+ }, children: view.presets.map((p) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: p.id, children: p.label }, p.id)) })
859
+ ] }),
860
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: `mishu-steps${preset.supported ? "" : " mishu-danger"}${failedTest ? " attention" : ""}`, children: [
861
+ preset.steps.length === 0 ? preset.howTo : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ol", { children: preset.steps.map((step, i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("li", { children: [
862
+ step.text,
863
+ step.link === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
864
+ " ",
865
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "mishu-btn", onClick: () => window.open(step.link.url, "_blank", "noopener"), children: step.link.label })
866
+ ] })
867
+ ] }, i)) }),
868
+ preset.supported ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-steps-help", children: [
869
+ t.mStepsHelp,
870
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(AskAI, { topic: { kind: "mail-setup", preset: preset.id }, lang, locale, openChat: openChat2, compact: true })
871
+ ] }) : null
654
872
  ] }),
655
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: "mishu-field", children: [
873
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "mishu-field", children: [
656
874
  t.sPassword,
657
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { type: "password", value: password, autoComplete: "new-password", placeholder: existing && view.secrets.available ? t.sPasswordKeep : "", onChange: (e) => {
875
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { type: "password", value: password, autoComplete: "new-password", placeholder: existing && view.secrets.available ? t.sPasswordKeep : "", onChange: (e) => {
658
876
  setPassword(e.target.value);
659
877
  setMessage(void 0);
878
+ setFailedTest(false);
660
879
  } })
661
880
  ] }),
662
- view.secrets.available ? null : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "mishu-hint mishu-warn", children: t.sPasswordTestOnly }),
663
- custom ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mishu-row", children: [
664
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: "mishu-field", children: [
881
+ lengthOff ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mishu-hint mishu-warn", children: t.mLength(preset.label, preset.passwordLength, typed.length) }) : null,
882
+ view.secrets.available ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mishu-hint mishu-warn", children: t.sPasswordTestOnly }),
883
+ custom ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-row", children: [
884
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "mishu-field", children: [
665
885
  t.sHost,
666
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { value: account.host ?? "", onChange: (e) => set({ host: e.target.value }) })
886
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { value: account.host ?? "", placeholder: "imap.example.com", onChange: (e) => set({ host: e.target.value }) })
667
887
  ] }),
668
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: "mishu-field", children: [
888
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "mishu-field", children: [
669
889
  t.sPort,
670
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { type: "number", value: account.port ?? 993, onChange: (e) => set({ port: Number(e.target.value) }) })
890
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { type: "number", value: account.port ?? 993, onChange: (e) => set({ port: Number(e.target.value) }) })
671
891
  ] })
672
892
  ] }) : null,
673
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mishu-row", children: [
674
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: "mishu-field", children: [
675
- t.sSince,
676
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { type: "number", min: 1, max: 90, value: account.sinceDays ?? 14, onChange: (e) => set({ sinceDays: Number(e.target.value) }) })
893
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("details", { className: "mishu-more", children: [
894
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("summary", { children: t.mMore }),
895
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-row", children: [
896
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "mishu-field", children: [
897
+ t.sLabel,
898
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { value: account.label ?? "", placeholder: account.address ?? "", onChange: (e) => set({ label: e.target.value }) })
899
+ ] }),
900
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "mishu-field", children: [
901
+ t.sUser,
902
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { value: account.user ?? "", placeholder: account.address ?? "", autoComplete: "off", onChange: (e) => set({ user: e.target.value }) })
903
+ ] })
677
904
  ] }),
678
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: "mishu-check", children: [
679
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { type: "checkbox", checked: account.enabled !== false, onChange: (e) => set({ enabled: e.target.checked }) }),
680
- t.sEnabled
905
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-row", children: [
906
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "mishu-field", children: [
907
+ t.sSince,
908
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { type: "number", min: 1, max: 90, value: account.sinceDays ?? 14, onChange: (e) => set({ sinceDays: Number(e.target.value) }) })
909
+ ] }),
910
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "mishu-check", children: [
911
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { type: "checkbox", checked: account.enabled !== false, onChange: (e) => set({ enabled: e.target.checked }) }),
912
+ t.sEnabled
913
+ ] })
681
914
  ] })
682
915
  ] }),
683
- message === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: `mishu-preview ${message.ok ? "" : "mishu-danger"}`, children: [
916
+ message === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: `mishu-preview ${message.ok ? "" : "mishu-danger"}`, children: [
684
917
  message.text,
685
- message.ok || !preset.supported ? null : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(AskAI, { topic: { kind: "mail-setup", preset: preset.id, error: message.text }, lang, locale, openChat: openChat2, compact: true })
918
+ message.ok || !preset.supported ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(AskAI, { topic: { kind: "mail-setup", preset: preset.id, error: message.text }, lang, locale, openChat: openChat2, compact: true })
686
919
  ] }),
687
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mishu-actions", children: [
688
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: "mishu-btn", disabled: busy || !preset.supported, onClick: () => {
689
- void test();
690
- }, children: t.sTest }),
691
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: "mishu-btn primary", disabled: busy || !preset.supported, onClick: () => {
920
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-actions", children: [
921
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "mishu-btn primary", disabled: busy || !preset.supported || (account.address ?? "") === "", onClick: () => {
922
+ void testAndSave();
923
+ }, children: busy ? t.sTesting : t.mTestSave }),
924
+ failedTest ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "mishu-btn mishu-btn-quiet", disabled: busy, onClick: () => {
925
+ setBusy(true);
692
926
  void save();
693
- }, children: t.sSave }),
694
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: "mishu-btn", onClick: () => onDone(), children: t.sCancel })
927
+ }, children: t.mSaveAnyway }) : null,
928
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "mishu-btn", onClick: () => onDone(), children: t.sCancel })
695
929
  ] })
696
930
  ] });
697
931
  }
698
932
 
699
933
  // src/client/Board.tsx
700
- var import_jsx_runtime3 = require("react/jsx-runtime");
934
+ var import_jsx_runtime4 = require("react/jsx-runtime");
701
935
  var SOURCE_KEY = "dsh-mishu.source";
702
936
  function loadSource() {
703
937
  try {
@@ -733,14 +967,14 @@ function saveWidths(widths) {
733
967
  }
734
968
  }
735
969
  function MishuBoard({ locale, openChat: openChat2 }) {
736
- const [board, setBoard] = (0, import_react3.useState)();
737
- const [error, setError] = (0, import_react3.useState)();
738
- const [busy, setBusy] = (0, import_react3.useState)(false);
739
- const [syncing, setSyncing] = (0, import_react3.useState)(false);
740
- const [dropOn, setDropOn] = (0, import_react3.useState)();
741
- const [widths, setWidths] = (0, import_react3.useState)(loadWidths);
742
- const [tab, setTab] = (0, import_react3.useState)("board");
743
- const [source, setSourceState] = (0, import_react3.useState)(loadSource);
970
+ const [board, setBoard] = (0, import_react4.useState)();
971
+ const [error, setError] = (0, import_react4.useState)();
972
+ const [busy, setBusy] = (0, import_react4.useState)(false);
973
+ const [syncing, setSyncing] = (0, import_react4.useState)(false);
974
+ const [dropOn, setDropOn] = (0, import_react4.useState)();
975
+ const [widths, setWidths] = (0, import_react4.useState)(loadWidths);
976
+ const [tab, setTab] = (0, import_react4.useState)("board");
977
+ const [source, setSourceState] = (0, import_react4.useState)(loadSource);
744
978
  const setSource = (next) => {
745
979
  setSourceState(next);
746
980
  try {
@@ -748,11 +982,11 @@ function MishuBoard({ locale, openChat: openChat2 }) {
748
982
  } catch {
749
983
  }
750
984
  };
751
- const dragged = (0, import_react3.useRef)(void 0);
752
- const columnsRef = (0, import_react3.useRef)(null);
985
+ const dragged = (0, import_react4.useRef)(void 0);
986
+ const columnsRef = (0, import_react4.useRef)(null);
753
987
  const lang = board?.lang ?? uiLang(locale());
754
988
  const t = TEXT[lang];
755
- const take = (0, import_react3.useCallback)((result) => {
989
+ const take = (0, import_react4.useCallback)((result) => {
756
990
  if (result.ok) {
757
991
  setBoard(result.board);
758
992
  setError(void 0);
@@ -760,8 +994,8 @@ function MishuBoard({ locale, openChat: openChat2 }) {
760
994
  setError(result.message);
761
995
  }
762
996
  }, []);
763
- const load = (0, import_react3.useCallback)(() => mishuApi.board(locale()).then(take), [locale, take]);
764
- (0, import_react3.useEffect)(() => {
997
+ const load = (0, import_react4.useCallback)(() => mishuApi.board(locale()).then(take), [locale, take]);
998
+ (0, import_react4.useEffect)(() => {
765
999
  void load();
766
1000
  const timer = setInterval(() => {
767
1001
  void load();
@@ -851,7 +1085,7 @@ function MishuBoard({ locale, openChat: openChat2 }) {
851
1085
  reopen: t.reopen,
852
1086
  stop: t.stop
853
1087
  };
854
- const card = (item, column) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1088
+ const card = (item, column) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
855
1089
  Card,
856
1090
  {
857
1091
  item,
@@ -875,9 +1109,12 @@ function MishuBoard({ locale, openChat: openChat2 }) {
875
1109
  `${item.target}-${item.id}`
876
1110
  );
877
1111
  if (board === void 0) {
878
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-page", children: [
879
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mishu-head", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h1", { children: t.title }) }),
880
- error === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mishu-empty", children: t.loading }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-error", children: [
1112
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mishu-page", children: [
1113
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mishu-head", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mishu-title", children: [
1114
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h1", { children: t.title }),
1115
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(RestartButton, { lang, locale })
1116
+ ] }) }),
1117
+ error === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "mishu-empty", children: t.loading }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mishu-error", children: [
881
1118
  t.failed,
882
1119
  error
883
1120
  ] })
@@ -902,7 +1139,7 @@ function MishuBoard({ locale, openChat: openChat2 }) {
902
1139
  { id: "manual", label: t.sourceManual }
903
1140
  ];
904
1141
  const template = `minmax(0, ${widths[0]}fr) 10px minmax(0, ${widths[1]}fr) 10px minmax(0, ${widths[2]}fr)`;
905
- const divider = (index) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1142
+ const divider = (index) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
906
1143
  "div",
907
1144
  {
908
1145
  className: "mishu-divider",
@@ -913,106 +1150,107 @@ function MishuBoard({ locale, openChat: openChat2 }) {
913
1150
  onDoubleClick: resetWidths
914
1151
  }
915
1152
  );
916
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-page", "data-mishu-board": "", children: [
917
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-head", children: [
918
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-title", children: [
919
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h1", { children: t.title }),
920
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-tabs", role: "tablist", children: [
921
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", role: "tab", "aria-selected": tab === "board", className: tab === "board" ? "active" : "", onClick: () => setTab("board"), children: t.tabBoard }),
922
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", role: "tab", "aria-selected": tab === "settings", className: tab === "settings" ? "active" : "", onClick: () => setTab("settings"), children: t.tabSettings })
923
- ] })
1153
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mishu-page", "data-mishu-board": "", children: [
1154
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mishu-head", children: [
1155
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mishu-title", children: [
1156
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h1", { children: t.title }),
1157
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mishu-tabs", role: "tablist", children: [
1158
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", role: "tab", "aria-selected": tab === "board", className: tab === "board" ? "active" : "", onClick: () => setTab("board"), children: t.tabBoard }),
1159
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", role: "tab", "aria-selected": tab === "settings", className: tab === "settings" ? "active" : "", onClick: () => setTab("settings"), children: t.tabSettings })
1160
+ ] }),
1161
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(RestartButton, { lang, locale })
924
1162
  ] }),
925
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-sources", children: [
926
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { children: [
927
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("i", { className: `mishu-dot ${board.sources.github.state}` }),
1163
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mishu-sources", children: [
1164
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { children: [
1165
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("i", { className: `mishu-dot ${board.sources.github.state}` }),
928
1166
  board.sources.github.text,
929
- board.sources.github.state === "error" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(AskAI, { topic: { kind: "github-error" }, lang, locale, openChat: openChat2, compact: true }) : null
1167
+ board.sources.github.state === "error" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(AskAI, { topic: { kind: "github-error" }, lang, locale, openChat: openChat2, compact: true }) : null
930
1168
  ] }),
931
- board.sources.mail.map((m) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { children: [
932
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("i", { className: `mishu-dot ${m.state}` }),
1169
+ board.sources.mail.map((m) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { children: [
1170
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("i", { className: `mishu-dot ${m.state}` }),
933
1171
  m.text,
934
- m.state === "error" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(AskAI, { topic: { kind: "mail-error", accountId: m.id }, lang, locale, openChat: openChat2, compact: true }) : null
1172
+ m.state === "error" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(AskAI, { topic: { kind: "mail-error", accountId: m.id }, lang, locale, openChat: openChat2, compact: true }) : null
935
1173
  ] }, m.id)),
936
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "mishu-btn", disabled: syncing, onClick: () => {
1174
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: "mishu-btn", disabled: syncing, onClick: () => {
937
1175
  void sync();
938
1176
  }, children: syncing ? t.syncing : t.sync })
939
1177
  ] })
940
1178
  ] }),
941
- tab === "settings" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MishuSettings, { lang, locale, openChat: openChat2 }) : null,
942
- tab === "settings" ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
943
- error === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-error", children: [
1179
+ tab === "settings" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(MishuSettings, { lang, locale, openChat: openChat2 }) : null,
1180
+ tab === "settings" ? null : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
1181
+ error === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mishu-error", children: [
944
1182
  t.failed,
945
1183
  error
946
1184
  ] }),
947
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("p", { className: "mishu-summary", children: [
1185
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("p", { className: "mishu-summary", children: [
948
1186
  board.summary,
949
1187
  " ",
950
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(AskAI, { topic: { kind: "summary" }, lang, locale, openChat: openChat2, compact: true })
1188
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(AskAI, { topic: { kind: "summary" }, lang, locale, openChat: openChat2, compact: true })
951
1189
  ] }),
952
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-metrics", children: [
953
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-metric", children: [
954
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mishu-metric-label", children: t.metricHandle }),
955
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-metric-value", children: [
1190
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mishu-metrics", children: [
1191
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mishu-metric", children: [
1192
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mishu-metric-label", children: t.metricHandle }),
1193
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mishu-metric-value", children: [
956
1194
  metrics.handle,
957
- metrics.overdue > 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("small", { className: "mishu-danger", children: [
1195
+ metrics.overdue > 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("small", { className: "mishu-danger", children: [
958
1196
  metrics.overdue,
959
1197
  " ",
960
1198
  t.metricOverdue
961
1199
  ] }) : null
962
1200
  ] })
963
1201
  ] }),
964
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-metric", children: [
965
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mishu-metric-label", children: t.metricSoon }),
966
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mishu-metric-value", children: metrics.dueSoon })
1202
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mishu-metric", children: [
1203
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mishu-metric-label", children: t.metricSoon }),
1204
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mishu-metric-value", children: metrics.dueSoon })
967
1205
  ] }),
968
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-metric", children: [
969
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mishu-metric-label", children: t.metricClosed }),
970
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mishu-metric-value", children: metrics.closedToday })
1206
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mishu-metric", children: [
1207
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mishu-metric-label", children: t.metricClosed }),
1208
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mishu-metric-value", children: metrics.closedToday })
971
1209
  ] }),
972
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-metric", children: [
973
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mishu-metric-label", children: t.metricShadow }),
974
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-metric-value", children: [
1210
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mishu-metric", children: [
1211
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mishu-metric-label", children: t.metricShadow }),
1212
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mishu-metric-value", children: [
975
1213
  metrics.shadow,
976
- board.markRead === "shadow" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("small", { className: "mishu-warn", children: t.shadowTag }) : null
1214
+ board.markRead === "shadow" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("small", { className: "mishu-warn", children: t.shadowTag }) : null
977
1215
  ] })
978
1216
  ] })
979
1217
  ] }),
980
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mishu-filters", role: "group", children: sources.map((s) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("button", { type: "button", "aria-pressed": source === s.id, className: `mishu-chip ${source === s.id ? "active" : ""}`, onClick: () => setSource(s.id), children: [
1218
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mishu-filters", role: "group", children: sources.map((s) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("button", { type: "button", "aria-pressed": source === s.id, className: `mishu-chip ${source === s.id ? "active" : ""}`, onClick: () => setSource(s.id), children: [
981
1219
  s.label,
982
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: count(s.id) })
1220
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: count(s.id) })
983
1221
  ] }, s.id)) }),
984
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-columns", ref: columnsRef, style: { ["--mishu-cols"]: template }, children: [
985
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("section", { className: `mishu-col ${dropOn === "handle" ? "drop" : ""}`, ...dropProps("handle"), "aria-label": t.handle, children: [
986
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-col-head", children: [
1222
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mishu-columns", ref: columnsRef, style: { ["--mishu-cols"]: template }, children: [
1223
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("section", { className: `mishu-col ${dropOn === "handle" ? "drop" : ""}`, ...dropProps("handle"), "aria-label": t.handle, children: [
1224
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mishu-col-head", children: [
987
1225
  t.handle,
988
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: columns.handle.length })
1226
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: columns.handle.length })
989
1227
  ] }),
990
- columns.handle.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mishu-empty", children: t.emptyHandle }) : columns.handle.map((item) => card(item, "handle"))
1228
+ columns.handle.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mishu-empty", children: t.emptyHandle }) : columns.handle.map((item) => card(item, "handle"))
991
1229
  ] }),
992
1230
  divider(0),
993
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("section", { className: `mishu-col ${dropOn === "remember" ? "drop" : ""}`, ...dropProps("remember"), "aria-label": t.remember, title: t.dropRemember, children: [
994
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-col-head", children: [
1231
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("section", { className: `mishu-col ${dropOn === "remember" ? "drop" : ""}`, ...dropProps("remember"), "aria-label": t.remember, title: t.dropRemember, children: [
1232
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mishu-col-head", children: [
995
1233
  t.remember,
996
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: columns.remember.length })
1234
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: columns.remember.length })
997
1235
  ] }),
998
- columns.remember.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mishu-empty", children: t.emptyRemember }) : columns.remember.map((item) => card(item, "remember")),
999
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(AddForm, { lang, locale, onAdded: (next) => setBoard(next) })
1236
+ columns.remember.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mishu-empty", children: t.emptyRemember }) : columns.remember.map((item) => card(item, "remember")),
1237
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(AddForm, { lang, locale, onAdded: (next) => setBoard(next) })
1000
1238
  ] }),
1001
1239
  divider(1),
1002
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("section", { className: `mishu-col ${dropOn === "done" ? "drop" : ""}`, ...dropProps("done"), "aria-label": t.done, title: t.dropDone, children: [
1003
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-col-head", children: [
1240
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("section", { className: `mishu-col ${dropOn === "done" ? "drop" : ""}`, ...dropProps("done"), "aria-label": t.done, title: t.dropDone, children: [
1241
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mishu-col-head", children: [
1004
1242
  t.done,
1005
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: columns.done.total })
1243
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: columns.done.total })
1006
1244
  ] }),
1007
- columns.done.groups.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mishu-empty", children: t.emptyDone }) : columns.done.groups.map((group) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("details", { className: "mishu-group", children: [
1008
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("summary", { children: [
1245
+ columns.done.groups.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mishu-empty", children: t.emptyDone }) : columns.done.groups.map((group) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("details", { className: "mishu-group", children: [
1246
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("summary", { children: [
1009
1247
  group.label,
1010
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: group.items.length })
1248
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: group.items.length })
1011
1249
  ] }),
1012
1250
  group.items.map((item) => card(item, "done"))
1013
1251
  ] }, group.reason)),
1014
- columns.done.total > 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mishu-hint", children: t.doneHint }) : null,
1015
- metrics.shadow > 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mishu-banner", children: t.shadow(metrics.shadow) }) : null
1252
+ columns.done.total > 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "mishu-hint", children: t.doneHint }) : null,
1253
+ metrics.shadow > 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mishu-banner", children: t.shadow(metrics.shadow) }) : null
1016
1254
  ] })
1017
1255
  ] })
1018
1256
  ] })
@@ -1020,8 +1258,8 @@ function MishuBoard({ locale, openChat: openChat2 }) {
1020
1258
  }
1021
1259
  function Card({ item, column, lang, locale, busy, label, openChat: openChat2, onAct, onDragStart, onDragEnd }) {
1022
1260
  const t = TEXT[lang];
1023
- const [open, setOpen] = (0, import_react3.useState)(false);
1024
- const [detail, setDetail] = (0, import_react3.useState)();
1261
+ const [open, setOpen] = (0, import_react4.useState)(false);
1262
+ const [detail, setDetail] = (0, import_react4.useState)();
1025
1263
  const explain = item.explain;
1026
1264
  const compact = column === "done";
1027
1265
  const toggle = () => {
@@ -1031,11 +1269,11 @@ function Card({ item, column, lang, locale, busy, label, openChat: openChat2, on
1031
1269
  void mishuApi.detail(locale(), item.id).then((r) => setDetail(r.ok ? r.detail : { error: r.message }));
1032
1270
  }
1033
1271
  };
1034
- const row = (name, text, className = "") => text === null || text === void 0 || text === "" ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: `mishu-row-explain ${className}`, children: [
1035
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "mishu-row-label", children: name }),
1036
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: text })
1272
+ const row = (name, text, className = "") => text === null || text === void 0 || text === "" ? null : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: `mishu-row-explain ${className}`, children: [
1273
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "mishu-row-label", children: name }),
1274
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: text })
1037
1275
  ] });
1038
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1276
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1039
1277
  "div",
1040
1278
  {
1041
1279
  className: `mishu-card ${item.tone === "normal" ? "" : item.tone}`,
@@ -1046,35 +1284,35 @@ function Card({ item, column, lang, locale, busy, label, openChat: openChat2, on
1046
1284
  },
1047
1285
  onDragEnd,
1048
1286
  children: [
1049
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mishu-card-title", children: item.title }),
1050
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mishu-card-meta", children: item.meta }),
1051
- !compact && explain !== null ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-explain", children: [
1287
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mishu-card-title", children: item.title }),
1288
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mishu-card-meta", children: item.meta }),
1289
+ !compact && explain !== null ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mishu-explain", children: [
1052
1290
  row(t.what, explain.what),
1053
1291
  row(column === "remember" ? t.whyKeep : t.why, explain.why),
1054
1292
  row(t.fix, explain.fix, "mishu-fix")
1055
1293
  ] }) : null,
1056
- !compact && explain === null && item.note !== null ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mishu-card-note", children: item.note }) : null,
1057
- open ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mishu-detail", children: detail === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mishu-empty", children: t.loading }) : "error" in detail ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mishu-danger", children: detail.error }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
1058
- compact && detail.explain !== null ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
1294
+ !compact && explain === null && item.note !== null ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mishu-card-note", children: item.note }) : null,
1295
+ open ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mishu-detail", children: detail === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mishu-empty", children: t.loading }) : "error" in detail ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mishu-danger", children: detail.error }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
1296
+ compact && detail.explain !== null ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
1059
1297
  row(t.what, detail.explain.what),
1060
1298
  row(t.whyDone, detail.explain.why)
1061
1299
  ] }) : null,
1062
- detail.did.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-row-explain", children: [
1063
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "mishu-row-label", children: t.did }),
1064
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: detail.did.map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { children: line }, i)) })
1300
+ detail.did.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mishu-row-explain", children: [
1301
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "mishu-row-label", children: t.did }),
1302
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: detail.did.map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { children: line }, i)) })
1065
1303
  ] }) : null,
1066
- detail.messages.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-messages", children: [
1067
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mishu-row-label", children: t.messages(detail.messages.length) }),
1068
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ul", { children: detail.messages.map((m, i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("li", { children: [
1069
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: m.at }),
1304
+ detail.messages.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mishu-messages", children: [
1305
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mishu-row-label", children: t.messages(detail.messages.length) }),
1306
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("ul", { children: detail.messages.map((m, i) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("li", { children: [
1307
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: m.at }),
1070
1308
  " ",
1071
1309
  m.title
1072
1310
  ] }, i)) })
1073
1311
  ] }) : null
1074
1312
  ] }) }) : null,
1075
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-actions", children: [
1076
- column === "handle" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(AskAI, { topic: item.target === "series" ? { kind: "series", id: item.id } : { kind: "matter", id: item.id }, lang, locale, openChat: openChat2 }) : null,
1077
- item.actions.map((action, index) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1313
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mishu-actions", children: [
1314
+ column === "handle" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(AskAI, { topic: item.target === "series" ? { kind: "series", id: item.id } : { kind: "matter", id: item.id }, lang, locale, openChat: openChat2 }) : null,
1315
+ item.actions.map((action, index) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1078
1316
  "button",
1079
1317
  {
1080
1318
  type: "button",
@@ -1085,8 +1323,8 @@ function Card({ item, column, lang, locale, busy, label, openChat: openChat2, on
1085
1323
  },
1086
1324
  action
1087
1325
  )),
1088
- item.target === "matter" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "mishu-btn mishu-btn-quiet", "aria-expanded": open, onClick: toggle, children: open ? t.hide : compact ? t.explainDone : t.detail }) : null,
1089
- column === "handle" ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(AskAI, { topic: item.target === "series" ? { kind: "series", id: item.id } : { kind: "matter", id: item.id }, lang, locale, openChat: openChat2, compact: true })
1326
+ item.target === "matter" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: "mishu-btn mishu-btn-quiet", "aria-expanded": open, onClick: toggle, children: open ? t.hide : compact ? t.explainDone : t.detail }) : null,
1327
+ column === "handle" ? null : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(AskAI, { topic: item.target === "series" ? { kind: "series", id: item.id } : { kind: "matter", id: item.id }, lang, locale, openChat: openChat2, compact: true })
1090
1328
  ] })
1091
1329
  ]
1092
1330
  }
@@ -1095,11 +1333,11 @@ function Card({ item, column, lang, locale, busy, label, openChat: openChat2, on
1095
1333
  var EMPTY = { title: "", due: "", repeat: "none", category: "other", note: "" };
1096
1334
  function AddForm({ lang, locale, onAdded }) {
1097
1335
  const t = TEXT[lang];
1098
- const [open, setOpen] = (0, import_react3.useState)(false);
1099
- const [item, setItem] = (0, import_react3.useState)(EMPTY);
1100
- const [preview, setPreview] = (0, import_react3.useState)();
1101
- const [saving, setSaving] = (0, import_react3.useState)(false);
1102
- (0, import_react3.useEffect)(() => {
1336
+ const [open, setOpen] = (0, import_react4.useState)(false);
1337
+ const [item, setItem] = (0, import_react4.useState)(EMPTY);
1338
+ const [preview, setPreview] = (0, import_react4.useState)();
1339
+ const [saving, setSaving] = (0, import_react4.useState)(false);
1340
+ (0, import_react4.useEffect)(() => {
1103
1341
  if (!open || item.title.trim() === "" || item.due === "") {
1104
1342
  setPreview(void 0);
1105
1343
  return;
@@ -1110,7 +1348,7 @@ function AddForm({ lang, locale, onAdded }) {
1110
1348
  return () => clearTimeout(timer);
1111
1349
  }, [open, item, locale]);
1112
1350
  if (!open) {
1113
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("button", { type: "button", className: "mishu-btn mishu-add-toggle", onClick: () => setOpen(true), children: [
1351
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("button", { type: "button", className: "mishu-btn mishu-add-toggle", onClick: () => setOpen(true), children: [
1114
1352
  "+ ",
1115
1353
  t.add
1116
1354
  ] });
@@ -1128,44 +1366,90 @@ function AddForm({ lang, locale, onAdded }) {
1128
1366
  setPreview({ ok: false, text: result.message });
1129
1367
  }
1130
1368
  };
1131
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-add", children: [
1132
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "mishu-field", children: [
1369
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mishu-add", children: [
1370
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "mishu-field", children: [
1133
1371
  t.addTitle,
1134
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { value: item.title, placeholder: t.addTitlePlaceholder, onChange: set("title") })
1372
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("input", { value: item.title, placeholder: t.addTitlePlaceholder, onChange: set("title") })
1135
1373
  ] }),
1136
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-row", children: [
1137
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "mishu-field", children: [
1374
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mishu-row", children: [
1375
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "mishu-field", children: [
1138
1376
  t.addDue,
1139
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { type: "date", value: item.due, onChange: set("due") })
1377
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("input", { type: "date", value: item.due, onChange: set("due") })
1140
1378
  ] }),
1141
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "mishu-field", children: [
1379
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "mishu-field", children: [
1142
1380
  t.addRepeat,
1143
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("select", { value: item.repeat, onChange: set("repeat"), children: Object.entries(t.repeats).map(([value, text]) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value, children: text }, value)) })
1381
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("select", { value: item.repeat, onChange: set("repeat"), children: Object.entries(t.repeats).map(([value, text]) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value, children: text }, value)) })
1144
1382
  ] })
1145
1383
  ] }),
1146
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-row", children: [
1147
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "mishu-field", children: [
1384
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mishu-row", children: [
1385
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "mishu-field", children: [
1148
1386
  t.addCategory,
1149
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("select", { value: item.category, onChange: set("category"), children: Object.entries(t.categories).map(([value, text]) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value, children: text }, value)) })
1387
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("select", { value: item.category, onChange: set("category"), children: Object.entries(t.categories).map(([value, text]) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value, children: text }, value)) })
1150
1388
  ] }),
1151
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "mishu-field", children: [
1389
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "mishu-field", children: [
1152
1390
  t.addNote,
1153
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { value: item.note, onChange: set("note") })
1391
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("input", { value: item.note, onChange: set("note") })
1154
1392
  ] })
1155
1393
  ] }),
1156
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: `mishu-preview ${preview?.ok === false ? "mishu-danger" : ""}`, children: preview?.text ?? t.previewHint }),
1157
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mishu-actions", children: [
1158
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "mishu-btn primary", disabled: saving || preview?.ok !== true, onClick: () => {
1394
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: `mishu-preview ${preview?.ok === false ? "mishu-danger" : ""}`, children: preview?.text ?? t.previewHint }),
1395
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mishu-actions", children: [
1396
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: "mishu-btn primary", disabled: saving || preview?.ok !== true, onClick: () => {
1159
1397
  void save();
1160
1398
  }, children: t.save }),
1161
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "mishu-btn", onClick: () => {
1399
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: "mishu-btn", onClick: () => {
1162
1400
  setOpen(false);
1163
1401
  setItem(EMPTY);
1164
1402
  }, children: t.cancel })
1165
1403
  ] }),
1166
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mishu-hint", children: t.chatHint })
1404
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "mishu-hint", children: t.chatHint })
1405
+ ] });
1406
+ }
1407
+ function RestartButton({ lang, locale }) {
1408
+ const t = TEXT[lang];
1409
+ const [why, setWhy] = (0, import_react4.useState)();
1410
+ const [status, setStatus] = (0, import_react4.useState)();
1411
+ (0, import_react4.useEffect)(() => {
1412
+ void restartApi.info(locale()).then((r) => {
1413
+ if (r.ok && !r.supported) setWhy(r.why);
1414
+ });
1415
+ }, [locale]);
1416
+ const restart = async () => {
1417
+ if (why !== void 0) {
1418
+ setStatus({ ok: false, text: why });
1419
+ return;
1420
+ }
1421
+ if (!window.confirm(t.restartConfirm)) return;
1422
+ setStatus({ ok: true, text: t.restarting });
1423
+ const r = await restartApi.restart(locale());
1424
+ if (!r.ok) {
1425
+ setStatus({ ok: false, text: r.message });
1426
+ } else if (r.reconnect === true) {
1427
+ setStatus({ ok: true, text: t.restartingWeb });
1428
+ setStatus({ ok: true, text: await reconnect(locale) ? t.restartReloading : t.restartSlow });
1429
+ }
1430
+ };
1431
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
1432
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: "mishu-btn", title: why === void 0 ? t.restartTip : `${t.restartTip}
1433
+ ${why}`, disabled: status?.ok === true, onClick: () => {
1434
+ void restart();
1435
+ }, children: t.restart }),
1436
+ status === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: status.ok ? "mishu-hint" : "mishu-hint mishu-warn", children: status.text })
1167
1437
  ] });
1168
1438
  }
1439
+ async function reconnect(locale) {
1440
+ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
1441
+ let wentDown = false;
1442
+ for (const until = Date.now() + 12e4; Date.now() < until; ) {
1443
+ await sleep(1500);
1444
+ const r = await restartApi.info(locale());
1445
+ if (!r.ok) wentDown = true;
1446
+ else if (wentDown) {
1447
+ window.location.reload();
1448
+ return true;
1449
+ }
1450
+ }
1451
+ return false;
1452
+ }
1169
1453
 
1170
1454
  // src/client/styles.ts
1171
1455
  var v = (name, fallback) => `var(--dsw-alias-${name}, ${fallback})`;
@@ -1181,6 +1465,7 @@ var DANGER = v("state-error-primary", "#d14343");
1181
1465
  var WARN = v("state-warn-primary", "#b7791f");
1182
1466
  var OK = v("state-success-primary", "#2f855a");
1183
1467
  var ACCENT = v("brand-primary", "#4d6bfe");
1468
+ var SURFACE = v("bg-layer-0", v("bg-base", "Canvas"));
1184
1469
  var STYLES = `
1185
1470
  .mishu-page{box-sizing:border-box;height:100%;overflow:auto;padding:20px 24px 32px;color:${TEXT2};font-size:13px;line-height:1.5}
1186
1471
  .mishu-page *{box-sizing:border-box}
@@ -1241,6 +1526,22 @@ var STYLES = `
1241
1526
  .mishu-row{display:grid;grid-template-columns:1fr 1fr;gap:6px}
1242
1527
  .mishu-preview{white-space:pre-wrap;font-size:12px;background:${LAYER2};border-radius:6px;padding:6px 8px;margin:4px 0 6px;color:${TEXT2}}
1243
1528
  .mishu-preview.mishu-danger{color:${DANGER}}
1529
+ .mishu-modal-backdrop{position:fixed;inset:0;z-index:1000;background:rgba(0,0,0,.45);display:flex;align-items:center;justify-content:center;padding:16px}
1530
+ .mishu-modal{background:${SURFACE};color:${TEXT2};border:1px solid ${LINE_STRONG};border-radius:12px;box-shadow:0 12px 40px rgba(0,0,0,.35);width:min(480px,100%);max-height:calc(100vh - 32px);overflow:auto;padding:14px 16px 16px;font-size:13px;line-height:1.5}
1531
+ .mishu-modal *{box-sizing:border-box}
1532
+ .mishu-modal-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px}
1533
+ .mishu-modal-head h2{font-size:15px;font-weight:600;margin:0}
1534
+ .mishu-steps{font-size:12px;color:${MUTED};background:${LAYER1};border-radius:8px;padding:8px 10px;margin:2px 0 10px;line-height:1.6}
1535
+ .mishu-steps ol{margin:0;padding-left:20px}
1536
+ .mishu-steps li{margin:2px 0 6px}
1537
+ .mishu-steps li .mishu-btn{margin-left:4px;vertical-align:baseline}
1538
+ .mishu-steps.attention{outline:2px solid ${ACCENT};outline-offset:1px;color:${TEXT2}}
1539
+ .mishu-steps-help{display:flex;align-items:center;gap:6px;margin-top:4px}
1540
+ .mishu-steps.mishu-danger{color:${DANGER}}
1541
+ .mishu-more{margin:4px 0 8px;font-size:12px;color:${MUTED}}
1542
+ .mishu-more summary{cursor:pointer;margin-bottom:6px}
1543
+ .mishu-code-row{display:flex;align-items:center;gap:10px;margin:2px 0 10px}
1544
+ .mishu-code{font:600 26px/1.2 ui-monospace,SFMono-Regular,Menlo,monospace;letter-spacing:3px;user-select:all;padding:4px 10px;border-radius:8px;background:${LAYER2}}
1244
1545
  .mishu-add>.mishu-hint{margin-bottom:8px}
1245
1546
  .mishu-title{display:flex;align-items:center;gap:14px;flex-wrap:wrap}
1246
1547
  .mishu-tabs{display:flex;gap:2px;background:${LAYER1};border-radius:8px;padding:2px}
@@ -1269,18 +1570,18 @@ var STYLES = `
1269
1570
  `;
1270
1571
 
1271
1572
  // src/client/index.tsx
1272
- var import_jsx_runtime4 = require("react/jsx-runtime");
1573
+ var import_jsx_runtime5 = require("react/jsx-runtime");
1273
1574
  var PACKAGE_NAME = "dsh-mishu";
1274
1575
  var inject = ["slots", "locale"];
1275
1576
  var PANEL_ID = "dsh-mishu";
1276
1577
  var NS = "dsh-mishu";
1277
1578
  var openChat;
1278
1579
  function MishuIcon({ size }) {
1279
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1.8, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
1280
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("rect", { x: "5", y: "4", width: "14", height: "17", rx: "2" }),
1281
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M9 4h6v3H9z" }),
1282
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M9 12l2 2 4-4" }),
1283
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M9 17h6" })
1580
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1.8, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
1581
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("rect", { x: "5", y: "4", width: "14", height: "17", rx: "2" }),
1582
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M9 4h6v3H9z" }),
1583
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M9 12l2 2 4-4" }),
1584
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M9 17h6" })
1284
1585
  ] });
1285
1586
  }
1286
1587
  function apply(ctx) {