@ljwei-stak/dsh-model-route-bot 0.66.3 → 0.67.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 (272) hide show
  1. package/.dsh-plugin/bot-product.mjs +81 -5
  2. package/.dsh-plugin/client.js +17490 -1791
  3. package/README.i18n.yaml +4 -4
  4. package/README.md +409 -364
  5. package/README.zh.md +409 -364
  6. package/apps/integration-client/README.md +31 -7
  7. package/apps/integration-client/api.mjs +14 -3
  8. package/apps/integration-client/binding-editor.jsx +308 -109
  9. package/apps/integration-client/binding-model.mjs +262 -0
  10. package/apps/integration-client/binding.css +144 -0
  11. package/apps/integration-client/bot-model-status.mjs +18 -0
  12. package/apps/integration-client/bot-profile-identity.jsx +197 -0
  13. package/apps/integration-client/bot-profile.css +57 -0
  14. package/apps/integration-client/bot-profile.mjs +97 -0
  15. package/apps/integration-client/bot-settings-dialog.css +18 -0
  16. package/apps/integration-client/bot-settings-dialog.jsx +111 -0
  17. package/apps/integration-client/bot-thread-header-bridge.css +20 -0
  18. package/apps/integration-client/bot-thread-header.jsx +278 -0
  19. package/apps/integration-client/bot-threads-panel.jsx +378 -0
  20. package/apps/integration-client/bot-threads.css +169 -0
  21. package/apps/integration-client/chat-design.mjs +250 -0
  22. package/apps/integration-client/chat-ui.jsx +175 -0
  23. package/apps/integration-client/chat.css +477 -0
  24. package/apps/integration-client/composer-draft-binding.mjs +50 -0
  25. package/apps/integration-client/composer-draft-bound.jsx +14 -0
  26. package/apps/integration-client/composer-draft-host.jsx +142 -0
  27. package/apps/integration-client/composer-draft-session.jsx +287 -0
  28. package/apps/integration-client/composer-draft-witness.mjs +115 -0
  29. package/apps/integration-client/composer-draft.css +4 -0
  30. package/apps/integration-client/composer-draft.mjs +322 -0
  31. package/apps/integration-client/contact-attention.jsx +54 -0
  32. package/apps/integration-client/data-panel.jsx +439 -0
  33. package/apps/integration-client/data.css +69 -0
  34. package/apps/integration-client/desktop-bridge.mjs +1 -0
  35. package/apps/integration-client/desktop-http-socket.mjs +49 -0
  36. package/apps/integration-client/desktop-keyboard.mjs +32 -0
  37. package/apps/integration-client/desktop-pane.jsx +99 -30
  38. package/apps/integration-client/desktop-stream.mjs +13 -3
  39. package/apps/integration-client/desktop-tools.jsx +19 -0
  40. package/apps/integration-client/desktop-touch.mjs +27 -0
  41. package/apps/integration-client/desktop.css +41 -0
  42. package/apps/integration-client/independent-chat-controller.mjs +224 -0
  43. package/apps/integration-client/independent-chat-entry.jsx +61 -0
  44. package/apps/integration-client/independent-chat-navigation.mjs +21 -0
  45. package/apps/integration-client/independent-chat-page.jsx +148 -0
  46. package/apps/integration-client/independent-chat-rich.jsx +64 -0
  47. package/apps/integration-client/independent-chat-rich.mjs +30 -0
  48. package/apps/integration-client/independent-chat.css +73 -0
  49. package/apps/integration-client/index.jsx +24 -16
  50. package/apps/integration-client/library-panel.jsx +4 -1
  51. package/apps/integration-client/licenses/jsqr-1.4.0-LICENSE.txt +202 -0
  52. package/apps/integration-client/main-route-editor.jsx +94 -0
  53. package/apps/integration-client/main-route-model.mjs +100 -0
  54. package/apps/integration-client/model-picker.css +37 -0
  55. package/apps/integration-client/model-picker.jsx +83 -0
  56. package/apps/integration-client/native-activity.css +141 -0
  57. package/apps/integration-client/native-activity.jsx +276 -0
  58. package/apps/integration-client/native-activity.mjs +384 -0
  59. package/apps/integration-client/notifications-panel.jsx +186 -0
  60. package/apps/integration-client/notifications.css +126 -0
  61. package/apps/integration-client/pairing-qr.jsx +79 -0
  62. package/apps/integration-client/panels.jsx +126 -115
  63. package/apps/integration-client/product-slots.jsx +46 -0
  64. package/apps/integration-client/routine-recorder.mjs +23 -2
  65. package/apps/integration-client/secure-pairing.jsx +84 -0
  66. package/apps/integration-client/tasks-panel.jsx +32 -10
  67. package/apps/integration-client/ui-icons.jsx +17 -0
  68. package/apps/integration-client/usage-explorer.jsx +43 -0
  69. package/apps/integration-client/usage-report.mjs +71 -0
  70. package/apps/integration-client/usage.css +34 -0
  71. package/apps/integration-client/web-panel-model.mjs +140 -0
  72. package/apps/integration-client/web-panel-page.jsx +221 -0
  73. package/apps/integration-client/web-panel-pins-live.jsx +28 -0
  74. package/apps/integration-client/web-panel.css +139 -0
  75. package/apps/integration-client/workspace-model.mjs +67 -0
  76. package/apps/integration-client/workspace-navigation.mjs +56 -0
  77. package/apps/integration-client/workspace-ui.jsx +173 -0
  78. package/apps/integration-client/workspace.css +332 -0
  79. package/modules/bot-runtime/SOURCE.json +176 -50
  80. package/modules/bot-runtime/index.mjs +169 -13
  81. package/modules/bot-runtime/product-overlay/OVERLAY.json +128 -2
  82. package/modules/bot-runtime/product-overlay/base/src/client/header.js +244 -0
  83. package/modules/bot-runtime/product-overlay/base/src/client/learning-card.js +202 -0
  84. package/modules/bot-runtime/product-overlay/base/src/client/model-menu.js +371 -0
  85. package/modules/bot-runtime/product-overlay/base/src/client/secret-card.js +363 -0
  86. package/modules/bot-runtime/product-overlay/base/src/client/sources.js +68 -0
  87. package/modules/bot-runtime/product-overlay/base/src/client/turn-error.js +260 -0
  88. package/modules/bot-runtime/product-overlay/base/src/host/channel.js +647 -0
  89. package/modules/bot-runtime/product-overlay/base/src/host/memory.js +2050 -0
  90. package/modules/bot-runtime/product-overlay/base/src/host/models.js +314 -0
  91. package/modules/bot-runtime/product-overlay/base/src/host/parts.js +1473 -0
  92. package/modules/bot-runtime/product-overlay/base/src/host/privacy.js +368 -0
  93. package/modules/bot-runtime/product-overlay/base/src/host/roster.js +776 -0
  94. package/modules/bot-runtime/product-overlay/base/src/host/store.js +512 -0
  95. package/modules/bot-runtime/product-overlay/base/src/host/usage.js +653 -0
  96. package/modules/bot-runtime/product-overlay/patches/src/client/details-drawer.js.patch +48 -2
  97. package/modules/bot-runtime/product-overlay/patches/src/client/header.js.patch +41 -0
  98. package/modules/bot-runtime/product-overlay/patches/src/client/index.js.patch +33 -1
  99. package/modules/bot-runtime/product-overlay/patches/src/client/learning-card.js.patch +20 -0
  100. package/modules/bot-runtime/product-overlay/patches/src/client/model-menu.js.patch +24 -0
  101. package/modules/bot-runtime/product-overlay/patches/src/client/secret-card.js.patch +25 -0
  102. package/modules/bot-runtime/product-overlay/patches/src/client/sources.js.patch +52 -0
  103. package/modules/bot-runtime/product-overlay/patches/src/client/turn-error.js.patch +23 -0
  104. package/modules/bot-runtime/product-overlay/patches/src/host/channel.js.patch +46 -0
  105. package/modules/bot-runtime/product-overlay/patches/src/host/memory.js.patch +11 -0
  106. package/modules/bot-runtime/product-overlay/patches/src/host/models.js.patch +16 -0
  107. package/modules/bot-runtime/product-overlay/patches/src/host/parts.js.patch +95 -0
  108. package/modules/bot-runtime/product-overlay/patches/src/host/privacy.js.patch +11 -0
  109. package/modules/bot-runtime/product-overlay/patches/src/host/roster.js.patch +145 -0
  110. package/modules/bot-runtime/product-overlay/patches/src/host/store.js.patch +68 -0
  111. package/modules/bot-runtime/product-overlay/patches/src/host/usage.js.patch +11 -0
  112. package/modules/bot-runtime/read-model.mjs +19 -4
  113. package/modules/bot-runtime/vendor/ds-bot/src/client/details-drawer.js +15 -5
  114. package/modules/bot-runtime/vendor/ds-bot/src/client/header.js +9 -2
  115. package/modules/bot-runtime/vendor/ds-bot/src/client/index.js +9 -2
  116. package/modules/bot-runtime/vendor/ds-bot/src/client/learning-card.js +2 -2
  117. package/modules/bot-runtime/vendor/ds-bot/src/client/model-menu.js +5 -3
  118. package/modules/bot-runtime/vendor/ds-bot/src/client/secret-card.js +3 -3
  119. package/modules/bot-runtime/vendor/ds-bot/src/client/sources.js +25 -2
  120. package/modules/bot-runtime/vendor/ds-bot/src/client/turn-error.js +3 -2
  121. package/modules/bot-runtime/vendor/ds-bot/src/host/channel.js +14 -2
  122. package/modules/bot-runtime/vendor/ds-bot/src/host/memory.js +1 -1
  123. package/modules/bot-runtime/vendor/ds-bot/src/host/models.js +7 -0
  124. package/modules/bot-runtime/vendor/ds-bot/src/host/parts.js +26 -9
  125. package/modules/bot-runtime/vendor/ds-bot/src/host/privacy.js +1 -1
  126. package/modules/bot-runtime/vendor/ds-bot/src/host/roster.js +112 -3
  127. package/modules/bot-runtime/vendor/ds-bot/src/host/store.js +34 -1
  128. package/modules/bot-runtime/vendor/ds-bot/src/host/usage.js +1 -1
  129. package/modules/independent-runtime/index.mjs +152 -62
  130. package/modules/independent-runtime/remote-tools.mjs +8 -5
  131. package/modules/openmaus-protocol/NOTICE +10 -0
  132. package/modules/openmaus-protocol/README.md +15 -0
  133. package/modules/openmaus-protocol/SOURCE.json +68 -0
  134. package/modules/openmaus-protocol/dist/protocol.mjs +1203 -0
  135. package/modules/openmaus-protocol/index.mjs +1 -0
  136. package/modules/openmaus-protocol/transport.mjs +77 -0
  137. package/modules/openmaus-protocol/vendor/LICENSE +202 -0
  138. package/modules/openmaus-protocol/vendor/companion/src/e2e/README.md +405 -0
  139. package/modules/openmaus-protocol/vendor/companion/src/e2e/credentials.ts +128 -0
  140. package/modules/openmaus-protocol/vendor/companion/src/e2e/descriptor.ts +84 -0
  141. package/modules/openmaus-protocol/vendor/companion/src/e2e/noise.ts +456 -0
  142. package/modules/openmaus-protocol/vendor/companion/src/e2e/phone.ts +104 -0
  143. package/modules/openmaus-protocol/vendor/companion/src/e2e/session.ts +417 -0
  144. package/modules/openmaus-protocol/vendor/companion/src/e2e/vectors/v1.json +2565 -0
  145. package/modules/openmaus-protocol/vendor/companion/src/e2e/vectors/v1.sha256 +1 -0
  146. package/modules/openmaus-protocol/vendor/companion/src/e2e/yamux.ts +335 -0
  147. package/package.json +20 -6
  148. package/packages/bot-acp/README.md +156 -0
  149. package/packages/bot-acp/licenses/LICENSE-OpenMausBot +202 -0
  150. package/packages/bot-acp/licenses/NOTICE.md +27 -0
  151. package/packages/bot-acp/src/acp-adapter.mjs +795 -0
  152. package/packages/bot-acp/src/acp-host.mjs +148 -0
  153. package/packages/bot-acp/src/native-launch.mjs +121 -0
  154. package/packages/bot-acp/src/permission-policy.mjs +283 -0
  155. package/packages/bot-acp/src/rpc-codec.mjs +265 -0
  156. package/packages/bot-acp/src/session-core.mjs +581 -0
  157. package/packages/bot-acp/src/stdio-rpc.mjs +329 -0
  158. package/packages/bot-engines/README.md +281 -0
  159. package/packages/bot-engines/licenses/LICENSE-OpenMausBot +202 -0
  160. package/packages/bot-engines/licenses/NOTICE.md +32 -0
  161. package/packages/bot-engines/src/claude-engine.mjs +772 -0
  162. package/packages/bot-engines/src/claude-llm-adapter.mjs +797 -0
  163. package/packages/bot-engines/src/claude-llm-turn.mjs +292 -0
  164. package/packages/bot-engines/src/claude-permission-broker.mjs +130 -0
  165. package/packages/bot-engines/src/claude-permission-proxy.mjs +87 -0
  166. package/packages/bot-engines/src/claude-protocol.mjs +177 -0
  167. package/packages/bot-engines/src/driver-catalog.mjs +334 -0
  168. package/packages/bot-engines/src/host-loop-request.mjs +95 -0
  169. package/packages/bot-engines/src/host-registrations.mjs +105 -0
  170. package/packages/capability-broker/src/cli-bootstrap.mjs +86 -16
  171. package/packages/capability-broker/src/cli-bridge-response.mjs +80 -0
  172. package/packages/capability-broker/src/cli-stdio-bridge.mjs +21 -8
  173. package/packages/cli-runtime/src/codex-session-core.mjs +4 -0
  174. package/packages/cli-runtime/src/native-cli-output.mjs +57 -0
  175. package/packages/cli-runtime/src/native-peer.ps1 +51 -3
  176. package/packages/cli-runtime/src/native-process.mjs +77 -14
  177. package/packages/model-router-plugin/README.md +3 -3
  178. package/packages/model-router-plugin/package.json +1 -1
  179. package/packages/orchestration/src/binding-product.mjs +19 -0
  180. package/packages/orchestration/src/bot-data-actions.mjs +45 -0
  181. package/packages/orchestration/src/bot-data-chart.mjs +109 -0
  182. package/packages/orchestration/src/bot-data-context.mjs +44 -0
  183. package/packages/orchestration/src/bot-data-engine.mjs +809 -0
  184. package/packages/orchestration/src/bot-data-io.mjs +186 -0
  185. package/packages/orchestration/src/bot-data-sql.mjs +195 -0
  186. package/packages/orchestration/src/bot-data-surface.mjs +144 -0
  187. package/packages/orchestration/src/bot-data-tools.mjs +68 -0
  188. package/packages/orchestration/src/bot-data-worker.mjs +228 -0
  189. package/packages/orchestration/src/bot-independent-execution.mjs +195 -0
  190. package/packages/orchestration/src/bot-independent-stream.mjs +74 -0
  191. package/packages/orchestration/src/bot-loop.mjs +152 -19
  192. package/packages/orchestration/src/bot-notifications.mjs +159 -0
  193. package/packages/orchestration/src/bot-policy.mjs +43 -4
  194. package/packages/orchestration/src/bot-profile.mjs +171 -0
  195. package/packages/orchestration/src/bot-routine.mjs +4 -4
  196. package/packages/orchestration/src/bot-runtime-assembly.mjs +255 -8
  197. package/packages/orchestration/src/bot-runtime-switch.mjs +13 -2
  198. package/packages/orchestration/src/bot-serving.mjs +164 -0
  199. package/packages/orchestration/src/bot-session-store.mjs +105 -9
  200. package/packages/orchestration/src/bot-settings.mjs +50 -11
  201. package/packages/orchestration/src/bot-thread-admission.mjs +84 -0
  202. package/packages/orchestration/src/bot-thread-host.mjs +187 -0
  203. package/packages/orchestration/src/bot-threads.mjs +790 -0
  204. package/packages/orchestration/src/data-product-access.mjs +37 -0
  205. package/packages/orchestration/src/data-tool-contract.mjs +291 -0
  206. package/packages/orchestration/src/desktop-http-carrier.mjs +120 -0
  207. package/packages/orchestration/src/desktop-proxy.mjs +311 -0
  208. package/packages/orchestration/src/desktop-sessions.mjs +43 -9
  209. package/packages/orchestration/src/ds-lifecycle.mjs +31 -4
  210. package/packages/orchestration/src/grant-refresh-queue.mjs +17 -0
  211. package/packages/orchestration/src/independent-chat-page.mjs +39 -0
  212. package/packages/orchestration/src/independent-chat-service.mjs +308 -0
  213. package/packages/orchestration/src/independent-context-state.mjs +44 -0
  214. package/packages/orchestration/src/independent-message-wire.mjs +84 -0
  215. package/packages/orchestration/src/independent-tool-catalog.mjs +175 -0
  216. package/packages/orchestration/src/independent-tool-families.mjs +73 -0
  217. package/packages/orchestration/src/independent-tool-host.mjs +344 -0
  218. package/packages/orchestration/src/main-bot-grant.mjs +15 -0
  219. package/packages/orchestration/src/main-model-routes.mjs +208 -0
  220. package/packages/orchestration/src/model-accounting.mjs +99 -35
  221. package/packages/orchestration/src/model-auxiliary-dispatch.mjs +187 -0
  222. package/packages/orchestration/src/model-loop-frame.mjs +179 -0
  223. package/packages/orchestration/src/model-prepared-generation.mjs +175 -0
  224. package/packages/orchestration/src/model-request-bounds.mjs +111 -0
  225. package/packages/orchestration/src/native-activity-contract.mjs +491 -0
  226. package/packages/orchestration/src/native-activity-service.mjs +102 -0
  227. package/packages/orchestration/src/native-activity-store.mjs +249 -0
  228. package/packages/orchestration/src/native-conversation-tools.mjs +78 -0
  229. package/packages/orchestration/src/native-data-tools.mjs +100 -0
  230. package/packages/orchestration/src/native-remote-actions.mjs +742 -0
  231. package/packages/orchestration/src/native-team-tools.mjs +73 -0
  232. package/packages/orchestration/src/pairing-invite.mjs +37 -0
  233. package/packages/orchestration/src/product-composition.mjs +1559 -1001
  234. package/packages/orchestration/src/remote-machines.mjs +82 -14
  235. package/packages/orchestration/src/routine-execution.mjs +5 -3
  236. package/packages/orchestration/src/routine-session.mjs +19 -13
  237. package/packages/orchestration/src/secure-pairing-host.mjs +112 -0
  238. package/packages/orchestration/src/task-journal.mjs +29 -0
  239. package/packages/orchestration/src/task-product.mjs +17 -0
  240. package/packages/orchestration/src/team-assignment-store.mjs +120 -0
  241. package/packages/orchestration/src/team-bridge.mjs +282 -0
  242. package/packages/orchestration/src/team-scheduler.mjs +83 -0
  243. package/packages/orchestration/src/team-sdk-tools.mjs +84 -0
  244. package/packages/orchestration/src/team-tool-contract.mjs +284 -0
  245. package/packages/orchestration/src/ui-host-namespace.mjs +23 -0
  246. package/packages/orchestration/src/web-panel-actions.mjs +103 -0
  247. package/packages/orchestration/src/web-panel-framing.mjs +227 -0
  248. package/packages/orchestration/src/web-panel-store.mjs +206 -0
  249. package/remote-computer-agent/README.md +39 -29
  250. package/remote-computer-agent/build.mjs +3 -0
  251. package/remote-computer-agent/dist/OPENMAUSBOT_LICENSE +202 -0
  252. package/remote-computer-agent/dist/OPENMAUSBOT_NOTICE +10 -0
  253. package/remote-computer-agent/dist/OPENMAUSBOT_SOURCE.json +68 -0
  254. package/remote-computer-agent/dist/cli-stdio-bridge.mjs +215 -25
  255. package/remote-computer-agent/dist/cli-stdio-bridge.mjs.map +4 -4
  256. package/remote-computer-agent/dist/cli.mjs +1688 -168
  257. package/remote-computer-agent/dist/cli.mjs.map +4 -4
  258. package/remote-computer-agent/dist/index.mjs +1579 -122
  259. package/remote-computer-agent/dist/index.mjs.map +4 -4
  260. package/remote-computer-agent/dist/native-peer.ps1 +51 -3
  261. package/remote-computer-agent/package-lock.json +308 -2
  262. package/remote-computer-agent/package.json +2 -1
  263. package/remote-computer-agent/pair-device.ps1 +20 -0
  264. package/remote-computer-agent/setup.ps1 +38 -16
  265. package/remote-computer-agent/src/cli.ts +24 -3
  266. package/remote-computer-agent/src/desktop-session.ts +11 -3
  267. package/remote-computer-agent/src/e2e-server.ts +81 -0
  268. package/remote-computer-agent/src/pairing-page.ts +35 -0
  269. package/remote-computer-agent/src/protocol.ts +25 -25
  270. package/remote-computer-agent/src/secure-pairing.ts +105 -0
  271. package/remote-computer-agent/src/store.ts +20 -5
  272. package/remote-computer-agent/src/transport.ts +39 -15
