@rubytech/create-sitedesk-code 0.1.382 → 0.1.383

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.
Files changed (76) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/config/brand.json +11 -11
  3. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +15 -8
  4. package/payload/platform/plugins/docs/references/admin-ui.md +9 -6
  5. package/payload/platform/plugins/docs/references/attachments.md +5 -1
  6. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/d1-command.test.d.ts +2 -0
  7. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/d1-command.test.d.ts.map +1 -0
  8. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/d1-command.test.js +23 -0
  9. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/d1-command.test.js.map +1 -0
  10. package/payload/platform/plugins/scheduling/mcp/dist/lib/d1-command.d.ts +12 -0
  11. package/payload/platform/plugins/scheduling/mcp/dist/lib/d1-command.d.ts.map +1 -0
  12. package/payload/platform/plugins/scheduling/mcp/dist/lib/d1-command.js +14 -0
  13. package/payload/platform/plugins/scheduling/mcp/dist/lib/d1-command.js.map +1 -0
  14. package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js +3 -1
  15. package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js.map +1 -1
  16. package/payload/platform/plugins/whatsapp/references/channels-whatsapp.md +1 -1
  17. package/payload/platform/services/claude-session-manager/dist/account-title-stores.d.ts +21 -0
  18. package/payload/platform/services/claude-session-manager/dist/account-title-stores.d.ts.map +1 -0
  19. package/payload/platform/services/claude-session-manager/dist/account-title-stores.js +71 -0
  20. package/payload/platform/services/claude-session-manager/dist/account-title-stores.js.map +1 -0
  21. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts +2 -2
  22. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
  23. package/payload/platform/services/claude-session-manager/dist/http-server.js +46 -103
  24. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  25. package/payload/platform/services/claude-session-manager/dist/index.js +13 -8
  26. package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
  27. package/payload/server/package.json +2 -1
  28. package/payload/server/public/assets/{AdminLoginScreens-C_Qn0UPy.js → AdminLoginScreens-C32Kg8HN.js} +1 -1
  29. package/payload/server/public/assets/AdminShell-DizHgGBB.js +1 -0
  30. package/payload/server/public/assets/{Checkbox-B76SHnPC.js → Checkbox-C-dvkjKb.js} +1 -1
  31. package/payload/server/public/assets/{admin-RTEhnrPk.js → admin-CSBsndZ4.js} +1 -1
  32. package/payload/server/public/assets/admin-types-hioowVct.js +1 -0
  33. package/payload/server/public/assets/{browser-Chmp3Xfv.js → browser-BUuA2PPl.js} +1 -1
  34. package/payload/server/public/assets/{calendar-CjE7hiqV.js → calendar-CGlyx54B.js} +1 -1
  35. package/payload/server/public/assets/chat-DT1PbRkD.js +1 -0
  36. package/payload/server/public/assets/data-BC4KTIX4.js +1 -0
  37. package/payload/server/public/assets/{graph-DEHmvpNl.js → graph-CvQZVxwZ.js} +1 -1
  38. package/payload/server/public/assets/{graph-labels-CYAjU3rz.js → graph-labels-C7bJMcXs.js} +1 -1
  39. package/payload/server/public/assets/{operator-BDTnuQhB.js → operator-4skjNtEa.js} +1 -1
  40. package/payload/server/public/assets/{page-D8FFXoI9.js → page-B0zvkWaG.js} +1 -1
  41. package/payload/server/public/assets/page-BYlBTwqJ.js +32 -0
  42. package/payload/server/public/assets/{public-BIOxrxZK.js → public-ClYyeEA1.js} +1 -1
  43. package/payload/server/public/assets/{rotate-ccw-K1xZvf3B.js → rotate-ccw-DPCP-Lmz.js} +1 -1
  44. package/payload/server/public/assets/useSubAccountSwitcher-B8FEcQNM.js +9 -0
  45. package/payload/server/public/assets/{useSubAccountSwitcher-B44qYovc.css → useSubAccountSwitcher-DqxG4I5C.css} +1 -1
  46. package/payload/server/public/brand/sitedesk-app-icon-192.png +0 -0
  47. package/payload/server/public/brand/sitedesk-app-icon-512.png +0 -0
  48. package/payload/server/public/brand/sitedesk-app-icon-maskable-512.png +0 -0
  49. package/payload/server/public/brand/sitedesk-black.png +0 -0
  50. package/payload/server/public/brand/sitedesk-favicon-180.png +0 -0
  51. package/payload/server/public/brand/sitedesk-favicon-32.png +0 -0
  52. package/payload/server/public/brand/sitedesk-favicon-512.png +0 -0
  53. package/payload/server/public/brand/sitedesk-horizontal-dark.png +0 -0
  54. package/payload/server/public/brand/sitedesk-horizontal.png +0 -0
  55. package/payload/server/public/brand/sitedesk-icon.svg +4 -4
  56. package/payload/server/public/brand/sitedesk-monochrome.png +0 -0
  57. package/payload/server/public/brand/sitedesk-og-image.png +0 -0
  58. package/payload/server/public/brand/sitedesk-square.png +0 -0
  59. package/payload/server/public/brand/sitedesk-tile.png +0 -0
  60. package/payload/server/public/brand/sitedesk-white.png +0 -0
  61. package/payload/server/public/brand-defaults.css +8 -8
  62. package/payload/server/public/browser.html +4 -4
  63. package/payload/server/public/calendar.html +4 -4
  64. package/payload/server/public/chat.html +7 -7
  65. package/payload/server/public/data.html +5 -5
  66. package/payload/server/public/graph.html +7 -7
  67. package/payload/server/public/index.html +9 -9
  68. package/payload/server/public/operator.html +9 -9
  69. package/payload/server/public/public.html +7 -7
  70. package/payload/server/server.js +150 -21
  71. package/payload/server/public/assets/AdminShell-iHdYhspw.js +0 -1
  72. package/payload/server/public/assets/admin-types-DJoj6VJv.js +0 -1
  73. package/payload/server/public/assets/chat-DiKmCMO1.js +0 -1
  74. package/payload/server/public/assets/data-5PpEsUR3.js +0 -1
  75. package/payload/server/public/assets/page-HeiBebPq.js +0 -32
  76. package/payload/server/public/assets/useSubAccountSwitcher-DPEkYkYd.js +0 -9
