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,100 @@
1
+ import { KiriyaError } from "../domain/errors.js";
2
+ import { message } from "../domain/message.js";
3
+ const PLUGIN_ID = /^[a-z][a-z0-9-]*$/;
4
+ /** Words the command line itself uses, which no module may take. */
5
+ const RESERVED_IDS = new Set(["core", "help", "mcp", "version"]);
6
+ /** The exported module, or why it is not one: the contract in docs/guides/plugins.md. */
7
+ function checkShape(exports) {
8
+ const exported = typeof exports === "object" && exports !== null && "default" in exports
9
+ ? exports.default
10
+ : exports;
11
+ if (typeof exported !== "object" || exported === null)
12
+ return { problem: message("core.plugin.no-module") };
13
+ const { id, summary, register, messages } = exported;
14
+ if (typeof id !== "string" || !PLUGIN_ID.test(id))
15
+ return { problem: message("core.plugin.bad-id") };
16
+ if (typeof register !== "function")
17
+ return { problem: message("core.plugin.no-register", { id }) };
18
+ if (typeof messages !== "object" || messages === null) {
19
+ return { problem: message("core.plugin.no-messages", { id }) };
20
+ }
21
+ for (const [key, text] of Object.entries(messages)) {
22
+ if (!key.startsWith(`${id}.`) || typeof text !== "string") {
23
+ return { problem: message("core.plugin.bad-message", { id, key }) };
24
+ }
25
+ }
26
+ if (typeof summary !== "string" || !(summary in messages)) {
27
+ return { problem: message("core.plugin.no-summary", { id }) };
28
+ }
29
+ // Help reads these optional fields as it prints, so a wrong shape is refused here rather than failing there.
30
+ const { about, examples, guide } = exported;
31
+ if (about !== undefined && (typeof about !== "string" || !(about in messages))) {
32
+ return { problem: message("core.plugin.bad-about", { id }) };
33
+ }
34
+ if (examples !== undefined && !(Array.isArray(examples) && examples.every((line) => typeof line === "string"))) {
35
+ return { problem: message("core.plugin.bad-examples", { id }) };
36
+ }
37
+ if (guide !== undefined && (typeof guide !== "string" || !guide.startsWith("https://"))) {
38
+ return { problem: message("core.plugin.bad-guide", { id }) };
39
+ }
40
+ return { plugin: exported };
41
+ }
42
+ /**
43
+ * Loads the plugins the configuration lists and registers their commands. A plugin
44
+ * that cannot be found, imported, checked or registered is recorded and skipped, so
45
+ * one broken plugin never stops kiriya; `kiriya doctor` reports it.
46
+ */
47
+ export class PluginLoader {
48
+ succeeded = [];
49
+ failed = [];
50
+ /** The English text of every loaded plugin's message keys. */
51
+ messages = {};
52
+ loaded() {
53
+ return this.succeeded;
54
+ }
55
+ problems() {
56
+ return this.failed;
57
+ }
58
+ async load(entries, baseDirectory, source, registry, ports) {
59
+ for (const entry of entries) {
60
+ let found;
61
+ try {
62
+ found = await source.load(entry, baseDirectory);
63
+ }
64
+ catch (error) {
65
+ if (!(error instanceof KiriyaError))
66
+ throw error;
67
+ this.failed.push({ entry, reason: error.detail });
68
+ continue;
69
+ }
70
+ const checked = checkShape(found.exports);
71
+ if ("problem" in checked) {
72
+ this.failed.push({ entry, reason: checked.problem });
73
+ continue;
74
+ }
75
+ const { plugin } = checked;
76
+ if (RESERVED_IDS.has(plugin.id) || registry.module(plugin.id) !== undefined) {
77
+ this.failed.push({ entry, reason: message("core.plugin.taken", { id: plugin.id }) });
78
+ continue;
79
+ }
80
+ try {
81
+ registry.register(plugin, ports);
82
+ }
83
+ catch (error) {
84
+ const detail = error instanceof Error ? error.message : String(error);
85
+ this.failed.push({ entry, reason: message("core.plugin.register-failed", { id: plugin.id, detail }) });
86
+ continue;
87
+ }
88
+ Object.assign(this.messages, plugin.messages);
89
+ this.succeeded.push({
90
+ entry,
91
+ id: plugin.id,
92
+ name: found.name,
93
+ version: found.version,
94
+ location: found.location,
95
+ commands: registry.module(plugin.id)?.commands.size ?? 0,
96
+ });
97
+ }
98
+ }
99
+ }
100
+ //# sourceMappingURL=plugin-loader.js.map
@@ -0,0 +1,28 @@
1
+ import { message } from "../domain/message.js";
2
+ /** "node (4100), node (4200)", to show in a confirmation what is about to end. */
3
+ export function processLabels(pids, names) {
4
+ return pids.map((pid) => `${names.get(pid) ?? "?"} (${pid})`).join(", ");
5
+ }
6
+ /** Ending results as output: a process already gone is a warning, and one that did not end is a failure. */
7
+ export function reportEnded(results, names) {
8
+ const failures = [];
9
+ const warnings = [];
10
+ for (const result of results) {
11
+ const params = { name: names.get(result.pid) ?? "?", pid: result.pid, code: result.code ?? result.outcome };
12
+ if (result.outcome === "not-found")
13
+ warnings.push(message("core.end.gone", params));
14
+ if (result.outcome === "still-running")
15
+ failures.push(message("core.end.still-running", params));
16
+ if (result.outcome === "denied")
17
+ failures.push(message("core.end.denied", params));
18
+ if (result.outcome === "failed")
19
+ failures.push(message("core.end.failed", params));
20
+ }
21
+ const processes = results.map((result) => ({
22
+ pid: result.pid,
23
+ name: names.get(result.pid) ?? null,
24
+ outcome: result.outcome,
25
+ }));
26
+ return { processes, failures, warnings };
27
+ }
28
+ //# sourceMappingURL=process-ending.js.map
@@ -0,0 +1,123 @@
1
+ import path from "node:path";
2
+ import { NotFoundError, RefusedError } from "../domain/errors.js";
3
+ import { hasGlob } from "../domain/glob.js";
4
+ import { isInside } from "./paths.js";
5
+ /** True when a path is a `.git` folder or lies inside one, in any letter case. */
6
+ function insideGitFolder(target) {
7
+ return target.split(/[\\/]/).some((segment) => segment.toLowerCase() === ".git");
8
+ }
9
+ /** Every value given for an input the command marks as a path. */
10
+ export function pathValues(schema, raw) {
11
+ const values = [];
12
+ schema.positionals.forEach((positional, index) => {
13
+ if (positional.path !== true)
14
+ return;
15
+ values.push(...raw.positionals.slice(index, positional.variadic ? undefined : index + 1));
16
+ });
17
+ for (const [name, option] of Object.entries(schema.options)) {
18
+ const value = raw.options[name];
19
+ if (option.path !== true || value === undefined || typeof value === "boolean")
20
+ continue;
21
+ values.push(...(typeof value === "string" ? [value] : value));
22
+ }
23
+ return values;
24
+ }
25
+ /**
26
+ * The folders an MCP client may reach. A path is inside when it lies under a root both
27
+ * as written and with every symlink followed, so neither `..` nor a link leads out.
28
+ */
29
+ export class RootScope {
30
+ fileSystem;
31
+ start;
32
+ roots;
33
+ realRoots;
34
+ guarded;
35
+ constructor(fileSystem,
36
+ /** Where relative paths start: the first root. */
37
+ start, roots, realRoots, guarded) {
38
+ this.fileSystem = fileSystem;
39
+ this.start = start;
40
+ this.roots = roots;
41
+ this.realRoots = realRoots;
42
+ this.guarded = guarded;
43
+ }
44
+ /**
45
+ * Folders resolve against `cwd`, which is the only root when none is given. Each must be
46
+ * a folder that exists. `guarded` files, such as kiriya's configuration file, stay out of
47
+ * reach of work that changes something even when a root holds them.
48
+ */
49
+ static async open(fileSystem, folders, cwd, guarded = []) {
50
+ const roots = [...new Set((folders.length === 0 ? [cwd] : folders).map((folder) => path.resolve(cwd, folder)))];
51
+ const realRoots = [];
52
+ for (const root of roots) {
53
+ if ((await fileSystem.stat(root))?.kind !== "directory")
54
+ throw new NotFoundError("core.mcp.root-missing", { path: root });
55
+ realRoots.push((await fileSystem.realPath(root)) ?? root);
56
+ }
57
+ const start = roots[0] ?? path.resolve(cwd);
58
+ return new RootScope(fileSystem, start, roots, realRoots, guarded.map((file) => path.resolve(cwd, file)));
59
+ }
60
+ /**
61
+ * RefusedError for the first value that leads outside every root. For work that
62
+ * `changes` something, a value that is a guarded file, or a folder holding one, is refused too.
63
+ */
64
+ async refuseOutside(values, changes = false) {
65
+ for (const value of values) {
66
+ for (const candidate of this.candidates(value)) {
67
+ const real = await this.real(candidate);
68
+ if (!this.within(candidate, this.roots) || real === null || !this.within(real, this.realRoots)) {
69
+ throw new RefusedError("core.mcp.outside-roots", { path: value, roots: this.roots.join(", ") });
70
+ }
71
+ if (changes) {
72
+ // git runs hooks and commands that its folder names, so a change there could run anything.
73
+ if (insideGitFolder(candidate) || insideGitFolder(real)) {
74
+ throw new RefusedError("core.mcp.git-folder", { path: value });
75
+ }
76
+ await this.refuseGuarded(value, candidate, real);
77
+ }
78
+ }
79
+ }
80
+ }
81
+ async refuseGuarded(value, candidate, real) {
82
+ for (const file of this.guarded) {
83
+ const realFile = await this.real(file);
84
+ if (isInside(file, candidate) || (realFile !== null && isInside(realFile, real))) {
85
+ throw new RefusedError("core.mcp.guarded", { path: value, file });
86
+ }
87
+ }
88
+ }
89
+ /** The path as written and, for a glob, the folder its expansion starts in, found the way `expandPaths` finds it. */
90
+ candidates(value) {
91
+ const whole = path.resolve(this.start, value);
92
+ if (!hasGlob(value))
93
+ return [whole];
94
+ const segments = (path.sep === "\\" ? value.split("\\").join("/") : value).split("/");
95
+ const firstGlob = segments.findIndex((segment) => hasGlob(segment));
96
+ return [whole, path.resolve(this.start, segments.slice(0, firstGlob).join("/") || ".")];
97
+ }
98
+ /**
99
+ * The path with the links of every part that exists followed. Null when an entry
100
+ * exists but cannot be followed, such as a link that leads nowhere, since writing
101
+ * through it would create whatever it names.
102
+ */
103
+ async real(target) {
104
+ const missing = [];
105
+ let current = target;
106
+ for (;;) {
107
+ const real = await this.fileSystem.realPath(current);
108
+ if (real !== null)
109
+ return path.join(real, ...missing);
110
+ if ((await this.fileSystem.lstat(current)) !== null)
111
+ return null;
112
+ const parent = path.dirname(current);
113
+ if (parent === current)
114
+ return null;
115
+ missing.unshift(path.basename(current));
116
+ current = parent;
117
+ }
118
+ }
119
+ within(target, roots) {
120
+ return roots.some((root) => isInside(target, root));
121
+ }
122
+ }
123
+ //# sourceMappingURL=root-scope.js.map
@@ -0,0 +1,26 @@
1
+ import { RefusedError } from "../domain/errors.js";
2
+ /** Refuses the whole command when any path is protected, before anything is asked or changed. */
3
+ export function refuseProtected(guard, paths, cwd) {
4
+ for (const target of paths) {
5
+ const reason = guard.reasonFor(target, cwd);
6
+ if (reason !== null)
7
+ throw new RefusedError("core.guard.refused", { path: target, reason });
8
+ }
9
+ }
10
+ /** A yes-or-no question for work that can be undone; anything but yes stops the command. */
11
+ export async function requireApproval(context, question, assumeYes) {
12
+ if (!(await context.confirmation.approve(question, assumeYes)))
13
+ throw new RefusedError("core.confirm.declined");
14
+ }
15
+ /**
16
+ * A typed confirmation for work that cannot be undone. A --confirm value that does
17
+ * not match stops the command before any prompt, since the plan is not what the script expected.
18
+ */
19
+ export async function requireTypedConfirmation(context, warning, expected, provided) {
20
+ if (provided !== undefined && provided !== expected) {
21
+ throw new RefusedError("core.confirm.mismatch", { provided, expected });
22
+ }
23
+ if (!(await context.confirmation.typed(warning, expected, provided)))
24
+ throw new RefusedError("core.confirm.declined");
25
+ }
26
+ //# sourceMappingURL=safety.js.map
@@ -0,0 +1,44 @@
1
+ import path from "node:path";
2
+ import { utf8Bytes, utf8Text } from "../domain/encodings.js";
3
+ import { NotFoundError, OperationFailedError, UsageError } from "../domain/errors.js";
4
+ import { formatBytes } from "../domain/values/bytes.js";
5
+ /** Commands that take text work in memory, so input stops here. */
6
+ export const INPUT_LIMIT_BYTES = 16 * 1024 * 1024;
7
+ const BYTE_ORDER_MARK = String.fromCharCode(0xfeff);
8
+ /** The value argument; everything piped in when it is `-` or missing; or a file's exact bytes with --file. */
9
+ export async function readInput(sources, cwd, value, file) {
10
+ if (file !== undefined) {
11
+ if (value !== undefined)
12
+ throw new UsageError("core.input.twice");
13
+ const target = path.resolve(cwd, file);
14
+ const stat = await sources.fileSystem.stat(target);
15
+ if (stat?.kind !== "file")
16
+ throw new NotFoundError("core.fs.not-found", { path: target });
17
+ if (stat.size > INPUT_LIMIT_BYTES) {
18
+ throw new OperationFailedError("core.input.too-large", { limit: formatBytes(INPUT_LIMIT_BYTES) });
19
+ }
20
+ return { bytes: await sources.content.read(target), from: "file" };
21
+ }
22
+ if (value !== undefined && value !== "-")
23
+ return { bytes: utf8Bytes(value), from: "argument" };
24
+ if (value === undefined && sources.stdin.isTerminal)
25
+ throw new UsageError("core.input.missing");
26
+ return { bytes: await sources.stdin.read(INPUT_LIMIT_BYTES), from: "stdin" };
27
+ }
28
+ /**
29
+ * The input as text, without a byte order mark. Text piped in also loses one final
30
+ * line ending, so `echo` in bash and in PowerShell, which end lines differently,
31
+ * give the same result.
32
+ */
33
+ export function inputText(input) {
34
+ const decoded = utf8Text(input.bytes);
35
+ if (decoded === null)
36
+ throw new UsageError("core.input.not-text");
37
+ const text = decoded.startsWith(BYTE_ORDER_MARK) ? decoded.slice(1) : decoded;
38
+ return input.from === "stdin" ? text.replace(/\r?\n$/, "") : text;
39
+ }
40
+ /** The bytes as given: a file or an argument exactly, piped text as inputText gives it. */
41
+ export function inputBytes(input) {
42
+ return input.from === "stdin" ? utf8Bytes(inputText(input)) : input.bytes;
43
+ }
44
+ //# sourceMappingURL=text-input.js.map
@@ -0,0 +1,34 @@
1
+ import path from "node:path";
2
+ import { DEPENDENCY_DIRECTORIES } from "../../config/dependency-directories.js";
3
+ import { KiriyaError } from "../domain/errors.js";
4
+ import { byCodePoint, isHiddenName } from "../domain/names.js";
5
+ /** Every entry below root in code-point order. Symlinks are listed, never followed; unreadable folders are skipped. */
6
+ export async function* walk(fileSystem, root, options) {
7
+ const maxDepth = options.maxDepth ?? Number.POSITIVE_INFINITY;
8
+ async function* visit(dir, rel, depth) {
9
+ let entries;
10
+ try {
11
+ entries = [...(await fileSystem.readDirectory(dir))];
12
+ }
13
+ catch (error) {
14
+ if (error instanceof KiriyaError)
15
+ return;
16
+ throw error;
17
+ }
18
+ entries.sort((a, b) => byCodePoint(a.name, b.name));
19
+ for (const entry of entries) {
20
+ const skipped = isHiddenName(entry.name) || (entry.kind === "directory" && DEPENDENCY_DIRECTORIES.has(entry.name));
21
+ if (!options.all && skipped)
22
+ continue;
23
+ if (entry.kind === "directory" && options.skipDirectories?.has(entry.name) === true)
24
+ continue;
25
+ const childPath = path.join(dir, entry.name);
26
+ const childRel = rel === "" ? entry.name : `${rel}/${entry.name}`;
27
+ yield { path: childPath, rel: childRel, name: entry.name, depth, kind: entry.kind };
28
+ if (entry.kind === "directory" && depth < maxDepth)
29
+ yield* visit(childPath, childRel, depth + 1);
30
+ }
31
+ }
32
+ yield* visit(root, "", 1);
33
+ }
34
+ //# sourceMappingURL=walk.js.map
@@ -0,0 +1,8 @@
1
+ export const SAFETY_LEVELS = ["read", "write", "destroy"];
2
+ export function done(data, notes = {}) {
3
+ return { kind: "done", data, warnings: notes.warnings ?? [], failures: notes.failures ?? [] };
4
+ }
5
+ export function preview(data, applyFlag, warnings = []) {
6
+ return { kind: "preview", data, applyFlag, warnings };
7
+ }
8
+ //# sourceMappingURL=command.js.map
@@ -0,0 +1,70 @@
1
+ const BASE64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
2
+ const BASE64_URL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
3
+ /** Base64 with padding, or the URL-safe alphabet without it. */
4
+ export function toBase64(bytes, urlSafe = false) {
5
+ const alphabet = urlSafe ? BASE64_URL : BASE64;
6
+ const pad = urlSafe ? "" : "=";
7
+ let text = "";
8
+ for (let index = 0; index < bytes.length; index += 3) {
9
+ const triple = ((bytes[index] ?? 0) << 16) | ((bytes[index + 1] ?? 0) << 8) | (bytes[index + 2] ?? 0);
10
+ text += alphabet.charAt((triple >> 18) & 63) + alphabet.charAt((triple >> 12) & 63);
11
+ text += index + 1 < bytes.length ? alphabet.charAt((triple >> 6) & 63) : pad;
12
+ text += index + 2 < bytes.length ? alphabet.charAt(triple & 63) : pad;
13
+ }
14
+ return text;
15
+ }
16
+ /** Standard or URL-safe base64, padded or not, with whitespace ignored; null when it is not base64. */
17
+ export function fromBase64(text) {
18
+ const clean = text
19
+ .replace(/\s+/g, "")
20
+ .replace(/-/g, "+")
21
+ .replace(/_/g, "/")
22
+ .replace(/={0,2}$/, "");
23
+ if (!/^[A-Za-z0-9+/]*$/.test(clean) || clean.length % 4 === 1)
24
+ return null;
25
+ const bytes = new Uint8Array(Math.floor((clean.length * 3) / 4));
26
+ let buffer = 0;
27
+ let bits = 0;
28
+ let written = 0;
29
+ for (const char of clean) {
30
+ buffer = (buffer << 6) | BASE64.indexOf(char);
31
+ bits += 6;
32
+ if (bits >= 8) {
33
+ bits -= 8;
34
+ bytes[written] = (buffer >> bits) & 0xff;
35
+ written += 1;
36
+ buffer &= (1 << bits) - 1;
37
+ }
38
+ }
39
+ return bytes;
40
+ }
41
+ export function toHex(bytes) {
42
+ let text = "";
43
+ for (const byte of bytes)
44
+ text += byte.toString(16).padStart(2, "0");
45
+ return text;
46
+ }
47
+ /** Hexadecimal digits in pairs, with whitespace and a leading 0x ignored; null when it is not hexadecimal. */
48
+ export function fromHex(text) {
49
+ const clean = text.replace(/\s+/g, "").replace(/^0x/i, "");
50
+ if (clean.length % 2 !== 0 || /[^0-9a-f]/i.test(clean))
51
+ return null;
52
+ const bytes = new Uint8Array(clean.length / 2);
53
+ for (let index = 0; index < bytes.length; index += 1) {
54
+ bytes[index] = Number.parseInt(clean.slice(index * 2, index * 2 + 2), 16);
55
+ }
56
+ return bytes;
57
+ }
58
+ export function utf8Bytes(text) {
59
+ return new TextEncoder().encode(text);
60
+ }
61
+ /** The bytes as UTF-8 text, or null when they are not valid UTF-8. */
62
+ export function utf8Text(bytes) {
63
+ try {
64
+ return new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes);
65
+ }
66
+ catch {
67
+ return null;
68
+ }
69
+ }
70
+ //# sourceMappingURL=encodings.js.map
@@ -0,0 +1,49 @@
1
+ import { message } from "./message.js";
2
+ export const ERROR_KINDS = [
3
+ "usage",
4
+ "not-found",
5
+ "conflict",
6
+ "refused",
7
+ "capability-unavailable",
8
+ "failed",
9
+ "interrupted",
10
+ ];
11
+ /**
12
+ * Every error that crosses into a use case or presentation is one of these.
13
+ * Adapters wrap Node.js and operating-system failures before they cross inward.
14
+ */
15
+ export class KiriyaError extends Error {
16
+ detail;
17
+ constructor(key, params = {}, options) {
18
+ super(key, options);
19
+ this.name = new.target.name;
20
+ this.detail = message(key, params);
21
+ }
22
+ }
23
+ /** Bad flags, values or arguments. */
24
+ export class UsageError extends KiriyaError {
25
+ kind = "usage";
26
+ }
27
+ export class NotFoundError extends KiriyaError {
28
+ kind = "not-found";
29
+ }
30
+ /** Something already exists where the command would create or move something. */
31
+ export class ConflictError extends KiriyaError {
32
+ kind = "conflict";
33
+ }
34
+ /** A protected path, or a confirmation that was declined or could not be asked. */
35
+ export class RefusedError extends KiriyaError {
36
+ kind = "refused";
37
+ }
38
+ /** This machine lacks what the command needs, such as a clipboard program. */
39
+ export class CapabilityUnavailableError extends KiriyaError {
40
+ kind = "capability-unavailable";
41
+ }
42
+ /** An operation the OS or Node.js reported as failed. */
43
+ export class OperationFailedError extends KiriyaError {
44
+ kind = "failed";
45
+ }
46
+ export class InterruptedError extends KiriyaError {
47
+ kind = "interrupted";
48
+ }
49
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1,57 @@
1
+ const GLOB_CHARACTERS = /[*?[{]/;
2
+ const REGEX_SPECIAL = new Set([".", "+", "^", "$", "(", ")", "|", "\\", "/"]);
3
+ export function hasGlob(text) {
4
+ return GLOB_CHARACTERS.test(text);
5
+ }
6
+ /**
7
+ * A glob as a RegExp over `/`-separated relative paths, ignoring case, the same on
8
+ * every OS: `*` and `?` stay within one folder, `**` crosses folders, and `[abc]`,
9
+ * `[!abc]` and `{ts,tsx}` work as in bash.
10
+ */
11
+ export function globToRegExp(pattern) {
12
+ let source = "";
13
+ let inBraces = false;
14
+ for (let index = 0; index < pattern.length; index += 1) {
15
+ const char = pattern.charAt(index);
16
+ if (char === "*") {
17
+ if (pattern.charAt(index + 1) === "*") {
18
+ const slashAfter = pattern.charAt(index + 2) === "/";
19
+ source += slashAfter ? "(?:.*/)?" : ".*";
20
+ index += slashAfter ? 2 : 1;
21
+ }
22
+ else {
23
+ source += "[^/]*";
24
+ }
25
+ }
26
+ else if (char === "?") {
27
+ source += "[^/]";
28
+ }
29
+ else if (char === "[") {
30
+ const close = pattern.indexOf("]", index + 1);
31
+ if (close < 0) {
32
+ source += "\\[";
33
+ }
34
+ else {
35
+ const body = pattern.slice(index + 1, close);
36
+ source += `[${body.startsWith("!") ? `^${body.slice(1)}` : body}]`;
37
+ index = close;
38
+ }
39
+ }
40
+ else if (char === "{") {
41
+ inBraces = true;
42
+ source += "(?:";
43
+ }
44
+ else if (char === "}" && inBraces) {
45
+ inBraces = false;
46
+ source += ")";
47
+ }
48
+ else if (char === "," && inBraces) {
49
+ source += "|";
50
+ }
51
+ else {
52
+ source += REGEX_SPECIAL.has(char) ? `\\${char}` : char;
53
+ }
54
+ }
55
+ return new RegExp(`^${source}$`, "i");
56
+ }
57
+ //# sourceMappingURL=glob.js.map
@@ -0,0 +1,10 @@
1
+ /** Options every command takes, wherever they appear before `--`. */
2
+ export const GLOBAL_OPTIONS = [
3
+ { name: "json", short: null, description: "core.option.json" },
4
+ { name: "no-color", short: null, description: "core.option.no-color" },
5
+ { name: "no-input", short: null, description: "core.option.no-input" },
6
+ { name: "debug", short: null, description: "core.option.debug" },
7
+ { name: "help", short: "h", description: "core.option.help" },
8
+ { name: "version", short: "V", description: "core.option.version" },
9
+ ];
10
+ //# sourceMappingURL=global-options.js.map
@@ -0,0 +1,54 @@
1
+ import { UsageError } from "./errors.js";
2
+ /** Typed access to raw values, with usage errors that name the option. */
3
+ export class RawReader {
4
+ raw;
5
+ constructor(raw) {
6
+ this.raw = raw;
7
+ }
8
+ positional(index) {
9
+ return this.raw.positionals[index];
10
+ }
11
+ positionalsFrom(index) {
12
+ return this.raw.positionals.slice(index);
13
+ }
14
+ flag(name) {
15
+ return this.raw.options[name] === true;
16
+ }
17
+ string(name) {
18
+ const value = this.raw.options[name];
19
+ if (value === undefined || value === false)
20
+ return undefined;
21
+ if (typeof value !== "string")
22
+ throw new UsageError("core.usage.expects-value", { option: name });
23
+ return value;
24
+ }
25
+ strings(name) {
26
+ const value = this.raw.options[name];
27
+ if (value === undefined || value === false)
28
+ return [];
29
+ if (typeof value === "string")
30
+ return [value];
31
+ if (Array.isArray(value))
32
+ return value;
33
+ throw new UsageError("core.usage.expects-value", { option: name });
34
+ }
35
+ choice(name, choices, fallback) {
36
+ const value = this.string(name);
37
+ if (value === undefined)
38
+ return fallback;
39
+ const match = choices.find((choice) => choice === value);
40
+ if (match === undefined)
41
+ throw new UsageError("core.usage.not-a-choice", { option: name, choices: choices.join(", ") });
42
+ return match;
43
+ }
44
+ positiveInteger(name, fallback) {
45
+ const value = this.string(name);
46
+ if (value === undefined)
47
+ return fallback;
48
+ const number = Number(value);
49
+ if (!Number.isInteger(number) || number < 1)
50
+ throw new UsageError("core.usage.not-a-positive-integer", { option: name });
51
+ return number;
52
+ }
53
+ }
54
+ //# sourceMappingURL=input-schema.js.map
@@ -0,0 +1,7 @@
1
+ export function message(key, params = {}) {
2
+ return { key, params };
3
+ }
4
+ export function isMessage(value) {
5
+ return typeof value === "object" && value !== null && "key" in value && "params" in value;
6
+ }
7
+ //# sourceMappingURL=message.js.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=module.js.map
@@ -0,0 +1,22 @@
1
+ export function isHiddenName(name) {
2
+ return name.startsWith(".");
3
+ }
4
+ /** Code-point order: unlike localeCompare, the same on every OS and in every locale. */
5
+ export function byCodePoint(a, b) {
6
+ return a < b ? -1 : a > b ? 1 : 0;
7
+ }
8
+ const FORBIDDEN = /[/\\<>:"|?*]/;
9
+ const RESERVED = /^(con|prn|aux|nul|com[0-9]|lpt[0-9])([.].*)?$/i;
10
+ /** Why a new name would not work on Windows, Linux and macOS alike, or null when it would. */
11
+ export function invalidNameReason(name) {
12
+ if (name === "" || name === "." || name === "..")
13
+ return "core.name.empty";
14
+ if (FORBIDDEN.test(name) || [...name].some((char) => char.charCodeAt(0) < 32))
15
+ return "core.name.characters";
16
+ if (/[. ]$/.test(name))
17
+ return "core.name.trailing";
18
+ if (RESERVED.test(name))
19
+ return "core.name.reserved";
20
+ return null;
21
+ }
22
+ //# sourceMappingURL=names.js.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=clipboard.js.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=clock.js.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=command-catalog.js.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=compression.js.map