@@ -2,6 +2,46 @@ param([ValidateSet('server','client','supervise','probe','protect')][string]$Mod
2
2
  $ErrorActionPreference = 'Stop'
3
3
  [Console]::InputEncoding = [System.Text.UTF8Encoding]::new($false, $true)
4
4
  [Console]::OutputEncoding = [System.Text.UTF8Encoding]::new($false)
5
+ $compilerPhase = $true
6
+ try {
7
+ # Host-allocated compilation storage is separate from the CLI's private
8
+ # profile/TEMP. The root hint is not a peer credential or an execution grant.
9
+ $compilerRoot = $env:DSH_NATIVE_COMPILER_ROOT
10
+ $compilerScratch = $env:DSH_NATIVE_COMPILER_SCRATCH
11
+ if ([string]::IsNullOrEmpty($compilerRoot) -or [string]::IsNullOrEmpty($compilerScratch) -or
12
+ $compilerRoot.Length -gt 140 -or $compilerScratch.Length -gt 160 -or
13
+ -not [System.IO.Path]::IsPathRooted($compilerRoot) -or -not [System.IO.Path]::IsPathRooted($compilerScratch) -or
14
+ [System.IO.Path]::GetFileName($compilerRoot) -notmatch '^dshc-[a-f0-9]{16}$' -or
15
+ [System.IO.Path]::GetFileName($compilerScratch) -notmatch '^c-[A-Za-z0-9]{6}$' -or
16
+ -not [string]::Equals([System.IO.Path]::GetDirectoryName($compilerScratch), $compilerRoot, [System.StringComparison]::OrdinalIgnoreCase)) { throw 'COMPILER_STORAGE_INVALID' }
17
+ $ownerSid = [System.Security.Principal.WindowsIdentity]::GetCurrent().User
18
+ foreach ($compilerPath in @($compilerRoot, $compilerScratch)) {
19
+ $directory = [System.IO.DirectoryInfo]::new($compilerPath)
20
+ if (-not $directory.Exists -or ($directory.Attributes -band [System.IO.FileAttributes]::ReparsePoint) -ne 0) { throw 'COMPILER_STORAGE_INVALID' }
21
+ $security = [System.Security.AccessControl.DirectorySecurity]::new()
22
+ $security.SetAccessRuleProtection($true, $false)
23
+ $security.SetOwner($ownerSid)
24
+ $security.AddAccessRule([System.Security.AccessControl.FileSystemAccessRule]::new($ownerSid, 'FullControl', 'ContainerInherit,ObjectInherit', 'None', 'Allow'))
25
+ $directory.SetAccessControl($security)
26
+ $actual = $directory.GetAccessControl()
27
+ $rules = @($actual.GetAccessRules($true, $true, [System.Security.Principal.SecurityIdentifier]))
28
+ if (-not $actual.AreAccessRulesProtected -or $rules.Count -ne 1 -or $rules[0].IdentityReference.Value -ne $ownerSid.Value -or
29
+ $rules[0].AccessControlType -ne [System.Security.AccessControl.AccessControlType]::Allow -or
30
+ $rules[0].FileSystemRights -ne [System.Security.AccessControl.FileSystemRights]::FullControl) { throw 'COMPILER_ACL_UNCONFIRMED' }
31
+ }
32
+ if ([System.IO.File]::ReadAllText([System.IO.Path]::Combine($compilerRoot, '.dsh-root')) -ne ('dsh-native-compiler-v1:' + [System.IO.Path]::GetFileName($compilerRoot) + "`n") -or
33
+ [System.IO.File]::ReadAllText([System.IO.Path]::Combine($compilerScratch, '.dsh-owner')) -notmatch '^[a-f0-9]{32}$') { throw 'COMPILER_STORAGE_INVALID' }
34
+ $compilerParameters = [System.CodeDom.Compiler.CompilerParameters]::new()
35
+ $compilerParameters.GenerateInMemory = $true
36
+ $compilerParameters.GenerateExecutable = $false
37
+ $compilerParameters.TempFiles = [System.CodeDom.Compiler.TempFileCollection]::new($compilerScratch, $false)
38
+ [void]$compilerParameters.ReferencedAssemblies.Add('System.dll')
39
+ [void]$compilerParameters.ReferencedAssemblies.Add('System.Core.dll')
40
+ $privateTemps = @{ TEMP = $env:TEMP; TMP = $env:TMP; TMPDIR = $env:TMPDIR }
41
+ try {
42
+ # csc's Win32 resource generator also uses the process TEMP; change it only
43
+ # for compilation, then restore it before admitting any CLI process.
44
+ $env:TEMP = $compilerScratch; $env:TMP = $compilerScratch; $env:TMPDIR = $compilerScratch
5
45
  # Only packaged source is compiled. No supplied command or script is evaluated.
6
46
  Add-Type -TypeDefinition @'
7
47
  using System;
@@ -286,8 +326,12 @@ public static class DshNativePeer {
286
326
  return result;
287
327
  }
288
328
  }
289
- '@
290
- try {
329
+ '@ -CompilerParameters $compilerParameters
330
+ } finally {
331
+ foreach ($key in @('TEMP','TMP','TMPDIR')) { [System.Environment]::SetEnvironmentVariable($key, $privateTemps[$key], 'Process') }
332
+ [System.Environment]::SetEnvironmentVariable('DSH_NATIVE_COMPILER_SCRATCH', $null, 'Process')
333
+ }
334
+ $compilerPhase = $false
291
335
  if ($Mode -eq 'probe') {
292
336
  $result = [DshNativePeer]::ProbeJob()
293
337
  $response = @{ peer = 'windows-kernel-pid'; supervisor = 'windows-job'; available = ($result -eq 'OK') }
@@ -308,4 +352,8 @@ try {
308
352
  elseif ($Mode -eq 'server') { [DshNativePeer]::Server($spec.endpoint,[int]$spec.rootPid,[string]$spec.rootStart,[int]$spec.ttlMs) }
309
353
  elseif ($Mode -eq 'client') { [DshNativePeer]::Client($spec.endpoint,[int]$spec.serverPid,[string]$spec.serverStart,[int]$spec.ttlMs) }
310
354
  else { [DshNativePeer]::Supervise($spec.executable,[string[]]$spec.args,$spec.cwd,[int]$spec.ttlMs) }
311
- } catch { [Console]::Error.WriteLine('NATIVE_PEER_REFUSED: ' + $_.Exception.GetBaseException().Message); exit 2 }
355
+ } catch {
356
+ $code = if ($compilerPhase) { 'NATIVE_COMPILER_FAILED' } else { $_.Exception.GetBaseException().Message }
357
+ if ($code -notmatch '^[A-Z][A-Z0-9_]{0,79}$') { $code = 'NATIVE_PEER_FAILED' }
358
+ [Console]::Error.WriteLine('NATIVE_PEER_REFUSED: ' + $code); exit 2
359
+ }
@@ -1,15 +1,16 @@
1
1
  {
2
2
  "name": "@ljwei-stak/dsh-remote-computer-agent",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@ljwei-stak/dsh-remote-computer-agent",
9
- "version": "0.1.1",
9
+ "version": "0.1.2",
10
10
  "dependencies": {
11
11
  "@modelcontextprotocol/server": "2.4.0",
12
12
  "better-sqlite3": "13.0.3",
13
+ "qrcode": "1.5.4",
13
14
  "ws": "8.22.1"
14
15
  },
15
16
  "bin": {
@@ -492,6 +493,30 @@
492
493
  "node": ">=20"
493
494
  }
494
495
  },
496
+ "node_modules/ansi-regex": {
497
+ "version": "5.0.1",
498
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
499
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
500
+ "license": "MIT",
501
+ "engines": {
502
+ "node": ">=8"
503
+ }
504
+ },
505
+ "node_modules/ansi-styles": {
506
+ "version": "4.3.0",
507
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
508
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
509
+ "license": "MIT",
510
+ "dependencies": {
511
+ "color-convert": "^2.0.1"
512
+ },
513
+ "engines": {
514
+ "node": ">=8"
515
+ },
516
+ "funding": {
517
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
518
+ }
519
+ },
495
520
  "node_modules/better-sqlite3": {
496
521
  "version": "13.0.3",
497
522
  "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-13.0.3.tgz",
@@ -504,6 +529,65 @@
504
529
  "node": ">=22"
505
530
  }
506
531
  },
532
+ "node_modules/camelcase": {
533
+ "version": "5.3.1",
534
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
535
+ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
536
+ "license": "MIT",
537
+ "engines": {
538
+ "node": ">=6"
539
+ }
540
+ },
541
+ "node_modules/cliui": {
542
+ "version": "6.0.0",
543
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
544
+ "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
545
+ "license": "ISC",
546
+ "dependencies": {
547
+ "string-width": "^4.2.0",
548
+ "strip-ansi": "^6.0.0",
549
+ "wrap-ansi": "^6.2.0"
550
+ }
551
+ },
552
+ "node_modules/color-convert": {
553
+ "version": "2.0.1",
554
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
555
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
556
+ "license": "MIT",
557
+ "dependencies": {
558
+ "color-name": "~1.1.4"
559
+ },
560
+ "engines": {
561
+ "node": ">=7.0.0"
562
+ }
563
+ },
564
+ "node_modules/color-name": {
565
+ "version": "1.1.4",
566
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
567
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
568
+ "license": "MIT"
569
+ },
570
+ "node_modules/decamelize": {
571
+ "version": "1.2.0",
572
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
573
+ "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
574
+ "license": "MIT",
575
+ "engines": {
576
+ "node": ">=0.10.0"
577
+ }
578
+ },
579
+ "node_modules/dijkstrajs": {
580
+ "version": "1.0.3",
581
+ "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz",
582
+ "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==",
583
+ "license": "MIT"
584
+ },
585
+ "node_modules/emoji-regex": {
586
+ "version": "8.0.0",
587
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
588
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
589
+ "license": "MIT"
590
+ },
507
591
  "node_modules/esbuild": {
508
592
  "version": "0.28.2",
509
593
  "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz",
@@ -546,6 +630,49 @@
546
630
  "@esbuild/win32-x64": "0.28.2"
547
631
  }
548
632
  },