@@ -1,8 +1,8 @@
1
1
  <svg width="600" height="600" viewBox="0 0 600 600" fill="none" xmlns="http://www.w3.org/2000/svg">
2
- <path d="M340 60 L60 60 L60 540 L540 540 L540 250" stroke="#2A2D38" stroke-width="46" stroke-linecap="square" stroke-linejoin="miter"/>
2
+ <path d="M340 60 L60 60 L60 540 L540 540 L540 250" stroke="#1a1a1a" stroke-width="46" stroke-linecap="square" stroke-linejoin="miter"/>
3
3
  <g transform="rotate(38 415 150)">
4
- <rect x="358" y="96" width="150" height="46" rx="8" fill="#FF6A00"/>
5
- <path d="M358 96 Q336 114 350 148 L372 140 Q360 120 378 108 Z" fill="#FF6A00"/>
6
- <rect x="418" y="140" width="26" height="120" rx="11" fill="#FF6A00"/>
4
+ <rect x="358" y="96" width="150" height="46" rx="8" fill="#ea7232"/>
5
+ <path d="M358 96 Q336 114 350 148 L372 140 Q360 120 378 108 Z" fill="#ea7232"/>
6
+ <rect x="418" y="140" width="26" height="120" rx="11" fill="#ea7232"/>
7
7
  </g>
8
8
  </svg>
@@ -1,12 +1,12 @@
1
1
  :root {
2
2
  /* Brand defaults — generated by bundle.js from brands/sitedesk-code/brand.json */
3
- --sage: #FF6A00;
4
- --sage-hover: #E65F00;
5
- --sage-subtle: rgba(255, 106, 0, 0.08);
6
- --sage-glow: rgba(255, 106, 0, 0.15);
7
- --visitor-bubble: #E8ECF0;
8
- --bg: #F6F5F2;
9
- --maxy-bubble: #F5F2ED;
10
- --font-display: 'Newsreader', Georgia, serif;
3
+ --sage: #ea7232;
4
+ --sage-hover: #CE642C;
5
+ --sage-subtle: rgba(234, 114, 50, 0.08);
6
+ --sage-glow: rgba(234, 114, 50, 0.18);
7
+ --visitor-bubble: #FFF5EF;
8
+ --bg: #FAFAF8;
9
+ --maxy-bubble: #ECECE6;
10
+ --font-display: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
11
11
  --font-body: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
12
12
  }
@@ -5,11 +5,11 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>Browser — Maxy</title>
7
7
  <link rel="icon" href="/favicon.ico">
8
- <script type="module" crossorigin src="/assets/browser-Chmp3Xfv.js"></script>
8
+ <script type="module" crossorigin src="/assets/browser-BUuA2PPl.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="/assets/chunk-CAM3fms7.js">
10
- <link rel="modulepreload" crossorigin href="/assets/useSubAccountSwitcher-DPEkYkYd.js">
11
- <link rel="modulepreload" crossorigin href="/assets/AdminShell-iHdYhspw.js">
12
- <link rel="stylesheet" crossorigin href="/assets/useSubAccountSwitcher-B44qYovc.css">
10
+ <link rel="modulepreload" crossorigin href="/assets/useSubAccountSwitcher-B8FEcQNM.js">
11
+ <link rel="modulepreload" crossorigin href="/assets/AdminShell-DizHgGBB.js">
12
+ <link rel="stylesheet" crossorigin href="/assets/useSubAccountSwitcher-DqxG4I5C.css">
13
13
  </head>
14
14
  <body>
15
15
  <div id="root"></div>
@@ -5,11 +5,11 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>Calendar — Maxy</title>
7
7
  <link rel="icon" href="/favicon.ico">
8
- <script type="module" crossorigin src="/assets/calendar-CjE7hiqV.js"></script>
8
+ <script type="module" crossorigin src="/assets/calendar-CGlyx54B.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="/assets/chunk-CAM3fms7.js">
10
- <link rel="modulepreload" crossorigin href="/assets/useSubAccountSwitcher-DPEkYkYd.js">
11
- <link rel="modulepreload" crossorigin href="/assets/AdminShell-iHdYhspw.js">
12
- <link rel="stylesheet" crossorigin href="/assets/useSubAccountSwitcher-B44qYovc.css">
10
+ <link rel="modulepreload" crossorigin href="/assets/useSubAccountSwitcher-B8FEcQNM.js">
11
+ <link rel="modulepreload" crossorigin href="/assets/AdminShell-DizHgGBB.js">
12
+ <link rel="stylesheet" crossorigin href="/assets/useSubAccountSwitcher-DqxG4I5C.css">
13
13
  </head>
14
14
  <body>
15
15
  <div id="root"></div>
