@openchambery/web 1.19.0-beta.9 → 1.19.0

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 (126) hide show
  1. package/dist/assets/AgentAvatar-DgGHpQoD.js +1 -0
  2. package/dist/assets/AssistantView-WZ8qXOm6.js +1 -0
  3. package/dist/assets/{ChatContainer-Dvicpi3T.js → ChatContainer-CPOlhHJn.js} +41 -43
  4. package/dist/assets/ContextPanel-ClzJl6RQ.js +288 -0
  5. package/dist/assets/{DiagramView-Ct9M_fMh.js → DiagramView-BFE0XxUH.js} +1 -1
  6. package/dist/assets/{FadeInOnReveal-By2F9vcI.js → FadeInOnReveal-BpIMrqet.js} +1 -1
  7. package/dist/assets/{Icon-DpjYnXxn.js → Icon-Bs6GJIoO.js} +1 -1
  8. package/dist/assets/{MarkdownRendererImpl-CTTZH1DE.js → MarkdownRendererImpl-BisXjTdJ.js} +1 -1
  9. package/dist/assets/{MobileDetailNavigation-BMQiOv_u.js → MobileDetailNavigation-DRiFdQXq.js} +1 -1
  10. package/dist/assets/{MobileShareBridge-D5J6Qnvn.js → MobileShareBridge-D-kwfbug.js} +2 -2
  11. package/dist/assets/MobileSurface-NsB1sKld.js +2 -0
  12. package/dist/assets/{MultiRunWindow-Bw_vmN_V.js → MultiRunWindow-C_Tbyfco.js} +1 -1
  13. package/dist/assets/{OnboardingScreen-BKmuT7AL.js → OnboardingScreen-n85WAcBc.js} +1 -1
  14. package/dist/assets/OverlayScrollbar-VZKKu-cu.js +2 -0
  15. package/dist/assets/{SettingsView-BcFNPdSl.js → SettingsView-BOrARuHr.js} +10 -10
  16. package/dist/assets/{SettingsWindow-5QE3UEs3.js → SettingsWindow-BmegFGj-.js} +1 -1
  17. package/dist/assets/{TerminalView-DyW2LZuM.js → TerminalView-BcFMX_mg.js} +1 -1
  18. package/dist/assets/{ToolOutputDialog-CZPvZV_w.js → ToolOutputDialog-DN2IYmqU.js} +4 -4
  19. package/dist/assets/appThemeRegistry-7v5TIiNK.js +2 -0
  20. package/dist/assets/{button-C7OXr4ae.js → button-BkTMa7Qj.js} +1 -1
  21. package/dist/assets/{clipboard-DWuULPzo.js → clipboard-BL4PvBYZ.js} +1 -1
  22. package/dist/assets/{collapsible-DaEya6b6.js → collapsible-CVL-5iEB.js} +1 -1
  23. package/dist/assets/{desktopHosts-Txp4xOVQ.js → desktopHosts-Dzx3McaD.js} +1 -1
  24. package/dist/assets/{desktopRelayRestore-C_FSEHKM.js → desktopRelayRestore-B9S0Rp5s.js} +1 -1
  25. package/dist/assets/dialog-CD0j-atu.js +1 -0
  26. package/dist/assets/{es-BX0Vm3Ac.js → es-C-RVtNF4.js} +2 -2
  27. package/dist/assets/{fileQueries-B_fTkH6s.js → fileQueries-_VUJM8AE.js} +1 -1
  28. package/dist/assets/{fr-CuPzXTYx.js → fr-C6VZ9yt-.js} +4 -4
  29. package/dist/assets/{gitApi-DAUlmpqX.js → gitApi-CxPLKmZ2.js} +3 -3
  30. package/dist/assets/{input-BzYA603C.js → input-Ca2tUhgN.js} +1 -1
  31. package/dist/assets/insertionBoundaries-2Mzsx_VV.js +4 -0
  32. package/dist/assets/{ja-DGtzjrFO.js → ja-BdksT20v.js} +3 -3
  33. package/dist/assets/{ko-DZ9Di0je.js → ko-CvsczTmf.js} +3 -3
  34. package/dist/assets/main-C1IdVCQf.js +29 -0
  35. package/dist/assets/{main-IaZbd8eq.js → main-dGakBRsd.js} +2 -2
  36. package/dist/assets/{markdown-worker-W06-MhF5.js → markdown-worker-9Sn2jsDp.js} +1 -1
  37. package/dist/assets/{markdownTheme-B89dbj3N.js → markdownTheme-DidS-jC5.js} +1 -1
  38. package/dist/assets/{miniChat-Byg-MsGQ.js → miniChat-C8rpOcNP.js} +2 -2
  39. package/dist/assets/mobile-Dm22ebC9.js +2 -0
  40. package/dist/assets/multirun-ColPhFw1.js +4 -0
  41. package/dist/assets/{persistence-6sclr7B6.js → persistence-aCOlo6ew.js} +2 -2
  42. package/dist/assets/pl-C84UGmMr.js +15 -0
  43. package/dist/assets/platform-ulFAVx1H.js +2 -0
  44. package/dist/assets/projectMeta-CKI_msIR.js +3 -0
  45. package/dist/assets/{pt-BR-Brf4RMsw.js → pt-BR-DISmT3zF.js} +2 -2
  46. package/dist/assets/radio-DKNOd1MW.js +1 -0
  47. package/dist/assets/renderElectronMiniChatApp-B8ly-dZn.js +2 -0
  48. package/dist/assets/renderMobileApp-OAlYU54b.js +23 -0
  49. package/dist/assets/{runtimeConfig-CMLxQH75.js → runtimeConfig-QFdp6Itq.js} +1 -1
  50. package/dist/assets/runtimeEndpointReset-MzR_-tYR.js +4 -0
  51. package/dist/assets/{shikiHighlight-g-Djz_ic.js → shikiHighlight-C7KkxQ9i.js} +1 -1
  52. package/dist/assets/{sortable-tabs-strip-nLsPC06f.js → sortable-tabs-strip-Bl26ebY_.js} +1 -1
  53. package/dist/assets/src-BwToVDxi.css +2 -0
  54. package/dist/assets/{store-DQY8Fkb0.js → store-Dge7C5E4.js} +4 -4
  55. package/dist/assets/{terminalApi-BpPeXWIu.js → terminalApi-HsIEks5U.js} +1 -1
  56. package/dist/assets/{tooltip-D_orJMYd.js → tooltip-GC3dg3gO.js} +1 -1
  57. package/dist/assets/{uk-C-wmaPTi.js → uk-Ba5HBTQU.js} +2 -2
  58. package/dist/assets/{url-BsaBG5-1.js → url-BQHM4bC4.js} +1 -1
  59. package/dist/assets/{useAppFontEffects-DcZfHbUS.js → useAppFontEffects-D0FmY4C_.js} +5 -5
  60. package/dist/assets/{useAssistantUIStore-BHsHXCKE.js → useAssistantUIStore-DxZsjSPQ.js} +1 -1
  61. package/dist/assets/{useDesktopWindowControlsLayout-FEUxMDnk.js → useDesktopWindowControlsLayout-Ce9FSwxa.js} +1 -1
  62. package/dist/assets/useEffectiveDirectory-C5CrdVlr.js +1 -0
  63. package/dist/assets/{useFontPreferences-ckzpXQaJ.js → useFontPreferences-DaFspdDd.js} +1 -1
  64. package/dist/assets/useMobileNavigationStore-jKG6OU5F.js +475 -0
  65. package/dist/assets/useSessionAutoCleanup-C6GD9W2z.js +1 -0
  66. package/dist/assets/{useUIStore-DzwCfRqr.js → useUIStore-Wyu09VUF.js} +1 -1
  67. package/dist/assets/{useWorkerHighlightedLines-D6-XaqdP.js → useWorkerHighlightedLines-mc9J5erB.js} +1 -1
  68. package/dist/assets/{utils-B1EK5zKa.js → utils-CJdWZupK.js} +1 -1
  69. package/dist/assets/{zh-CN-DueRrIql.js → zh-CN-BZYwBvs-.js} +2 -2
  70. package/dist/assets/zh-TW-BsJuPsIi.js +15 -0
  71. package/dist/index.html +9 -9
  72. package/dist/mini-chat.html +9 -9
  73. package/dist/mobile.html +9 -9
  74. package/package.json +3 -2
  75. package/server/index.js +12 -15
  76. package/server/lib/config-sync/DOCUMENTATION.md +6 -7
  77. package/server/lib/config-sync/engine.js +0 -8
  78. package/server/lib/config-sync/index.js +0 -7
  79. package/server/lib/config-sync/receiver.js +0 -35
  80. package/server/lib/config-sync/routes.js +8 -41
  81. package/server/lib/config-sync/routes.test.js +1 -38
  82. package/server/lib/notifications/APNS.md +53 -38
  83. package/server/lib/notifications/DOCUMENTATION.md +5 -4
  84. package/server/lib/notifications/apns-runtime.js +235 -71
  85. package/server/lib/notifications/apns-runtime.test.js +447 -0
  86. package/server/lib/notifications/apns-titles.js +212 -0
  87. package/server/lib/notifications/apns-titles.test.js +55 -0
  88. package/server/lib/notifications/routes.js +2 -1
  89. package/server/lib/notifications/runtime.js +5 -13
  90. package/server/lib/opencode/openchamber-routes.js +1 -7
  91. package/server/lib/opencode/settings-helpers.js +0 -3
  92. package/server/lib/opencode/shutdown-runtime.js +0 -2
  93. package/server/lib/relay/DOCUMENTATION.md +2 -2
  94. package/server/lib/relay/service.js +45 -3
  95. package/server/lib/relay/service.test.js +117 -0
  96. package/server/lib/relay/signing-key.js +1 -1
  97. package/server/lib/session-goal/DOCUMENTATION.md +3 -3
  98. package/server/lib/session-goal/runtime.js +3 -3
  99. package/server/lib/session-title/DOCUMENTATION.md +1 -2
  100. package/dist/assets/AgentAvatar-DDcjamcJ.js +0 -1
  101. package/dist/assets/AssistantView-BipKB0Xu.js +0 -1
  102. package/dist/assets/ContextPanel-DxaTJbBJ.js +0 -288
  103. package/dist/assets/MobileSurface-Bob51m6v.js +0 -2
  104. package/dist/assets/OverlayScrollbar-Ch3J6ASR.js +0 -2
  105. package/dist/assets/appThemeRegistry-Ds7o-iDC.js +0 -2
  106. package/dist/assets/dialog-DPS0W9eS.js +0 -1
  107. package/dist/assets/insertionBoundaries-DN03Ffgf.js +0 -1
  108. package/dist/assets/main-rv0Iw_-o.js +0 -29
  109. package/dist/assets/mobile-eAdQk_4x.js +0 -2
  110. package/dist/assets/multirun-lZV5lnAU.js +0 -4
  111. package/dist/assets/pl-BuCO3qb1.js +0 -15
  112. package/dist/assets/platform-CbeLpKPk.js +0 -2
  113. package/dist/assets/projectMeta-2o-eC3Cz.js +0 -3
  114. package/dist/assets/radio-CHY-FZIg.js +0 -1
  115. package/dist/assets/renderElectronMiniChatApp-DuK-UF8v.js +0 -2
  116. package/dist/assets/renderMobileApp-B-UiIevb.js +0 -23
  117. package/dist/assets/runtimeEndpointReset-5XhUYqlE.js +0 -4
  118. package/dist/assets/src-RGaBtbGz.css +0 -2
  119. package/dist/assets/useEffectiveDirectory-BmTAJUVK.js +0 -1
  120. package/dist/assets/useMobileNavigationStore-DkUlpkW4.js +0 -475
  121. package/dist/assets/useSessionAutoCleanup-CQmXCiFr.js +0 -1
  122. package/dist/assets/zh-TW-6875X80V.js +0 -15
  123. package/server/lib/config-sync/credential-auth.js +0 -39
  124. package/server/lib/session-assist/DOCUMENTATION.md +0 -62
  125. package/server/lib/session-assist/runtime.js +0 -376
  126. package/server/lib/session-assist/runtime.test.js +0 -114