633
+ "node_modules/find-up": {
634
+ "version": "4.1.0",
635
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
636
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
637
+ "license": "MIT",
638
+ "dependencies": {
639
+ "locate-path": "^5.0.0",
640
+ "path-exists": "^4.0.0"
641
+ },
642
+ "engines": {
643
+ "node": ">=8"
644
+ }
645
+ },
646
+ "node_modules/get-caller-file": {
647
+ "version": "2.0.5",
648
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
649
+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
650
+ "license": "ISC",
651
+ "engines": {
652
+ "node": "6.* || 8.* || >= 10.*"
653
+ }
654
+ },
655
+ "node_modules/is-fullwidth-code-point": {
656
+ "version": "3.0.0",
657
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
658
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
659
+ "license": "MIT",
660
+ "engines": {
661
+ "node": ">=8"
662
+ }
663
+ },
664
+ "node_modules/locate-path": {
665
+ "version": "5.0.0",
666
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
667
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
668
+ "license": "MIT",
669
+ "dependencies": {
670
+ "p-locate": "^4.1.0"
671
+ },
672
+ "engines": {
673
+ "node": ">=8"
674
+ }
675
+ },
549
676
  "node_modules/node-addon-api": {
550
677
  "version": "8.9.2",
551
678
  "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.9.2.tgz",
@@ -555,6 +682,51 @@
555
682
  "node": "^18 || ^20 || >= 21"
556
683
  }