@@ -5,15 +5,15 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>Chat — Maxy</title>
7
7
  <link rel="icon" href="/favicon.ico">
8
- <script type="module" crossorigin src="/assets/chat-DiKmCMO1.js"></script>
8
+ <script type="module" crossorigin src="/assets/chat-DT1PbRkD.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="/assets/chunk-CAM3fms7.js">
10
- <link rel="modulepreload" crossorigin href="/assets/useSubAccountSwitcher-DPEkYkYd.js">
11
- <link rel="modulepreload" crossorigin href="/assets/AdminShell-iHdYhspw.js">
12
- <link rel="modulepreload" crossorigin href="/assets/admin-types-DJoj6VJv.js">
10
+ <link rel="modulepreload" crossorigin href="/assets/useSubAccountSwitcher-B8FEcQNM.js">
11
+ <link rel="modulepreload" crossorigin href="/assets/AdminShell-DizHgGBB.js">
12
+ <link rel="modulepreload" crossorigin href="/assets/admin-types-hioowVct.js">
13
13
  <link rel="modulepreload" crossorigin href="/assets/preload-helper-B_l5jfgx.js">
14
- <link rel="modulepreload" crossorigin href="/assets/rotate-ccw-K1xZvf3B.js">
15
- <link rel="modulepreload" crossorigin href="/assets/page-HeiBebPq.js">
16
- <link rel="stylesheet" crossorigin href="/assets/useSubAccountSwitcher-B44qYovc.css">
14
+ <link rel="modulepreload" crossorigin href="/assets/rotate-ccw-DPCP-Lmz.js">
15
+ <link rel="modulepreload" crossorigin href="/assets/page-BYlBTwqJ.js">
16
+ <link rel="stylesheet" crossorigin href="/assets/useSubAccountSwitcher-DqxG4I5C.css">
17
17
  </head>
18
18
  <body>
19
19
  <div id="root"></div>
@@ -5,12 +5,12 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>Data — Maxy</title>
7
7
  <link rel="icon" href="/favicon.ico">
8
- <script type="module" crossorigin src="/assets/data-5PpEsUR3.js"></script>
8
+ <script type="module" crossorigin src="/assets/data-BC4KTIX4.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="/assets/chunk-CAM3fms7.js">
10
- <link rel="modulepreload" crossorigin href="/assets/useSubAccountSwitcher-DPEkYkYd.js">
11
- <link rel="modulepreload" crossorigin href="/assets/graph-labels-CYAjU3rz.js">
12
- <link rel="modulepreload" crossorigin href="/assets/page-D8FFXoI9.js">
13
- <link rel="stylesheet" crossorigin href="/assets/useSubAccountSwitcher-B44qYovc.css">
10
+ <link rel="modulepreload" crossorigin href="/assets/useSubAccountSwitcher-B8FEcQNM.js">
11
+ <link rel="modulepreload" crossorigin href="/assets/graph-labels-C7bJMcXs.js">
12
+ <link rel="modulepreload" crossorigin href="/assets/page-B0zvkWaG.js">
13
+ <link rel="stylesheet" crossorigin href="/assets/useSubAccountSwitcher-DqxG4I5C.css">
14
14
  </head>
15
15
  <body>
16
16
  <div id="root"></div>
@@ -5,14 +5,14 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>Graph — Maxy</title>
7
7
  <link rel="icon" href="/favicon.ico">
8
- <script type="module" crossorigin src="/assets/graph-DEHmvpNl.js"></script>
8
+ <script type="module" crossorigin src="/assets/graph-CvQZVxwZ.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="/assets/chunk-CAM3fms7.js">
10
- <link rel="modulepreload" crossorigin href="/assets/useSubAccountSwitcher-DPEkYkYd.js">
11
- <link rel="modulepreload" crossorigin href="/assets/graph-labels-CYAjU3rz.js">
12
- <link rel="modulepreload" crossorigin href="/assets/AdminShell-iHdYhspw.js">
13
- <link rel="modulepreload" crossorigin href="/assets/Checkbox-B76SHnPC.js">
14
- <link rel="modulepreload" crossorigin href="/assets/rotate-ccw-K1xZvf3B.js">
15
- <link rel="stylesheet" crossorigin href="/assets/useSubAccountSwitcher-B44qYovc.css">
10
+ <link rel="modulepreload" crossorigin href="/assets/useSubAccountSwitcher-B8FEcQNM.js">
11
+ <link rel="modulepreload" crossorigin href="/assets/graph-labels-C7bJMcXs.js">
12
+ <link rel="modulepreload" crossorigin href="/assets/AdminShell-DizHgGBB.js">
13
+ <link rel="modulepreload" crossorigin href="/assets/Checkbox-C-dvkjKb.js">
14
+ <link rel="modulepreload" crossorigin href="/assets/rotate-ccw-DPCP-Lmz.js">
15
+ <link rel="stylesheet" crossorigin href="/assets/useSubAccountSwitcher-DqxG4I5C.css">
16
16
  </head>
17
17
  <body>
18
18
  <div id="root"></div>
@@ -5,16 +5,16 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>SiteDesk</title>
7
7
  <link rel="icon" href="/favicon.ico">