package/dist/index.html CHANGED
@@ -552,25 +552,25 @@
552
552
  opacity: 0.72;
553
553
  }
554
554
  </style>
555
- <script type="module" crossorigin src="/assets/main-IaZbd8eq.js"></script>
555
+ <script type="module" crossorigin src="/assets/main-dGakBRsd.js"></script>
556
556
  <link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-C0FnF6B9.js">
557
557
  <link rel="modulepreload" crossorigin href="/assets/vendor-base-ui-CnHfUmDN.js">
558
558
  <link rel="modulepreload" crossorigin href="/assets/vendor-zustand-B4dlGEM2.js">
559
- <link rel="modulepreload" crossorigin href="/assets/useUIStore-DzwCfRqr.js">
559
+ <link rel="modulepreload" crossorigin href="/assets/useUIStore-Wyu09VUF.js">
560
560
  <link rel="modulepreload" crossorigin href="/assets/vendor-pathe-vBmvQE8f.js">
561
561
  <link rel="modulepreload" crossorigin href="/assets/vendor-react-DLPElpoQ.js">
562
562
  <link rel="modulepreload" crossorigin href="/assets/vendor-tanstack-query-core-BWz0ose6.js">
563
- <link rel="modulepreload" crossorigin href="/assets/persistence-6sclr7B6.js">
564
- <link rel="modulepreload" crossorigin href="/assets/desktopHosts-Txp4xOVQ.js">
565
- <link rel="modulepreload" crossorigin href="/assets/desktopRelayRestore-C_FSEHKM.js">
563
+ <link rel="modulepreload" crossorigin href="/assets/persistence-aCOlo6ew.js">
564
+ <link rel="modulepreload" crossorigin href="/assets/desktopHosts-Dzx3McaD.js">
565
+ <link rel="modulepreload" crossorigin href="/assets/desktopRelayRestore-B9S0Rp5s.js">
566
566
  <link rel="modulepreload" crossorigin href="/assets/vendor-opencode-sdk-C07HQypa.js">