557
684
  },
685
+ "node_modules/p-limit": {
686
+ "version": "2.3.0",
687
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
688
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
689
+ "license": "MIT",
690
+ "dependencies": {
691
+ "p-try": "^2.0.0"
692
+ },
693
+ "engines": {
694
+ "node": ">=6"
695
+ },
696
+ "funding": {
697
+ "url": "https://github.com/sponsors/sindresorhus"
698
+ }
699
+ },
700
+ "node_modules/p-locate": {
701
+ "version": "4.1.0",
702
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
703
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
704
+ "license": "MIT",
705
+ "dependencies": {
706
+ "p-limit": "^2.2.0"
707
+ },
708
+ "engines": {
709
+ "node": ">=8"
710
+ }
711
+ },
712
+ "node_modules/p-try": {
713
+ "version": "2.2.0",
714
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
715
+ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
716
+ "license": "MIT",
717
+ "engines": {
718
+ "node": ">=6"
719
+ }
720
+ },
721
+ "node_modules/path-exists": {
722
+ "version": "4.0.0",
723
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
724
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
725
+ "license": "MIT",
726
+ "engines": {
727
+ "node": ">=8"
728
+ }
729
+ },
558
730
  "node_modules/playwright": {
559
731
  "version": "1.64.1",
560
732
  "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.64.1.tgz",
@@ -584,6 +756,99 @@
584
756
  "node": ">=20"
585
757
  }
