kiriya 0.1.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 (282) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/LICENSE +21 -0
  3. package/README.md +87 -0
  4. package/dist/src/config/clean-rules.js +39 -0
  5. package/dist/src/config/config-keys.js +24 -0
  6. package/dist/src/config/dependency-directories.js +16 -0
  7. package/dist/src/config/modules.js +38 -0
  8. package/dist/src/config/protected-paths.js +32 -0
  9. package/dist/src/config/rebuildable-directories.js +20 -0
  10. package/dist/src/core/application/command-registry.js +57 -0
  11. package/dist/src/core/application/config-values.js +33 -0
  12. package/dist/src/core/application/path-guard.js +69 -0
  13. package/dist/src/core/application/paths.js +77 -0
  14. package/dist/src/core/application/plugin-loader.js +100 -0
  15. package/dist/src/core/application/process-ending.js +28 -0
  16. package/dist/src/core/application/root-scope.js +123 -0
  17. package/dist/src/core/application/safety.js +26 -0
  18. package/dist/src/core/application/text-input.js +44 -0
  19. package/dist/src/core/application/walk.js +34 -0
  20. package/dist/src/core/domain/command.js +8 -0
  21. package/dist/src/core/domain/encodings.js +70 -0
  22. package/dist/src/core/domain/errors.js +49 -0
  23. package/dist/src/core/domain/glob.js +57 -0
  24. package/dist/src/core/domain/global-options.js +10 -0
  25. package/dist/src/core/domain/input-schema.js +54 -0
  26. package/dist/src/core/domain/message.js +7 -0
  27. package/dist/src/core/domain/module.js +2 -0
  28. package/dist/src/core/domain/names.js +22 -0
  29. package/dist/src/core/domain/ports/clipboard.js +2 -0
  30. package/dist/src/core/domain/ports/clock.js +2 -0
  31. package/dist/src/core/domain/ports/command-catalog.js +2 -0
  32. package/dist/src/core/domain/ports/compression.js +2 -0
  33. package/dist/src/core/domain/ports/config-store.js +2 -0
  34. package/dist/src/core/domain/ports/confirmation.js +2 -0
  35. package/dist/src/core/domain/ports/environment.js +2 -0
  36. package/dist/src/core/domain/ports/file-content.js +2 -0
  37. package/dist/src/core/domain/ports/file-system.js +2 -0
  38. package/dist/src/core/domain/ports/hasher.js +2 -0
  39. package/dist/src/core/domain/ports/network.js +2 -0
  40. package/dist/src/core/domain/ports/opener.js +2 -0
  41. package/dist/src/core/domain/ports/passthrough.js +2 -0
  42. package/dist/src/core/domain/ports/plugin-inventory.js +2 -0
  43. package/dist/src/core/domain/ports/plugin-source.js +2 -0
  44. package/dist/src/core/domain/ports/port-table.js +2 -0
  45. package/dist/src/core/domain/ports/process-runner.js +2 -0
  46. package/dist/src/core/domain/ports/process-table.js +2 -0
  47. package/dist/src/core/domain/ports/protected-paths.js +2 -0
  48. package/dist/src/core/domain/ports/random-source.js +2 -0
  49. package/dist/src/core/domain/ports/standard-input.js +2 -0
  50. package/dist/src/core/domain/ports/system-info.js +2 -0
  51. package/dist/src/core/domain/ports/trash.js +2 -0
  52. package/dist/src/core/domain/secrets.js +59 -0
  53. package/dist/src/core/domain/targets.js +41 -0
  54. package/dist/src/core/domain/text-case.js +39 -0
  55. package/dist/src/core/domain/values/bytes.js +13 -0
  56. package/dist/src/core/domain/view.js +2 -0
  57. package/dist/src/core/infrastructure/node/can-listen.js +10 -0
  58. package/dist/src/core/infrastructure/node/closed-standard-input.adapter.js +12 -0
  59. package/dist/src/core/infrastructure/node/config-location.js +27 -0
  60. package/dist/src/core/infrastructure/node/fs-errors.js +22 -0
  61. package/dist/src/core/infrastructure/node/json-config-store.adapter.js +69 -0
  62. package/dist/src/core/infrastructure/node/node-compression.adapter.js +82 -0
  63. package/dist/src/core/infrastructure/node/node-environment.adapter.js +21 -0
  64. package/dist/src/core/infrastructure/node/node-file-content.adapter.js +99 -0
  65. package/dist/src/core/infrastructure/node/node-file-system.adapter.js +169 -0
  66. package/dist/src/core/infrastructure/node/node-hasher.adapter.js +32 -0
  67. package/dist/src/core/infrastructure/node/node-network.adapter.js +168 -0
  68. package/dist/src/core/infrastructure/node/node-plugin-source.adapter.js +89 -0
  69. package/dist/src/core/infrastructure/node/node-process-runner.adapter.js +48 -0
  70. package/dist/src/core/infrastructure/node/node-random-source.adapter.js +7 -0
  71. package/dist/src/core/infrastructure/node/node-standard-input.adapter.js +24 -0
  72. package/dist/src/core/infrastructure/node/node-system-info.adapter.js +63 -0
  73. package/dist/src/core/infrastructure/node/process-signals.js +51 -0
  74. package/dist/src/core/infrastructure/node/run-program.js +65 -0
  75. package/dist/src/core/infrastructure/node/system-clock.adapter.js +22 -0
  76. package/dist/src/core/infrastructure/node/typed-programs.js +45 -0
  77. package/dist/src/core/infrastructure/platform/linux/freedesktop-trash.adapter.js +115 -0
  78. package/dist/src/core/infrastructure/platform/linux/linux-clipboard.adapter.js +70 -0
  79. package/dist/src/core/infrastructure/platform/linux/linux-opener.adapter.js +21 -0
  80. package/dist/src/core/infrastructure/platform/linux/linux-port-table.adapter.js +97 -0
  81. package/dist/src/core/infrastructure/platform/linux/linux-process-table.adapter.js +61 -0
  82. package/dist/src/core/infrastructure/platform/macos/macos-clipboard.adapter.js +29 -0
  83. package/dist/src/core/infrastructure/platform/macos/macos-opener.adapter.js +13 -0
  84. package/dist/src/core/infrastructure/platform/macos/macos-port-table.adapter.js +86 -0
  85. package/dist/src/core/infrastructure/platform/macos/macos-process-table.adapter.js +62 -0
  86. package/dist/src/core/infrastructure/platform/macos/macos-trash.adapter.js +64 -0
  87. package/dist/src/core/infrastructure/platform/windows/system32.js +6 -0
  88. package/dist/src/core/infrastructure/platform/windows/windows-clipboard.adapter.js +50 -0
  89. package/dist/src/core/infrastructure/platform/windows/windows-opener.adapter.js +11 -0
  90. package/dist/src/core/infrastructure/platform/windows/windows-port-table.adapter.js +38 -0
  91. package/dist/src/core/infrastructure/platform/windows/windows-process-table.adapter.js +134 -0
  92. package/dist/src/core/infrastructure/platform/windows/windows-trash.adapter.js +86 -0
  93. package/dist/src/core/presentation/cli/argv.js +83 -0
  94. package/dist/src/core/presentation/cli/cli-application.js +201 -0
  95. package/dist/src/core/presentation/cli/cli-view-format.js +46 -0
  96. package/dist/src/core/presentation/cli/help.js +202 -0
  97. package/dist/src/core/presentation/cli/json-output.js +28 -0
  98. package/dist/src/core/presentation/cli/style.js +21 -0
  99. package/dist/src/core/presentation/cli/suggest.js +25 -0
  100. package/dist/src/core/presentation/cli/terminal-confirmation.js +63 -0
  101. package/dist/src/core/presentation/ended-processes.js +18 -0
  102. package/dist/src/core/presentation/i18n/translator.js +23 -0
  103. package/dist/src/core/presentation/list-preview.js +10 -0
  104. package/dist/src/core/presentation/mcp/elicitation.js +55 -0
  105. package/dist/src/core/presentation/mcp/mcp-application.js +60 -0
  106. package/dist/src/core/presentation/mcp/mcp-confirmation.js +59 -0
  107. package/dist/src/core/presentation/mcp/mcp-server.js +355 -0
  108. package/dist/src/core/presentation/mcp/protocol.js +32 -0
  109. package/dist/src/core/presentation/mcp/request-state.js +66 -0
  110. package/dist/src/core/presentation/mcp/tool-definitions.js +149 -0
  111. package/dist/src/core/presentation/mcp/tool-results.js +56 -0
  112. package/dist/src/i18n/locales/en.js +827 -0
  113. package/dist/src/main.js +154 -0
  114. package/dist/src/modules/archive/application/archive-sources.js +55 -0
  115. package/dist/src/modules/archive/application/create-tar.use-case.js +123 -0
  116. package/dist/src/modules/archive/application/create-zip.use-case.js +106 -0
  117. package/dist/src/modules/archive/application/extract-tar.use-case.js +240 -0
  118. package/dist/src/modules/archive/application/extract-zip.use-case.js +181 -0
  119. package/dist/src/modules/archive/application/tar-reader.js +45 -0
  120. package/dist/src/modules/archive/application/zip-reader.js +57 -0
  121. package/dist/src/modules/archive/archive.module.js +27 -0
  122. package/dist/src/modules/archive/domain/crc32.js +18 -0
  123. package/dist/src/modules/archive/domain/tar-format.js +97 -0
  124. package/dist/src/modules/archive/domain/tar-stream.js +223 -0
  125. package/dist/src/modules/archive/domain/zip-format.js +158 -0
  126. package/dist/src/modules/archive/presentation/tar.view.js +17 -0
  127. package/dist/src/modules/archive/presentation/untar.view.js +30 -0
  128. package/dist/src/modules/archive/presentation/unzip.view.js +24 -0
  129. package/dist/src/modules/archive/presentation/zip.view.js +17 -0
  130. package/dist/src/modules/clip/application/copy-text.use-case.js +43 -0
  131. package/dist/src/modules/clip/application/paste-text.use-case.js +25 -0
  132. package/dist/src/modules/clip/clip.module.js +16 -0
  133. package/dist/src/modules/clip/presentation/clip.views.js +7 -0
  134. package/dist/src/modules/completion/application/print-script.use-case.js +38 -0
  135. package/dist/src/modules/completion/application/suggest-words.use-case.js +37 -0
  136. package/dist/src/modules/completion/completion.module.js +14 -0
  137. package/dist/src/modules/completion/domain/scripts.js +91 -0
  138. package/dist/src/modules/completion/domain/suggest.js +134 -0
  139. package/dist/src/modules/completion/presentation/completion.views.js +6 -0
  140. package/dist/src/modules/config/application/config-commands.js +14 -0
  141. package/dist/src/modules/config/application/get-setting.use-case.js +25 -0
  142. package/dist/src/modules/config/application/list-config-keys.use-case.js +26 -0
  143. package/dist/src/modules/config/application/list-settings.use-case.js +28 -0
  144. package/dist/src/modules/config/application/set-setting.use-case.js +53 -0
  145. package/dist/src/modules/config/application/show-config-path.use-case.js +21 -0
  146. package/dist/src/modules/config/application/unset-setting.use-case.js +28 -0
  147. package/dist/src/modules/config/config.module.js +28 -0
  148. package/dist/src/modules/config/presentation/config.views.js +33 -0
  149. package/dist/src/modules/convert/application/convert-case.use-case.js +38 -0
  150. package/dist/src/modules/convert/application/convert-codecs.use-case.js +92 -0
  151. package/dist/src/modules/convert/application/convert-input.js +16 -0
  152. package/dist/src/modules/convert/application/convert-json.use-case.js +51 -0
  153. package/dist/src/modules/convert/application/convert-time.use-case.js +39 -0
  154. package/dist/src/modules/convert/application/decode-jwt.use-case.js +52 -0
  155. package/dist/src/modules/convert/convert.module.js +29 -0
  156. package/dist/src/modules/convert/domain/json-syntax.js +135 -0
  157. package/dist/src/modules/convert/domain/jwt.js +29 -0
  158. package/dist/src/modules/convert/domain/moments.js +20 -0
  159. package/dist/src/modules/convert/presentation/convert.views.js +44 -0
  160. package/dist/src/modules/docker/application/clean-engine.use-case.js +77 -0
  161. package/dist/src/modules/docker/application/compose-project.js +45 -0
  162. package/dist/src/modules/docker/application/docker-engine.js +40 -0
  163. package/dist/src/modules/docker/application/list-containers.use-case.js +69 -0
  164. package/dist/src/modules/docker/application/run-compose.use-case.js +83 -0
  165. package/dist/src/modules/docker/application/show-logs.use-case.js +51 -0
  166. package/dist/src/modules/docker/application/stop-project.use-case.js +56 -0
  167. package/dist/src/modules/docker/docker.module.js +23 -0
  168. package/dist/src/modules/docker/domain/compose-file.js +105 -0
  169. package/dist/src/modules/docker/domain/engine-output.js +65 -0
  170. package/dist/src/modules/docker/presentation/docker.views.js +63 -0
  171. package/dist/src/modules/doctor/application/run-checks.use-case.js +128 -0
  172. package/dist/src/modules/doctor/doctor.module.js +13 -0
  173. package/dist/src/modules/doctor/domain/versions.js +22 -0
  174. package/dist/src/modules/doctor/presentation/doctor.view.js +30 -0
  175. package/dist/src/modules/env/application/check-dotenv.use-case.js +116 -0
  176. package/dist/src/modules/env/application/inspect-path.use-case.js +71 -0
  177. package/dist/src/modules/env/application/path-entries.js +28 -0
  178. package/dist/src/modules/env/application/show-variables.use-case.js +47 -0
  179. package/dist/src/modules/env/domain/dotenv.js +62 -0
  180. package/dist/src/modules/env/env.module.js +17 -0
  181. package/dist/src/modules/env/presentation/env.views.js +43 -0
  182. package/dist/src/modules/files/application/clean-builds.use-case.js +149 -0
  183. package/dist/src/modules/files/application/compare-paths.use-case.js +127 -0
  184. package/dist/src/modules/files/application/copy-paths.use-case.js +101 -0
  185. package/dist/src/modules/files/application/create-paths.use-case.js +85 -0
  186. package/dist/src/modules/files/application/delete-paths.use-case.js +127 -0
  187. package/dist/src/modules/files/application/find-duplicates.use-case.js +105 -0
  188. package/dist/src/modules/files/application/find-files.use-case.js +131 -0
  189. package/dist/src/modules/files/application/hash-files.use-case.js +73 -0
  190. package/dist/src/modules/files/application/list-entries.use-case.js +87 -0
  191. package/dist/src/modules/files/application/measure-folders.use-case.js +102 -0
  192. package/dist/src/modules/files/application/move-entry.js +19 -0
  193. package/dist/src/modules/files/application/move-paths.use-case.js +82 -0
  194. package/dist/src/modules/files/application/read-text.use-case.js +92 -0
  195. package/dist/src/modules/files/application/rename-paths.use-case.js +184 -0
  196. package/dist/src/modules/files/application/replace-text.use-case.js +146 -0
  197. package/dist/src/modules/files/application/search-text.use-case.js +115 -0
  198. package/dist/src/modules/files/application/show-info.use-case.js +80 -0
  199. package/dist/src/modules/files/application/show-tree.use-case.js +75 -0
  200. package/dist/src/modules/files/application/sync-folders.use-case.js +162 -0
  201. package/dist/src/modules/files/application/text-files.js +46 -0
  202. package/dist/src/modules/files/application/transfers.js +35 -0
  203. package/dist/src/modules/files/domain/case-style.js +18 -0
  204. package/dist/src/modules/files/domain/filters.js +9 -0
  205. package/dist/src/modules/files/domain/sync-plan.js +35 -0
  206. package/dist/src/modules/files/domain/text-encoding.js +75 -0
  207. package/dist/src/modules/files/domain/values.js +28 -0
  208. package/dist/src/modules/files/files.module.js +70 -0
  209. package/dist/src/modules/files/presentation/clean.view.js +15 -0
  210. package/dist/src/modules/files/presentation/compare.view.js +50 -0
  211. package/dist/src/modules/files/presentation/copy.view.js +17 -0
  212. package/dist/src/modules/files/presentation/delete.view.js +16 -0
  213. package/dist/src/modules/files/presentation/dupes.view.js +20 -0
  214. package/dist/src/modules/files/presentation/find.view.js +16 -0
  215. package/dist/src/modules/files/presentation/grep.view.js +27 -0
  216. package/dist/src/modules/files/presentation/hash.view.js +15 -0
  217. package/dist/src/modules/files/presentation/info.view.js +36 -0
  218. package/dist/src/modules/files/presentation/list.view.js +17 -0
  219. package/dist/src/modules/files/presentation/move.view.js +14 -0
  220. package/dist/src/modules/files/presentation/new.view.js +8 -0
  221. package/dist/src/modules/files/presentation/read.view.js +6 -0
  222. package/dist/src/modules/files/presentation/rename.view.js +16 -0
  223. package/dist/src/modules/files/presentation/replace.view.js +26 -0
  224. package/dist/src/modules/files/presentation/size.view.js +24 -0
  225. package/dist/src/modules/files/presentation/sync.view.js +37 -0
  226. package/dist/src/modules/files/presentation/tree.view.js +22 -0
  227. package/dist/src/modules/gen/application/gen-options.js +18 -0
  228. package/dist/src/modules/gen/application/generate-passwords.use-case.js +39 -0
  229. package/dist/src/modules/gen/application/generate-tokens.use-case.js +38 -0
  230. package/dist/src/modules/gen/application/generate-ulids.use-case.js +40 -0
  231. package/dist/src/modules/gen/application/generate-uuids.use-case.js +32 -0
  232. package/dist/src/modules/gen/domain/identifiers.js +65 -0
  233. package/dist/src/modules/gen/domain/secrets.js +43 -0
  234. package/dist/src/modules/gen/gen.module.js +20 -0
  235. package/dist/src/modules/git/application/fetch-repositories.use-case.js +50 -0
  236. package/dist/src/modules/git/application/git-client.js +62 -0
  237. package/dist/src/modules/git/application/pull-repositories.use-case.js +67 -0
  238. package/dist/src/modules/git/application/repositories.js +67 -0
  239. package/dist/src/modules/git/application/show-status.use-case.js +49 -0
  240. package/dist/src/modules/git/application/switch-branch.use-case.js +118 -0
  241. package/dist/src/modules/git/domain/repository-status.js +37 -0
  242. package/dist/src/modules/git/git.module.js +25 -0
  243. package/dist/src/modules/git/presentation/git.views.js +100 -0
  244. package/dist/src/modules/net/application/check-connection.use-case.js +71 -0
  245. package/dist/src/modules/net/application/list-addresses.use-case.js +29 -0
  246. package/dist/src/modules/net/application/lookup-name.use-case.js +55 -0
  247. package/dist/src/modules/net/net.module.js +17 -0
  248. package/dist/src/modules/net/presentation/net.views.js +39 -0
  249. package/dist/src/modules/open/application/open-target.use-case.js +53 -0
  250. package/dist/src/modules/open/domain/targets.js +45 -0
  251. package/dist/src/modules/open/open.module.js +12 -0
  252. package/dist/src/modules/open/presentation/open.view.js +6 -0
  253. package/dist/src/modules/port/application/end-port-owners.use-case.js +68 -0
  254. package/dist/src/modules/port/application/find-free-port.use-case.js +40 -0
  255. package/dist/src/modules/port/application/find-listeners.use-case.js +34 -0
  256. package/dist/src/modules/port/application/port-owners.js +25 -0
  257. package/dist/src/modules/port/domain/port-number.js +8 -0
  258. package/dist/src/modules/port/port.module.js +17 -0
  259. package/dist/src/modules/port/presentation/port.views.js +27 -0
  260. package/dist/src/modules/proc/application/end-processes.use-case.js +77 -0
  261. package/dist/src/modules/proc/application/find-processes.use-case.js +50 -0
  262. package/dist/src/modules/proc/application/list-processes.use-case.js +41 -0
  263. package/dist/src/modules/proc/application/show-tree.use-case.js +40 -0
  264. package/dist/src/modules/proc/domain/process-tree.js +55 -0
  265. package/dist/src/modules/proc/presentation/proc.views.js +28 -0
  266. package/dist/src/modules/proc/proc.module.js +19 -0
  267. package/dist/src/modules/sys/application/create-report.use-case.js +30 -0
  268. package/dist/src/modules/sys/application/find-tools.use-case.js +20 -0
  269. package/dist/src/modules/sys/application/machine-facts.js +44 -0
  270. package/dist/src/modules/sys/application/show-info.use-case.js +29 -0
  271. package/dist/src/modules/sys/domain/tools.js +17 -0
  272. package/dist/src/modules/sys/presentation/sys.views.js +67 -0
  273. package/dist/src/modules/sys/sys.module.js +17 -0
  274. package/dist/src/modules/wait/application/poll.js +26 -0
  275. package/dist/src/modules/wait/application/wait-file.use-case.js +55 -0
  276. package/dist/src/modules/wait/application/wait-port.use-case.js +76 -0
  277. package/dist/src/modules/wait/application/wait-url.use-case.js +71 -0
  278. package/dist/src/modules/wait/domain/reasons.js +14 -0
  279. package/dist/src/modules/wait/domain/wait-input.js +50 -0
  280. package/dist/src/modules/wait/presentation/wait.views.js +31 -0
  281. package/dist/src/modules/wait/wait.module.js +21 -0
  282. package/package.json +57 -0