8
- <script type="module" crossorigin src="/assets/admin-RTEhnrPk.js"></script>
8
+ <script type="module" crossorigin src="/assets/admin-CSBsndZ4.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="/assets/chunk-CAM3fms7.js">
10
- <link rel="modulepreload" crossorigin href="/assets/useSubAccountSwitcher-DPEkYkYd.js">
11
- <link rel="modulepreload" crossorigin href="/assets/graph-labels-CYAjU3rz.js">
12
- <link rel="modulepreload" crossorigin href="/assets/AdminShell-iHdYhspw.js">
13
- <link rel="modulepreload" crossorigin href="/assets/admin-types-DJoj6VJv.js">
14
- <link rel="modulepreload" crossorigin href="/assets/Checkbox-B76SHnPC.js">
15
- <link rel="modulepreload" crossorigin href="/assets/AdminLoginScreens-C_Qn0UPy.js">
16
- <link rel="modulepreload" crossorigin href="/assets/page-D8FFXoI9.js">
17
- <link rel="stylesheet" crossorigin href="/assets/useSubAccountSwitcher-B44qYovc.css">
10
+ <link rel="modulepreload" crossorigin href="/assets/useSubAccountSwitcher-B8FEcQNM.js">
11
+ <link rel="modulepreload" crossorigin href="/assets/graph-labels-C7bJMcXs.js">
12
+ <link rel="modulepreload" crossorigin href="/assets/AdminShell-DizHgGBB.js">
13
+ <link rel="modulepreload" crossorigin href="/assets/admin-types-hioowVct.js">
14
+ <link rel="modulepreload" crossorigin href="/assets/Checkbox-C-dvkjKb.js">
15
+ <link rel="modulepreload" crossorigin href="/assets/AdminLoginScreens-C32Kg8HN.js">
16
+ <link rel="modulepreload" crossorigin href="/assets/page-B0zvkWaG.js">
17
+ <link rel="stylesheet" crossorigin href="/assets/useSubAccountSwitcher-DqxG4I5C.css">
18
18
  <link rel="stylesheet" crossorigin href="/assets/AdminLoginScreens-CWMpccrR.css">
19
19
  <link rel="stylesheet" href="/brand-defaults.css">
20
20
  </head>
@@ -5,17 +5,17 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>Operator — Maxy</title>
7
7
  <link rel="icon" href="/favicon.ico">
8
- <script type="module" crossorigin src="/assets/operator-BDTnuQhB.js"></script>
8
+ <script type="module" crossorigin src="/assets/operator-4skjNtEa.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="/assets/chunk-CAM3fms7.js">
10
- <link rel="modulepreload" crossorigin href="/assets/useSubAccountSwitcher-DPEkYkYd.js">
11
- <link rel="modulepreload" crossorigin href="/assets/AdminShell-iHdYhspw.js">
12
- <link rel="modulepreload" crossorigin href="/assets/admin-types-DJoj6VJv.js">
13
- <link rel="modulepreload" crossorigin href="/assets/Checkbox-B76SHnPC.js">
14
- <link rel="modulepreload" crossorigin href="/assets/AdminLoginScreens-C_Qn0UPy.js">
10
+ <link rel="modulepreload" crossorigin href="/assets/useSubAccountSwitcher-B8FEcQNM.js">
11
+ <link rel="modulepreload" crossorigin href="/assets/AdminShell-DizHgGBB.js">
12
+ <link rel="modulepreload" crossorigin href="/assets/admin-types-hioowVct.js">
13
+ <link rel="modulepreload" crossorigin href="/assets/Checkbox-C-dvkjKb.js">
14
+ <link rel="modulepreload" crossorigin href="/assets/AdminLoginScreens-C32Kg8HN.js">
15
15
  <link rel="modulepreload" crossorigin href="/assets/preload-helper-B_l5jfgx.js">
16
- <link rel="modulepreload" crossorigin href="/assets/rotate-ccw-K1xZvf3B.js">
17
- <link rel="modulepreload" crossorigin href="/assets/page-HeiBebPq.js">
18
- <link rel="stylesheet" crossorigin href="/assets/useSubAccountSwitcher-B44qYovc.css">
16
+ <link rel="modulepreload" crossorigin href="/assets/rotate-ccw-DPCP-Lmz.js">
17
+ <link rel="modulepreload" crossorigin href="/assets/page-BYlBTwqJ.js">
18
+ <link rel="stylesheet" crossorigin href="/assets/useSubAccountSwitcher-DqxG4I5C.css">
19
19
  <link rel="stylesheet" crossorigin href="/assets/AdminLoginScreens-CWMpccrR.css">
20
20
  </head>
21
21
  <body>
@@ -5,15 +5,15 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>SiteDesk</title>
7
7
  <link rel="icon" href="/favicon.ico">
8
- <script type="module" crossorigin src="/assets/public-BIOxrxZK.js"></script>
8
+ <script type="module" crossorigin src="/assets/public-ClYyeEA1.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="/assets/chunk-CAM3fms7.js">
10
- <link rel="modulepreload" crossorigin href="/assets/useSubAccountSwitcher-DPEkYkYd.js">
11
- <link rel="modulepreload" crossorigin href="/assets/AdminShell-iHdYhspw.js">
12
- <link rel="modulepreload" crossorigin href="/assets/admin-types-DJoj6VJv.js">
10
+ <link rel="modulepreload" crossorigin href="/assets/useSubAccountSwitcher-B8FEcQNM.js">
11
+ <link rel="modulepreload" crossorigin href="/assets/AdminShell-DizHgGBB.js">
12
+ <link rel="modulepreload" crossorigin href="/assets/admin-types-hioowVct.js">
13
13
  <link rel="modulepreload" crossorigin href="/assets/preload-helper-B_l5jfgx.js">