586
758
  },
759
+ "node_modules/pngjs": {
760
+ "version": "5.0.0",
761
+ "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz",
762
+ "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==",
763
+ "license": "MIT",
764
+ "engines": {
765
+ "node": ">=10.13.0"
766
+ }
767
+ },
768
+ "node_modules/qrcode": {
769
+ "version": "1.5.4",
770
+ "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.4.tgz",
771
+ "integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==",
772
+ "license": "MIT",
773
+ "dependencies": {
774
+ "dijkstrajs": "^1.0.1",
775
+ "pngjs": "^5.0.0",
776
+ "yargs": "^15.3.1"
777
+ },
778
+ "bin": {
779
+ "qrcode": "bin/qrcode"
780
+ },
781
+ "engines": {
782
+ "node": ">=10.13.0"
783
+ }
784
+ },
785
+ "node_modules/require-directory": {
786
+ "version": "2.1.1",
787
+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
788
+ "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
789
+ "license": "MIT",
790
+ "engines": {
791
+ "node": ">=0.10.0"
792
+ }
793
+ },
794
+ "node_modules/require-main-filename": {
795
+ "version": "2.0.0",
796
+ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
797
+ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
798
+ "license": "ISC"
799
+ },
800
+ "node_modules/set-blocking": {
801
+ "version": "2.0.0",
802
+ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
803
+ "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
804
+ "license": "ISC"
805
+ },
806
+ "node_modules/string-width": {
807
+ "version": "4.2.3",
808
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
809
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
810
+ "license": "MIT",
811
+ "dependencies": {
812
+ "emoji-regex": "^8.0.0",
813
+ "is-fullwidth-code-point": "^3.0.0",
814
+ "strip-ansi": "^6.0.1"
815
+ },
816
+ "engines": {
817
+ "node": ">=8"
818
+ }
819
+ },
820
+ "node_modules/strip-ansi": {
821
+ "version": "6.0.1",
822
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
823
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
824
+ "license": "MIT",
825
+ "dependencies": {
826
+ "ansi-regex": "^5.0.1"
827
+ },
828
+ "engines": {
829
+ "node": ">=8"
830
+ }
831
+ },
832
+ "node_modules/which-module": {
833
+ "version": "2.0.1",
834
+ "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz",
835
+ "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==",
836
+ "license": "ISC"
837
+ },
838
+ "node_modules/wrap-ansi": {
839
+ "version": "6.2.0",
840
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
841
+ "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
842
+ "license": "MIT",
843
+ "dependencies": {
844
+ "ansi-styles": "^4.0.0",
845
+ "string-width": "^4.1.0",
846
+ "strip-ansi": "^6.0.0"
847
+ },
848
+ "engines": {
849
+ "node": ">=8"
850
+ }
851
+ },
587
852
  "node_modules/ws": {
588
853
  "version": "8.22.1",
589
854
  "resolved": "https://registry.npmjs.org/ws/-/ws-8.22.1.tgz",
@@ -605,6 +870,47 @@
605
870
  }
606
871
  }
607
872
  },