@@ -0,0 +1,62 @@
1
+ import path from "node:path";
2
+ import { CapabilityUnavailableError } from "../../../domain/errors.js";
3
+ import { endProcesses } from "../../node/process-signals.js";
4
+ /** `ps -axww -o pid=,ppid=,rss=,comm=`: comm comes last so its spaces survive; rss is in kilobytes. */
5
+ export function parsePsStats(output) {
6
+ const stats = new Map();
7
+ for (const line of output.split("\n")) {
8
+ const match = /^\s*(\d+)\s+(\d+)\s+(\d+)\s+(.+?)\s*$/.exec(line);
9
+ if (match === null)
10
+ continue;
11
+ stats.set(Number(match[1]), { ppid: Number(match[2]), memoryBytes: Number(match[3]) * 1024, path: match[4] ?? "" });
12
+ }
13
+ return stats;
14
+ }
15
+ /** `ps -axww -o pid=,args=`: each process's command line. */
16
+ export function parsePsArgs(output) {
17
+ const commands = new Map();
18
+ for (const line of output.split("\n")) {
19
+ const match = /^\s*(\d+)\s+(.*?)\s*$/.exec(line);
20
+ if (match !== null && match[2] !== undefined && match[2] !== "")
21
+ commands.set(Number(match[1]), match[2]);
22
+ }
23
+ return commands;
24
+ }
25
+ /** Two runs of ps, because a name and a command line can both hold spaces and ps separates columns with spaces. */
26
+ export class MacosProcessTableAdapter {
27
+ processRunner;
28
+ selfPid = process.pid;
29
+ constructor(processRunner) {
30
+ this.processRunner = processRunner;
31
+ }
32
+ async list(_detailed, signal) {
33
+ const [stats, args] = await Promise.all([
34
+ this.ps(["-axww", "-o", "pid=,ppid=,rss=,comm="], signal),
35
+ this.ps(["-axww", "-o", "pid=,args="], signal),
36
+ ]);
37
+ const commands = parsePsArgs(args);
38
+ const processes = [...parsePsStats(stats)].map(([pid, stat]) => ({
39
+ pid,
40
+ ppid: stat.ppid,
41
+ name: path.posix.basename(stat.path),
42
+ command: commands.get(pid) ?? null,
43
+ memoryBytes: stat.memoryBytes,
44
+ }));
45
+ return { processes, detailed: true };
46
+ }
47
+ end(pids, force) {
48
+ return endProcesses(pids, force);
49
+ }
50
+ protectedPids() {
51
+ return new Set([0, 1, process.pid, process.ppid]);
52
+ }
53
+ async ps(args, signal) {
54
+ const result = await this.processRunner.run("/bin/ps", args, { signal, timeoutMs: 30_000 });
55
+ if (result.code !== 0) {
56
+ const detail = result.stderr.trim().split("\n")[0] ?? "";
57
+ throw new CapabilityUnavailableError("core.processes.failed", { program: "ps", code: result.code, detail });
58
+ }
59
+ return result.stdout;
60
+ }
61
+ }
62
+ //# sourceMappingURL=macos-process-table.adapter.js.map
@@ -0,0 +1,64 @@
1
+ import { constants } from "node:fs";
2
+ import { access, rename } from "node:fs/promises";
3
+ import { basename, extname, join } from "node:path";
4
+ import { message } from "../../../domain/message.js";
5
+ import { runProgram } from "../../node/run-program.js";
6
+ const SYSTEM_TRASH = "/usr/bin/trash";
7
+ async function exists(path) {
8
+ try {
9
+ await access(path, constants.F_OK);
10
+ return true;
11
+ }
12
+ catch {
13
+ return false;
14
+ }
15
+ }
16
+ /**
17
+ * macOS 15 and later ship /usr/bin/trash; older systems get a plain move into
18
+ * ~/.Trash, which Finder cannot Put Back. Verified on macOS 26 in the phase 0 spike.
19
+ */
20
+ export class MacosTrashAdapter {
21
+ environment;
22
+ location = "core.trash.location.macos";
23
+ constructor(environment) {
24
+ this.environment = environment;
25
+ }
26
+ async send(paths) {
27
+ const useSystem = await exists(SYSTEM_TRASH);
28
+ const outcomes = [];
29
+ for (const path of paths)
30
+ outcomes.push(useSystem ? await this.withSystemTrash(path) : await this.byMove(path));
31
+ return outcomes;
32
+ }
33
+ async withSystemTrash(path) {
34
+ const result = await runProgram(SYSTEM_TRASH, [path], { timeoutMs: 10 * 60_000 });
35
+ if (result.code === 0 && !(await exists(path)))
36
+ return { path, ok: true };
37
+ return {
38
+ path,
39
+ ok: false,
40
+ reason: message("core.trash.failed", { detail: result.stderr.trim() || `exit ${result.code}` }),
41
+ };
42
+ }
43
+ async byMove(path) {
44
+ const trash = join(this.environment.homeDirectory, ".Trash");
45
+ const name = basename(path);
46
+ const extension = extname(name);
47
+ const stem = name.slice(0, name.length - extension.length);
48
+ try {
49
+ for (let attempt = 1;; attempt += 1) {
50
+ const candidate = join(trash, attempt === 1 ? name : `${stem} ${attempt}${extension}`);
51
+ if (await exists(candidate))
52
+ continue;
53
+ await rename(path, candidate);
54
+ return { path, ok: true };
55
+ }
56
+ }
57
+ catch (error) {
58
+ const code = error.code;
59
+ const key = code === "EXDEV" ? "core.trash.other-device" : "core.trash.failed";
60
+ return { path, ok: false, reason: message(key, { detail: code ?? error.message }) };
61
+ }
62
+ }
63
+ }
64
+ //# sourceMappingURL=macos-trash.adapter.js.map
@@ -0,0 +1,6 @@
1
+ import path from "node:path";
2
+ /** A program in Windows' System32 folder, by full path, so nothing earlier in PATH can stand in for it. */
3
+ export function system32(program) {
4
+ return path.win32.join(process.env["SystemRoot"] ?? "C:\\Windows", "System32", program);
5
+ }
6
+ //# sourceMappingURL=system32.js.map
@@ -0,0 +1,50 @@
1
+ import { CapabilityUnavailableError, OperationFailedError } from "../../../domain/errors.js";
2
+ import { firstLine, runPowerShellTyped } from "../../node/typed-programs.js";
3
+ const PREAMBLE = String.raw `
4
+ $ErrorActionPreference = 'Stop'
5
+ $mode = $ExecutionContext.SessionState.LanguageMode
6
+ if ($mode -ne 'FullLanguage') { "mode|$mode"; exit 0 }
7
+ `;
8
+ const WRITE_SCRIPT = `${PREAMBLE}
9
+ $bytes = [Convert]::FromBase64String([Console]::In.ReadToEnd().Trim())
10
+ Set-Clipboard -Value ([Text.Encoding]::UTF8.GetString($bytes))
11
+ "done|"
12
+ `;
13
+ const READ_SCRIPT = `${PREAMBLE}
14
+ $text = Get-Clipboard -Raw
15
+ if ($null -eq $text) { $text = '' }
16
+ "text|" + [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($text))
17
+ `;
18
+ /**
19
+ * Set-Clipboard and Get-Clipboard through Windows PowerShell, because clip.exe garbles
20
+ * UTF-8. Text travels as base64 on stdin and stdout, so no code page touches it. Like
21
+ * the trash, the cmdlets need full language mode. Verified in the phase 0 spike.
22
+ */
23
+ export class WindowsClipboardAdapter {
24
+ backend() {
25
+ return Promise.resolve("PowerShell Set-Clipboard");
26
+ }
27
+ async write(text, signal) {
28
+ await this.run(WRITE_SCRIPT, "done|", signal, Buffer.from(text, "utf8").toString("base64"));
29
+ }
30
+ async read(signal) {
31
+ const encoded = await this.run(READ_SCRIPT, "text|", signal);
32
+ return Buffer.from(encoded, "base64").toString("utf8");
33
+ }
34
+ /** What the script printed after `prefix`. */
35
+ async run(script, prefix, signal, input = "") {
36
+ const result = await runPowerShellTyped(script, { input, signal, timeoutMs: 60_000 });
37
+ const lines = result.stdout.split(/\r?\n/).map((line) => line.trim());
38
+ const mode = lines.find((line) => line.startsWith("mode|"));
39
+ if (mode !== undefined) {
40
+ throw new CapabilityUnavailableError("core.clipboard.windows.language-mode", { mode: mode.slice(5) });
41
+ }
42
+ const answer = lines.find((line) => line.startsWith(prefix));
43
+ if (result.code !== 0 || answer === undefined) {
44
+ const detail = firstLine(result.stderr);
45
+ throw new OperationFailedError("core.clipboard.failed", { program: "PowerShell", code: result.code, detail });
46
+ }
47
+ return answer.slice(prefix.length);
48
+ }
49
+ }
50
+ //# sourceMappingURL=windows-clipboard.adapter.js.map
@@ -0,0 +1,11 @@
1
+ import path from "node:path";
2
+ import { launchDetached } from "../../node/typed-programs.js";
3
+ /** explorer.exe opens a file in its application, a folder in a window, and a web address in the browser. */
4
+ export class WindowsOpenerAdapter {
5
+ open(target) {
6
+ // explorer.exe exits with 1 even when it opened the target, so only whether it started counts.
7
+ const explorer = path.win32.join(process.env["SystemRoot"] ?? "C:\\Windows", "explorer.exe");
8
+ return launchDetached(explorer, [target]);
9
+ }
10
+ }
11
+ //# sourceMappingURL=windows-opener.adapter.js.map
@@ -0,0 +1,38 @@
1
+ import { CapabilityUnavailableError } from "../../../domain/errors.js";
2
+ import { canListen } from "../../node/can-listen.js";
3
+ import { system32 } from "./system32.js";
4
+ const LINE = /^\s*TCP\s+(\S+):(\d+)\s+(\S+):(\d+)\s+\S+\s+(\d+)\s*$/;
5
+ /**
6
+ * `netstat -ano`. The state column is translated on Windows in other languages, so a
7
+ * listener is recognised by its foreign port of 0 rather than by the word LISTENING.
8
+ */
9
+ export function parseWindowsNetstat(output) {
10
+ const listeners = [];
11
+ for (const line of output.split(/\r?\n/)) {
12
+ const match = LINE.exec(line);
13
+ if (match === null || match[4] !== "0")
14
+ continue;
15
+ const address = (match[1] ?? "").replace(/^\[(.*)\]$/, "$1");
16
+ listeners.push({ address, port: Number(match[2]), pid: Number(match[5]) });
17
+ }
18
+ return listeners;
19
+ }
20
+ /** netstat shows owners without elevation and took about 30 ms in measurements. */
21
+ export class WindowsPortTableAdapter {
22
+ processRunner;
23
+ constructor(processRunner) {
24
+ this.processRunner = processRunner;
25
+ }
26
+ async listeners(signal) {
27
+ const result = await this.processRunner.run(system32("netstat.exe"), ["-ano"], { signal, timeoutMs: 60_000 });
28
+ if (result.code !== 0) {
29
+ const detail = result.stderr.trim().split(/\r?\n/)[0] ?? "";
30
+ throw new CapabilityUnavailableError("core.ports.failed", { program: "netstat", code: result.code, detail });
31
+ }
32
+ return parseWindowsNetstat(result.stdout);
33
+ }
34
+ canListen(port) {
35
+ return canListen(port);
36
+ }
37
+ }
38
+ //# sourceMappingURL=windows-port-table.adapter.js.map
@@ -0,0 +1,134 @@
1
+ import { CapabilityUnavailableError, InterruptedError } from "../../../domain/errors.js";
2
+ import { endProcesses } from "../../node/process-signals.js";
3
+ import { runPowerShell } from "../../node/run-program.js";
4
+ import { system32 } from "./system32.js";
5
+ const BYTE_ORDER_MARK = String.fromCharCode(0xfeff);
6
+ /** The fields of one CSV line, where a quoted field may hold commas. */
7
+ export function csvFields(line) {
8
+ const fields = [];
9
+ let current = "";
10
+ let quoted = false;
11
+ for (const char of line) {
12
+ if (char === '"') {
13
+ quoted = !quoted;
14
+ }
15
+ else if (char === "," && !quoted) {
16
+ fields.push(current);
17
+ current = "";
18
+ }
19
+ else {
20
+ current += char;
21
+ }
22
+ }
23
+ fields.push(current);
24
+ return fields;
25
+ }
26
+ /**
27
+ * `tasklist /fo csv /nh`: image name, PID, session name, session number, and memory
28
+ * such as "45,120 K" in the machine's own number format, so only its digits are read.
29
+ */
30
+ export function parseTasklist(output) {
31
+ return output
32
+ .split(/\r?\n/)
33
+ .filter((line) => line.startsWith('"'))
34
+ .flatMap((line) => {
35
+ const fields = csvFields(line);
36
+ const pid = fields[1] ?? "";
37
+ if (!/^\d+$/.test(pid))
38
+ return [];
39
+ const digits = (fields[4] ?? "").replace(/\D/g, "");
40
+ const memoryBytes = digits === "" ? null : Number(digits) * 1024;
41
+ return [{ pid: Number(pid), ppid: null, name: fields[0] ?? "", command: null, memoryBytes }];
42
+ });
43
+ }
44
+ /** The JSON the CIM script prints; null when it is not that JSON. */
45
+ export function parseCimProcesses(output) {
46
+ const text = output.trim();
47
+ let rows;
48
+ try {
49
+ rows = JSON.parse(text.startsWith(BYTE_ORDER_MARK) ? text.slice(1) : text);
50
+ }
51
+ catch {
52
+ return null;
53
+ }
54
+ if (!Array.isArray(rows))
55
+ return null;
56
+ return rows.flatMap((row) => {
57
+ if (typeof row !== "object" || row === null)
58
+ return [];
59
+ const value = row;
60
+ if (typeof value.pid !== "number")
61
+ return [];
62
+ return [
63
+ {
64
+ pid: value.pid,
65
+ ppid: typeof value.ppid === "number" ? value.ppid : null,
66
+ name: typeof value.name === "string" ? value.name : "",
67
+ command: typeof value.command === "string" && value.command !== "" ? value.command : null,
68
+ memoryBytes: typeof value.memory === "number" ? value.memory : null,
69
+ },
70
+ ];
71
+ });
72
+ }
73
+ /** UTF-8 output fails harmlessly under Constrained Language Mode; the listing still works there. */
74
+ const CIM_SCRIPT = String.raw `
75
+ try { [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 } catch { }
76
+ $rows = @(Get-CimInstance -ClassName Win32_Process | ForEach-Object {
77
+ [pscustomobject]@{ pid = $_.ProcessId; ppid = $_.ParentProcessId; name = $_.Name; command = $_.CommandLine; memory = $_.WorkingSetSize }
78
+ })
79
+ ConvertTo-Json -InputObject $rows -Compress
80
+ `;
81
+ function listingFailed(program, result) {
82
+ const detail = result.stderr.trim().split(/\r?\n/)[0] ?? "";
83
+ return new CapabilityUnavailableError("core.processes.failed", { program, code: result.code, detail });
84
+ }
85
+ /**
86
+ * Names and memory come from tasklist, measured at about 0.7 s. Parent ids and command
87
+ * lines need Get-CimInstance through PowerShell, which takes a second or more; WMIC is gone
88
+ * from current Windows. Verified on Windows Server 2025 in the phase 0 spike.
89
+ */
90
+ export class WindowsProcessTableAdapter {
91
+ processRunner;
92
+ selfPid = process.pid;
93
+ constructor(processRunner) {
94
+ this.processRunner = processRunner;
95
+ }
96
+ async list(detailed, signal) {
97
+ if (!detailed)
98
+ return { processes: await this.fromTasklist(signal), detailed: false };
99
+ return { processes: await this.fromCim(signal), detailed: true };
100
+ }
101
+ end(pids, force) {
102
+ return endProcesses(pids, force);
103
+ }
104
+ protectedPids() {
105
+ // 0 is the System Idle Process and 4 the System process.
106
+ return new Set([0, 4, process.pid, process.ppid]);
107
+ }
108
+ async fromTasklist(signal) {
109
+ const result = await this.processRunner.run(system32("tasklist.exe"), ["/fo", "csv", "/nh"], {
110
+ signal,
111
+ timeoutMs: 60_000,
112
+ });
113
+ if (result.code !== 0)
114
+ throw listingFailed("tasklist", result);
115
+ return parseTasklist(result.stdout);
116
+ }
117
+ async fromCim(signal) {
118
+ let result;
119
+ try {
120
+ result = await runPowerShell(CIM_SCRIPT, { signal, timeoutMs: 120_000 });
121
+ }
122
+ catch (error) {
123
+ if (signal.aborted)
124
+ throw new InterruptedError("core.error.interrupted", {}, { cause: error });
125
+ const detail = error instanceof Error ? error.message : String(error);
126
+ throw new CapabilityUnavailableError("core.process.cannot-start", { program: "powershell.exe", detail });
127
+ }
128
+ const processes = result.code === 0 ? parseCimProcesses(result.stdout) : null;
129
+ if (processes === null)
130
+ throw listingFailed("Get-CimInstance", result);
131
+ return processes;
132
+ }
133
+ }
134
+ //# sourceMappingURL=windows-process-table.adapter.js.map
@@ -0,0 +1,86 @@
1
+ import { CapabilityUnavailableError } from "../../../domain/errors.js";
2
+ import { message } from "../../../domain/message.js";
3
+ import { runPowerShell } from "../../node/run-program.js";
4
+ const NEWLINE = String.fromCharCode(10);
5
+ /**
6
+ * SHFileOperation with FOF_ALLOWUNDO sends to the Recycle Bin without dialogs. It
7
+ * deletes permanently on drives without a Recycle Bin, so only fixed local drives
8
+ * are accepted. Under Constrained Language Mode Add-Type cannot load the C#, which
9
+ * is reported rather than worked around. Verified in the phase 0 spike.
10
+ */
11
+ const SCRIPT = String.raw `
12
+ $ErrorActionPreference = 'Stop'
13
+ $mode = $ExecutionContext.SessionState.LanguageMode
14
+ "mode|$mode"
15
+ if ($mode -ne 'FullLanguage') { exit 0 }
16
+ Add-Type -TypeDefinition @'
17
+ using System;
18
+ using System.Runtime.InteropServices;
19
+ public static class KiriyaRecycleBin {
20
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
21
+ private struct Operation {
22
+ public IntPtr Window; public uint Function; public string From; public string To;
23
+ public ushort Flags; public bool Aborted; public IntPtr NameMappings; public string Title;
24
+ }
25
+ [DllImport("shell32.dll", CharSet = CharSet.Unicode)]
26
+ private static extern int SHFileOperation(ref Operation operation);
27
+ public static int Send(string path) {
28
+ var operation = new Operation { Function = 3, From = path + new string((char)0, 2), Flags = 0x0040 | 0x0010 | 0x0400 | 0x0004 };
29
+ int code = SHFileOperation(ref operation);
30
+ return code != 0 ? code : (operation.Aborted ? -1 : 0);
31
+ }
32
+ }
33
+ '@
34
+ $paths = $env:KIRIYA_TRASH_PATHS -split [char]10
35
+ for ($i = 0; $i -lt $paths.Length; $i++) {
36
+ $p = $paths[$i]
37
+ if ($p -eq '') { continue }
38
+ try {
39
+ $root = [System.IO.Path]::GetPathRoot($p)
40
+ if ($root.StartsWith('\\')) { "network|$i"; continue }
41
+ $drive = New-Object System.IO.DriveInfo($root)
42
+ if ($drive.DriveType -ne 'Fixed') { "drive|$i|$($drive.DriveType)"; continue }
43
+ $code = [KiriyaRecycleBin]::Send($p)
44
+ if ($code -eq 0 -and -not (Test-Path -LiteralPath $p)) { "ok|$i" } else { "error|$i|SHFileOperation returned $code" }
45
+ } catch { "error|$i|$($_.Exception.Message)" }
46
+ }
47
+ `;
48
+ export class WindowsTrashAdapter {
49
+ location = "core.trash.location.recycle-bin";
50
+ async send(paths) {
51
+ const result = await runPowerShell(SCRIPT, {
52
+ env: { KIRIYA_TRASH_PATHS: paths.join(NEWLINE) },
53
+ timeoutMs: 10 * 60_000,
54
+ });
55
+ const lines = result.stdout
56
+ .split(/\r?\n/)
57
+ .map((line) => line.trim())
58
+ .filter((line) => line !== "");
59
+ const mode = lines.find((line) => line.startsWith("mode|"))?.slice(5) ?? "unknown";
60
+ if (mode !== "FullLanguage")
61
+ throw new CapabilityUnavailableError("core.trash.windows.language-mode", { mode });
62
+ const byIndex = new Map();
63
+ for (const line of lines) {
64
+ const [status, indexText, ...rest] = line.split("|");
65
+ if (indexText === undefined || !/^[0-9]+$/.test(indexText))
66
+ continue;
67
+ const index = Number(indexText);
68
+ const path = paths[index] ?? "";
69
+ if (status === "ok")
70
+ byIndex.set(index, { path, ok: true });
71
+ else if (status === "network")
72
+ byIndex.set(index, { path, ok: false, reason: message("core.trash.windows.network") });
73
+ else if (status === "drive") {
74
+ byIndex.set(index, { path, ok: false, reason: message("core.trash.windows.drive", { drive: rest.join("|") }) });
75
+ }
76
+ else
77
+ byIndex.set(index, { path, ok: false, reason: message("core.trash.failed", { detail: rest.join("|") }) });
78
+ }
79
+ return paths.map((path, index) => byIndex.get(index) ?? {
80
+ path,
81
+ ok: false,
82
+ reason: message("core.trash.failed", { detail: result.stderr.trim().split(/\r?\n/)[0] ?? "no result" }),
83
+ });
84
+ }
85
+ }
86
+ //# sourceMappingURL=windows-trash.adapter.js.map
@@ -0,0 +1,83 @@
1
+ import { parseArgs } from "node:util";
2
+ import { UsageError } from "../../domain/errors.js";
3
+ import { message } from "../../domain/message.js";
4
+ import { closest } from "./suggest.js";
5
+ const GLOBAL_TOKENS = {
6
+ "--json": "json",
7
+ "--no-color": "noColor",
8
+ "--no-input": "noInput",
9
+ "--debug": "debug",
10
+ "--help": "help",
11
+ "-h": "help",
12
+ "--version": "version",
13
+ "-V": "version",
14
+ };
15
+ /** Global flags may appear anywhere before `--`; they are taken out before the command parses the rest. */
16
+ export function splitGlobalFlags(argv) {
17
+ const flags = {
18
+ json: false,
19
+ noColor: false,
20
+ noInput: false,
21
+ debug: false,
22
+ help: false,
23
+ version: false,
24
+ };
25
+ const rest = [];
26
+ let passthrough = false;
27
+ for (const token of argv) {
28
+ const flag = passthrough ? undefined : GLOBAL_TOKENS[token];
29
+ if (token === "--")
30
+ passthrough = true;
31
+ if (flag === undefined)
32
+ rest.push(token);
33
+ else
34
+ flags[flag] = true;
35
+ }
36
+ return { flags, rest };
37
+ }
38
+ /** Node's parseArgs errors carry English text; turn the common ones into message keys. */
39
+ function usageError(error, schema) {
40
+ const code = error.code;
41
+ const text = error instanceof Error ? error.message : String(error);
42
+ const option = /'(?:-\w, )?(-{1,2}[^'\s=,]+)/.exec(text)?.[1];
43
+ if (code === "ERR_PARSE_ARGS_UNKNOWN_OPTION" && option !== undefined) {
44
+ const known = [...Object.keys(schema.options), ...Object.keys(GLOBAL_TOKENS).map((token) => token.slice(2))].map((name) => `--${name}`);
45
+ const suggestion = option.startsWith("--") ? closest(option, known) : undefined;
46
+ return new UsageError("core.usage.unknown-option", suggestion === undefined ? { option } : { option, hint: message("core.usage.did-you-mean", { suggestion }) });
47
+ }
48
+ if (code === "ERR_PARSE_ARGS_INVALID_OPTION_VALUE" && option !== undefined) {
49
+ const name = option.replace(/^-+/, "");
50
+ const key = text.includes("does not take an argument") ? "core.usage.takes-no-value" : "core.usage.expects-value";
51
+ return new UsageError(key, { option: name });
52
+ }
53
+ return new UsageError("core.usage.bad-arguments", { detail: text });
54
+ }
55
+ /** argv for one command, checked against its schema: unknown flags and argument counts are usage errors. */
56
+ export function parseCommandArguments(schema, args) {
57
+ const options = {};
58
+ for (const [name, spec] of Object.entries(schema.options)) {
59
+ options[name] = {
60
+ type: spec.type,
61
+ ...(spec.short === undefined ? {} : { short: spec.short }),
62
+ ...(spec.multiple === true ? { multiple: true } : {}),
63
+ };
64
+ }
65
+ let parsed;
66
+ try {
67
+ parsed = parseArgs({ args: [...args], options, allowPositionals: true, strict: true });
68
+ }
69
+ catch (error) {
70
+ throw usageError(error, schema);
71
+ }
72
+ const variadic = schema.positionals.some((positional) => positional.variadic);
73
+ if (!variadic && parsed.positionals.length > schema.positionals.length) {
74
+ throw new UsageError("core.usage.too-many-arguments", {
75
+ extra: parsed.positionals.slice(schema.positionals.length).join(" "),
76
+ });
77
+ }
78
+ const missing = schema.positionals.find((positional, index) => positional.required && parsed.positionals[index] === undefined);
79
+ if (missing !== undefined)
80
+ throw new UsageError("core.usage.missing-argument", { name: missing.name });
81
+ return { positionals: parsed.positionals, options: parsed.values };
82
+ }
83
+ //# sourceMappingURL=argv.js.map