@psnext/slingcli 2.4.20260526-1 → 2.4.20260527-2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (227) hide show
  1. package/bin/sling.js +4 -1
  2. package/node_modules/@aws-sdk/core/package.json +2 -2
  3. package/node_modules/@aws-sdk/credential-provider-env/package.json +2 -2
  4. package/node_modules/@aws-sdk/credential-provider-http/dist-cjs/fromHttp/fromHttp.js +12 -6
  5. package/node_modules/@aws-sdk/credential-provider-http/dist-es/fromHttp/fromHttp.js +12 -6
  6. package/node_modules/@aws-sdk/credential-provider-http/package.json +3 -2
  7. package/node_modules/@aws-sdk/credential-provider-ini/package.json +9 -9
  8. package/node_modules/@aws-sdk/credential-provider-login/package.json +3 -3
  9. package/node_modules/@aws-sdk/credential-provider-node/package.json +7 -7
  10. package/node_modules/@aws-sdk/credential-provider-process/package.json +2 -2
  11. package/node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/token-providers/package.json +3 -3
  12. package/node_modules/@aws-sdk/credential-provider-sso/package.json +4 -4
  13. package/node_modules/@aws-sdk/credential-provider-web-identity/package.json +3 -3
  14. package/node_modules/@aws-sdk/middleware-websocket/package.json +2 -2
  15. package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/cognito-identity/index.js +1 -1
  16. package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/signin/index.js +1 -1
  17. package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/sso/index.js +1 -1
  18. package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/sso-oidc/index.js +1 -1
  19. package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/sts/index.js +1 -1
  20. package/node_modules/@aws-sdk/nested-clients/package.json +3 -3
  21. package/node_modules/@aws-sdk/signature-v4-multi-region/package.json +1 -2
  22. package/node_modules/@aws-sdk/xml-builder/package.json +2 -2
  23. package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/compaction.js +18 -24
  24. package/node_modules/@earendil-works/pi-agent-core/package.json +2 -2
  25. package/node_modules/@earendil-works/pi-ai/dist/cli.js +14 -0
  26. package/node_modules/@earendil-works/pi-ai/dist/models.generated.js +73 -58
  27. package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.js +2 -1
  28. package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.js +8 -22
  29. package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.js +1 -1
  30. package/node_modules/@earendil-works/pi-ai/dist/providers/images/openrouter.js +1 -1
  31. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex-responses.js +60 -40
  32. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.js +1 -1
  33. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.js +1 -1
  34. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/device-code.js +55 -0
  35. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/github-copilot.js +45 -69
  36. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/index.js +1 -0
  37. package/node_modules/@earendil-works/pi-ai/dist/utils/overflow.js +5 -2
  38. package/node_modules/@earendil-works/pi-ai/package.json +4 -3
  39. package/node_modules/@earendil-works/pi-coding-agent/dist/cli/file-processor.js +2 -3
  40. package/node_modules/@earendil-works/pi-coding-agent/dist/config.js +18 -12
  41. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-runtime.js +2 -1
  42. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-services.js +3 -2
  43. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.js +8 -2
  44. package/node_modules/@earendil-works/pi-coding-agent/dist/core/auth-storage.js +2 -1
  45. package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/compaction.js +18 -24
  46. package/node_modules/@earendil-works/pi-coding-agent/dist/core/export-html/index.js +8 -6
  47. package/node_modules/@earendil-works/pi-coding-agent/dist/core/export-html/template.js +6 -3
  48. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/loader.js +12 -29
  49. package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-registry.js +5 -1
  50. package/node_modules/@earendil-works/pi-coding-agent/dist/core/output-guard.js +52 -22
  51. package/node_modules/@earendil-works/pi-coding-agent/dist/core/package-manager.js +63 -36
  52. package/node_modules/@earendil-works/pi-coding-agent/dist/core/prompt-templates.js +6 -20
  53. package/node_modules/@earendil-works/pi-coding-agent/dist/core/resource-loader.js +38 -31
  54. package/node_modules/@earendil-works/pi-coding-agent/dist/core/sdk.js +9 -4
  55. package/node_modules/@earendil-works/pi-coding-agent/dist/core/session-manager.js +32 -24
  56. package/node_modules/@earendil-works/pi-coding-agent/dist/core/settings-manager.js +6 -13
  57. package/node_modules/@earendil-works/pi-coding-agent/dist/core/skills.js +8 -22
  58. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/bash.js +54 -53
  59. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/edit-diff.js +8 -1
  60. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/edit.js +44 -81
  61. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/file-mutation-queue.js +27 -12
  62. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/find.js +2 -3
  63. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/grep.js +3 -3
  64. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/ls.js +5 -5
  65. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/output-accumulator.js +9 -3
  66. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/path-utils.js +39 -21
  67. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/read.js +9 -8
  68. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/truncate.js +12 -2
  69. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/write.js +20 -35
  70. package/node_modules/@earendil-works/pi-coding-agent/dist/main.js +5 -6
  71. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/config-selector.js +1 -1
  72. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/footer.js +14 -5
  73. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/login-dialog.js +29 -4
  74. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/user-message.js +1 -1
  75. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.js +4 -4
  76. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/theme/theme.js +37 -28
  77. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-client.js +64 -7
  78. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-mode.js +15 -3
  79. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/clipboard-native.js +14 -8
  80. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/image-resize-core.js +124 -0
  81. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/image-resize-worker.js +31 -0
  82. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/image-resize.js +75 -115
  83. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/paths.js +33 -7
  84. package/node_modules/@earendil-works/pi-coding-agent/npm-shrinkwrap.json +13 -26
  85. package/node_modules/@earendil-works/pi-coding-agent/package.json +6 -6
  86. package/node_modules/@earendil-works/pi-tui/dist/components/editor.js +40 -55
  87. package/node_modules/@earendil-works/pi-tui/dist/components/input.js +2 -2
  88. package/node_modules/@earendil-works/pi-tui/dist/components/markdown.js +12 -2
  89. package/node_modules/@earendil-works/pi-tui/dist/native-modifiers.js +53 -0
  90. package/node_modules/@earendil-works/pi-tui/dist/terminal-image.js +4 -1
  91. package/node_modules/@earendil-works/pi-tui/dist/terminal.js +38 -16
  92. package/node_modules/@earendil-works/pi-tui/dist/utils.js +19 -12
  93. package/node_modules/@earendil-works/pi-tui/native/darwin/prebuilds/darwin-arm64/darwin-modifiers.node +0 -0
  94. package/node_modules/@earendil-works/pi-tui/native/darwin/prebuilds/darwin-x64/darwin-modifiers.node +0 -0
  95. package/node_modules/@earendil-works/pi-tui/native/win32/prebuilds/win32-arm64/win32-console-mode.node +0 -0
  96. package/node_modules/@earendil-works/pi-tui/native/win32/prebuilds/win32-x64/win32-console-mode.node +0 -0
  97. package/node_modules/@earendil-works/pi-tui/package.json +3 -5
  98. package/node_modules/@smithy/node-http-handler/package.json +2 -2
  99. package/package.json +6 -6
  100. package/slingshot/index.js +246 -244
  101. package/node_modules/koffi/CHANGELOG.md +0 -1093
  102. package/node_modules/koffi/LICENSE.txt +0 -22
  103. package/node_modules/koffi/README.md +0 -43
  104. package/node_modules/koffi/build/koffi/darwin_arm64/koffi.node +0 -0
  105. package/node_modules/koffi/build/koffi/darwin_x64/koffi.node +0 -0
  106. package/node_modules/koffi/build/koffi/freebsd_arm64/koffi.node +0 -0
  107. package/node_modules/koffi/build/koffi/freebsd_ia32/koffi.node +0 -0
  108. package/node_modules/koffi/build/koffi/freebsd_x64/koffi.node +0 -0
  109. package/node_modules/koffi/build/koffi/linux_arm64/koffi.node +0 -0
  110. package/node_modules/koffi/build/koffi/linux_armhf/koffi.node +0 -0
  111. package/node_modules/koffi/build/koffi/linux_ia32/koffi.node +0 -0
  112. package/node_modules/koffi/build/koffi/linux_loong64/koffi.node +0 -0
  113. package/node_modules/koffi/build/koffi/linux_riscv64d/koffi.node +0 -0
  114. package/node_modules/koffi/build/koffi/linux_x64/koffi.node +0 -0
  115. package/node_modules/koffi/build/koffi/musl_arm64/koffi.node +0 -0
  116. package/node_modules/koffi/build/koffi/musl_x64/koffi.node +0 -0
  117. package/node_modules/koffi/build/koffi/openbsd_ia32/koffi.node +0 -0
  118. package/node_modules/koffi/build/koffi/openbsd_x64/koffi.node +0 -0
  119. package/node_modules/koffi/build/koffi/win32_arm64/koffi.exp +0 -0
  120. package/node_modules/koffi/build/koffi/win32_arm64/koffi.lib +0 -0
  121. package/node_modules/koffi/build/koffi/win32_arm64/koffi.node +0 -0
  122. package/node_modules/koffi/build/koffi/win32_ia32/koffi.exp +0 -0
  123. package/node_modules/koffi/build/koffi/win32_ia32/koffi.lib +0 -0
  124. package/node_modules/koffi/build/koffi/win32_ia32/koffi.node +0 -0
  125. package/node_modules/koffi/build/koffi/win32_x64/koffi.exp +0 -0
  126. package/node_modules/koffi/build/koffi/win32_x64/koffi.lib +0 -0
  127. package/node_modules/koffi/build/koffi/win32_x64/koffi.node +0 -0
  128. package/node_modules/koffi/doc/benchmarks.md +0 -126
  129. package/node_modules/koffi/doc/callbacks.md +0 -210
  130. package/node_modules/koffi/doc/contribute.md +0 -148
  131. package/node_modules/koffi/doc/functions.md +0 -250
  132. package/node_modules/koffi/doc/index.md +0 -61
  133. package/node_modules/koffi/doc/input.md +0 -471
  134. package/node_modules/koffi/doc/migration.md +0 -159
  135. package/node_modules/koffi/doc/misc.md +0 -180
  136. package/node_modules/koffi/doc/output.md +0 -305
  137. package/node_modules/koffi/doc/packaging.md +0 -88
  138. package/node_modules/koffi/doc/platforms.md +0 -36
  139. package/node_modules/koffi/doc/pointers.md +0 -328
  140. package/node_modules/koffi/doc/start.md +0 -118
  141. package/node_modules/koffi/doc/unions.md +0 -186
  142. package/node_modules/koffi/doc/variables.md +0 -102
  143. package/node_modules/koffi/index.d.ts +0 -288
  144. package/node_modules/koffi/index.js +0 -634
  145. package/node_modules/koffi/indirect.js +0 -533
  146. package/node_modules/koffi/lib/native/base/base.cc +0 -11015
  147. package/node_modules/koffi/lib/native/base/base.hh +0 -6003
  148. package/node_modules/koffi/lib/native/base/crc.inc +0 -2214
  149. package/node_modules/koffi/lib/native/base/crc_gen.py +0 -72
  150. package/node_modules/koffi/lib/native/base/mimetypes.inc +0 -1248
  151. package/node_modules/koffi/lib/native/base/mimetypes_gen.py +0 -58
  152. package/node_modules/koffi/lib/native/base/tower.cc +0 -821
  153. package/node_modules/koffi/lib/native/base/tower.hh +0 -81
  154. package/node_modules/koffi/lib/native/base/unicode.inc +0 -408
  155. package/node_modules/koffi/lib/native/base/unicode_gen.py +0 -152
  156. package/node_modules/koffi/package.json +0 -38
  157. package/node_modules/koffi/src/cnoke/LICENSE.txt +0 -22
  158. package/node_modules/koffi/src/cnoke/README.md +0 -99
  159. package/node_modules/koffi/src/cnoke/assets/FindCNoke.cmake +0 -127
  160. package/node_modules/koffi/src/cnoke/assets/toolchains.json +0 -126
  161. package/node_modules/koffi/src/cnoke/assets/win_delay_hook.c +0 -36
  162. package/node_modules/koffi/src/cnoke/cnoke.js +0 -170
  163. package/node_modules/koffi/src/cnoke/package.json +0 -24
  164. package/node_modules/koffi/src/cnoke/src/builder.js +0 -511
  165. package/node_modules/koffi/src/cnoke/src/index.js +0 -10
  166. package/node_modules/koffi/src/cnoke/src/tools.js +0 -407
  167. package/node_modules/koffi/src/koffi/CMakeLists.txt +0 -182
  168. package/node_modules/koffi/src/koffi/src/abi_arm32.cc +0 -1018
  169. package/node_modules/koffi/src/koffi/src/abi_arm32_asm.S +0 -169
  170. package/node_modules/koffi/src/koffi/src/abi_arm64.cc +0 -1295
  171. package/node_modules/koffi/src/koffi/src/abi_arm64_asm.S +0 -195
  172. package/node_modules/koffi/src/koffi/src/abi_arm64_asm.asm +0 -174
  173. package/node_modules/koffi/src/koffi/src/abi_loong64.cc +0 -5
  174. package/node_modules/koffi/src/koffi/src/abi_loong64_asm.S +0 -204
  175. package/node_modules/koffi/src/koffi/src/abi_riscv64.cc +0 -915
  176. package/node_modules/koffi/src/koffi/src/abi_riscv64_asm.S +0 -203
  177. package/node_modules/koffi/src/koffi/src/abi_x64_sysv.cc +0 -939
  178. package/node_modules/koffi/src/koffi/src/abi_x64_sysv_asm.S +0 -231
  179. package/node_modules/koffi/src/koffi/src/abi_x64_win.cc +0 -715
  180. package/node_modules/koffi/src/koffi/src/abi_x64_win_asm.S +0 -166
  181. package/node_modules/koffi/src/koffi/src/abi_x64_win_asm.asm +0 -192
  182. package/node_modules/koffi/src/koffi/src/abi_x86.cc +0 -860
  183. package/node_modules/koffi/src/koffi/src/abi_x86_asm.S +0 -193
  184. package/node_modules/koffi/src/koffi/src/abi_x86_asm.asm +0 -177
  185. package/node_modules/koffi/src/koffi/src/call.cc +0 -1326
  186. package/node_modules/koffi/src/koffi/src/call.hh +0 -179
  187. package/node_modules/koffi/src/koffi/src/errno.inc +0 -462
  188. package/node_modules/koffi/src/koffi/src/ffi.cc +0 -2702
  189. package/node_modules/koffi/src/koffi/src/ffi.hh +0 -354
  190. package/node_modules/koffi/src/koffi/src/init.js +0 -105
  191. package/node_modules/koffi/src/koffi/src/parser.cc +0 -220
  192. package/node_modules/koffi/src/koffi/src/parser.hh +0 -54
  193. package/node_modules/koffi/src/koffi/src/util.cc +0 -1807
  194. package/node_modules/koffi/src/koffi/src/util.hh +0 -221
  195. package/node_modules/koffi/src/koffi/src/uv.cc +0 -193
  196. package/node_modules/koffi/src/koffi/src/uv.def +0 -10
  197. package/node_modules/koffi/src/koffi/src/uv.hh +0 -40
  198. package/node_modules/koffi/src/koffi/src/win32.cc +0 -198
  199. package/node_modules/koffi/src/koffi/src/win32.hh +0 -119
  200. package/node_modules/koffi/src/koffi/tools/write_trampolines.js +0 -77
  201. package/node_modules/koffi/vendor/node-addon-api/LICENSE.md +0 -9
  202. package/node_modules/koffi/vendor/node-addon-api/README.md +0 -95
  203. package/node_modules/koffi/vendor/node-addon-api/napi-inl.deprecated.h +0 -186
  204. package/node_modules/koffi/vendor/node-addon-api/napi-inl.h +0 -7033
  205. package/node_modules/koffi/vendor/node-addon-api/napi.h +0 -3309
  206. package/node_modules/koffi/vendor/node-api-headers/LICENSE +0 -21
  207. package/node_modules/koffi/vendor/node-api-headers/README.md +0 -95
  208. package/node_modules/koffi/vendor/node-api-headers/def/js_native_api.def +0 -125
  209. package/node_modules/koffi/vendor/node-api-headers/def/node_api.def +0 -157
  210. package/node_modules/koffi/vendor/node-api-headers/include/js_native_api.h +0 -591
  211. package/node_modules/koffi/vendor/node-api-headers/include/js_native_api_types.h +0 -210
  212. package/node_modules/koffi/vendor/node-api-headers/include/node_api.h +0 -265
  213. package/node_modules/koffi/vendor/node-api-headers/include/node_api_types.h +0 -58
  214. package/node_modules/koffi/vendor/node-api-headers/include/uv/aix.h +0 -32
  215. package/node_modules/koffi/vendor/node-api-headers/include/uv/bsd.h +0 -34
  216. package/node_modules/koffi/vendor/node-api-headers/include/uv/darwin.h +0 -61
  217. package/node_modules/koffi/vendor/node-api-headers/include/uv/errno.h +0 -483
  218. package/node_modules/koffi/vendor/node-api-headers/include/uv/linux.h +0 -34
  219. package/node_modules/koffi/vendor/node-api-headers/include/uv/os390.h +0 -33
  220. package/node_modules/koffi/vendor/node-api-headers/include/uv/posix.h +0 -31
  221. package/node_modules/koffi/vendor/node-api-headers/include/uv/sunos.h +0 -44
  222. package/node_modules/koffi/vendor/node-api-headers/include/uv/threadpool.h +0 -37
  223. package/node_modules/koffi/vendor/node-api-headers/include/uv/tree.h +0 -521
  224. package/node_modules/koffi/vendor/node-api-headers/include/uv/unix.h +0 -512
  225. package/node_modules/koffi/vendor/node-api-headers/include/uv/version.h +0 -43
  226. package/node_modules/koffi/vendor/node-api-headers/include/uv/win.h +0 -698
  227. package/node_modules/koffi/vendor/node-api-headers/include/uv.h +0 -1990