873
+ "node_modules/y18n": {
874
+ "version": "4.0.3",
875
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
876
+ "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
877
+ "license": "ISC"
878
+ },
879
+ "node_modules/yargs": {
880
+ "version": "15.4.1",
881
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
882
+ "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
883
+ "license": "MIT",
884
+ "dependencies": {
885
+ "cliui": "^6.0.0",
886
+ "decamelize": "^1.2.0",
887
+ "find-up": "^4.1.0",
888
+ "get-caller-file": "^2.0.1",
889
+ "require-directory": "^2.1.1",
890
+ "require-main-filename": "^2.0.0",
891
+ "set-blocking": "^2.0.0",
892
+ "string-width": "^4.2.0",
893
+ "which-module": "^2.0.0",
894
+ "y18n": "^4.0.0",
895
+ "yargs-parser": "^18.1.2"
896
+ },
897
+ "engines": {
898
+ "node": ">=8"
899
+ }
900
+ },
901
+ "node_modules/yargs-parser": {
902
+ "version": "18.1.3",
903
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
904
+ "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
905
+ "license": "ISC",
906
+ "dependencies": {
907
+ "camelcase": "^5.0.0",
908
+ "decamelize": "^1.2.0"
909
+ },
910
+ "engines": {
911
+ "node": ">=6"
912
+ }
913
+ },
608
914
  "node_modules/zod": {
609
915
  "version": "4.6.7",
610
916
  "resolved": "https://registry.npmjs.org/zod/-/zod-4.6.7.tgz",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ljwei-stak/dsh-remote-computer-agent",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "bin": {
@@ -16,6 +16,7 @@
16
16
  "dependencies": {
17
17
  "@modelcontextprotocol/server": "2.4.0",
18
18
  "better-sqlite3": "13.0.3",
19
+ "qrcode": "1.5.4",
19
20
  "ws": "8.22.1"
20
21
  },
21
22
  "optionalDependencies": {
@@ -0,0 +1,20 @@
1
+ # Regenerates an unredeemed invitation without rewriting tasks, roots or permissions.
2
+ [CmdletBinding()]
3
+ param([switch]$OpenPage,[switch]$ResetPairing)
4
+ $ErrorActionPreference = 'Stop'
5
+ try {
6
+ $launch = Get-Content -Raw -LiteralPath (Join-Path $PSScriptRoot 'launch.json') | ConvertFrom-Json
7
+ $connection = Get-Content -Raw -LiteralPath (Join-Path $PSScriptRoot 'connection.json') | ConvertFrom-Json
8
+ if ($connection.pairingMode -ne 'secure') { throw 'This installation uses compatibility pairing.' }
9
+ if ($ResetPairing) {
10
+ & $launch.node $launch.cli revoke $launch.config $connection.clientId | Out-Null
11
+ if ($LASTEXITCODE -ne 0) { throw 'The old pairing could not be revoked; no new invitation was created.' }
12
+ Write-Host 'The previous pairing was revoked. Its connections and grants are no longer valid.'
13
+ }
14
+ $page = Join-Path $PSScriptRoot 'private/pairing.html'
15
+ $lines = @(& $launch.node $launch.cli invite-page $launch.config $connection.clientId $connection.ceilingFile $connection.endpoint $page)
16
+ if ($LASTEXITCODE -ne 0) { throw 'Check paired devices on this computer. To revoke a pairing whose credential the Host lost, run: pair-device.cmd -ResetPairing. This disconnects the previous pairing.' }
17
+ $result = ($lines -join "`n") | ConvertFrom-Json
18
+ Write-Host ('Pairing page: ' + $result.pageFile)
19
+ if ($OpenPage) { Start-Process -FilePath $result.pageFile -WindowStyle Normal }
20
+ } catch { Write-Error $_.Exception.Message; exit 1 }
@@ -88,7 +88,7 @@ try {
88
88
  # Snapshot only installer-owned files, never the running SQLite database.
89
89
  $privateDir = Join-Path $InstallRoot 'private'; PrivateDirectory $privateDir
90
90
  $backupDir = Join-Path $privateDir ('backup-' + (Get-Date -Format 'yyyyMMdd-HHmmss') + '-' + [Guid]::NewGuid().ToString('N').Substring(0,6)); PrivateDirectory $backupDir
91
- foreach ($relative in @('config.json','launch.json','connection.json','private/pairing.private.json','private/native.secret','private/ceiling.json')) {
91
+ foreach ($relative in @('config.json','launch.json','connection.json','private/pairing.private.json','private/pairing.html','private/pairing.html.private.json','private/native.secret','private/ceiling.json')) {
92
92
  $source = Join-Path $InstallRoot $relative
93
93
  if (Test-Path -LiteralPath $source -PathType Leaf) { $target = Join-Path $backupDir ($relative.Replace('/','-')); Copy-Item -LiteralPath $source -Destination $target; PrivateAcl $target }
94
94
  }
@@ -112,17 +112,20 @@ try {
112
112
  if (!$HelperPath) { foreach ($candidate in @((Join-Path $PackageRoot 'helpers/dsh-desktop-helper.exe'),(Join-Path $PackageRoot 'dsh-desktop-helper.exe'))) { if (Test-Path -LiteralPath $candidate -PathType Leaf) { $HelperPath=$candidate; break } } }
113
113
  if (!$HelperPath -or !(Test-Path -LiteralPath $HelperPath -PathType Leaf)) { throw 'The interactive desktop helper is missing from the package.' }
114
114
  $HelperPath = [IO.Path]::GetFullPath($HelperPath)
115
- $workspace = [IO.Path]::GetFullPath((Answer 'workspace' 'Workspace directory for this cloud computer' (Join-Path $env:USERPROFILE 'DSH-Workspace')))
116
- $bindAddress = [string](Answer 'bindAddress' 'Private VPN IP to listen on, or 127.0.0.1 for local use' '127.0.0.1')
115
+ $pairingMode = [string](Answer 'pairingMode' 'Pairing mode: secure for a short invitation, or legacy for an existing Host' 'secure')
116
+ if ($pairingMode -notin @('secure','legacy')) { throw 'Choose secure or legacy pairing.' }
117
+ $securePairing = $pairingMode -eq 'secure'
118
+ $workspace = [IO.Path]::GetFullPath((Answer 'workspace' 'Shared workspace directory on this computer' (Join-Path $env:USERPROFILE 'DSH-Workspace')))
119
+ $bindAddress = [string](Answer 'bindAddress' 'One local IP to listen on, or 127.0.0.1 for local use' '127.0.0.1')
117
120
  $parsedAddress = $null; if (![Net.IPAddress]::TryParse($bindAddress, [ref]$parsedAddress) -or $bindAddress -in @('0.0.0.0','::')) { throw 'Supply one concrete local/private VPN IP address.' }
118
121
  $loopbackBind = [Net.IPAddress]::IsLoopback($parsedAddress)
119
- $protectedTunnel = if ($loopbackBind) { $false } else { YesNo 'protectedTunnel' 'This address is on your configured private WireGuard/Tailscale network. Confirm y/n' }
120
- if (!$loopbackBind -and !$protectedTunnel) { throw 'Configure a private VPN or HTTPS reverse proxy before exposing this Agent.' }
122
+ $protectedTunnel = if ($loopbackBind -or $securePairing) { $false } else { YesNo 'protectedTunnel' 'This address is on your configured private WireGuard/Tailscale network. Confirm y/n' }
123
+ if (!$loopbackBind -and !$protectedTunnel -and !$securePairing) { throw 'Configure a private VPN or HTTPS reverse proxy before exposing this Agent.' }
121
124
  $port = [int](Answer 'port' 'Agent port' 9701); if ($port -lt 1 -or $port -gt 65535) { throw 'Invalid port.' }
122
125
  $displayHost = if ($bindAddress.Contains(':')) { "[$bindAddress]" } else { $bindAddress }
123
126
  $endpoint = [string](Answer 'endpoint' 'Agent URL reachable from your Host computer' ("http://{0}:{1}" -f $displayHost,$port))
124
127
  $endpointUri = $null; if (![Uri]::TryCreate($endpoint, [UriKind]::Absolute, [ref]$endpointUri) -or $endpointUri.Scheme -notin @('http','https') -or $endpointUri.UserInfo -or $endpointUri.Query -or $endpointUri.Fragment -or $endpointUri.AbsolutePath -ne '/') { throw 'Supply an http(s) Agent base URL without credentials, query or path.' }
125
- if ($endpointUri.Scheme -eq 'http' -and !$endpointUri.IsLoopback -and !$protectedTunnel) { throw 'HTTP remote endpoints require your explicitly confirmed private VPN.' }
128
+ if ($endpointUri.Scheme -eq 'http' -and !$endpointUri.IsLoopback -and !$protectedTunnel -and !$securePairing) { throw 'HTTP remote endpoints require your explicitly confirmed private VPN.' }
126
129
  $managed = YesNo 'hostManagedBots' 'Allow this trusted Host to manage all of its team Bots (recommended for automatic Bot setup)? Explicit y enables it'
127
130
  $botIds = @(); if (!$managed) { $botIds = @(([string](Answer 'botIds' 'Allowed Bot IDs, separated by commas' '')).Split(',') | ForEach-Object { $_.Trim() } | Where-Object { $_ }); if (!$botIds.Count) { throw 'At least one fixed Bot ID is required when team management is disabled.' } }
128
131
  $clientId = [string](Answer 'clientId' 'Name for this paired Host' 'desktop-host')
@@ -137,7 +140,7 @@ try {
137
140
  if (!(Test-Path -LiteralPath $workspace)) { New-Item -ItemType Directory -Path $workspace -Force | Out-Null }
138
141
  $nativeSecret=Join-Path $privateDir 'native.secret'; $bytes=New-Object byte[] 32; $rng=[Security.Cryptography.RandomNumberGenerator]::Create(); try { $rng.GetBytes($bytes) } finally { $rng.Dispose() }; PrivateText $nativeSecret ([Convert]::ToBase64String($bytes).TrimEnd('=').Replace('+','-').Replace('/','_'))
139
142
  $powershellExe=Join-Path $env:SystemRoot 'System32/WindowsPowerShell/v1.0/powershell.exe'
140
- $config=@{dataDir=(Join-Path $privateDir 'data');roots=@{project=$workspace};isolation='application';network=@{mode=$(if($loopbackBind){'loopback'}else{'wireguard'});host=$bindAddress;port=$port;allowedHosts=@(@($endpointUri.Authority,("{0}:{1}" -f $displayHost,$port))|Select-Object -Unique)};desktop=@{pipeName="dsh-desktop-$installationId";secretFile=$nativeSecret};browserOrigins=@();executables=@{}}
143
+ $config=@{dataDir=(Join-Path $privateDir 'data');roots=@{project=$workspace};isolation='application';network=@{mode=$(if($securePairing){'e2e'}elseif($loopbackBind){'loopback'}else{'wireguard'});host=$bindAddress;port=$port;allowedHosts=@(@($endpointUri.Authority,("{0}:{1}" -f $displayHost,$port))|Select-Object -Unique)};desktop=@{pipeName="dsh-desktop-$installationId";secretFile=$nativeSecret};browserOrigins=@();executables=@{}}
141
144
  if ($protectedTunnel) { $config.network.protectedTunnel=$true }
142
145
  if ($browserOrigin) { $config.browserOrigins=@($browserOrigin) }
143
146
  $jobHelper=Join-Path (Split-Path -Parent $HelperPath) 'dsh-process-job.exe'
@@ -146,16 +149,27 @@ try {
146
149
  $toolNames=@('machine_ping','fs_list','fs_read','fs_write','operation_status','operation_cancel','artifact_stat','artifact_read','worktree_create','worktree_diff','worktree_integrate','browser_open','browser_snapshot','browser_click','browser_type','browser_script','browser_upload','browser_download','browser_close','desktop_screenshot','desktop_click','desktop_type','desktop_key','desktop_scroll')
147
150
  if ($allowCommands) { $toolNames += 'shell_exec' }
148
151
  $ceilingFile=Join-Path $privateDir 'ceiling.json'; PrivateJson $ceilingFile @{botIds=$botIds;hostManagedBots=$managed;roots=@('project');tools=$toolNames}
149
- # Capture CLI pairing output in memory. A pairing token is never printed.
150
- $pairLines=@(& $NodePath $cliFile pair $configFile $clientId $ceilingFile);if($LASTEXITCODE -ne 0){throw 'Local pairing failed; check the complete package and private configuration.'}
151
- $paired=($pairLines -join "`n")|ConvertFrom-Json
152
- if ($paired.token -notmatch '^[A-Za-z0-9_-]{43}$' -or !$paired.machineId) { throw 'Invalid local pairing receipt.' }
153
- $pairFile=Join-Path $privateDir 'pairing.private.json'
154
- $pairExport=@{schemaVersion=1;agentApiMajor=1;machineId=$paired.machineId;clientId=$paired.clientId;secretRef=$paired.secretRef;token=$paired.token;endpoint=$endpoint.TrimEnd('/');protectedTunnel=$protectedTunnel;hostManagedBots=$managed;botIds=$botIds;rootIds=@('project');tools=$toolNames}
155
- PrivateJson $pairFile $pairExport
156
- PrivateJson (Join-Path $InstallRoot 'connection.json') @{schemaVersion=1;machineId=$paired.machineId;clientId=$clientId;endpoint=$pairExport.endpoint;protectedTunnel=$protectedTunnel;hostManagedBots=$managed;botIds=$botIds;rootIds=@('project');tools=$toolNames;pairingFile=$pairFile}
152
+ if ($securePairing) {
153
+ $identityLines=@(& $NodePath $cliFile identity $configFile);if($LASTEXITCODE -ne 0){throw 'Cannot initialize the device identity.'}
154
+ $paired=($identityLines -join "`n")|ConvertFrom-Json
155
+ $pairFile=Join-Path $privateDir 'pairing.html.private.json'
156
+ } else {
157
+ # Compatibility path: a long-term pairing token is never printed.
158
+ $pairLines=@(& $NodePath $cliFile pair $configFile $clientId $ceilingFile);if($LASTEXITCODE -ne 0){throw 'Local pairing failed; check the complete package and private configuration.'}
159
+ $paired=($pairLines -join "`n")|ConvertFrom-Json
160
+ if ($paired.token -notmatch '^[A-Za-z0-9_-]{43}$' -or !$paired.machineId) { throw 'Invalid local pairing receipt.' }
161
+ $pairFile=Join-Path $privateDir 'pairing.private.json'
162
+ $pairExport=@{schemaVersion=1;agentApiMajor=1;machineId=$paired.machineId;clientId=$paired.clientId;secretRef=$paired.secretRef;token=$paired.token;endpoint=$endpoint.TrimEnd('/');protectedTunnel=$protectedTunnel;hostManagedBots=$managed;botIds=$botIds;rootIds=@('project');tools=$toolNames}
163
+ PrivateJson $pairFile $pairExport
164
+ }
165
+ PrivateJson (Join-Path $InstallRoot 'connection.json') @{schemaVersion=1;machineId=$paired.machineId;clientId=$clientId;endpoint=$endpoint.TrimEnd('/');protectedTunnel=$protectedTunnel;hostManagedBots=$managed;botIds=$botIds;rootIds=@('project');tools=$toolNames;pairingFile=$pairFile;pairingMode=$pairingMode;ceilingFile=$ceilingFile}
157
166
  PrivateJson (Join-Path $InstallRoot 'launch.json') @{node=$NodePath;cli=$cliFile;config=$configFile;packageRoot=$PackageRoot;stdout=(Join-Path $privateDir 'agent.stdout.log');stderr=(Join-Path $privateDir 'agent.stderr.log')}
158
167
  $launcher=Join-Path $InstallRoot 'launch-agent.ps1';Copy-Item -LiteralPath (Join-Path $PSScriptRoot 'launch-agent.ps1') -Destination $launcher;PrivateAcl $launcher
168
+ if ($securePairing) {
169
+ $pairLauncher=Join-Path $InstallRoot 'pair-device.ps1';Copy-Item -LiteralPath (Join-Path $PSScriptRoot 'pair-device.ps1') -Destination $pairLauncher;PrivateAcl $pairLauncher
170
+ $pairCmd = @('@echo off', 'powershell.exe -NoLogo -NoProfile -ExecutionPolicy Bypass -File "%~dp0pair-device.ps1" -OpenPage %*', 'if errorlevel 1 pause') -join [Environment]::NewLine
171
+ PrivateText (Join-Path $InstallRoot 'pair-device.cmd') $pairCmd
172
+ }
159
173
  $agentXml=TaskXml $powershellExe ('-NoLogo -NoProfile -NonInteractive -WindowStyle Hidden -ExecutionPolicy Bypass -File "'+$launcher+'"') $InstallRoot
160
174
  $desktopXml=TaskXml $HelperPath ('--desktop-mode full --pipe '+$config.desktop.pipeName+' --secret-file "'+$nativeSecret+'"') (Split-Path -Parent $HelperPath)
161
175
  PrivateText (Join-Path $privateDir 'agent-task.xml') $agentXml;PrivateText (Join-Path $privateDir 'desktop-task.xml') $desktopXml
@@ -164,7 +178,15 @@ try {
164
178
  if (!$NoStart -and (YesNo 'startNow' 'Start the desktop helper and Agent now?' $true)) {
165
179
  foreach($taskName in @($desktopTask,$agentTask)){if($MockTaskRegistry){continue};Start-ScheduledTask -TaskName $taskName}
166
180
  }
181
+ if ($securePairing) {
182
+ $inviteLines=@(& $NodePath $cliFile invite-page $configFile $clientId $ceilingFile $endpoint (Join-Path $privateDir 'pairing.html'))
183
+ if ($LASTEXITCODE -ne 0) { throw 'Services were configured; invitation creation failed. Run pair-device.cmd to try again.' }
184
+ $inviteReceipt=($inviteLines -join "`n")|ConvertFrom-Json
185
+ PrivateAcl $inviteReceipt.pageFile;PrivateAcl $inviteReceipt.pairingFile
186
+ Write-Host ('Open the local pairing page: ' + $inviteReceipt.pageFile)
187
+ Write-Host 'This invitation lasts two minutes. Run pair-device.cmd to refresh an unredeemed invitation.'
188
+ }
167
189
  Write-Host "Configured user-owned cloud computer at $InstallRoot"
168
190
  Write-Host "Import this private pairing file in your Host app: $pairFile"
169
- Write-Host 'The token stays in that protected file. Keep this Windows user signed in for full desktop access.'
191
+ Write-Host 'Keep this Windows user signed in for full desktop access.'
170
192
  } catch { Write-Error ('Setup stopped: ' + $_.Exception.Message); exit 1 }
@@ -5,9 +5,10 @@ import { Agent } from './agent.js'
5
5
  import { Store } from './store.js'
6
6
  import { serve } from './transport.js'
7
7
  import { fail } from './protocol.js'
8
+ import { writePairingPage } from './pairing-page.js'
8
9
  const [command,configPath,...args]=process.argv.slice(2)
9
10
  try{
10
- if(!configPath)fail('USAGE: dsh-remote-agent init|serve|pair|rotate|revoke <config.json> [clientId ceiling.json]')
11
+ if(!configPath)fail('USAGE: dsh-remote-agent init|serve|identity|devices|invite|invite-page|pair|rotate|revoke <config.json> [clientId ceiling.json endpoint page.html]')
11
12
  const file=resolve(configPath)
12
13
  if(command==='init'){
13
14
  const root=resolve(args[0]??'.');const config={dataDir:join(dirname(file),'data'),roots:{project:root},isolation:'application',network:{mode:'loopback',host:'127.0.0.1',port:9701},executables:{node:process.execPath},browserOrigins:[]}
@@ -15,11 +16,31 @@ try{
15
16
  }else{
16
17
  const config=JSON.parse(await readFile(file,'utf8'))
17
18
  if(command==='serve'){
19
+ let invitation:any
20
+ if(args.length){
21
+ if(args[0]!=='--invite'||args.length!==4)fail('USAGE: serve <config.json> --invite <clientId> <ceiling.json> <endpoint>')
22
+ const local=new Store(config.dataDir,undefined,{admin:true})
23
+ try{const ceiling=JSON.parse(await readFile(resolve(args[2]),'utf8'));for(const root of ceiling.roots??[])if(!config.roots[root])fail('UNKNOWN_ROOT');invitation=local.invite(args[1],ceiling,{endpoint:args[3]})}finally{local.close()}
24
+ }
18
25
  const agent=new Agent(config);let handle:any;try{handle=await serve(agent,config.network)}catch(e){await agent.close();throw e}
19
- console.log(JSON.stringify({machineId:agent.store.machineId,listening:handle.address,protocols:handle.supportedMcpVersions}));let stopping=false
26
+ console.log(JSON.stringify({machineId:agent.store.machineId,listening:handle.address,protocols:handle.supportedMcpVersions}));if(invitation)console.log(JSON.stringify(invitation));let stopping=false
20
27
  const stop=async()=>{if(stopping)return;stopping=true;await handle.close();await agent.close()};process.once('SIGINT',()=>void stop());process.once('SIGTERM',()=>void stop())
21
28
  }else{
22
- const store=new Store(config.dataDir,undefined,{admin:true});try{let result:any;if(command==='pair'){const ceiling=JSON.parse(await readFile(resolve(args[1]),'utf8'));for(const root of ceiling.roots??[])if(!config.roots[root])fail('UNKNOWN_ROOT');result=store.pair(args[0],ceiling)}else if(command==='rotate')result=store.rotate(args[0]);else if(command==='revoke'){store.revoke(args[0]);result={revoked:true}}else fail('UNKNOWN_COMMAND');console.log(JSON.stringify(result))}finally{store.close()}
29
+ const store=new Store(config.dataDir,undefined,{admin:true})
30
+ try{
31
+ let result:any
32
+ if(['pair','invite','invite-page'].includes(command)){
33
+ if(!args[0]||!args[1]||command==='invite-page'&&!args[3])fail('PAIRING_ARGUMENTS_REQUIRED')
34
+ const ceiling=JSON.parse(await readFile(resolve(args[1]),'utf8'));for(const root of ceiling.roots??[])if(!config.roots[root])fail('UNKNOWN_ROOT')
35
+ result=command==='pair'?store.pair(args[0],ceiling):store.invite(args[0],ceiling,{endpoint:args[2]})
36
+ if(command==='invite-page')result=await writePairingPage(result,args[3])
37
+ }else if(command==='identity')result={machineId:store.machineId,transport:store.pairing.identity()}
38
+ else if(command==='devices')result={machineId:store.machineId,devices:store.db.prepare('SELECT id,revision,revoked,ceiling FROM clients ORDER BY id').all().map((row:any)=>({clientId:row.id,revision:row.revision,revoked:!!row.revoked,ceiling:JSON.parse(row.ceiling)}))}
39
+ else if(command==='rotate')result=store.rotate(args[0])
40
+ else if(command==='revoke'){store.revoke(args[0]);result={revoked:true}}
41
+ else fail('UNKNOWN_COMMAND')
42
+ console.log(JSON.stringify(result))
43
+ }finally{store.close()}
23
44
  }
24
45
  }
25
46
  }catch(e:any){console.error(e.code??'AGENT_START_FAILED');process.exitCode=1}