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,158 @@
1
+ /**
2
+ * The ZIP format as pure functions over bytes: stored and deflated entries with
3
+ * UTF-8 names. ZIP64, which archives of 4 GB or 65,535 entries need, is detected
4
+ * and refused by the caller rather than guessed.
5
+ */
6
+ export const STORED = 0;
7
+ export const DEFLATED = 8;
8
+ export const ZIP32_LIMIT = 0xffffffff;
9
+ export const MAX_ENTRIES = 0xffff;
10
+ export const LOCAL_HEADER_LENGTH = 30;
11
+ export const END_RECORD_LENGTH = 22;
12
+ /** The end record sits within this many bytes of the end: its own length plus the longest comment. */
13
+ export const END_SEARCH_LENGTH = END_RECORD_LENGTH + 0xffff;
14
+ const LOCAL_SIGNATURE = 0x04034b50;
15
+ const CENTRAL_SIGNATURE = 0x02014b50;
16
+ const END_SIGNATURE = 0x06054b50;
17
+ const CENTRAL_HEADER_LENGTH = 46;
18
+ const UTF8_NAMES = 0x0800;
19
+ const ENCRYPTED = 0x0001;
20
+ const DIRECTORY_ATTRIBUTE = 0x10;
21
+ const ARCHIVE_ATTRIBUTE = 0x20;
22
+ const encoder = new TextEncoder();
23
+ function view(bytes) {
24
+ return new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
25
+ }
26
+ /** ZIP stores local time in two-second steps from 1980. */
27
+ function toDos(epochMs) {
28
+ const d = new Date(Math.max(epochMs, new Date(1980, 0, 1).getTime()));
29
+ return {
30
+ time: (d.getHours() << 11) | (d.getMinutes() << 5) | Math.floor(d.getSeconds() / 2),
31
+ date: ((d.getFullYear() - 1980) << 9) | ((d.getMonth() + 1) << 5) | d.getDate(),
32
+ };
33
+ }
34
+ function fromDos(time, date) {
35
+ return new Date(((date >> 9) & 0x7f) + 1980, ((date >> 5) & 0x0f) - 1, date & 0x1f, (time >> 11) & 0x1f, (time >> 5) & 0x3f, (time & 0x1f) * 2).getTime();
36
+ }
37
+ export function localHeader(entry) {
38
+ const name = encoder.encode(entry.name);
39
+ const bytes = new Uint8Array(LOCAL_HEADER_LENGTH + name.length);
40
+ const fields = view(bytes);
41
+ const { time, date } = toDos(entry.modifiedMs);
42
+ fields.setUint32(0, LOCAL_SIGNATURE, true);
43
+ fields.setUint16(4, 20, true);
44
+ fields.setUint16(6, UTF8_NAMES, true);
45
+ fields.setUint16(8, entry.method, true);
46
+ fields.setUint16(10, time, true);
47
+ fields.setUint16(12, date, true);
48
+ fields.setUint32(14, entry.crc, true);
49
+ fields.setUint32(18, entry.compressedSize, true);
50
+ fields.setUint32(22, entry.size, true);
51
+ fields.setUint16(26, name.length, true);
52
+ bytes.set(name, LOCAL_HEADER_LENGTH);
53
+ return bytes;
54
+ }
55
+ export function centralHeader(entry, localOffset) {
56
+ const name = encoder.encode(entry.name);
57
+ const bytes = new Uint8Array(CENTRAL_HEADER_LENGTH + name.length);
58
+ const fields = view(bytes);
59
+ const { time, date } = toDos(entry.modifiedMs);
60
+ fields.setUint32(0, CENTRAL_SIGNATURE, true);
61
+ fields.setUint16(4, 20, true);
62
+ fields.setUint16(6, 20, true);
63
+ fields.setUint16(8, UTF8_NAMES, true);
64
+ fields.setUint16(10, entry.method, true);
65
+ fields.setUint16(12, time, true);
66
+ fields.setUint16(14, date, true);
67
+ fields.setUint32(16, entry.crc, true);
68
+ fields.setUint32(20, entry.compressedSize, true);
69
+ fields.setUint32(24, entry.size, true);
70
+ fields.setUint16(28, name.length, true);
71
+ fields.setUint32(38, entry.isDirectory ? DIRECTORY_ATTRIBUTE : ARCHIVE_ATTRIBUTE, true);
72
+ fields.setUint32(42, localOffset, true);
73
+ bytes.set(name, CENTRAL_HEADER_LENGTH);
74
+ return bytes;
75
+ }
76
+ export function endRecord(location) {
77
+ const bytes = new Uint8Array(END_RECORD_LENGTH);
78
+ const fields = view(bytes);
79
+ fields.setUint32(0, END_SIGNATURE, true);
80
+ fields.setUint16(8, location.count, true);
81
+ fields.setUint16(10, location.count, true);
82
+ fields.setUint32(12, location.size, true);
83
+ fields.setUint32(16, location.offset, true);
84
+ return bytes;
85
+ }
86
+ /** The central directory's place, from the last bytes of an archive; null when they hold no end record. */
87
+ export function findDirectory(tail) {
88
+ const fields = view(tail);
89
+ for (let index = tail.length - END_RECORD_LENGTH; index >= 0; index -= 1) {
90
+ if (fields.getUint32(index, true) === END_SIGNATURE) {
91
+ return {
92
+ count: fields.getUint16(index + 10, true),
93
+ size: fields.getUint32(index + 12, true),
94
+ offset: fields.getUint32(index + 16, true),
95
+ };
96
+ }
97
+ }
98
+ return null;
99
+ }
100
+ export function usesZip64(location) {
101
+ return location.count === MAX_ENTRIES || location.offset === ZIP32_LIMIT || location.size === ZIP32_LIMIT;
102
+ }
103
+ /** Every entry in central directory bytes; null when the directory is damaged. */
104
+ export function parseDirectory(bytes, count) {
105
+ const fields = view(bytes);
106
+ const entries = [];
107
+ let position = 0;
108
+ for (let index = 0; index < count; index += 1) {
109
+ if (position + CENTRAL_HEADER_LENGTH > bytes.length)
110
+ return null;
111
+ if (fields.getUint32(position, true) !== CENTRAL_SIGNATURE)
112
+ return null;
113
+ const flags = fields.getUint16(position + 8, true);
114
+ const nameLength = fields.getUint16(position + 28, true);
115
+ const extraLength = fields.getUint16(position + 30, true);
116
+ const commentLength = fields.getUint16(position + 32, true);
117
+ const nameStart = position + CENTRAL_HEADER_LENGTH;
118
+ if (nameStart + nameLength > bytes.length)
119
+ return null;
120
+ const name = new TextDecoder(flags & UTF8_NAMES ? "utf-8" : "latin1").decode(bytes.subarray(nameStart, nameStart + nameLength));
121
+ entries.push({
122
+ name,
123
+ isDirectory: name.endsWith("/") || (fields.getUint32(position + 38, true) & DIRECTORY_ATTRIBUTE) !== 0,
124
+ method: fields.getUint16(position + 10, true),
125
+ encrypted: (flags & ENCRYPTED) !== 0,
126
+ crc: fields.getUint32(position + 16, true),
127
+ compressedSize: fields.getUint32(position + 20, true),
128
+ size: fields.getUint32(position + 24, true),
129
+ modifiedMs: fromDos(fields.getUint16(position + 12, true), fields.getUint16(position + 14, true)),
130
+ localOffset: fields.getUint32(position + 42, true),
131
+ });
132
+ position = nameStart + nameLength + extraLength + commentLength;
133
+ }
134
+ return entries;
135
+ }
136
+ /** Where an entry's data starts, from its local header; null when the header is damaged. */
137
+ export function dataOffset(localOffset, header) {
138
+ if (header.length < LOCAL_HEADER_LENGTH)
139
+ return null;
140
+ const fields = view(header);
141
+ if (fields.getUint32(0, true) !== LOCAL_SIGNATURE)
142
+ return null;
143
+ return localOffset + LOCAL_HEADER_LENGTH + fields.getUint16(26, true) + fields.getUint16(28, true);
144
+ }
145
+ /**
146
+ * The folder names an entry may be written under, or null for a name that would
147
+ * escape the target folder: absolute, with a drive letter, or with a `..` segment.
148
+ */
149
+ export function safeEntrySegments(name) {
150
+ const normalized = name.split(String.fromCharCode(92)).join("/");
151
+ if (normalized.startsWith("/") || /^[A-Za-z]:/.test(normalized))
152
+ return null;
153
+ const segments = normalized.split("/").filter((segment) => segment !== "" && segment !== ".");
154
+ if (segments.some((segment) => segment === ".."))
155
+ return null;
156
+ return segments;
157
+ }
158
+ //# sourceMappingURL=zip-format.js.map
@@ -0,0 +1,17 @@
1
+ import { message } from "../../../core/domain/message.js";
2
+ export const tarView = (output, format) => {
3
+ const ratio = output.bytesIn === 0 ? 100 : Math.round((output.bytesOut / output.bytesIn) * 100);
4
+ const summary = message("archive.tar.done", {
5
+ path: format.path(output.archive),
6
+ entries: output.entries,
7
+ bytesIn: format.bytes(output.bytesIn),
8
+ bytesOut: format.bytes(output.bytesOut),
9
+ ratio,
10
+ });
11
+ const lines = [format.green(format.text(summary))];
12
+ if (output.skippedLinks > 0) {
13
+ lines.push(format.dim(format.text(message("archive.tar.skipped-links", { count: output.skippedLinks }))));
14
+ }
15
+ return lines;
16
+ };
17
+ //# sourceMappingURL=tar.view.js.map
@@ -0,0 +1,30 @@
1
+ import { message } from "../../../core/domain/message.js";
2
+ export const untarView = (output, format) => {
3
+ if (output.mode === "list") {
4
+ const lines = output.entries.map((entry) => {
5
+ const size = entry.type === "file" ? format.bytes(entry.size) : "";
6
+ // Links and special files are listed, but never extracted.
7
+ const name = entry.type === "link" || entry.type === "other" ? format.dim(entry.name) : entry.name;
8
+ return ` ${format.time(entry.modifiedMs)} ${size.padStart(9)} ${name}`;
9
+ });
10
+ const total = message("archive.unzip.list-total", {
11
+ count: output.entries.length,
12
+ size: format.bytes(output.bytes),
13
+ });
14
+ lines.push("", format.text(total));
15
+ return lines;
16
+ }
17
+ if (!output.extracted)
18
+ return [];
19
+ const summary = message("archive.unzip.done", {
20
+ files: output.files,
21
+ size: format.bytes(output.bytes),
22
+ target: format.path(output.target),
23
+ });
24
+ const lines = [format.green(format.text(summary))];
25
+ if (output.skippedLinks > 0) {
26
+ lines.push(format.dim(format.text(message("archive.untar.skipped-links", { count: output.skippedLinks }))));
27
+ }
28
+ return lines;
29
+ };
30
+ //# sourceMappingURL=untar.view.js.map
@@ -0,0 +1,24 @@
1
+ import { message } from "../../../core/domain/message.js";
2
+ export const unzipView = (output, format) => {
3
+ if (output.mode === "list") {
4
+ const lines = output.entries.map((entry) => {
5
+ const size = entry.isDirectory ? "" : format.bytes(entry.size);
6
+ return ` ${format.time(entry.modifiedMs)} ${size.padStart(9)} ${entry.name}`;
7
+ });
8
+ const total = message("archive.unzip.list-total", {
9
+ count: output.entries.length,
10
+ size: format.bytes(output.bytes),
11
+ });
12
+ lines.push("", format.text(total));
13
+ return lines;
14
+ }
15
+ if (!output.extracted)
16
+ return [];
17
+ const summary = message("archive.unzip.done", {
18
+ files: output.files,
19
+ size: format.bytes(output.bytes),
20
+ target: format.path(output.target),
21
+ });
22
+ return [format.green(format.text(summary))];
23
+ };
24
+ //# sourceMappingURL=unzip.view.js.map
@@ -0,0 +1,17 @@
1
+ import { message } from "../../../core/domain/message.js";
2
+ export const zipView = (output, format) => {
3
+ const ratio = output.bytesIn === 0 ? 100 : Math.round((output.bytesOut / output.bytesIn) * 100);
4
+ const summary = message("archive.zip.done", {
5
+ path: format.path(output.archive),
6
+ entries: output.entries,
7
+ bytesIn: format.bytes(output.bytesIn),
8
+ bytesOut: format.bytes(output.bytesOut),
9
+ ratio,
10
+ });
11
+ const lines = [format.green(format.text(summary))];
12
+ if (output.skippedLinks > 0) {
13
+ lines.push(format.dim(format.text(message("archive.zip.skipped-links", { count: output.skippedLinks }))));
14
+ }
15
+ return lines;
16
+ };
17
+ //# sourceMappingURL=zip.view.js.map
@@ -0,0 +1,43 @@
1
+ import { inputText, readInput } from "../../../core/application/text-input.js";
2
+ import { done } from "../../../core/domain/command.js";
3
+ import { UsageError } from "../../../core/domain/errors.js";
4
+ import { RawReader } from "../../../core/domain/input-schema.js";
5
+ import { message } from "../../../core/domain/message.js";
6
+ import { looksSecret } from "../../../core/domain/secrets.js";
7
+ export const copySpec = {
8
+ id: "clip.copy",
9
+ summary: "clip.copy.summary",
10
+ examples: ['kiriya clip copy "hello"', "git log -1 | kiriya clip copy", "kiriya clip copy --file notes.md"],
11
+ // It replaces what is on the clipboard, which is why it is there.
12
+ safety: "write",
13
+ idempotent: true,
14
+ usesNetwork: false,
15
+ runsUserCommands: false,
16
+ input: {
17
+ positionals: [{ name: "text", description: "clip.copy.arg.text", required: false, variadic: false }],
18
+ options: { file: { type: "string", description: "clip.copy.option.file", valueName: "<path>", path: true } },
19
+ parse(raw) {
20
+ const reader = new RawReader(raw);
21
+ return { value: reader.positional(0), file: reader.string("file") };
22
+ },
23
+ },
24
+ };
25
+ export class CopyText {
26
+ clipboard;
27
+ sources;
28
+ spec = copySpec;
29
+ constructor(clipboard, sources) {
30
+ this.clipboard = clipboard;
31
+ this.sources = sources;
32
+ }
33
+ async execute(input, context) {
34
+ const text = inputText(await readInput(this.sources, context.cwd, input.value, input.file));
35
+ if (text === "")
36
+ throw new UsageError("clip.copy.empty");
37
+ await this.clipboard.write(text, context.signal);
38
+ // Clipboard history and other programs can read it long after.
39
+ const warnings = looksSecret(text) ? [message("clip.copy.secret")] : [];
40
+ return done({ characters: [...text].length }, { warnings });
41
+ }
42
+ }
43
+ //# sourceMappingURL=copy-text.use-case.js.map
@@ -0,0 +1,25 @@
1
+ import { done } from "../../../core/domain/command.js";
2
+ export const pasteSpec = {
3
+ id: "clip.paste",
4
+ summary: "clip.paste.summary",
5
+ examples: ["kiriya clip paste", "kiriya clip paste > notes.txt", "kiriya clip paste --json"],
6
+ safety: "read",
7
+ // The clipboard can change between runs.
8
+ idempotent: false,
9
+ usesNetwork: false,
10
+ runsUserCommands: false,
11
+ // The clipboard often holds a password on its way to a form.
12
+ sensitive: true,
13
+ input: { positionals: [], options: {}, parse: () => ({}) },
14
+ };
15
+ export class PasteText {
16
+ clipboard;
17
+ spec = pasteSpec;
18
+ constructor(clipboard) {
19
+ this.clipboard = clipboard;
20
+ }
21
+ async execute(_input, context) {
22
+ return done({ text: await this.clipboard.read(context.signal) });
23
+ }
24
+ }
25
+ //# sourceMappingURL=paste-text.use-case.js.map
@@ -0,0 +1,16 @@
1
+ import { CopyText } from "./application/copy-text.use-case.js";
2
+ import { PasteText } from "./application/paste-text.use-case.js";
3
+ import { copyView, pasteView } from "./presentation/clip.views.js";
4
+ export const clipModule = {
5
+ id: "clip",
6
+ summary: "clip.summary",
7
+ about: "clip.about",
8
+ examples: ['kiriya clip copy "hello"', "kiriya clip copy --file notes.md", "kiriya clip paste"],
9
+ guide: "https://github.com/SatPaingOo/kiriya/blob/main/docs/modules/clip.md",
10
+ register(registrar, ports) {
11
+ const sources = { stdin: ports.stdin, fileSystem: ports.fileSystem, content: ports.fileContent };
12
+ registrar.add(new CopyText(ports.clipboard, sources), copyView);
13
+ registrar.add(new PasteText(ports.clipboard), pasteView);
14
+ },
15
+ };
16
+ //# sourceMappingURL=clip.module.js.map
@@ -0,0 +1,7 @@
1
+ import { message } from "../../../core/domain/message.js";
2
+ export const copyView = (output, format) => [
3
+ format.dim(format.text(message("clip.copy.done", { count: output.characters }))),
4
+ ];
5
+ /** The text itself, one final line ending aside, which the terminal adds back. */
6
+ export const pasteView = (output) => output.text === "" ? [] : output.text.replace(/\r?\n$/, "").split(/\r?\n/);
7
+ //# sourceMappingURL=clip.views.js.map
@@ -0,0 +1,38 @@
1
+ import { done } from "../../../core/domain/command.js";
2
+ import { UsageError } from "../../../core/domain/errors.js";
3
+ import { RawReader } from "../../../core/domain/input-schema.js";
4
+ import { completionScript, SHELLS } from "../domain/scripts.js";
5
+ export const scriptSpec = {
6
+ id: "completion",
7
+ summary: "completion.script.summary",
8
+ examples: [
9
+ 'eval "$(kiriya completion bash)"',
10
+ "kiriya completion fish > ~/.config/fish/completions/kiriya.fish",
11
+ "kiriya completion powershell | Out-String | Invoke-Expression",
12
+ ],
13
+ safety: "read",
14
+ idempotent: true,
15
+ usesNetwork: false,
16
+ runsUserCommands: false,
17
+ input: {
18
+ positionals: [
19
+ { name: "shell", description: "completion.arg.shell", required: true, variadic: false, choices: SHELLS },
20
+ ],
21
+ options: {},
22
+ parse(raw) {
23
+ const text = new RawReader(raw).positional(0) ?? "";
24
+ const shell = SHELLS.find((candidate) => candidate === text);
25
+ if (shell === undefined)
26
+ throw new UsageError("completion.shell-invalid", { shell: text });
27
+ return { shell };
28
+ },
29
+ },
30
+ };
31
+ /** Prints the script and installs nothing, so it can be read before it is loaded. */
32
+ export class PrintScript {
33
+ spec = scriptSpec;
34
+ execute(input) {
35
+ return Promise.resolve(done({ shell: input.shell, script: completionScript(input.shell) }));
36
+ }
37
+ }
38
+ //# sourceMappingURL=print-script.use-case.js.map
@@ -0,0 +1,37 @@
1
+ import { done } from "../../../core/domain/command.js";
2
+ import { GLOBAL_OPTIONS } from "../../../core/domain/global-options.js";
3
+ import { RawReader } from "../../../core/domain/input-schema.js";
4
+ import { suggest } from "../domain/suggest.js";
5
+ export const suggestSpec = {
6
+ id: "completion.suggest",
7
+ summary: "completion.suggest.summary",
8
+ examples: ["kiriya completion suggest --word=files --current=li", "kiriya completion suggest --current= --json"],
9
+ safety: "read",
10
+ idempotent: true,
11
+ usesNetwork: false,
12
+ runsUserCommands: false,
13
+ input: {
14
+ positionals: [],
15
+ options: {
16
+ current: { type: "string", description: "completion.suggest.option.current", valueName: "<word>" },
17
+ word: { type: "string", multiple: true, description: "completion.suggest.option.word", valueName: "<word>" },
18
+ },
19
+ parse(raw) {
20
+ const reader = new RawReader(raw);
21
+ return { current: reader.string("current") ?? "", words: reader.strings("word") };
22
+ },
23
+ },
24
+ };
25
+ /** Never runs what is on the line: it only reads the command catalog. */
26
+ export class SuggestWords {
27
+ commands;
28
+ spec = suggestSpec;
29
+ constructor(commands) {
30
+ this.commands = commands;
31
+ }
32
+ execute(input) {
33
+ const suggestions = suggest(this.commands.catalog(), GLOBAL_OPTIONS, input.words, input.current);
34
+ return Promise.resolve(done({ suggestions }));
35
+ }
36
+ }
37
+ //# sourceMappingURL=suggest-words.use-case.js.map
@@ -0,0 +1,14 @@
1
+ import { PrintScript } from "./application/print-script.use-case.js";
2
+ import { SuggestWords } from "./application/suggest-words.use-case.js";
3
+ import { scriptView, suggestView } from "./presentation/completion.views.js";
4
+ export const completionModule = {
5
+ id: "completion",
6
+ summary: "completion.summary",
7
+ about: "completion.about",
8
+ guide: "https://github.com/SatPaingOo/kiriya/blob/main/docs/modules/completion.md",
9
+ register(registrar, ports) {
10
+ registrar.add(new PrintScript(), scriptView);
11
+ registrar.add(new SuggestWords(ports.commands), suggestView);
12
+ },
13
+ };
14
+ //# sourceMappingURL=completion.module.js.map
@@ -0,0 +1,91 @@
1
+ export const SHELLS = ["bash", "zsh", "fish", "powershell"];
2
+ /*
3
+ * Each script only gathers the words on the line and asks `kiriya completion suggest`
4
+ * what can come next, so every shell completes the same way and plugins installed
5
+ * later complete too. Words travel as --word=<word> and --current=<word>: Windows
6
+ * PowerShell 5.1 drops empty arguments to programs, and a word such as --json must
7
+ * never be read as an option of suggest itself. An empty answer hands completion
8
+ * back to the shell, which then offers file names.
9
+ */
10
+ const BASH = [
11
+ "# kiriya completion for bash.",
12
+ '# Load it from ~/.bashrc: eval "$(kiriya completion bash)"',
13
+ "_kiriya_complete() {",
14
+ ' local args=("--current=${COMP_WORDS[COMP_CWORD]}")',
15
+ " local i",
16
+ " # Word by word: bash 3.2, as macOS ships it, joins a sliced array into one word.",
17
+ " for ((i = 1; i < COMP_CWORD; i++)); do",
18
+ ' args+=("--word=${COMP_WORDS[i]}")',
19
+ " done",
20
+ " local lines",
21
+ ' lines=$(kiriya completion suggest "${args[@]}" 2>/dev/null) || return 0',
22
+ " COMPREPLY=()",
23
+ ' [ -z "$lines" ] && return 0',
24
+ " local IFS=$'\\n'",
25
+ " COMPREPLY=($(printf '%s\\n' \"$lines\" | cut -f1))",
26
+ "}",
27
+ "# With no suggestion, -o default lets bash complete file names.",
28
+ "complete -o default -F _kiriya_complete kiriya",
29
+ ];
30
+ const ZSH = [
31
+ "#compdef kiriya",
32
+ "# kiriya completion for zsh.",
33
+ '# Load it from ~/.zshrc, after compinit: eval "$(kiriya completion zsh)"',
34
+ "_kiriya() {",
35
+ " local -a args lines candidates",
36
+ " local word line tab=$'\\t'",
37
+ ' args=("--current=${words[CURRENT]}")',
38
+ ' for word in "${(@)words[2,CURRENT-1]}"; do',
39
+ ' args+=("--word=$word")',
40
+ " done",
41
+ ' lines=("${(@f)$(kiriya completion suggest "${args[@]}" 2>/dev/null)}")',
42
+ ' if [[ -z "${lines[1]}" ]]; then',
43
+ " _files",
44
+ " return",
45
+ " fi",
46
+ ' for line in "${lines[@]}"; do',
47
+ ' candidates+=("${${line%%${tab}*}//:/\\\\:}:${line#*${tab}}")',
48
+ " done",
49
+ " _describe 'kiriya' candidates",
50
+ "}",
51
+ "compdef _kiriya kiriya",
52
+ ];
53
+ const FISH = [
54
+ "# kiriya completion for fish.",
55
+ "# Save it once: kiriya completion fish > ~/.config/fish/completions/kiriya.fish",
56
+ "function __kiriya_complete",
57
+ " set -l words (commandline -opc)",
58
+ " set -l lines (kiriya completion suggest --current=(commandline -ct) --word=$words[2..-1] 2>/dev/null)",
59
+ " if test (count $lines) -eq 0",
60
+ " __fish_complete_path (commandline -ct)",
61
+ " return",
62
+ " end",
63
+ " printf '%s\\n' $lines",
64
+ "end",
65
+ "complete -c kiriya -f -a '(__kiriya_complete)'",
66
+ ];
67
+ const POWERSHELL = [
68
+ "# kiriya completion for PowerShell.",
69
+ "# Load it from your profile: kiriya completion powershell | Out-String | Invoke-Expression",
70
+ "Register-ArgumentCompleter -Native -CommandName kiriya -ScriptBlock {",
71
+ " param($wordToComplete, $commandAst, $cursorPosition)",
72
+ " $words = @($commandAst.CommandElements | Select-Object -Skip 1 | ForEach-Object { $_.ToString() })",
73
+ " if ($wordToComplete -ne '' -and $words.Count -gt 0) { $words = @($words | Select-Object -SkipLast 1) }",
74
+ ' $arguments = @("--current=$wordToComplete") + @($words | ForEach-Object { "--word=$_" })',
75
+ " kiriya completion suggest @arguments 2>$null | ForEach-Object {",
76
+ ' $parts = $_ -split "`t", 2',
77
+ " $tip = if ($parts.Count -gt 1 -and $parts[1] -ne '') { $parts[1] } else { $parts[0] }",
78
+ " [System.Management.Automation.CompletionResult]::new($parts[0], $parts[0], 'ParameterValue', $tip)",
79
+ " }",
80
+ "}",
81
+ ];
82
+ const SCRIPTS = {
83
+ bash: BASH,
84
+ zsh: ZSH,
85
+ fish: FISH,
86
+ powershell: POWERSHELL,
87
+ };
88
+ export function completionScript(shell) {
89
+ return `${SCRIPTS[shell].join("\n")}\n`;
90
+ }
91
+ //# sourceMappingURL=scripts.js.map
@@ -0,0 +1,134 @@
1
+ /** The values an option lists in its value name, such as `<hex|base64|base64url>`. */
2
+ export function optionChoices(option) {
3
+ const match = /^<([a-z0-9-]+(?:\|[a-z0-9-]+)+)>$/.exec(option.valueName ?? "");
4
+ return match?.[1]?.split("|") ?? [];
5
+ }
6
+ function ownCommand(module) {
7
+ return module.commands.find((command) => command.verb === "");
8
+ }
9
+ function positionalChoices(command, index) {
10
+ const positionals = command.spec.input.positionals;
11
+ const last = positionals.at(-1);
12
+ const positional = positionals[index] ?? (last?.variadic === true ? last : undefined);
13
+ return [...(positional?.choices ?? [])];
14
+ }
15
+ function findOption(command, word) {
16
+ if (command === undefined)
17
+ return undefined;
18
+ const options = command.spec.input.options;
19
+ if (word.startsWith("--"))
20
+ return options[word.slice(2).split("=")[0] ?? ""];
21
+ return Object.values(options).find((option) => option.short === word.slice(1));
22
+ }
23
+ /** Where the line stands after the words before the one being completed; null after a word kiriya does not know. */
24
+ function locate(modules, words) {
25
+ let module;
26
+ let command;
27
+ let argument = 0;
28
+ let help = null;
29
+ let pending;
30
+ let literal = false;
31
+ let started = false;
32
+ for (const word of words) {
33
+ if (pending !== undefined) {
34
+ pending = undefined;
35
+ continue;
36
+ }
37
+ if (!literal && word === "--") {
38
+ literal = true;
39
+ continue;
40
+ }
41
+ if (!literal && word.length > 1 && word.startsWith("-")) {
42
+ const option = findOption(command ?? (module === undefined ? undefined : ownCommand(module)), word);
43
+ if (option?.type === "string" && !word.includes("="))
44
+ pending = option;
45
+ continue;
46
+ }
47
+ if (help !== null) {
48
+ help.push(word);
49
+ continue;
50
+ }
51
+ if (!started) {
52
+ started = true;
53
+ if (word === "help") {
54
+ help = [];
55
+ continue;
56
+ }
57
+ module = modules.find((candidate) => candidate.id === word);
58
+ if (module === undefined)
59
+ return null;
60
+ continue;
61
+ }
62
+ if (module !== undefined && command === undefined) {
63
+ const named = module.commands.find((candidate) => candidate.verb !== "" && candidate.verb === word);
64
+ command = named ?? ownCommand(module);
65
+ if (command === undefined)
66
+ return null;
67
+ // A module that is one command takes this word as its first argument.
68
+ if (named === undefined)
69
+ argument = 1;
70
+ continue;
71
+ }
72
+ argument += 1;
73
+ }
74
+ return { module, command, argument, help, pending, literal };
75
+ }
76
+ function moduleSuggestions(modules) {
77
+ return modules.map((module) => ({ value: module.id, description: module.summary }));
78
+ }
79
+ function verbSuggestions(module) {
80
+ return module.commands
81
+ .filter((command) => command.verb !== "")
82
+ .map((command) => ({ value: command.verb, description: command.spec.summary }));
83
+ }
84
+ function plain(values) {
85
+ return values.map((value) => ({ value, description: null }));
86
+ }
87
+ /**
88
+ * What can come next on a command line: modules, then commands, options and their
89
+ * values. `words` are the words after `kiriya` and before the one being completed. An
90
+ * empty result means a free value such as a path, which the shell completes as a file name.
91
+ */
92
+ export function suggest(modules, globals, words, current) {
93
+ const position = locate(modules, words);
94
+ if (position === null)
95
+ return [];
96
+ const starting = (suggestion) => suggestion.value.startsWith(current);
97
+ if (position.pending !== undefined)
98
+ return plain(optionChoices(position.pending)).filter(starting);
99
+ const command = position.command ?? (position.module === undefined ? undefined : ownCommand(position.module));
100
+ if (!position.literal && current.startsWith("--") && current.includes("=")) {
101
+ const name = current.slice(2, current.indexOf("="));
102
+ const option = findOption(command, `--${name}`);
103
+ if (option === undefined)
104
+ return [];
105
+ return plain(optionChoices(option).map((choice) => `--${name}=${choice}`)).filter(starting);
106
+ }
107
+ if (!position.literal && current.startsWith("-")) {
108
+ const own = Object.entries(command?.spec.input.options ?? {}).map(([name, option]) => ({
109
+ value: `--${name}`,
110
+ description: option.description,
111
+ }));
112
+ const global = globals.map((option) => ({ value: `--${option.name}`, description: option.description }));
113
+ return [...own, ...global].filter(starting);
114
+ }
115
+ if (position.help !== null) {
116
+ const [moduleName, ...rest] = position.help;
117
+ if (moduleName === undefined)
118
+ return moduleSuggestions(modules).filter(starting);
119
+ const helpModule = modules.find((module) => module.id === moduleName);
120
+ return helpModule === undefined || rest.length > 0 ? [] : verbSuggestions(helpModule).filter(starting);
121
+ }
122
+ if (position.module === undefined) {
123
+ const help = { value: "help", description: "completion.help-word" };
124
+ const mcp = { value: "mcp", description: "core.mcp.summary" };
125
+ return [...moduleSuggestions(modules), help, mcp].filter(starting);
126
+ }
127
+ if (position.command === undefined) {
128
+ const own = ownCommand(position.module);
129
+ const choices = own === undefined ? [] : positionalChoices(own, 0);
130
+ return [...verbSuggestions(position.module), ...plain(choices)].filter(starting);
131
+ }
132
+ return plain(positionalChoices(position.command, position.argument)).filter(starting);
133
+ }
134
+ //# sourceMappingURL=suggest.js.map