567
567
  <link rel="modulepreload" crossorigin href="/assets/vendor-aparajita-capacitor-secure-storage-CjQdwfjS.js">
568
- <link rel="modulepreload" crossorigin href="/assets/platform-CbeLpKPk.js">
569
- <link rel="modulepreload" crossorigin href="/assets/terminalApi-BpPeXWIu.js">
568
+ <link rel="modulepreload" crossorigin href="/assets/platform-ulFAVx1H.js">
569
+ <link rel="modulepreload" crossorigin href="/assets/terminalApi-HsIEks5U.js">
570
570
  <link rel="modulepreload" crossorigin href="/assets/types-BuiqMmh_.js">
571
571
  <link rel="modulepreload" crossorigin href="/assets/capgoAdapter-DCowZ2ab.js">
572
- <link rel="modulepreload" crossorigin href="/assets/runtimeConfig-CMLxQH75.js">
573
- <link rel="stylesheet" crossorigin href="/assets/src-RGaBtbGz.css">
572
+ <link rel="modulepreload" crossorigin href="/assets/runtimeConfig-QFdp6Itq.js">
573
+ <link rel="stylesheet" crossorigin href="/assets/src-BwToVDxi.css">
574
574
  </head>
575
575
  <body class="h-full bg-background text-foreground">
576
576
  <!-- Keep the startup layer outside #root. React replaces every child of
@@ -74,25 +74,25 @@
74
74
  }
75
75
  </style>
76
76
 
77
- <script type="module" crossorigin src="/assets/miniChat-Byg-MsGQ.js"></script>
77
+ <script type="module" crossorigin src="/assets/miniChat-C8rpOcNP.js"></script>
78
78
  <link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-C0FnF6B9.js">
79
79
  <link rel="modulepreload" crossorigin href="/assets/vendor-base-ui-CnHfUmDN.js">
80
80
  <link rel="modulepreload" crossorigin href="/assets/vendor-zustand-B4dlGEM2.js">
81
- <link rel="modulepreload" crossorigin href="/assets/useUIStore-DzwCfRqr.js">
81
+ <link rel="modulepreload" crossorigin href="/assets/useUIStore-Wyu09VUF.js">
82
82
  <link rel="modulepreload" crossorigin href="/assets/vendor-pathe-vBmvQE8f.js">
83
83
  <link rel="modulepreload" crossorigin href="/assets/vendor-react-DLPElpoQ.js">
84
84
  <link rel="modulepreload" crossorigin href="/assets/vendor-tanstack-query-core-BWz0ose6.js">
85
- <link rel="modulepreload" crossorigin href="/assets/persistence-6sclr7B6.js">
86
- <link rel="modulepreload" crossorigin href="/assets/desktopHosts-Txp4xOVQ.js">
87
- <link rel="modulepreload" crossorigin href="/assets/desktopRelayRestore-C_FSEHKM.js">
85
+ <link rel="modulepreload" crossorigin href="/assets/persistence-aCOlo6ew.js">
86
+ <link rel="modulepreload" crossorigin href="/assets/desktopHosts-Dzx3McaD.js">
87
+ <link rel="modulepreload" crossorigin href="/assets/desktopRelayRestore-B9S0Rp5s.js">
88
88
  <link rel="modulepreload" crossorigin href="/assets/vendor-opencode-sdk-C07HQypa.js">
89
89
  <link rel="modulepreload" crossorigin href="/assets/vendor-aparajita-capacitor-secure-storage-CjQdwfjS.js">
