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,80 @@
1
+ import path from "node:path";
2
+ import { expandPaths, measure } from "../../../core/application/paths.js";
3
+ import { done } from "../../../core/domain/command.js";
4
+ import { RawReader } from "../../../core/domain/input-schema.js";
5
+ import { isHiddenName } from "../../../core/domain/names.js";
6
+ import { HASH_ALGORITHMS } from "../../../core/domain/ports/hasher.js";
7
+ function symbolic(mode) {
8
+ let text = "";
9
+ for (const shift of [6, 3, 0]) {
10
+ ["r", "w", "x"].forEach((bit, index) => {
11
+ text += mode & (1 << (shift + 2 - index)) ? bit : "-";
12
+ });
13
+ }
14
+ return text;
15
+ }
16
+ export const infoSpec = {
17
+ id: "files.info",
18
+ summary: "files.info.summary",
19
+ examples: [
20
+ "kiriya files info package.json",
21
+ "kiriya files info src --json",
22
+ 'kiriya files info "dist/*.zip" --hash sha256',
23
+ ],
24
+ safety: "read",
25
+ idempotent: true,
26
+ usesNetwork: false,
27
+ runsUserCommands: false,
28
+ input: {
29
+ positionals: [{ name: "paths", description: "files.info.arg.paths", required: true, variadic: true, path: true }],
30
+ options: {
31
+ hash: { type: "string", description: "files.info.option.hash", valueName: `<${HASH_ALGORITHMS.join("|")}>` },
32
+ },
33
+ parse(raw) {
34
+ const reader = new RawReader(raw);
35
+ const hash = reader.string("hash") === undefined ? undefined : reader.choice("hash", HASH_ALGORITHMS, "sha256");
36
+ return { paths: reader.positionalsFrom(0), hash };
37
+ },
38
+ },
39
+ };
40
+ export class ShowInfo {
41
+ fileSystem;
42
+ hasher;
43
+ environment;
44
+ spec = infoSpec;
45
+ constructor(fileSystem, hasher, environment) {
46
+ this.fileSystem = fileSystem;
47
+ this.hasher = hasher;
48
+ this.environment = environment;
49
+ }
50
+ async execute(input, context) {
51
+ const items = [];
52
+ for (const target of await expandPaths(this.fileSystem, input.paths, context.cwd, false)) {
53
+ const stat = await this.fileSystem.lstat(target);
54
+ if (stat === null)
55
+ continue;
56
+ const size = stat.kind === "directory" ? await measure(this.fileSystem, target) : null;
57
+ const hash = input.hash !== undefined && stat.kind === "file"
58
+ ? { algorithm: input.hash, value: await this.hasher.hashFile(target, input.hash) }
59
+ : null;
60
+ items.push({
61
+ path: target,
62
+ kind: stat.kind,
63
+ target: stat.kind === "symlink" ? await this.fileSystem.readLink(target) : null,
64
+ bytes: size === null ? stat.size : size.bytes,
65
+ contents: size === null ? null : { files: size.files, directories: size.directories },
66
+ createdMs: stat.createdMs,
67
+ modifiedMs: stat.modifiedMs,
68
+ accessedMs: stat.accessedMs,
69
+ writable: (stat.mode & 0o200) !== 0,
70
+ permissions: this.environment.os === "windows"
71
+ ? null
72
+ : { symbolic: symbolic(stat.mode), octal: (stat.mode & 0o777).toString(8).padStart(3, "0") },
73
+ hidden: isHiddenName(path.basename(target)),
74
+ hash,
75
+ });
76
+ }
77
+ return done({ items });
78
+ }
79
+ }
80
+ //# sourceMappingURL=show-info.use-case.js.map
@@ -0,0 +1,75 @@
1
+ import path from "node:path";
2
+ import { DEPENDENCY_DIRECTORIES } from "../../../config/dependency-directories.js";
3
+ import { done } from "../../../core/domain/command.js";
4
+ import { KiriyaError, NotFoundError } from "../../../core/domain/errors.js";
5
+ import { RawReader } from "../../../core/domain/input-schema.js";
6
+ import { byCodePoint, isHiddenName } from "../../../core/domain/names.js";
7
+ export const treeSpec = {
8
+ id: "files.tree",
9
+ summary: "files.tree.summary",
10
+ examples: ["kiriya files tree", "kiriya files tree src --depth 5", "kiriya files tree --all --json"],
11
+ safety: "read",
12
+ idempotent: true,
13
+ usesNetwork: false,
14
+ runsUserCommands: false,
15
+ input: {
16
+ positionals: [{ name: "path", description: "files.tree.arg.path", required: false, variadic: false, path: true }],
17
+ options: {
18
+ depth: { type: "string", description: "files.tree.option.depth", valueName: "<n>" },
19
+ all: { type: "boolean", description: "files.tree.option.all" },
20
+ },
21
+ parse(raw) {
22
+ const reader = new RawReader(raw);
23
+ return { path: reader.positional(0) ?? ".", depth: reader.positiveInteger("depth", 3), all: reader.flag("all") };
24
+ },
25
+ },
26
+ };
27
+ export class ShowTree {
28
+ fileSystem;
29
+ spec = treeSpec;
30
+ constructor(fileSystem) {
31
+ this.fileSystem = fileSystem;
32
+ }
33
+ async execute(input, context) {
34
+ const root = path.resolve(context.cwd, input.path);
35
+ const stat = await this.fileSystem.stat(root);
36
+ if (stat === null)
37
+ throw new NotFoundError("core.fs.not-found", { path: root });
38
+ if (stat.kind !== "directory")
39
+ throw new NotFoundError("core.path.not-a-folder", { path: root });
40
+ const counts = { directories: 0, files: 0 };
41
+ const nodes = await this.children(root, 1, input, counts);
42
+ return done({ root, depth: input.depth, nodes, ...counts });
43
+ }
44
+ async children(folder, depth, input, counts) {
45
+ const entries = [...(await this.fileSystem.readDirectory(folder))]
46
+ .filter((entry) => input.all || !isHiddenName(entry.name))
47
+ .sort((a, b) => Number(b.kind === "directory") - Number(a.kind === "directory") || byCodePoint(a.name, b.name));
48
+ const nodes = [];
49
+ for (const entry of entries) {
50
+ const entryPath = path.join(folder, entry.name);
51
+ const isFolder = entry.kind === "directory";
52
+ const closed = isFolder && !input.all && DEPENDENCY_DIRECTORIES.has(entry.name);
53
+ if (isFolder)
54
+ counts.directories += 1;
55
+ else
56
+ counts.files += 1;
57
+ let children = [];
58
+ let unreadable = false;
59
+ if (isFolder && !closed && depth < input.depth) {
60
+ try {
61
+ children = await this.children(entryPath, depth + 1, input, counts);
62
+ }
63
+ catch (error) {
64
+ if (!(error instanceof KiriyaError))
65
+ throw error;
66
+ unreadable = true;
67
+ }
68
+ }
69
+ const target = entry.kind === "symlink" ? await this.fileSystem.readLink(entryPath) : null;
70
+ nodes.push({ name: entry.name, kind: entry.kind, target, closed, unreadable, children });
71
+ }
72
+ return nodes;
73
+ }
74
+ }
75
+ //# sourceMappingURL=show-tree.use-case.js.map
@@ -0,0 +1,162 @@
1
+ import path from "node:path";
2
+ import { isInside } from "../../../core/application/paths.js";
3
+ import { requireApproval, requireTypedConfirmation } from "../../../core/application/safety.js";
4
+ import { walk } from "../../../core/application/walk.js";
5
+ import { done, preview } from "../../../core/domain/command.js";
6
+ import { KiriyaError, NotFoundError, OperationFailedError, RefusedError, UsageError, } from "../../../core/domain/errors.js";
7
+ import { RawReader } from "../../../core/domain/input-schema.js";
8
+ import { message } from "../../../core/domain/message.js";
9
+ import { planSync } from "../domain/sync-plan.js";
10
+ const osPath = (root, rel) => path.join(root, ...rel.split("/"));
11
+ export const syncSpec = {
12
+ id: "files.sync",
13
+ summary: "files.sync.summary",
14
+ examples: [
15
+ "kiriya files sync photos E:/backup/photos",
16
+ "kiriya files sync site dist --apply",
17
+ "kiriya files sync docs ../mirror/docs --delete --apply",
18
+ ],
19
+ safety: "destroy",
20
+ idempotent: true,
21
+ usesNetwork: false,
22
+ runsUserCommands: false,
23
+ input: {
24
+ positionals: [
25
+ { name: "source", description: "files.sync.arg.source", required: true, variadic: false, path: true },
26
+ { name: "target", description: "files.sync.arg.target", required: true, variadic: false, path: true },
27
+ ],
28
+ options: {
29
+ delete: { type: "boolean", description: "files.sync.option.delete" },
30
+ apply: { type: "boolean", description: "files.sync.option.apply" },
31
+ yes: { type: "boolean", description: "files.sync.option.yes", short: "y", terminalOnly: true },
32
+ confirm: { type: "string", description: "files.sync.option.confirm", valueName: "<name>", terminalOnly: true },
33
+ },
34
+ parse(raw) {
35
+ const reader = new RawReader(raw);
36
+ return {
37
+ source: reader.positional(0) ?? "",
38
+ target: reader.positional(1) ?? "",
39
+ withDelete: reader.flag("delete"),
40
+ apply: reader.flag("apply"),
41
+ yes: reader.flag("yes"),
42
+ confirm: reader.string("confirm"),
43
+ };
44
+ },
45
+ },
46
+ };
47
+ export class SyncFolders {
48
+ fileSystem;
49
+ environment;
50
+ spec = syncSpec;
51
+ constructor(fileSystem, environment) {
52
+ this.fileSystem = fileSystem;
53
+ this.environment = environment;
54
+ }
55
+ async execute(input, context) {
56
+ const source = path.resolve(context.cwd, input.source);
57
+ const target = path.resolve(context.cwd, input.target);
58
+ await this.checkPair(source, target);
59
+ const plan = planSync(await this.snapshot(source), await this.snapshot(target), input.withDelete);
60
+ const data = {
61
+ source,
62
+ target,
63
+ copy: plan.copy,
64
+ update: plan.update,
65
+ remove: plan.remove,
66
+ bytes: plan.bytes,
67
+ applied: false,
68
+ };
69
+ if (plan.copy.length + plan.update.length + plan.remove.length === 0)
70
+ return done(data);
71
+ if (!input.apply)
72
+ return preview(data, "--apply");
73
+ if (plan.remove.length > 0) {
74
+ const warning = message("files.sync.warn-delete", { count: plan.remove.length, target });
75
+ await requireTypedConfirmation(context, warning, path.basename(target), input.confirm);
76
+ }
77
+ else {
78
+ const question = message("files.sync.ask", { count: plan.copy.length + plan.update.length, target });
79
+ await requireApproval(context, question, input.yes);
80
+ }
81
+ const failures = [];
82
+ for (const rel of [...plan.copy, ...plan.update]) {
83
+ if (context.signal.aborted)
84
+ break;
85
+ const to = osPath(target, rel);
86
+ try {
87
+ await this.fileSystem.createDirectory(path.dirname(to));
88
+ // Copying keeps the source's modification time, so the next sync sees the file as unchanged.
89
+ await this.fileSystem.copy(osPath(source, rel), to, true);
90
+ }
91
+ catch (error) {
92
+ if (!(error instanceof KiriyaError))
93
+ throw error;
94
+ failures.push(error.detail);
95
+ }
96
+ }
97
+ for (const rel of plan.remove) {
98
+ const doomed = osPath(target, rel);
99
+ if (!isInside(doomed, target))
100
+ throw new OperationFailedError("files.sync.outside", { path: doomed });
101
+ try {
102
+ await this.fileSystem.remove(doomed);
103
+ }
104
+ catch (error) {
105
+ if (!(error instanceof KiriyaError))
106
+ throw error;
107
+ if (!(error instanceof NotFoundError))
108
+ failures.push(error.detail);
109
+ }
110
+ }
111
+ for (const rel of plan.removeDirectories) {
112
+ try {
113
+ await this.fileSystem.removeEmptyDirectory(osPath(target, rel));
114
+ }
115
+ catch (error) {
116
+ // A folder that cannot go is left in place; the files that mattered are already handled.
117
+ if (!(error instanceof KiriyaError))
118
+ throw error;
119
+ }
120
+ }
121
+ return done({ ...data, applied: true }, { failures });
122
+ }
123
+ /** Refuses pairs where a sync could clobber the source, or wipe a drive or a home folder by mistake. */
124
+ async checkPair(source, target) {
125
+ if ((await this.fileSystem.stat(source))?.kind !== "directory") {
126
+ throw new UsageError("files.sync.source-not-folder", { path: source });
127
+ }
128
+ if (isInside(target, source) || isInside(source, target))
129
+ throw new UsageError("files.sync.nested");
130
+ if (target === path.parse(target).root) {
131
+ throw new RefusedError("core.guard.refused", {
132
+ path: target,
133
+ reason: message("core.guard.drive-root", { path: target }),
134
+ });
135
+ }
136
+ if (target.toLowerCase() === path.resolve(this.environment.homeDirectory).toLowerCase()) {
137
+ throw new RefusedError("core.guard.refused", {
138
+ path: target,
139
+ reason: message("core.guard.home", { path: target }),
140
+ });
141
+ }
142
+ }
143
+ /** Files and folders below root; symlinks are left out. A missing root is empty. */
144
+ async snapshot(root) {
145
+ const files = new Map();
146
+ const directories = new Set();
147
+ if ((await this.fileSystem.stat(root))?.kind !== "directory")
148
+ return { files, directories };
149
+ for await (const entry of walk(this.fileSystem, root, { all: true })) {
150
+ if (entry.kind === "directory") {
151
+ directories.add(entry.rel);
152
+ }
153
+ else if (entry.kind === "file") {
154
+ const stat = await this.fileSystem.lstat(entry.path);
155
+ if (stat !== null)
156
+ files.set(entry.rel, { size: stat.size, modifiedMs: stat.modifiedMs });
157
+ }
158
+ }
159
+ return { files, directories };
160
+ }
161
+ }
162
+ //# sourceMappingURL=sync-folders.use-case.js.map
@@ -0,0 +1,46 @@
1
+ import path from "node:path";
2
+ import { walk } from "../../../core/application/walk.js";
3
+ import { KiriyaError } from "../../../core/domain/errors.js";
4
+ import { globToRegExp } from "../../../core/domain/glob.js";
5
+ import { decodeText, MAX_TEXT_BYTES } from "../domain/text-encoding.js";
6
+ /** A text file, or null when it is binary, larger than MAX_TEXT_BYTES, or unreadable. */
7
+ export async function readTextFile(fileSystem, content, target) {
8
+ try {
9
+ const stat = await fileSystem.stat(target);
10
+ if (stat?.kind !== "file" || stat.size > MAX_TEXT_BYTES)
11
+ return null;
12
+ return decodeText(await content.read(target));
13
+ }
14
+ catch (error) {
15
+ if (error instanceof KiriyaError)
16
+ return null;
17
+ throw error;
18
+ }
19
+ }
20
+ /**
21
+ * Files at or below the given paths. A file named directly is always kept; files
22
+ * found inside folders must pass the extension list and the name glob, which
23
+ * matches the name, or the path relative to the folder when the glob has a `/`.
24
+ */
25
+ export async function selectFiles(fileSystem, paths, selection) {
26
+ const extensions = new Set(selection.extensions);
27
+ const pattern = selection.name === undefined ? null : globToRegExp(selection.name);
28
+ const patternHasSlash = selection.name?.includes("/") === true;
29
+ const keep = (name, rel) => (extensions.size === 0 || extensions.has(path.extname(name).toLowerCase())) &&
30
+ (pattern === null || pattern.test(patternHasSlash ? rel : name));
31
+ const files = [];
32
+ for (const target of paths) {
33
+ const stat = await fileSystem.lstat(target);
34
+ if (stat?.kind === "file") {
35
+ files.push(target);
36
+ }
37
+ else if (stat?.kind === "directory") {
38
+ for await (const entry of walk(fileSystem, target, { all: selection.all })) {
39
+ if (entry.kind === "file" && keep(entry.name, entry.rel))
40
+ files.push(entry.path);
41
+ }
42
+ }
43
+ }
44
+ return files;
45
+ }
46
+ //# sourceMappingURL=text-files.js.map
@@ -0,0 +1,35 @@
1
+ import path from "node:path";
2
+ import { expandPaths, isInside, outermost } from "../../../core/application/paths.js";
3
+ import { UsageError } from "../../../core/domain/errors.js";
4
+ /**
5
+ * Where copy and move put things. Several sources, a target that is a folder, or a
6
+ * target ending in a separator: into that folder. One source and a new name: at that name.
7
+ */
8
+ export async function planTransfers(fileSystem, sourceArgs, targetArg, cwd, windows) {
9
+ const target = path.resolve(cwd, targetArg);
10
+ const sources = outermost(await expandPaths(fileSystem, sourceArgs, cwd, false));
11
+ const endsWithSeparator = targetArg.endsWith("/") || (windows && targetArg.endsWith("\\"));
12
+ const only = sources.length === 1 ? sources[0] : undefined;
13
+ const renamingCase = only !== undefined && (await fileSystem.sameEntry(only, target));
14
+ const intoFolder = !renamingCase && (sources.length > 1 || endsWithSeparator || (await fileSystem.stat(target))?.kind === "directory");
15
+ const seen = new Set();
16
+ const transfers = [];
17
+ for (const source of sources) {
18
+ const destination = intoFolder ? path.join(target, path.basename(source)) : target;
19
+ if (path.resolve(source) === path.resolve(destination)) {
20
+ throw new UsageError("files.transfer.already-there", { path: source });
21
+ }
22
+ if (!renamingCase && isInside(destination, source)) {
23
+ throw new UsageError("files.transfer.into-itself", { path: source });
24
+ }
25
+ // Compared without case, because two such names are one file on Windows and macOS.
26
+ const key = destination.toLowerCase();
27
+ if (seen.has(key))
28
+ throw new UsageError("files.transfer.same-destination", { path: destination });
29
+ seen.add(key);
30
+ const conflict = (await fileSystem.lstat(destination)) !== null && !(await fileSystem.sameEntry(source, destination));
31
+ transfers.push({ source, destination, conflict });
32
+ }
33
+ return transfers;
34
+ }
35
+ //# sourceMappingURL=transfers.js.map
@@ -0,0 +1,18 @@
1
+ import { isHiddenName } from "../../../core/domain/names.js";
2
+ import { toCase } from "../../../core/domain/text-case.js";
3
+ /** The cases a file name can take; `constant` and `title` suit text better than names. */
4
+ export const CASE_STYLES = ["kebab", "snake", "camel", "pascal", "lower", "upper"];
5
+ /**
6
+ * A name in another case. Only the part before the first dot changes, so suffixes
7
+ * and extensions stay (`UserService.test.ts` -> `user-service.test.ts`) and
8
+ * dotfiles such as `.gitignore` keep their name.
9
+ */
10
+ export function renameByCase(name, style) {
11
+ if (isHiddenName(name))
12
+ return name;
13
+ const dot = name.indexOf(".");
14
+ const stem = dot < 0 ? name : name.slice(0, dot);
15
+ const rest = dot < 0 ? "" : name.slice(dot);
16
+ return `${toCase(stem, style)}${rest}`;
17
+ }
18
+ //# sourceMappingURL=case-style.js.map
@@ -0,0 +1,9 @@
1
+ /** Extension flags as given, such as ".ts,tsx" twice, as a lower-case list with dots: [".ts", ".tsx"]. */
2
+ export function parseExtensions(values) {
3
+ return values
4
+ .flatMap((value) => value.split(","))
5
+ .map((extension) => extension.trim())
6
+ .filter((extension) => extension !== "")
7
+ .map((extension) => `.${extension.replace(/^[.]/, "")}`.toLowerCase());
8
+ }
9
+ //# sourceMappingURL=filters.js.map
@@ -0,0 +1,35 @@
1
+ import { byCodePoint } from "../../../core/domain/names.js";
2
+ /** FAT and network shares store modification times in 2-second steps. */
3
+ export const MODIFIED_TOLERANCE_MS = 2000;
4
+ /** Files are compared by size and modification time. */
5
+ export function planSync(source, target, withDelete) {
6
+ const copy = [];
7
+ const update = [];
8
+ let bytes = 0;
9
+ for (const [rel, entry] of source.files) {
10
+ const existing = target.files.get(rel);
11
+ if (existing === undefined) {
12
+ copy.push(rel);
13
+ bytes += entry.size;
14
+ }
15
+ else if (existing.size !== entry.size ||
16
+ Math.abs(existing.modifiedMs - entry.modifiedMs) > MODIFIED_TOLERANCE_MS) {
17
+ update.push(rel);
18
+ bytes += entry.size;
19
+ }
20
+ }
21
+ const remove = withDelete ? [...target.files.keys()].filter((rel) => !source.files.has(rel)) : [];
22
+ const removeDirectories = withDelete
23
+ ? [...target.directories]
24
+ .filter((rel) => !source.directories.has(rel))
25
+ .sort((a, b) => b.split("/").length - a.split("/").length || byCodePoint(a, b))
26
+ : [];
27
+ return {
28
+ copy: copy.sort(byCodePoint),
29
+ update: update.sort(byCodePoint),
30
+ remove: remove.sort(byCodePoint),
31
+ removeDirectories,
32
+ bytes,
33
+ };
34
+ }
35
+ //# sourceMappingURL=sync-plan.js.map
@@ -0,0 +1,75 @@
1
+ export const TEXT_ENCODINGS = ["utf8", "utf8-bom", "utf16le", "utf16be"];
2
+ /** Text files larger than this are skipped by grep and replace and refused by read. */
3
+ export const MAX_TEXT_BYTES = 50 * 1024 * 1024;
4
+ const BOM = String.fromCharCode(0xfeff);
5
+ const NUL = String.fromCharCode(0);
6
+ function swapPairs(bytes) {
7
+ const swapped = new Uint8Array(bytes.length - (bytes.length % 2));
8
+ for (let index = 0; index + 1 < bytes.length; index += 2) {
9
+ swapped[index] = bytes[index + 1] ?? 0;
10
+ swapped[index + 1] = bytes[index] ?? 0;
11
+ }
12
+ return swapped;
13
+ }
14
+ /** A NUL anywhere, or more than 10% control characters in the first 8000, means the bytes are not text. */
15
+ function looksBinary(text) {
16
+ if (text.includes(NUL))
17
+ return true;
18
+ const sample = text.slice(0, 8000);
19
+ let control = 0;
20
+ for (let index = 0; index < sample.length; index += 1) {
21
+ const code = sample.charCodeAt(index);
22
+ if (code < 32 && code !== 9 && code !== 10 && code !== 12 && code !== 13 && code !== 27)
23
+ control += 1;
24
+ }
25
+ return sample.length > 0 && control / sample.length > 0.1;
26
+ }
27
+ /** Text with the encoding it was stored in, or null when the bytes are not text. */
28
+ export function decodeText(bytes) {
29
+ const checked = (text, encoding) => looksBinary(text) ? null : { text, encoding };
30
+ if (bytes[0] === 0xff && bytes[1] === 0xfe) {
31
+ return checked(new TextDecoder("utf-16le", { ignoreBOM: true }).decode(bytes.subarray(2)), "utf16le");
32
+ }
33
+ if (bytes[0] === 0xfe && bytes[1] === 0xff) {
34
+ return checked(new TextDecoder("utf-16le", { ignoreBOM: true }).decode(swapPairs(bytes.subarray(2))), "utf16be");
35
+ }
36
+ const bom = bytes[0] === 0xef && bytes[1] === 0xbb && bytes[2] === 0xbf;
37
+ try {
38
+ const text = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bom ? bytes.subarray(3) : bytes);
39
+ return checked(text, bom ? "utf8-bom" : "utf8");
40
+ }
41
+ catch {
42
+ return null;
43
+ }
44
+ }
45
+ function utf16(text, littleEndian) {
46
+ const bytes = new Uint8Array(text.length * 2);
47
+ const view = new DataView(bytes.buffer);
48
+ for (let index = 0; index < text.length; index += 1)
49
+ view.setUint16(index * 2, text.charCodeAt(index), littleEndian);
50
+ return bytes;
51
+ }
52
+ /** The bytes decodeText read: the encoding and its byte-order mark are kept. */
53
+ export function encodeText(file) {
54
+ switch (file.encoding) {
55
+ case "utf8":
56
+ return new TextEncoder().encode(file.text);
57
+ case "utf8-bom":
58
+ return new TextEncoder().encode(BOM + file.text);
59
+ case "utf16le":
60
+ return utf16(BOM + file.text, true);
61
+ case "utf16be":
62
+ return utf16(BOM + file.text, false);
63
+ }
64
+ }
65
+ /** Lines without their endings; a final line ending does not start another line. */
66
+ export function splitLines(text) {
67
+ const lines = text.split(/\r?\n/);
68
+ if (lines.length > 1 && lines[lines.length - 1] === "")
69
+ lines.pop();
70
+ return lines;
71
+ }
72
+ export function escapeRegExp(text) {
73
+ return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
74
+ }
75
+ //# sourceMappingURL=text-encoding.js.map
@@ -0,0 +1,28 @@
1
+ import { UsageError } from "../../../core/domain/errors.js";
2
+ const SIZE_UNITS = { "": 1, b: 1, k: 1024, m: 1024 ** 2, g: 1024 ** 3, t: 1024 ** 4 };
3
+ /** "500", "10KB", "1.5 MB", "2g" -> bytes, with 1 KB = 1024 bytes. */
4
+ export function parseSize(text) {
5
+ const match = /^(\d+(?:[.]\d+)?)\s*([bkmgt]?)(?:i?b)?$/i.exec(text.trim());
6
+ const unit = SIZE_UNITS[(match?.[2] ?? "").toLowerCase()];
7
+ if (match === null || unit === undefined)
8
+ throw new UsageError("files.value.size", { value: text });
9
+ return Math.round(Number(match[1]) * unit);
10
+ }
11
+ const AGE_UNITS = {
12
+ m: 60_000,
13
+ h: 3_600_000,
14
+ d: 86_400_000,
15
+ w: 7 * 86_400_000,
16
+ y: 365 * 86_400_000,
17
+ };
18
+ /** "30m", "12h", "7d", "2w", "1y" before `now`, or a date such as 2026-01-31, as epoch milliseconds. */
19
+ export function parseTime(text, now) {
20
+ const age = /^(\d+)\s*([mhdwy])$/i.exec(text.trim());
21
+ if (age !== null)
22
+ return now - Number(age[1]) * (AGE_UNITS[(age[2] ?? "").toLowerCase()] ?? 0);
23
+ const date = Date.parse(text);
24
+ if (Number.isNaN(date))
25
+ throw new UsageError("files.value.time", { value: text });
26
+ return date;
27
+ }
28
+ //# sourceMappingURL=values.js.map
@@ -0,0 +1,70 @@
1
+ import { CleanBuilds } from "./application/clean-builds.use-case.js";
2
+ import { ComparePaths } from "./application/compare-paths.use-case.js";
3
+ import { CopyPaths } from "./application/copy-paths.use-case.js";
4
+ import { CreatePaths } from "./application/create-paths.use-case.js";
5
+ import { DeletePaths } from "./application/delete-paths.use-case.js";
6
+ import { FindDuplicates } from "./application/find-duplicates.use-case.js";
7
+ import { FindFiles } from "./application/find-files.use-case.js";
8
+ import { HashFiles } from "./application/hash-files.use-case.js";
9
+ import { ListEntries } from "./application/list-entries.use-case.js";
10
+ import { MeasureFolders } from "./application/measure-folders.use-case.js";
11
+ import { MovePaths } from "./application/move-paths.use-case.js";
12
+ import { ReadText } from "./application/read-text.use-case.js";
13
+ import { RenamePaths } from "./application/rename-paths.use-case.js";
14
+ import { ReplaceText } from "./application/replace-text.use-case.js";
15
+ import { SearchText } from "./application/search-text.use-case.js";
16
+ import { ShowInfo } from "./application/show-info.use-case.js";
17
+ import { ShowTree } from "./application/show-tree.use-case.js";
18
+ import { SyncFolders } from "./application/sync-folders.use-case.js";
19
+ import { cleanView } from "./presentation/clean.view.js";
20
+ import { compareView } from "./presentation/compare.view.js";
21
+ import { copyView } from "./presentation/copy.view.js";
22
+ import { deleteView } from "./presentation/delete.view.js";
23
+ import { dupesView } from "./presentation/dupes.view.js";
24
+ import { findView } from "./presentation/find.view.js";
25
+ import { grepView } from "./presentation/grep.view.js";
26
+ import { hashView } from "./presentation/hash.view.js";
27
+ import { infoView } from "./presentation/info.view.js";
28
+ import { listView } from "./presentation/list.view.js";
29
+ import { moveView } from "./presentation/move.view.js";
30
+ import { newView } from "./presentation/new.view.js";
31
+ import { readView } from "./presentation/read.view.js";
32
+ import { renameView } from "./presentation/rename.view.js";
33
+ import { replaceView } from "./presentation/replace.view.js";
34
+ import { sizeView } from "./presentation/size.view.js";
35
+ import { syncView } from "./presentation/sync.view.js";
36
+ import { treeView } from "./presentation/tree.view.js";
37
+ export const filesModule = {
38
+ id: "files",
39
+ summary: "files.summary",
40
+ about: "files.about",
41
+ examples: [
42
+ 'kiriya files find --name "*.log" --older 30d',
43
+ "kiriya files grep TODO src --ext .ts",
44
+ "kiriya files delete dist --dry-run",
45
+ "kiriya files clean ~/projects",
46
+ ],
47
+ guide: "https://github.com/SatPaingOo/kiriya/blob/main/docs/modules/files.md",
48
+ register(registrar, ports) {
49
+ const { fileSystem, fileContent, hasher, processRunner, trash, environment, clock, protectedPaths } = ports;
50
+ registrar.add(new CreatePaths(fileSystem, environment), newView);
51
+ registrar.add(new ListEntries(fileSystem), listView);
52
+ registrar.add(new ShowTree(fileSystem), treeView);
53
+ registrar.add(new ShowInfo(fileSystem, hasher, environment), infoView);
54
+ registrar.add(new ReadText(fileSystem, fileContent), readView);
55
+ registrar.add(new FindFiles(fileSystem, clock), findView);
56
+ registrar.add(new SearchText(fileSystem, fileContent), grepView);
57
+ registrar.add(new HashFiles(fileSystem, hasher), hashView);
58
+ registrar.add(new FindDuplicates(fileSystem, hasher), dupesView);
59
+ registrar.add(new ComparePaths(fileSystem, fileContent, hasher), compareView);
60
+ registrar.add(new CopyPaths(fileSystem, protectedPaths, environment), copyView);
61
+ registrar.add(new MovePaths(fileSystem, trash, protectedPaths, environment), moveView);
62
+ registrar.add(new RenamePaths(fileSystem, protectedPaths), renameView);
63
+ registrar.add(new ReplaceText(fileSystem, fileContent), replaceView);
64
+ registrar.add(new DeletePaths(fileSystem, trash, protectedPaths), deleteView);
65
+ registrar.add(new CleanBuilds(fileSystem, processRunner, protectedPaths), cleanView);
66
+ registrar.add(new SyncFolders(fileSystem, environment), syncView);
67
+ registrar.add(new MeasureFolders(fileSystem), sizeView);
68
+ },
69
+ };
70
+ //# sourceMappingURL=files.module.js.map
@@ -0,0 +1,15 @@
1
+ import { message } from "../../../core/domain/message.js";
2
+ export const cleanView = (output, format) => {
3
+ const lines = output.candidates.map((candidate) => ` ${format.bytes(candidate.bytes).padStart(9)} ${format.path(candidate.path)} ${format.dim(format.text(candidate.reason))}`);
4
+ const tracked = output.tracked > 0
5
+ ? format.dim(` · ${format.text(message("files.clean.tracked", { count: output.tracked }))}`)
6
+ : "";
7
+ const total = message("files.clean.total", { count: output.candidates.length, size: format.bytes(output.bytes) });
8
+ lines.push("", `${format.text(total)}${tracked}`);
9
+ if (output.removed > 0) {
10
+ const removed = message("files.clean.done", { count: output.removed, size: format.bytes(output.bytes) });
11
+ lines.push(format.green(format.text(removed)));
12
+ }
13
+ return lines;
14
+ };
15
+ //# sourceMappingURL=clean.view.js.map