@@ -1,821 +0,0 @@
1
- // SPDX-License-Identifier: MIT
2
- // SPDX-FileCopyrightText: 2025 Niels Martignène <niels.martignene@protonmail.com>
3
-
4
- #include "base.hh"
5
- #include "tower.hh"
6
-
7
- #if defined(_WIN32)
8
- #if !defined(NOMINMAX)
9
- #define NOMINMAX
10
- #endif
11
- #if !defined(WIN32_LEAN_AND_MEAN)
12
- #define WIN32_LEAN_AND_MEAN
13
- #endif
14
- #define SECURITY_WIN32
15
- #include <windows.h>
16
- #include <security.h>
17
- #else
18
- #include <fcntl.h>
19
- #include <poll.h>
20
- #include <sys/socket.h>
21
- #endif
22
-
23
- namespace K {
24
-
25
- #if defined(_WIN32)
26
-
27
- struct OverlappedPipe {
28
- OVERLAPPED ov = {};
29
- HANDLE h = nullptr;
30
- uint8_t buf[1024];
31
-
32
- ~OverlappedPipe();
33
- };
34
-
35
- OverlappedPipe::~OverlappedPipe()
36
- {
37
- if (h) {
38
- CancelIo(h);
39
- CloseHandle(h);
40
- }
41
- if (ov.hEvent) {
42
- CloseHandle(ov.hEvent);
43
- }
44
- }
45
-
46
- static bool CheckPipePath(const char *path)
47
- {
48
- if (!StartsWith(path, "\\\\.\\pipe\\")) {
49
- LogError("Control pipe names must start with '%1'", "\\\\.\\pipe\\");
50
- return false;
51
- }
52
- if (!path[9]) {
53
- LogError("Truncated control pipe name '%1'", path);
54
- return false;
55
- }
56
-
57
- return true;
58
- }
59
-
60
- static OverlappedPipe *BindPipe(const char *path)
61
- {
62
- OverlappedPipe *pipe = new OverlappedPipe();
63
- K_DEFER_N(err_guard) { delete pipe; };
64
-
65
- pipe->ov.hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
66
- if (!pipe->ov.hEvent) {
67
- LogError("Failed to create event: %1", GetWin32ErrorString());
68
- return nullptr;
69
- }
70
-
71
- pipe->h = CreateNamedPipeA(path, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
72
- PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 8192, 8192, 0, nullptr);
73
- if (pipe->h == INVALID_HANDLE_VALUE) {
74
- pipe->h = nullptr;
75
-
76
- LogError("Failed to create named control pipe: %1", GetWin32ErrorString());
77
- return nullptr;
78
- }
79
-
80
- if (ConnectNamedPipe(pipe->h, &pipe->ov) || GetLastError() == ERROR_PIPE_CONNECTED) {
81
- SetEvent(pipe->ov.hEvent);
82
- } else if (GetLastError() != ERROR_IO_PENDING) {
83
- LogError("Failed to connect to named pipe: %1", GetWin32ErrorString());
84
- return nullptr;
85
- }
86
-
87
- err_guard.Disable();
88
- return pipe;
89
- }
90
-
91
- static OverlappedPipe *ConnectPipe(const char *path)
92
- {
93
- OverlappedPipe *pipe = new OverlappedPipe();
94
- K_DEFER_N(err_guard) { delete pipe; };
95
-
96
- pipe->ov.hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
97
- if (!pipe->ov.hEvent) {
98
- LogError("Failed to create event: %1", GetWin32ErrorString());
99
- return nullptr;
100
- }
101
-
102
- for (int i = 0; i < 10; i++) {
103
- if (!WaitNamedPipeA(path, 10))
104
- continue;
105
-
106
- pipe->h = CreateFileA(path, GENERIC_READ | GENERIC_WRITE,
107
- 0, nullptr, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, nullptr);
108
-
109
- if (pipe->h != INVALID_HANDLE_VALUE)
110
- break;
111
- pipe->h = nullptr;
112
-
113
- if (GetLastError() != ERROR_PIPE_BUSY) {
114
- LogError("Failed to connect to named pipe: %1", GetWin32ErrorString());
115
- return nullptr;
116
- }
117
- }
118
-
119
- if (!pipe->h) {
120
- LogError("Failed to connect to named pipe: %1", GetWin32ErrorString());
121
- return nullptr;
122
- }
123
-
124
- err_guard.Disable();
125
- return pipe;
126
- }
127
-
128
- // Does not print errors
129
- static bool StartRead(OverlappedPipe *pipe)
130
- {
131
- ResetEvent(pipe->ov.hEvent);
132
-
133
- if (!::ReadFile(pipe->h, pipe->buf, K_SIZE(pipe->buf), nullptr, &pipe->ov) &&
134
- GetLastError() != ERROR_IO_PENDING)
135
- return false;
136
-
137
- return true;
138
- }
139
-
140
- // Does not print errors
141
- static Size FinalizeRead(OverlappedPipe *pipe)
142
- {
143
- DWORD len = 0;
144
- if (!GetOverlappedResult(pipe->h, &pipe->ov, &len, TRUE))
145
- return -1;
146
-
147
- return len;
148
- }
149
-
150
- // Does not print errors
151
- static Size ReadSync(OverlappedPipe *pipe, void *buf, Size buf_len, int timeout)
152
- {
153
- DWORD len = 0;
154
-
155
- if (!::ReadFile(pipe->h, buf, (DWORD)buf_len, nullptr, &pipe->ov) &&
156
- GetLastError() != ERROR_IO_PENDING)
157
- return -1;
158
- if (timeout > 0)
159
- WaitForSingleObject(pipe->ov.hEvent, timeout);
160
- if (!GetOverlappedResult(pipe->h, &pipe->ov, &len, timeout < 0) &&
161
- GetLastError() != ERROR_IO_INCOMPLETE)
162
- return -1;
163
-
164
- return (Size)len;
165
- }
166
-
167
- // Does not print errors
168
- static Size WriteSync(OverlappedPipe *pipe, const void *buf, Size buf_len)
169
- {
170
- OVERLAPPED ov = {};
171
- DWORD written = 0;
172
-
173
- if (!::WriteFile(pipe->h, buf, (DWORD)buf_len, nullptr, &ov) &&
174
- GetLastError() != ERROR_IO_PENDING)
175
- return -1;
176
- if (!GetOverlappedResult(pipe->h, &ov, &written, TRUE))
177
- return -1;
178
-
179
- return (Size)written;
180
- }
181
-
182
- bool TowerServer::Bind(const char *path)
183
- {
184
- K_ASSERT(!name[0]);
185
- K_ASSERT(!pipes.len);
186
-
187
- K_DEFER_N(err_guard) { Stop(); };
188
-
189
- if (!CheckPipePath(path))
190
- return false;
191
- if (!CopyString(path, name)) {
192
- LogError("Control pipe name '%1' is too long", path);
193
- return false;
194
- }
195
-
196
- OverlappedPipe *pipe = BindPipe(path);
197
- if (!pipe)
198
- return false;
199
- pipes.Append(pipe);
200
-
201
- err_guard.Disable();
202
- return true;
203
- }
204
-
205
- void TowerServer::Start(std::function<bool(StreamReader *, StreamWriter *)> func)
206
- {
207
- K_ASSERT(pipes.len == 1);
208
- K_ASSERT(!sources.len);
209
- K_ASSERT(!handle_func);
210
-
211
- sources.Append({ pipes[0]->ov.hEvent, -1 });
212
- handle_func = func;
213
- }
214
-
215
- void TowerServer::Stop()
216
- {
217
- for (OverlappedPipe *pipe: pipes) {
218
- delete pipe;
219
- }
220
- pipes.Clear();
221
- sources.Clear();
222
-
223
- MemSet(name, 0, K_SIZE(name));
224
-
225
- handle_func = {};
226
- }
227
-
228
- static bool IsSignaled(HANDLE h)
229
- {
230
- DWORD ret = WaitForSingleObject(h, 0);
231
- return ret == WAIT_OBJECT_0;
232
- }
233
-
234
- bool TowerServer::Process(uint64_t ready)
235
- {
236
- // Accept new clients
237
- if (ready & 1) {
238
- OverlappedPipe *client = pipes[0];
239
-
240
- if (IsSignaled(client->ov.hEvent)) {
241
- OverlappedPipe *pipe = BindPipe(name);
242
-
243
- // We're kind of screwed if this happens, let the caller know and fail hard
244
- if (!pipe) {
245
- sources.len = 0;
246
- return false;
247
- }
248
-
249
- pipes[0] = pipe;
250
- sources[0].handle = pipe->ov.hEvent;
251
-
252
- if (pipes.Available()) [[likely]] {
253
- if (FinalizeRead(client) == 0 && StartRead(client)) {
254
- pipes.Append(client);
255
- sources.Append({ client->ov.hEvent, -1 });
256
-
257
- LogDebug("Client has connected");
258
- } else {
259
- LogError("Failed to accept client: %1", GetWin32ErrorString());
260
- delete client;
261
- }
262
- } else {
263
- LogError("Too many connections, refusing new client");
264
- delete client;
265
- }
266
- }
267
- }
268
-
269
- RunClients([&](Size idx, OverlappedPipe *pipe) {
270
- if (!(ready & (1ull << idx)))
271
- return true;
272
-
273
- Span<uint8_t> buf = MakeSpan(pipe->buf, FinalizeRead(pipe));
274
- if (buf.len < 0) {
275
- LogDebug("Client has disconnected");
276
- return false;
277
- }
278
-
279
- const auto read = [&](Span<uint8_t> out_buf) {
280
- if (buf.len) {
281
- Size copy_len = std::min(buf.len, out_buf.len);
282
- MemCpy(out_buf.ptr, buf.ptr, copy_len);
283
-
284
- buf.ptr += copy_len;
285
- buf.len -= copy_len;
286
-
287
- return copy_len;
288
- }
289
-
290
- Size received = ReadSync(pipe, out_buf.ptr, out_buf.len, 1000);
291
- if (received < 0) {
292
- LogError("Failed to receive data from client: %1", GetWin32ErrorString());
293
- } else if (!received) {
294
- LogError("Client has timed out");
295
- received = -1;
296
- }
297
-
298
- return received;
299
- };
300
-
301
- const auto write = [&](Span<const uint8_t> buf) {
302
- while (buf.len) {
303
- Size sent = WriteSync(pipe, buf.ptr, buf.len);
304
- if (sent < 0) {
305
- LogError("Failed to send data to server: %1", GetWin32ErrorString());
306
- return false;
307
- }
308
-
309
- buf.ptr += sent;
310
- buf.len -= sent;
311
- }
312
-
313
- return true;
314
- };
315
-
316
- StreamReader reader(read, "<client>");
317
- StreamWriter writer(write, "<client>");
318
-
319
- if (!handle_func(&reader, &writer))
320
- return false;
321
- if (!reader.Close())
322
- return false;
323
- if (!writer.Close())
324
- return false;
325
-
326
- if (!StartRead(pipe)) {
327
- LogDebug("Client has disconnected");
328
- return false;
329
- }
330
-
331
- return true;
332
- });
333
-
334
- return true;
335
- }
336
-
337
- void TowerServer::Send(FunctionRef<void(StreamWriter *)> func)
338
- {
339
- RunClients([&](Size, OverlappedPipe *pipe) {
340
- const auto write = [&](Span<const uint8_t> buf) {
341
- while (buf.len) {
342
- Size sent = WriteSync(pipe, buf.ptr, buf.len);
343
- if (sent < 0) {
344
- LogError("Failed to send data to server: %1", GetWin32ErrorString());
345
- return false;
346
- }
347
-
348
- buf.ptr += sent;
349
- buf.len -= sent;
350
- }
351
-
352
- return true;
353
- };
354
-
355
- StreamWriter writer(write, "<client>");
356
- func(&writer);
357
-
358
- return writer.Close();
359
- });
360
- }
361
-
362
- void TowerServer::RunClients(FunctionRef<bool(Size, OverlappedPipe *)> func)
363
- {
364
- Size j = 1;
365
- for (Size i = 1; i < pipes.len; i++) {
366
- OverlappedPipe *pipe = pipes[i];
367
-
368
- pipes[j] = pipe;
369
- sources[j].handle = pipe->ov.hEvent;
370
-
371
- if (!func(i, pipe)) {
372
- delete pipe;
373
- continue;
374
- }
375
-
376
- j++;
377
- }
378
- pipes.len = j;
379
- sources.len = j;
380
- }
381
-
382
- bool TowerClient::Connect(const char *path)
383
- {
384
- Stop();
385
-
386
- K_DEFER_N(err_guard) { Stop(); };
387
-
388
- if (!CheckPipePath(path))
389
- return false;
390
-
391
- pipe = ConnectPipe(path);
392
- if (!pipe)
393
- return false;
394
-
395
- if (!StartRead(pipe)) {
396
- LogError("Failed to connect to named pipe: %1", GetWin32ErrorString());
397
- return false;
398
- }
399
-
400
- err_guard.Disable();
401
- return true;
402
- }
403
-
404
- void TowerClient::Start(std::function<void(StreamReader *)> func)
405
- {
406
- K_ASSERT(pipe);
407
- K_ASSERT(!handle_func);
408
-
409
- src = { pipe->ov.hEvent, -1 };
410
- handle_func = func;
411
- }
412
-
413
- void TowerClient::Stop()
414
- {
415
- if (pipe) {
416
- delete pipe;
417
- pipe = nullptr;
418
- }
419
-
420
- handle_func = {};
421
- }
422
-
423
- bool TowerClient::Process()
424
- {
425
- if (!IsSignaled(pipe->ov.hEvent))
426
- return true;
427
-
428
- Span<uint8_t> buf = MakeSpan(pipe->buf, FinalizeRead(pipe));
429
- if (buf.len < 0) {
430
- LogError("Lost connection to server");
431
- return false;
432
- }
433
-
434
- const auto read = [&](Span<uint8_t> out_buf) {
435
- if (buf.len) {
436
- Size copy_len = std::min(buf.len, out_buf.len);
437
- MemCpy(out_buf.ptr, buf.ptr, copy_len);
438
-
439
- buf.ptr += copy_len;
440
- buf.len -= copy_len;
441
-
442
- return copy_len;
443
- }
444
-
445
- Size received = ReadSync(pipe, out_buf.ptr, out_buf.len, -1);
446
- if (received < 0) {
447
- LogError("Failed to receive data from server: %1", strerror(errno));
448
- }
449
- return received;
450
- };
451
-
452
- StreamReader reader(read, "<client>");
453
- handle_func(&reader);
454
-
455
- if (!reader.Close())
456
- return false;
457
-
458
- if (!StartRead(pipe)) {
459
- LogError("Lost connection to server");
460
- return false;
461
- }
462
-
463
- return true;
464
- }
465
-
466
- bool TowerClient::Send(FunctionRef<void(StreamWriter *)> func)
467
- {
468
- const auto write = [&](Span<const uint8_t> buf) {
469
- while (buf.len) {
470
- Size sent = WriteSync(pipe, buf.ptr, buf.len);
471
- if (sent < 0) {
472
- LogError("Failed to send data to server: %1", GetWin32ErrorString());
473
- return false;
474
- }
475
-
476
- buf.ptr += sent;
477
- buf.len -= sent;
478
- }
479
-
480
- return true;
481
- };
482
-
483
- StreamWriter writer(write, "<server>");
484
- func(&writer);
485
-
486
- return writer.Close();
487
- }
488
-
489
- const char *GetControlSocketPath(ControlScope scope, const char *name, Allocator *alloc)
490
- {
491
- K_ASSERT(strlen(name) < 64);
492
-
493
- switch (scope) {
494
- case ControlScope::System: return Fmt(alloc, "\\\\.\\pipe\\tower\\system\\%1", name).ptr;
495
-
496
- case ControlScope::User: {
497
- char buf[128] = {};
498
-
499
- ULONG size = K_SIZE(buf);
500
- BOOL success = GetUserNameExA(NameUniqueId, buf, &size);
501
- K_CRITICAL(success, "Failed to get user name");
502
-
503
- Span<const char> uuid = MakeSpan(buf, size);
504
- return Fmt(alloc, "\\\\.\\pipe\\tower\\%1\\%2", TrimStr(uuid, "{}"), name).ptr;
505
- } break;
506
- }
507
-
508
- K_UNREACHABLE();
509
- }
510
-
511
- #else
512
-
513
- bool TowerServer::Bind(const char *path)
514
- {
515
- K_ASSERT(fd < 0);
516
-
517
- K_DEFER_N(err_guard) { Stop(); };
518
-
519
- fd = CreateSocket(SocketType::Unix, SOCK_STREAM);
520
- if (fd < 0)
521
- return false;
522
- SetDescriptorNonBlock(fd, true);
523
-
524
- if (!BindUnixSocket(fd, path))
525
- return false;
526
- if (listen(fd, 4) < 0) {
527
- LogError("listen() failed: %1", strerror(errno));
528
- return false;
529
- }
530
-
531
- err_guard.Disable();
532
- return true;
533
- }
534
-
535
- void TowerServer::Start(std::function<bool(StreamReader *, StreamWriter *)> func)
536
- {
537
- K_ASSERT(fd >= 0);
538
- K_ASSERT(!handle_func);
539
-
540
- sources.Append({ fd, -1 });
541
- handle_func = func;
542
- }
543
-
544
- void TowerServer::Stop()
545
- {
546
- if (fd >= 0) {
547
- CloseDescriptor(fd);
548
- fd = -1;
549
- }
550
-
551
- for (Size i = 1; i < sources.len; i++) {
552
- CloseDescriptor(sources[i].fd);
553
- }
554
- sources.Clear();
555
-
556
- handle_func = {};
557
- }
558
-
559
- static bool IsReadable(int fd, int timeout)
560
- {
561
- struct pollfd pfd = { fd, POLLIN, 0 };
562
-
563
- if (poll(&pfd, 1, timeout) < 0)
564
- return true;
565
- if (pfd.revents)
566
- return true;
567
-
568
- return false;
569
- }
570
-
571
- bool TowerServer::Process(uint64_t ready)
572
- {
573
- // Accept new clients
574
- if (ready & 1) {
575
- #if defined(SOCK_CLOEXEC)
576
- int sock = accept4(fd, nullptr, nullptr, SOCK_NONBLOCK | SOCK_CLOEXEC);
577
- #else
578
- int sock = accept(fd, nullptr, nullptr);
579
- #endif
580
-
581
- if (sock >= 0) {
582
- #if !defined(SOCK_CLOEXEC)
583
- fcntl(sock, F_SETFD, FD_CLOEXEC);
584
- #endif
585
- #if !defined(MSG_DONTWAIT)
586
- SetDescriptorNonBlock(sock, true);
587
- #endif
588
-
589
- if (sources.Available()) [[likely]] {
590
- sources.Append({ sock, -1 });
591
- LogDebug("Client has connected");
592
- } else {
593
- LogError("Too many connections, refusing new client");
594
- CloseDescriptor(sock);
595
- }
596
- } else if (errno != EAGAIN) {
597
- LogError("Failed to accept client: %1", strerror(errno));
598
- }
599
- }
600
-
601
- RunClients([&](Size idx, int sock) {
602
- if (!(ready & (1ull << idx)))
603
- return true;
604
-
605
- // Handle disconnection and errors first
606
- {
607
- struct pollfd pfd = { sock, POLLIN, 0 };
608
- K_IGNORE poll(&pfd, 1, 1000);
609
-
610
- if (pfd.revents & (POLLHUP | POLLERR)) {
611
- LogDebug("Client has disconnected");
612
- return false;
613
- }
614
- }
615
-
616
- const auto read = [&](Span<uint8_t> out_buf) {
617
- Size received = recv(sock, out_buf.ptr, out_buf.len, 0);
618
- if (received < 0) {
619
- if (errno == EAGAIN) {
620
- if (IsReadable(sock, 1000)) {
621
- received = recv(sock, out_buf.ptr, out_buf.len, 0);
622
- } else {
623
- LogError("Client has timed out");
624
- }
625
- } else {
626
- LogError("Failed to receive data from client: %1", strerror(errno));
627
- }
628
- }
629
-
630
- return received;
631
- };
632
-
633
- const auto write = [&](Span<const uint8_t> buf) {
634
- while (buf.len) {
635
- Size sent = send(sock, buf.ptr, (size_t)buf.len, 0);
636
- if (sent < 0) {
637
- LogError("Failed to send data to server: %1", strerror(errno));
638
- return false;
639
- }
640
-
641
- buf.ptr += sent;
642
- buf.len -= sent;
643
- }
644
-
645
- return true;
646
- };
647
-
648
- StreamReader reader(read, "<client>");
649
- StreamWriter writer(write, "<client>");
650
-
651
- if (!handle_func(&reader, &writer))
652
- return false;
653
- if (!reader.Close())
654
- return false;
655
- if (!writer.Close())
656
- return false;
657
-
658
- return true;
659
- });
660
-
661
- return true;
662
- }
663
-
664
- void TowerServer::Send(FunctionRef<void(StreamWriter *)> func)
665
- {
666
- RunClients([&](Size, int sock) {
667
- const auto write = [&](Span<const uint8_t> buf) {
668
- while (buf.len) {
669
- Size sent = send(sock, buf.ptr, (size_t)buf.len, 0);
670
- if (sent < 0) {
671
- LogError("Failed to send data to server: %1", strerror(errno));
672
- return false;
673
- }
674
-
675
- buf.ptr += sent;
676
- buf.len -= sent;
677
- }
678
-
679
- return true;
680
- };
681
-
682
- StreamWriter writer(write, "<client>");
683
- func(&writer);
684
-
685
- return writer.Close();
686
- });
687
- }
688
-
689
- void TowerServer::RunClients(FunctionRef<bool(Size, int)> func)
690
- {
691
- Size j = 1;
692
- for (Size i = 1; i < sources.len; i++) {
693
- const WaitSource &src = sources[i];
694
-
695
- sources[j] = src;
696
-
697
- if (!func(i, src.fd)) {
698
- close(src.fd);
699
- continue;
700
- }
701
-
702
- j++;
703
- }
704
- sources.len = j;
705
- }
706
-
707
- bool TowerClient::Connect(const char *path)
708
- {
709
- Stop();
710
-
711
- K_DEFER_N(err_guard) { Stop(); };
712
-
713
- sock = CreateSocket(SocketType::Unix, SOCK_STREAM);
714
- if (sock < 0)
715
- return false;
716
- if (!ConnectUnixSocket(sock, path))
717
- return false;
718
-
719
- err_guard.Disable();
720
- return true;
721
- }
722
-
723
- void TowerClient::Start(std::function<void(StreamReader *)> func)
724
- {
725
- K_ASSERT(sock >= 0);
726
- K_ASSERT(!handle_func);
727
-
728
- src = { sock, -1 };
729
- handle_func = func;
730
- }
731
-
732
- void TowerClient::Stop()
733
- {
734
- CloseDescriptor(sock);
735
- sock = -1;
736
-
737
- handle_func = {};
738
- }
739
-
740
- bool TowerClient::Process()
741
- {
742
- // We need to poll because StreamReader does not support non-blocking reads,
743
- // so make sure there's data on the other end. The caller probably knows and may
744
- // have skipped the call to Process but we don't want to enforce this; Process()
745
- // should work and do nothing if there's nothing to do.
746
- if (!IsReadable(sock, 0))
747
- return true;
748
-
749
- const auto read = [&](Span<uint8_t> out_buf) {
750
- Size received = recv(sock, out_buf.ptr, out_buf.len, 0);
751
- if (received < 0) {
752
- LogError("Failed to receive data from server: %1", strerror(errno));
753
- }
754
- return received;
755
- };
756
-
757
- StreamReader reader(read, "<client>");
758
- handle_func(&reader);
759
-
760
- return reader.Close();
761
- }
762
-
763
- bool TowerClient::Send(FunctionRef<void(StreamWriter *)> func)
764
- {
765
- const auto write = [&](Span<const uint8_t> buf) {
766
- while (buf.len) {
767
- Size sent = send(sock, buf.ptr, (size_t)buf.len, 0);
768
- if (sent < 0) {
769
- LogError("Failed to send data to server: %1", strerror(errno));
770
- return false;
771
- }
772
-
773
- buf.ptr += sent;
774
- buf.len -= sent;
775
- }
776
-
777
- return true;
778
- };
779
-
780
- StreamWriter writer(write, "<server>");
781
- func(&writer);
782
-
783
- return writer.Close();
784
- }
785
-
786
- const char *GetControlSocketPath(ControlScope scope, const char *name, Allocator *alloc)
787
- {
788
- K_ASSERT(strlen(name) < 64);
789
-
790
- switch (scope) {
791
- case ControlScope::System: {
792
- const char *prefix = TestFile("/run", FileType::Directory) ? "/run" : "/var/run";
793
- return Fmt(alloc, "%1/%2.sock", prefix, name).ptr;
794
- } break;
795
-
796
- case ControlScope::User: {
797
- const char *xdg = GetEnv("XDG_RUNTIME_DIR");
798
- const char *path = nullptr;
799
-
800
- if (xdg) {
801
- path = Fmt(alloc, "%1/%2.sock", xdg, name).ptr;
802
- } else {
803
- const char *prefix = TestFile("/run", FileType::Directory) ? "/run" : "/var/run";
804
- uid_t uid = getuid();
805
-
806
- path = Fmt(alloc, "%1/%2/%3.sock", prefix, uid, name).ptr;
807
- }
808
-
809
- // Best effort
810
- EnsureDirectoryExists(path);
811
-
812
- return path;
813
- } break;
814
- }
815
-
816
- K_UNREACHABLE();
817
- }
818
-
819
- #endif
820
-
821
- }