90
- <link rel="modulepreload" crossorigin href="/assets/platform-CbeLpKPk.js">
91
- <link rel="modulepreload" crossorigin href="/assets/terminalApi-BpPeXWIu.js">
90
+ <link rel="modulepreload" crossorigin href="/assets/platform-ulFAVx1H.js">
91
+ <link rel="modulepreload" crossorigin href="/assets/terminalApi-HsIEks5U.js">
92
92
  <link rel="modulepreload" crossorigin href="/assets/types-BuiqMmh_.js">
93
93
  <link rel="modulepreload" crossorigin href="/assets/capgoAdapter-DCowZ2ab.js">
94
- <link rel="modulepreload" crossorigin href="/assets/runtimeConfig-CMLxQH75.js">
95
- <link rel="stylesheet" crossorigin href="/assets/src-RGaBtbGz.css">
94
+ <link rel="modulepreload" crossorigin href="/assets/runtimeConfig-QFdp6Itq.js">
95
+ <link rel="stylesheet" crossorigin href="/assets/src-BwToVDxi.css">
96
96
  </head>
97
97
  <body class="h-full bg-background text-foreground">
98
98
  <div id="root" class="h-full">
package/dist/mobile.html CHANGED
@@ -63,25 +63,25 @@
63
63
  })();
64
64
  </script>
65
65
 
66
- <script type="module" crossorigin src="/assets/mobile-eAdQk_4x.js"></script>
66
+ <script type="module" crossorigin src="/assets/mobile-Dm22ebC9.js"></script>
67
67
  <link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-C0FnF6B9.js">
68
68
  <link rel="modulepreload" crossorigin href="/assets/vendor-base-ui-CnHfUmDN.js">
69
69
  <link rel="modulepreload" crossorigin href="/assets/vendor-zustand-B4dlGEM2.js">
70
- <link rel="modulepreload" crossorigin href="/assets/useUIStore-DzwCfRqr.js">
70
+ <link rel="modulepreload" crossorigin href="/assets/useUIStore-Wyu09VUF.js">
71
71
  <link rel="modulepreload" crossorigin href="/assets/vendor-pathe-vBmvQE8f.js">
72
72
  <link rel="modulepreload" crossorigin href="/assets/vendor-react-DLPElpoQ.js">
73
73
  <link rel="modulepreload" crossorigin href="/assets/vendor-tanstack-query-core-BWz0ose6.js">
74
- <link rel="modulepreload" crossorigin href="/assets/persistence-6sclr7B6.js">
75
- <link rel="modulepreload" crossorigin href="/assets/desktopHosts-Txp4xOVQ.js">
76
- <link rel="modulepreload" crossorigin href="/assets/desktopRelayRestore-C_FSEHKM.js">
74
+ <link rel="modulepreload" crossorigin href="/assets/persistence-aCOlo6ew.js">
75
+ <link rel="modulepreload" crossorigin href="/assets/desktopHosts-Dzx3McaD.js">
76
+ <link rel="modulepreload" crossorigin href="/assets/desktopRelayRestore-B9S0Rp5s.js">
77
77
  <link rel="modulepreload" crossorigin href="/assets/vendor-opencode-sdk-C07HQypa.js">
78
78
  <link rel="modulepreload" crossorigin href="/assets/vendor-aparajita-capacitor-secure-storage-CjQdwfjS.js">
79
- <link rel="modulepreload" crossorigin href="/assets/platform-CbeLpKPk.js">
80
- <link rel="modulepreload" crossorigin href="/assets/terminalApi-BpPeXWIu.js">
79
+ <link rel="modulepreload" crossorigin href="/assets/platform-ulFAVx1H.js">
80
+ <link rel="modulepreload" crossorigin href="/assets/terminalApi-HsIEks5U.js">
81
81
  <link rel="modulepreload" crossorigin href="/assets/types-BuiqMmh_.js">
82
82
  <link rel="modulepreload" crossorigin href="/assets/capgoAdapter-DCowZ2ab.js">
83
- <link rel="modulepreload" crossorigin href="/assets/runtimeConfig-CMLxQH75.js">
84
- <link rel="stylesheet" crossorigin href="/assets/src-RGaBtbGz.css">
83
+ <link rel="modulepreload" crossorigin href="/assets/runtimeConfig-QFdp6Itq.js">
84
+ <link rel="stylesheet" crossorigin href="/assets/src-BwToVDxi.css">
85
85
  </head>
86
86
  <body class="h-full bg-background text-foreground">
87
87
  <div id="root" class="h-full"></div>
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "@openchambery/web",
3
- "version": "1.19.0-beta.9",
3
+ "version": "1.19.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "./server/index.js",
7
7
  "types": "./server/index.d.ts",
8
8
  "bin": {
9
- "openchamber": "./bin/cli.js"
9
+ "openchamber": "./bin/cli.js",
10
+ "openchambery": "./bin/cli.js"
10
11
  },