14
- <link rel="modulepreload" crossorigin href="/assets/rotate-ccw-K1xZvf3B.js">
15
- <link rel="modulepreload" crossorigin href="/assets/page-HeiBebPq.js">
16
- <link rel="stylesheet" crossorigin href="/assets/useSubAccountSwitcher-B44qYovc.css">
14
+ <link rel="modulepreload" crossorigin href="/assets/rotate-ccw-DPCP-Lmz.js">
15
+ <link rel="modulepreload" crossorigin href="/assets/page-BYlBTwqJ.js">
16
+ <link rel="stylesheet" crossorigin href="/assets/useSubAccountSwitcher-DqxG4I5C.css">
17
17
  <link rel="stylesheet" href="/brand-defaults.css">
18
18
  </head>
19
19
  <body class="public-surface">
@@ -5272,6 +5272,92 @@ function resolveScratchpadPath(raw, scratchpadRootAbs) {
5272
5272
  return resolveUnderRoot(raw, scratchpadRootAbs, "scratchpad");
5273
5273
  }
5274
5274
 
5275
+ // app/lib/doc-to-text.ts
5276
+ import { unzipSync, strFromU8 } from "fflate";
5277
+ var DOCX = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
5278
+ var ODT = "application/vnd.oasis.opendocument.text";
5279
+ var CONVERTIBLE_DOC_MIME = /* @__PURE__ */ new Set([
5280
+ DOCX,
5281
+ ODT,
5282
+ "text/rtf",
5283
+ "application/rtf"
5284
+ ]);
5285
+ function bareMime(mimeType) {
5286
+ return mimeType.split(";")[0].trim().toLowerCase();
5287
+ }
5288
+ function unescapeXml(s) {
5289
+ return s.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&apos;/g, "'").replace(/&amp;/g, "&");
5290
+ }
5291
+ function unzipEntry(buffer, entry) {
5292
+ const files = unzipSync(new Uint8Array(buffer));
5293
+ const bytes = files[entry];
5294
+ if (!bytes) throw new Error(`zip entry not found: ${entry}`);
5295
+ return strFromU8(bytes);
5296
+ }
5297
+ function docxToText(buffer) {
5298
+ const xml = unzipEntry(buffer, "word/document.xml");
5299
+ const paras = [];
5300
+ for (const p of xml.split("</w:p>")) {
5301
+ const withBreaks = p.replace(/<w:tab\b[^>]*\/?>/g, " ").replace(/<w:br\b[^>]*\/?>/g, "\n");
5302
+ let line = "";
5303
+ for (const m of withBreaks.matchAll(/<w:t\b[^>]*>([\s\S]*?)<\/w:t>/g)) {
5304
+ line += unescapeXml(m[1]);
5305
+ }
5306
+ if (line.length > 0) paras.push(line);
5307
+ }
5308
+ return paras.join("\n");
5309
+ }
5310
+ function odtToText(buffer) {
5311
+ const xml = unzipEntry(buffer, "content.xml");
5312
+ const body = xml.replace(/^[\s\S]*?<office:text\b[^>]*>/, "").replace(/<\/office:text>[\s\S]*$/, "");
5313
+ const withBreaks = body.replace(/<text:line-break\b[^>]*\/?>/g, "\n").replace(/<text:tab\b[^>]*\/?>/g, " ").replace(/<\/text:(?:p|h)>/g, "\n");
5314
+ const stripped = withBreaks.replace(/<[^>]+>/g, "");
5315
+ return unescapeXml(stripped).replace(/\n{3,}/g, "\n\n").trim();
5316
+ }
5317
+ var RTF_DROP_DEST = /^\\(?:\*|fonttbl|colortbl|stylesheet|listtable|info|pict)\b/;
5318
+ function stripRtfDestinations(s) {
5319
+ let out = "";
5320
+ for (let i = 0; i < s.length; i++) {
5321
+ const ch = s[i];
5322
+ if (ch === "\\" && i + 1 < s.length) {
5323
+ out += ch + s[i + 1];
5324
+ i++;
5325
+ continue;
5326
+ }
5327
+ if (ch === "{" && RTF_DROP_DEST.test(s.slice(i + 1))) {
5328
+ let depth = 1;
5329
+ let j = i + 1;
5330
+ for (; j < s.length && depth > 0; j++) {
5331
+ if (s[j] === "\\") {
5332
+ j++;
5333
+ continue;
5334
+ }
5335
+ if (s[j] === "{") depth++;
5336
+ else if (s[j] === "}") depth--;
5337
+ }
5338
+ i = j - 1;
5339
+ continue;
5340
+ }
5341
+ out += ch;
5342
+ }
5343
+ return out;
5344
+ }
5345
+ function rtfToText(rtf) {
5346
+ let s = stripRtfDestinations(rtf);
5347
+ s = s.replace(/\\par[d]?\b/g, "\n").replace(/\\line\b/g, "\n").replace(/\\tab\b/g, " ");
5348
+ s = s.replace(/\\'([0-9a-fA-F]{2})/g, (_m, h) => String.fromCharCode(parseInt(h, 16)));
5349
+ s = s.replace(/\\[a-zA-Z]+-?\d* ?/g, "");
5350
+ s = s.replace(/\\([{}\\])/g, "$1").replace(/[{}]/g, "");
5351
+ return s.replace(/[ \t]{2,}/g, " ").replace(/\n{3,}/g, "\n\n").trim();
5352
+ }
5353
+ function docToText(buffer, mimeType) {
5354
+ const mime = bareMime(mimeType);
5355
+ if (mime === DOCX) return docxToText(buffer);
5356
+ if (mime === ODT) return odtToText(buffer);
5357
+ if (mime === "text/rtf" || mime === "application/rtf") return rtfToText(buffer.toString("latin1"));
5358
+ return null;
5359
+ }
5360
+
5275
5361
  // app/lib/attachments.ts
5276
5362
  function uploadsDirFor(accountId, subPath, attachmentId) {
5277
5363
  return subPath ? resolve7(DATA_ROOT, "accounts", accountId, "uploads", subPath, attachmentId) : resolve7(DATA_ROOT, "accounts", accountId, "uploads", attachmentId);
@@ -5289,6 +5375,14 @@ var SUPPORTED_MIME_TYPES = /* @__PURE__ */ new Set([
5289
5375
  "text/calendar",
5290
5376
  "application/zip",
5291
5377
  "application/x-zip-compressed",
5378
+ // Task 1347 — Word/OpenDocument/RTF text documents. The bytes are converted to
5379
+ // a readable-text sibling at ingestion (writeAttachment → doc-to-text.ts)
5380
+ // because the on-device Read tool cannot parse the binary containers. rtf is
5381
+ // reported by browsers as either text/rtf or application/rtf.
5382
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
5383
+ "application/vnd.oasis.opendocument.text",
5384
+ "text/rtf",
5385
+ "application/rtf",
5292
5386
  // Task 1240 — voice recordings persist as playable clips in the admin bubble.
5293
5387
  // These match AUDIO_MIME_TYPES in app/lib/stt/audio-mime.ts exactly.
5294
5388
  "audio/ogg",
@@ -5304,6 +5398,7 @@ var MAX_FILE_SIZE_BYTES = 50 * 1024 * 1024;
5304
5398
  var MAX_FILES_PER_MESSAGE = 5;
5305
5399
  var MAX_DATA_UPLOAD_BYTES = 2 * 1024 * 1024 * 1024;
5306
5400
  var MAX_ZIP_UNCOMPRESSED_BYTES = 100 * 1024 * 1024;
5401
+ var EXTRACTED_TEXT_SUFFIX = ".extracted.txt";
5307
5402
  function assertSupportedMime(mimeType) {
5308
5403
  const bare = mimeType.split(";")[0].trim().toLowerCase();
5309
5404
  if (!SUPPORTED_MIME_TYPES.has(bare)) {
@@ -5329,7 +5424,15 @@ async function writeAttachment(accountId, subPath, filename, mimeType, sizeBytes
5329
5424
  };
5330
5425
  await writeFile2(storagePath, buffer);
5331
5426
  await writeFile2(metaPath, JSON.stringify(meta, null, 2));
5332
- return { attachmentId, filename, storagePath, metaPath, mimeType, sizeBytes };
5427
+ let readableTextPath;
5428
+ if (CONVERTIBLE_DOC_MIME.has(mimeType.split(";")[0].trim().toLowerCase())) {
5429
+ const text = docToText(buffer, mimeType);
5430
+ if (text) {
5431
+ readableTextPath = resolve7(dir, `${attachmentId}${EXTRACTED_TEXT_SUFFIX}`);
5432
+ await writeFile2(readableTextPath, text);
5433
+ }
5434
+ }
5435
+ return { attachmentId, filename, storagePath, metaPath, mimeType, sizeBytes, readableTextPath };
5333
5436
  }
5334
5437
  async function storeAttachment(accountId, file) {
5335
5438
  assertSupportedMime(file.type);
@@ -5370,6 +5473,8 @@ var MIME_BY_EXT = {
5370
5473
  ".zip": "application/zip",
5371
5474
  ".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
5372
5475
  ".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
5476
+ ".odt": "application/vnd.oasis.opendocument.text",
5477
+ ".rtf": "text/rtf",
5373
5478
  ".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
5374
5479
  ".ics": "text/calendar"
5375
5480
  };
@@ -6223,6 +6328,15 @@ async function loginConnectionLoop(accountId, login) {
6223
6328
  } catch (err) {
6224
6329
  const current = activeLogins.get(accountId);
6225
6330
  if (current?.id !== login.id) return;
6331
+ await drainCredsSaveQueue();
6332
+ const preRetryCensus = credsCensus(login.authDir);
6333
+ if (!preRetryCensus.hasAccountSignature) {
6334
+ current.error = "WhatsApp accepted the code but did not finish linking. This usually means the number has reached its linked-device limit or has a stale linked device. On the phone, open WhatsApp, Linked Devices, remove existing devices, then ask for a new code.";
6335
+ console.error(
6336
+ `${TAG17} op=pairing-incomplete cid=${cidShort} closeKind=${closeKind(getStatusCode(err), false)} reason=no-account-signature`
6337
+ );
6338
+ return;
6339
+ }
6226
6340
  const classification = classifyDisconnect(err);
6227
6341
  if (!classification.shouldRetry || attempt >= LOGIN_MAX_RECONNECTS) {
6228
6342
  if (attempt >= LOGIN_MAX_RECONNECTS) {
@@ -7924,16 +8038,29 @@ function pickActivity(entries, grown, nowMs, concurrencyWindowMs) {
7924
8038
  // server/routes/whatsapp-reader.ts
7925
8039
  var app4 = new Hono();
7926
8040
  app4.get("/conversations", requireAdminSession, async (c) => {
8041
+ const cacheKey = c.var.cacheKey;
8042
+ const scopeAccountId = getAccountIdForSession(cacheKey) ?? null;
8043
+ const validAccounts = listValidAccounts();
8044
+ const multiAccount = validAccounts.length > 1;
8045
+ if (multiAccount && !scopeAccountId) {
8046
+ console.log(`[wa-reader] op=list-scope-unresolved cacheKey=${cacheKey.slice(0, 8)}`);
8047
+ return c.json({ conversations: [] });
8048
+ }
7927
8049
  const cfg = claudeConfigDir();
7928
8050
  if (!cfg) return c.json({ conversations: [] });
7929
8051
  const projectsRoot = join14(cfg, "projects");
7930
8052
  const userTitles = loadUserTitles(ACCOUNTS_DIR ?? null);
7931
8053
  const rows = [];
8054
+ let sessionRowsExcludedUntagged = 0;
7932
8055
  for (const { path: path2 } of enumerateJsonls(projectsRoot)) {
7933
8056
  const sessionId = basename4(path2).replace(/\.jsonl$/, "");
7934
8057
  const projectDir = dirname3(path2);
7935
8058
  const meta = readSidecarMeta(join14(projectDir, `${sessionId}.meta.json`));
7936
8059
  if (!isReaderChannelSession(meta.role, meta.channel)) continue;
8060
+ if (multiAccount) {
8061
+ if (meta.accountId === null) sessionRowsExcludedUntagged += 1;
8062
+ if (meta.accountId !== scopeAccountId) continue;
8063
+ }
7937
8064
  let body = "";
7938
8065
  try {
7939
8066
  body = readFileSync15(path2, "utf8");
@@ -7958,7 +8085,7 @@ app4.get("/conversations", requireAdminSession, async (c) => {
7958
8085
  });
7959
8086
  }
7960
8087
  const sessionRows = selectReaderChannelSessions(rows).filter((r) => r.channel !== "whatsapp");
7961
- const account = resolveAccount();
8088
+ const account = multiAccount ? validAccounts.find((a) => a.accountId === scopeAccountId) ?? null : resolveAccount();
7962
8089
  let users = [];
7963
8090
  if (account) {
7964
8091
  try {
@@ -7991,8 +8118,9 @@ app4.get("/conversations", requireAdminSession, async (c) => {
7991
8118
  const storeRows = account ? buildStoreConversationRows(account.accountId, readConversationSummaries(account.accountId)) : [];
7992
8119
  const adminScope = storeRows.filter((r) => r.scope === "admin").length;
7993
8120
  const publicScope = storeRows.length - adminScope;
8121
+ const sessionRowCount = sessionConversations.length;
7994
8122
  console.log(
7995
- `[wa-reader] op=list accountId=${account?.accountId ?? "null"} conversations=${storeRows.length} adminScope=${adminScope} publicScope=${publicScope}`
8123
+ `[wa-reader] op=list pinnedAccount=${scopeAccountId?.slice(0, 8) ?? "null"} resolvedAccount=${account?.accountId.slice(0, 8) ?? "null"} multiAccount=${multiAccount} conversations=${sessionRowCount + storeRows.length} sessionRows=${sessionRowCount} storeRows=${storeRows.length} adminScope=${adminScope} publicScope=${publicScope} sessionRowsExcludedUntagged=${sessionRowsExcludedUntagged}`
7996
8124
  );
7997
8125
  return c.json({ conversations: [...sessionConversations, ...storeRows] });
7998
8126
  });
@@ -8730,7 +8858,7 @@ app5.get("/attachment/:attachmentId", (c) => {
8730
8858
  let dataFile;
8731
8859
  let buffer;
8732
8860
  try {
8733
- dataFile = readdirSync9(dir).find((f) => !f.endsWith(".meta.json"));
8861
+ dataFile = readdirSync9(dir).find((f) => !f.endsWith(".meta.json") && !f.endsWith(EXTRACTED_TEXT_SUFFIX));
8734
8862
  if (!dataFile) throw new Error("no data file");
8735
8863
  buffer = readFileSync16(resolve13(dir, dataFile));
8736
8864
  } catch {
@@ -9359,8 +9487,13 @@ ${result.result.text}` : result.result.text;
9359
9487
  console.error(`[webchat:inbound] op=send-refused kind=files reason=store-failed detail=${detail}`);
9360
9488
  return c.json({ error: "failed to store attachment" }, 500);
9361
9489
  }
9490
+ for (const s of stored) {
9491
+ const dot = s.filename.lastIndexOf(".");
9492
+ const ext = dot >= 0 ? s.filename.slice(dot).toLowerCase() : "";
9493
+ console.log(`[attach-ingest] mime=${s.mimeType} ext=${ext} converted=${!!s.readableTextPath} path=${s.storagePath}`);
9494
+ }
9362
9495
  if (stored.length > 0) {
9363
- const listing = stored.map((s) => `${s.filename} (${s.storagePath})`).join(", ");
9496
+ const listing = stored.map((s) => `${s.filename} (${s.readableTextPath ?? s.storagePath})`).join(", ");
9364
9497
  const note = `[The operator uploaded ${stored.length} file(s): ${listing}]`;
9365
9498
  text = text.length > 0 ? `${text}
9366
9499
 
@@ -11118,7 +11251,7 @@ app15.get("/:attachmentId", requireAdminSession, async (c) => {
11118
11251
  return new Response("Not found", { status: 404 });
11119
11252
  }
11120
11253
  const entries = await readdir(dir);
11121
- const dataFile = entries.find((f) => !f.endsWith(".meta.json"));
11254
+ const dataFile = entries.find((f) => !f.endsWith(".meta.json") && !f.endsWith(EXTRACTED_TEXT_SUFFIX));
11122
11255
  if (!dataFile) {
11123
11256
  return new Response("Not found", { status: 404 });
11124
11257
  }
@@ -13598,11 +13731,11 @@ app21.get("/download", requireAdminSession, async (c) => {
13598
13731
  const nodeStream = createReadStream2(absolute);
13599
13732
  const webStream = Readable2.toWeb(nodeStream);
13600
13733
  if (disposition === "inline") {
13601
- if (!mimeType.startsWith("image/")) {
13602
- console.error(`[data] op=thumb-refused path="${relPath}" mime="${mimeType}" reason=not-image`);
13603
- return c.json({ error: "Inline serve is image-only" }, 400);
13734
+ if (!mimeType.startsWith("image/") && mimeType !== "application/pdf") {
13735
+ console.error(`[data] op=inline-refused path="${relPath}" mime="${mimeType}" reason=not-image-or-pdf`);
13736
+ return c.json({ error: "Inline serve is image- or PDF-only" }, 400);
13604
13737
  }
13605
- console.error(`[data] op=thumb-serve path="${relPath}" mime="${mimeType}" size=${info.size} status=200`);
13738
+ console.error(`[data] op=inline-serve path="${relPath}" mime="${mimeType}" size=${info.size} status=200`);
13606
13739
  return new Response(webStream, {
13607
13740
  status: 200,
13608
13741
  headers: {
@@ -16546,10 +16679,8 @@ app29.post("/", requireAdminSession, async (c) => {
16546
16679
  return c.json({ error: "sessionId must be a v4 UUID" }, 400);
16547
16680
  }
16548
16681
  const base = managerBase("session-delete:wrapper");
16549
- const accountId = getAccountIdForSession(c.var.cacheKey);
16550
- const acctQuery = accountId ? `?accountId=${encodeURIComponent(accountId)}` : "";
16551
16682
  try {
16552
- const stop = await fetch(`${base}/${sessionId}/stop${acctQuery}`, { method: "POST" });
16683
+ const stop = await fetch(`${base}/${sessionId}/stop`, { method: "POST" });
16553
16684
  if (stop.status !== 204 && stop.status !== 200 && stop.status !== 404) {
16554
16685
  console.error(`[session-delete] sessionId=${sessionId} stop-status=${stop.status}`);
16555
16686
  return c.json({ error: `stop-failed-${stop.status}` }, 502);
@@ -16560,7 +16691,7 @@ app29.post("/", requireAdminSession, async (c) => {
16560
16691
  }
16561
16692
  let del;
16562
16693
  try {
16563
- del = await fetch(`${base}/${sessionId}${acctQuery}`, { method: "DELETE" });
16694
+ del = await fetch(`${base}/${sessionId}`, { method: "DELETE" });
16564
16695
  } catch (err) {
16565
16696
  console.error(`[session-delete] sessionId=${sessionId} delete-unreachable err=${err instanceof Error ? err.message : String(err)}`);
16566
16697
  return c.json({ error: "manager-unreachable" }, 502);
@@ -16589,11 +16720,9 @@ app30.post("/", requireAdminSession, async (c) => {
16589
16720
  if (!SESSION_ID_RE2.test(sessionId)) {
16590
16721
  return c.json({ error: "sessionId must be a v4 UUID" }, 400);
16591
16722
  }
16592
- const accountId = getAccountIdForSession(c.var.cacheKey);
16593
- const acctQuery = accountId ? `?accountId=${encodeURIComponent(accountId)}` : "";
16594
16723
  let res;
16595
16724
  try {
16596
- res = await fetch(`${managerBase("session-stop:wrapper")}/${sessionId}/stop${acctQuery}`, { method: "POST" });
16725
+ res = await fetch(`${managerBase("session-stop:wrapper")}/${sessionId}/stop`, { method: "POST" });
16597
16726
  } catch (err) {
16598
16727
  console.error(`[session-stop] sessionId=${sessionId} manager-unreachable err=${err instanceof Error ? err.message : String(err)}`);
16599
16728
  return c.json({ error: "manager-unreachable" }, 502);
@@ -22856,14 +22985,14 @@ var chatRoutes = createChatRoutes({
22856
22985
  awaitReply: (key, timeoutMs) => webchatGateway.awaitReply(key, timeoutMs)
22857
22986
  });
22858
22987
  app55.use("*", clientIpMiddleware);
22988
+ function allowsSameOriginFraming(path2) {
22989
+ return path2 === "/vnc-viewer.html" || path2.startsWith("/api/admin/attachment/") || path2.startsWith("/api/public-reader/attachment/") || path2 === "/api/admin/files/download";
22990
+ }
22859
22991
  app55.use("*", async (c, next) => {
22860
22992
  await next();
22861
22993
  c.header("X-Content-Type-Options", "nosniff");
22862
22994
  c.header("Referrer-Policy", "strict-origin-when-cross-origin");
22863
- c.header(
22864
- "X-Frame-Options",
22865
- c.req.path === "/vnc-viewer.html" ? "SAMEORIGIN" : "DENY"
22866
- );
22995
+ c.header("X-Frame-Options", allowsSameOriginFraming(c.req.path) ? "SAMEORIGIN" : "DENY");
22867
22996
  });
22868
22997
  var HTTP_LOG_PATHS = /* @__PURE__ */ new Set(["/vnc-viewer.html", "/vnc-popout.html"]);
22869
22998
  app55.use("*", async (c, next) => {