11
12
  "publishConfig": {
12
13
  "access": "public"
package/server/index.js CHANGED
@@ -58,7 +58,6 @@ import { createOpenCodeResolutionRuntime } from './lib/opencode/opencode-resolut
58
58
  import { createBootstrapRuntime } from './lib/opencode/bootstrap-runtime.js';
59
59
  import { createSessionRuntime } from './lib/opencode/session-runtime.js';
60
60
  import { createOpenCodeWatcherRuntime } from './lib/opencode/watcher.js';
61
- import { createSessionAssistRuntime } from './lib/session-assist/runtime.js';
62
61
  import { createSessionTitleRuntime } from './lib/session-title/runtime.js';
63
62
  import { createSessionIndexService } from './lib/session-index/service.js';
64
63
  import { createSessionIndexSyncRuntime } from './lib/session-index/sync-runtime.js';
@@ -90,7 +89,7 @@ import { applyRuntimeCorsHeaders } from './lib/request-cors.js';
90
89
  import { createClientPairingRuntime } from './lib/client-auth/pairing.js';
91
90
  import { createPreviewProxyRuntime } from './lib/preview/proxy-runtime.js';
92
91
  import { attachRealtimeProxy } from './lib/realtime-proxy.js';
93
- import { createRelayService, isRelayHostRuntime } from './lib/relay/service.js';
92
+ import { createRelayService, isRelayHostRuntime, resolveEffectiveRelayUrl } from './lib/relay/service.js';
94
93
  import { createRelayHostLock } from './lib/relay/host-lock.js';
95
94
  import { createProxyMiddleware, responseInterceptor } from 'http-proxy-middleware';
96
95
  import webPush from 'web-push';
@@ -362,6 +361,10 @@ const apnsRuntime = createApnsRuntime({
362
361
  readSettingsFromDiskMigrated,
363
362
  writeSettingsToDisk,
364
363
  readSettingsStrict: readSettingsFromDiskStrict,
364
+ resolveEffectiveRelayUrl: async () => {
365
+ const settings = await readSettingsFromDiskMigrated();
366
+ return resolveEffectiveRelayUrl({ settings });
367
+ },
365
368
  });
366
369
 
367
370
  const addOrUpdateApnsToken = (...args) => apnsRuntime.addOrUpdateApnsToken(...args);
@@ -685,12 +688,6 @@ const getSmallModelService = async () => {
685
688
  return smallModelServiceInstance;
686
689
  };
687
690
 
688
- const sessionAssistRuntime = createSessionAssistRuntime({
689
- buildOpenCodeUrl,
690
- getOpenCodeAuthHeaders,
691
- getSmallModelService,
692
- });
693
-
694
691
  const sessionTitleRuntime = createSessionTitleRuntime({
695
692
  buildOpenCodeUrl,
696
693
  getOpenCodeAuthHeaders,
@@ -769,9 +766,8 @@ const openCodeWatcherRuntime = createOpenCodeWatcherRuntime({
769
766
  },
770
767
  });
771
768
 
772
- // Session-assist, session-title, and session-goal subscribe to the hub directly: they need the
769
+ // Session-title and session-goal subscribe to the hub directly: they need the
773
770
  // envelope's directory to route their own OpenCode calls to the right instance.
774
- console.log('[session-assist] listening for session events');
775
771
  console.log('[session-title] listening for session events');
776
772
  console.log('[session-goal] listening for session events');
777
773
  globalMessageStreamHub.subscribeEvent((event) => {
@@ -781,7 +777,6 @@ globalMessageStreamHub.subscribeEvent((event) => {
781
777
  const directory = typeof event?.directory === 'string' && event.directory && event.directory !== 'global'
782
778
  ? event.directory
783
779
  : '';
784
- sessionAssistRuntime.processPayload(payload, directory);
785
780
  sessionTitleRuntime.processPayload(payload, directory);
786
781
  sessionGoalRuntime.processPayload(payload, directory);
787
782
  });
@@ -1065,9 +1060,9 @@ const completeOpenCodeStartup = () => {
1065
1060
  if (openCodeLifecycleState.openCodeProcess && !openCodeLifecycleState.isExternalOpenCode) {
1066
1061
  startHealthMonitoring();
1067
1062
  }
1068
- // The global watcher used to start only for desktop notifications; the
1069
- // session-assist runtime also rides its event hub, so it now starts
1070
- // unconditionally once OpenCode is up.
1063
+ // The global watcher used to start only for desktop notifications; session-title
1064
+ // and session-goal also ride its event hub, so it now starts unconditionally
1065
+ // once OpenCode is up.
1071
1066
  void ensureGlobalWatcherStarted().catch((error) => {
1072
1067
  console.warn(`Global event watcher startup failed: ${error?.message || error}`);
1073
1068
  });
@@ -1099,7 +1094,6 @@ const gracefulShutdownRuntime = createGracefulShutdownRuntime({
1099
1094
  },
1100
1095
  syncToHmrState,
1101
1096
  openCodeWatcherRuntime,
1102
- sessionAssistRuntime,
1103
1097
  sessionTitleRuntime,
1104
1098
  sessionGoalRuntime,
1105
1099
  sessionRuntime,
@@ -1514,6 +1508,9 @@ async function main(options = {}) {
1514
1508
  ]);
1515
1509
  return pendingRelay || deviceRelay;
1516
1510
  },
1511
+ onRelayUrlChanged: async () => {
1512
+ await apnsRuntime.reRegisterAllTokens();
1513
+ },
1517
1514
  });
1518
1515
  relayServiceInstance = relayService;
1519
1516
  relayService.registerRoutes(app);
@@ -17,7 +17,6 @@ Own the direction-agnostic OpenCode config sync contract: allowlist planning on
17
17
  | `local-backup.js` | Local (pull destination) generational backup + tar extract |
18
18
  | `tar.js` | `collectLocalTarBuffer` (buffered) |
19
19
  | `engine.js` | `applyConfigSyncPlan` orchestration for **push** (prepare → putTar* → finalize) |
20
- | `credential-auth.js` | Credential grant enforcement helpers |
21
20
  | `target-id.js` | `ssh:<instanceId>` namespace helper |
22
21
 
23
22
  ## Contract shape
@@ -28,6 +27,7 @@ Own the direction-agnostic OpenCode config sync contract: allowlist planning on
28
27
  - **Plan** (source-computed): `{ direction: 'push' | 'pull', syncRunId?, sourceTargetId?, targetId?, files, directories, agentsRoot, authFile, deletes, totalBytes, selections? }`
29
28
  - **Selections**: `{ fileGroups: boolean[], singleFiles: boolean[], directories: boolean[], agentsRoot: boolean, authFile: boolean }`
30
29
  - Preview and apply must share one selections snapshot so the confirmed scope cannot drift.
30
+ - `authFile` defaults unchecked like an opt-in ordinary selection; once checked it syncs the same way as other allowlisted files (no extra grant).
31
31
 
32
32
  ## Direction flow
33
33
 
@@ -45,7 +45,7 @@ Switching direction in the wizard **must** discard the previous preview and re-c
45
45
  - Prepare (remote or local) writes generational backups under `<backupRoot>/<syncRunId>/` and prunes older than `OPENCODE_CONFIG_SYNC_BACKUP_GENERATIONS`. Failed runs keep their scene until pruned.
46
46
  - Finalize confirms the run's backup directory exists.
47
47
  - Run records (Electron `sync-run-store`) persist `direction` alongside `syncRunId` / summary; they are not stored in `settings.json`.
48
- - **Credential sync:** target reachability credential transfer. `auth.json` is omitted unless the SSH target has an explicit grant. Push and pull reuse the same grant. Unauthorized credential plans fail with `code: credential_sync_unauthorized`.
48
+ - **`auth.json` sync:** treated like any other selected allowlist item. Default selection leaves it unchecked; when selected, push/pull transfer it under the dedicated auth backup directory with no separate credential grant.
49
49
 
50
50
  ## HTTP receive protocol (direct / later relay)
51
51
 
@@ -53,18 +53,17 @@ Routes under `/api/openchamber/config-sync/*` (global `/api` auth gate: session
53
53
 
54
54
  | Method | Path | Role |
55
55
  |--------|------|------|
56
- | POST | `/probe` | Inventory + existence vs plan; reports `inboundCredentialAuthorized` |
56
+ | POST | `/probe` | Inventory + existence vs plan |
57
57
  | POST | `/prepare` | Generational local backup + deletes; one inflight `syncRunId` |
58
58
  | PUT | `/put/:kind?syncRunId=` | Stream tar.gz (`config` \| `agents` \| `auth`) |
59
59
  | GET | `/download/:kind` | Stream tar.gz for pull source |
60
60
  | POST | `/finalize` | Confirm backup generation + success receipt |
61
61
  | POST | `/abort` | Clear inflight |
62
- | GET/PUT | `/credential-auth` | Host inbound credential grant (`configSyncInboundCredentialAuthorized`) |
63
62
 
64
- `auth` put/download requires inbound credential authorization (`credential_sync_unauthorized`). Concurrent prepare → `sync_in_progress`.
63
+ `auth` put/download follows the same selection/plan rules as other kinds. Concurrent prepare → `sync_in_progress`.
65
64
 
66
65
  ## Composition
67
66
 
68
67
  - Electron SSH: `TargetExecutor` push + inventory/tar pull.
69
- - Electron direct hosts: `direct-config-sync.mjs` calls these HTTP routes (`host:<id>` grants in `desktopCredentialSyncGrants`, channel `host-settings`).
70
- - **Relay hosts (ticket 06):** UI opens an E2EE tunnel (`packages/ui/src/lib/relay/relay-config-sync.ts`) and calls the same HTTP routes via `tunnel.fetch`. Target id is `relay:<serverId>` (signing-key fingerprint). Preview/apply refresh candidates and refuse on `serverId` mismatch (`relay_identity_changed`) with no fallback identity. Outbound credential grants use channel `pairing-settings` (pairing trust UX / host trust settings for the paired relay). Inbound credential grants remain `configSyncInboundCredentialAuthorized` on the receiving Host. Auth is always bearer + grant — never “reachable ⇒ trusted”.
68
+ - Electron direct hosts: `direct-config-sync.mjs` calls these HTTP routes.
69
+ - **Relay hosts (ticket 06):** UI opens an E2EE tunnel (`packages/ui/src/lib/relay/relay-config-sync.ts`) and calls the same HTTP routes via `tunnel.fetch`. Target id is `relay:<serverId>` (signing-key fingerprint). Preview/apply refresh candidates and refuse on `serverId` mismatch (`relay_identity_changed`) with no fallback identity. Auth remains the global `/api` bearer gate; selected `auth.json` transfers without a separate credential grant.
@@ -1,13 +1,11 @@
1
1
  import path from 'node:path';
2
2
 
3
3
  import { assertPlanDirection } from './contract.js';
4
- import { assertCredentialSyncAuthorized } from './credential-auth.js';
5
4
  import { collectLocalTarBuffer } from './tar.js';
6
5
 
7
6
  /**
8
7
  * Run a source-side plan against a TargetExecutor (probe → prepare → putTar* → finalize).
9
8
  * Direction-agnostic orchestration; ticket 02 only drives push from a local home snapshot.
10
- * Credential-bearing plans require an explicit per-target grant (ticket 03).
11
9
  *
12
10
  * @param {{
13
11
  * plan: object,
@@ -15,7 +13,6 @@ import { collectLocalTarBuffer } from './tar.js';
15
13
  * syncRunId: string,
16
14
  * sourceHomedir: string,
17
15
  * collectTar?: typeof collectLocalTarBuffer,
18
- * credentialSyncAuthorized?: boolean,
19
16
  * }} args
20
17
  */
21
18
  export const applyConfigSyncPlan = async ({
@@ -24,13 +21,8 @@ export const applyConfigSyncPlan = async ({
24
21
  syncRunId,
25
22
  sourceHomedir,
26
23
  collectTar = collectLocalTarBuffer,
27
- credentialSyncAuthorized = false,
28
24
  }) => {
29
25
  assertPlanDirection(plan);
30
- assertCredentialSyncAuthorized(plan, {
31
- targetId: plan?.targetId || 'unknown',
32
- authorized: credentialSyncAuthorized === true,
33
- });
34
26
  const home = String(sourceHomedir || '');
35
27
  const configDir = path.join(home, '.config', 'opencode');
36
28
  const tarEntries = [
@@ -48,13 +48,6 @@ export {
48
48
  } from './scripts.js';
49
49
  export { collectLocalTarBuffer } from './tar.js';
50
50
  export { applyConfigSyncPlan, probePathsForPlan } from './engine.js';
51
- export {
52
- CREDENTIAL_SYNC_UNAUTHORIZED_CODE,
53
- CREDENTIAL_SYNC_GRANT_CHANNEL_INSTANCE_SETTINGS,
54
- CredentialSyncUnauthorizedError,
55
- planIncludesCredentials,
56
- assertCredentialSyncAuthorized,
57
- } from './credential-auth.js';
58
51
  export {
59
52
  buildDefaultSyncSelections,
60
53
  normalizeSyncSelections,
@@ -11,7 +11,6 @@ import {
11
11
  OPENCODE_CONFIG_SYNC_MAX_BYTES,
12
12
  OPENCODE_CONFIG_SYNC_MAX_FILES,
13
13
  } from './constants.js';
14
- import { CREDENTIAL_SYNC_UNAUTHORIZED_CODE } from './credential-auth.js';
15
14
  import {
16
15
  extractTarGzBuffer,
17
16
  finalizeLocalSyncDestination,
@@ -20,8 +19,6 @@ import {
20
19
  import { walkAllowlistDirectory } from './plan.js';
21
20
  import { sanitizeSyncRunIdForPath } from './scripts.js';
22
21
 
23
- const INBOUND_CREDENTIAL_SETTINGS_KEY = 'configSyncInboundCredentialAuthorized';
24
-
25
22
  /**
26
23
  * In-process receiver for HTTP config-sync (direct/relay hosts).
27
24
  * One inflight sync at a time; backups use the same local generational helpers as pull.
@@ -29,8 +26,6 @@ const INBOUND_CREDENTIAL_SETTINGS_KEY = 'configSyncInboundCredentialAuthorized';
29
26
  export const createConfigSyncReceiver = (deps = {}) => {
30
27
  const {
31
28
  homedir = () => os.homedir(),
32
- readSettings = async () => ({}),
33
- writeSettingsPatch = async () => {},
34
29
  } = deps;
35
30
 
36
31
  let inflight = null;
@@ -148,18 +143,6 @@ export const createConfigSyncReceiver = (deps = {}) => {
148
143
  };
149
144
  };
150
145
 
151
- const isInboundCredentialAuthorized = async () => {
152
- const settings = await readSettings();
153
- return settings?.[INBOUND_CREDENTIAL_SETTINGS_KEY] === true;
154
- };
155
-
156
- const setInboundCredentialAuthorized = async (authorized) => {
157
- await writeSettingsPatch({
158
- [INBOUND_CREDENTIAL_SETTINGS_KEY]: authorized === true,
159
- });
160
- return { authorized: authorized === true };
161
- };
162
-
163
146
  const probe = async (plan) => {
164
147
  const snapshot = buildInventory();
165
148
  const existing = new Set(snapshot.remoteExisting);
@@ -171,7 +154,6 @@ export const createConfigSyncReceiver = (deps = {}) => {
171
154
  return {
172
155
  ...snapshot,
173
156
  remoteExisting: [...new Set(planPaths.filter((rel) => existing.has(rel)))],
174
- inboundCredentialAuthorized: await isInboundCredentialAuthorized(),
175
157
  };
176
158
  };
177
159
 
@@ -211,14 +193,6 @@ export const createConfigSyncReceiver = (deps = {}) => {
211
193
  error.code = 'sync_not_prepared';
212
194
  throw error;
213
195
  }
214
- if (kind === 'auth') {
215
- const authorized = await isInboundCredentialAuthorized();
216
- if (!authorized) {
217
- const error = new Error('Credential sync is not authorized on this host');
218
- error.code = CREDENTIAL_SYNC_UNAUTHORIZED_CODE;
219
- throw error;
220
- }
221
- }
222
196
  const buffer = await readStreamToBuffer(stream, { maxBytes: OPENCODE_CONFIG_SYNC_MAX_BYTES });
223
197
  const home = homedir();
224
198
  if (kind === 'config') {
@@ -279,12 +253,6 @@ export const createConfigSyncReceiver = (deps = {}) => {
279
253
  return collectTarGz(home, ['.agents']);
280
254
  }
281
255
  if (kind === 'auth') {
282
- const authorized = await isInboundCredentialAuthorized();
283
- if (!authorized) {
284
- const error = new Error('Credential sync is not authorized on this host');
285
- error.code = CREDENTIAL_SYNC_UNAUTHORIZED_CODE;
286
- throw error;
287
- }
288
256
  return collectTarGz(path.join(home, '.local', 'share', 'opencode'), ['auth.json']);
289
257
  }
290
258
  const error = new Error(`Unsupported download kind: ${String(kind)}`);
@@ -315,7 +283,6 @@ export const createConfigSyncReceiver = (deps = {}) => {
315
283
  };
316
284
 
317
285
  return {
318
- INBOUND_CREDENTIAL_SETTINGS_KEY,
319
286
  probe,
320
287
  prepare,
321
288
  put,
@@ -323,8 +290,6 @@ export const createConfigSyncReceiver = (deps = {}) => {
323
290
  finalize,
324
291
  abort,
325
292
  getInflight: () => inflight,
326
- isInboundCredentialAuthorized,
327
- setInboundCredentialAuthorized,
328
293
  buildInventory,
329
294
  };
330
295
  };
@@ -2,43 +2,29 @@ import { createConfigSyncReceiver } from './receiver.js';
2
2
 
3
3
  /**
4
4
  * Register HTTP config-sync receive/download routes for direct (and later relay) hosts.
5
- * Auth is the global `/api` UI/client-token gate. Credential kinds additionally
6
- * require inbound credential authorization on this host.
5
+ * Auth is the global `/api` UI/client-token gate. Selected kinds (including auth)
6
+ * sync when present in the plan — no extra credential grant checks.
7
7
  *
8
8
  * @param {import('express').Express} app
9
9
  * @param {{
10
10
  * receiver?: ReturnType<typeof createConfigSyncReceiver>,
11
- * readSettingsFromDiskMigrated?: () => Promise<object>,
12
- * persistSettings?: (changes: object) => Promise<object>,
13
11
  * express?: typeof import('express'),
14
12
  * }} deps
15
13
  */
16
14
  export const registerConfigSyncRoutes = (app, deps = {}) => {
17
15
  const {
18
- readSettingsFromDiskMigrated,
19
- persistSettings,
20
16
  express,
21
17
  } = deps;
22
18
 
23
- const receiver = deps.receiver || createConfigSyncReceiver({
24
- readSettings: async () => (typeof readSettingsFromDiskMigrated === 'function'
25
- ? readSettingsFromDiskMigrated()
26
- : {}),
27
- writeSettingsPatch: async (patch) => {
28
- if (typeof persistSettings === 'function') {
29
- await persistSettings(patch);
30
- }
31
- },
32
- });
19
+ const receiver = deps.receiver || createConfigSyncReceiver();
33
20
 
34
21
  const sendError = (res, error, fallbackStatus = 500) => {
35
22
  const code = typeof error?.code === 'string' ? error.code : undefined;
36
- const status = code === 'credential_sync_unauthorized' ? 403
37
- : code === 'sync_in_progress' ? 409
38
- : code === 'sync_not_prepared' ? 409
39
- : code === 'sync_payload_too_large' || code === 'sync_too_many_files' ? 413
40
- : code === 'sync_invalid_kind' ? 400
41
- : fallbackStatus;
23
+ const status = code === 'sync_in_progress' ? 409
24
+ : code === 'sync_not_prepared' ? 409
25
+ : code === 'sync_payload_too_large' || code === 'sync_too_many_files' ? 413
26
+ : code === 'sync_invalid_kind' ? 400
27
+ : fallbackStatus;
42
28
  res.status(status).json({
43
29
  error: error instanceof Error ? error.message : String(error),
44
30
  ...(code ? { code } : {}),
@@ -118,24 +104,5 @@ export const registerConfigSyncRoutes = (app, deps = {}) => {
118
104
  }
119
105
  });
120
106
 
121
- app.get('/api/openchamber/config-sync/credential-auth', async (_req, res) => {
122
- try {
123
- const authorized = await receiver.isInboundCredentialAuthorized();
124
- res.json({ authorized });
125
- } catch (error) {
126
- sendError(res, error);
127
- }
128
- });
129
-
130
- app.put('/api/openchamber/config-sync/credential-auth', express?.json?.({ limit: '16kb' }) || ((req, _res, next) => next()), async (req, res) => {
131
- try {
132
- const authorized = req.body?.authorized === true;
133
- const result = await receiver.setInboundCredentialAuthorized(authorized);
134
- res.json(result);
135
- } catch (error) {
136
- sendError(res, error);
137
- }
138
- });
139
-
140
107
  return { receiver };
141
108
  };
@@ -8,7 +8,6 @@ import request from 'supertest';
8
8
 
9
9
  import { createConfigSyncReceiver } from './receiver.js';
10
10
  import { registerConfigSyncRoutes } from './routes.js';
11
- import { CREDENTIAL_SYNC_UNAUTHORIZED_CODE } from './credential-auth.js';
12
11
 
13
12
  const tempDirs = [];
14
13
 
@@ -31,18 +30,13 @@ const createApp = async () => {
31
30
  await fsp.writeFile(path.join(configDir, 'opencode.jsonc'), '{}\n');
32
31
  await fsp.writeFile(path.join(configDir, 'AGENTS.md'), 'hi\n');
33
32
 
34
- let settings = {};
35
33
  const receiver = createConfigSyncReceiver({
36
34
  homedir: () => home,
37
- readSettings: async () => ({ ...settings }),
38
- writeSettingsPatch: async (patch) => {
39
- settings = { ...settings, ...patch };
40
- },
41
35
  });
42
36
 
43
37
  const app = express();
44
38
  registerConfigSyncRoutes(app, { receiver, express });
45
- return { app, home, receiver, getSettings: () => settings };
39
+ return { app, home, receiver };
46
40
  };
47
41
 
48
42
  describe('config-sync HTTP routes', () => {
@@ -79,27 +73,6 @@ describe('config-sync HTTP routes', () => {
79
73
  await expect(fsp.stat(backup)).resolves.toMatchObject({ });
80
74
  });
81
75
 
82
- it('rejects auth put without inbound credential authorization', async () => {
83
- const { app } = await createApp();
84
- const plan = {
85
- direction: 'push',
86
- files: [],
87
- directories: [],
88
- deletes: [],
89
- agentsRoot: null,
90
- authFile: { bytes: 2 },
91
- totalBytes: 2,
92
- };
93
- await request(app).post('/api/openchamber/config-sync/prepare').send({ plan, syncRunId: 'run-auth' });
94
- const put = await request(app)
95
- .put('/api/openchamber/config-sync/put/auth?syncRunId=run-auth')
96
- .set('Content-Type', 'application/gzip')
97
- .send(Buffer.from('xx'));
98
- expect(put.status).toBe(403);
99
- expect(put.body.code).toBe(CREDENTIAL_SYNC_UNAUTHORIZED_CODE);
100
- await request(app).post('/api/openchamber/config-sync/abort').send({ syncRunId: 'run-auth' });
101
- });
102
-
103
76
  it('rejects a second concurrent prepare', async () => {
104
77
  const { app } = await createApp();
105
78
  const plan = {
@@ -131,7 +104,6 @@ describe('config-sync HTTP routes', () => {
131
104
  totalBytes: 0,
132
105
  };
133
106
  await request(app).post('/api/openchamber/config-sync/prepare').send({ plan, syncRunId: 'run-stream' });
134
- await receiver.setInboundCredentialAuthorized(true);
135
107
 
136
108
  // Tiny invalid tar still proves chunk aggregation reached extract.
137
109
  await expect(receiver.put({
@@ -142,13 +114,4 @@ describe('config-sync HTTP routes', () => {
142
114
 
143
115
  await request(app).post('/api/openchamber/config-sync/abort').send({ syncRunId: 'run-stream' });
144
116
  });
145
-
146
- it('persists inbound credential authorization flag', async () => {
147
- const { app, getSettings } = await createApp();
148
- const before = await request(app).get('/api/openchamber/config-sync/credential-auth');
149
- expect(before.body.authorized).toBe(false);
150
- const after = await request(app).put('/api/openchamber/config-sync/credential-auth').send({ authorized: true });
151
- expect(after.body.authorized).toBe(true);
152
- expect(getSettings().configSyncInboundCredentialAuthorized).toBe(true);
153
- });
154
117
  });