@outfitter/cli 0.1.0-rc.2 → 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 (250) hide show
  1. package/README.md +21 -32
  2. package/dist/actions.d.ts +12 -1
  3. package/dist/actions.js +170 -3
  4. package/dist/borders/index.d.ts +3 -0
  5. package/dist/borders/index.js +13 -0
  6. package/dist/box/index.d.ts +4 -0
  7. package/dist/box/index.js +13 -0
  8. package/dist/cli.js +1 -1
  9. package/dist/colors/index.d.ts +3 -0
  10. package/dist/colors/index.js +18 -0
  11. package/dist/command.d.ts +40 -3
  12. package/dist/command.js +45 -3
  13. package/dist/demo/index.d.ts +78 -0
  14. package/dist/demo/index.js +148 -0
  15. package/dist/demo/registry.d.ts +7 -0
  16. package/dist/demo/registry.js +28 -0
  17. package/dist/demo/renderers/borders.d.ts +7 -0
  18. package/dist/demo/renderers/borders.js +17 -0
  19. package/dist/demo/renderers/box.d.ts +7 -0
  20. package/dist/demo/renderers/box.js +18 -0
  21. package/dist/demo/renderers/colors.d.ts +7 -0
  22. package/dist/demo/renderers/colors.js +18 -0
  23. package/dist/demo/renderers/indicators.d.ts +7 -0
  24. package/dist/demo/renderers/indicators.js +17 -0
  25. package/dist/demo/renderers/list.d.ts +7 -0
  26. package/dist/demo/renderers/list.js +19 -0
  27. package/dist/demo/renderers/markdown.d.ts +7 -0
  28. package/dist/demo/renderers/markdown.js +18 -0
  29. package/dist/demo/renderers/progress.d.ts +7 -0
  30. package/dist/demo/renderers/progress.js +17 -0
  31. package/dist/demo/renderers/spinner.d.ts +7 -0
  32. package/dist/demo/renderers/spinner.js +19 -0
  33. package/dist/demo/renderers/table.d.ts +7 -0
  34. package/dist/demo/renderers/table.js +19 -0
  35. package/dist/demo/renderers/text.d.ts +7 -0
  36. package/dist/demo/renderers/text.js +16 -0
  37. package/dist/demo/renderers/tree.d.ts +7 -0
  38. package/dist/demo/renderers/tree.js +18 -0
  39. package/dist/demo/section.d.ts +5 -0
  40. package/dist/demo/section.js +23 -0
  41. package/dist/demo/templates.d.ts +4 -0
  42. package/dist/demo/templates.js +10 -0
  43. package/dist/demo/types.d.ts +3 -0
  44. package/dist/demo/types.js +8 -0
  45. package/dist/index.d.ts +5 -8
  46. package/dist/index.js +9 -43
  47. package/dist/input.d.ts +163 -2
  48. package/dist/input.js +425 -11
  49. package/dist/list/index.d.ts +3 -0
  50. package/dist/list/index.js +9 -0
  51. package/dist/output.js +1 -1
  52. package/dist/pagination.d.ts +62 -2
  53. package/dist/pagination.js +84 -6
  54. package/dist/preset/full.d.ts +14 -0
  55. package/dist/preset/full.js +41 -0
  56. package/dist/preset/standard.d.ts +11 -0
  57. package/dist/preset/standard.js +30 -0
  58. package/dist/prompt/confirm.d.ts +4 -0
  59. package/dist/prompt/confirm.js +9 -0
  60. package/dist/prompt/group.d.ts +4 -0
  61. package/dist/prompt/group.js +9 -0
  62. package/dist/prompt/index.d.ts +7 -0
  63. package/dist/prompt/index.js +32 -0
  64. package/dist/prompt/select.d.ts +4 -0
  65. package/dist/prompt/select.js +11 -0
  66. package/dist/prompt/text.d.ts +4 -0
  67. package/dist/prompt/text.js +11 -0
  68. package/dist/prompt/types.d.ts +3 -0
  69. package/dist/prompt/types.js +8 -0
  70. package/dist/prompt/validators.d.ts +2 -0
  71. package/dist/prompt/validators.js +8 -0
  72. package/dist/render/borders.d.ts +2 -0
  73. package/dist/render/borders.js +15 -0
  74. package/dist/render/box.d.ts +3 -0
  75. package/dist/render/box.js +23 -0
  76. package/dist/render/colors.d.ts +1 -1
  77. package/dist/render/colors.js +6 -3
  78. package/dist/render/date.js +1 -1
  79. package/dist/render/format-relative.js +1 -1
  80. package/dist/render/format.js +1 -1
  81. package/dist/render/heading.d.ts +3 -0
  82. package/dist/render/heading.js +14 -0
  83. package/dist/render/index.d.ts +26 -7
  84. package/dist/render/index.js +160 -26
  85. package/dist/render/indicators.d.ts +2 -0
  86. package/dist/render/indicators.js +14 -0
  87. package/dist/render/json.js +1 -1
  88. package/dist/render/layout.d.ts +5 -0
  89. package/dist/render/layout.js +25 -0
  90. package/dist/render/list.d.ts +2 -2
  91. package/dist/render/list.js +2 -2
  92. package/dist/render/markdown.js +4 -4
  93. package/dist/render/progress.js +1 -1
  94. package/dist/render/separator.d.ts +3 -0
  95. package/dist/render/separator.js +14 -0
  96. package/dist/render/shapes.js +10 -9
  97. package/dist/render/spinner.d.ts +2 -0
  98. package/dist/render/spinner.js +12 -0
  99. package/dist/render/stack.d.ts +3 -0
  100. package/dist/render/stack.js +38 -0
  101. package/dist/render/table.d.ts +2 -1
  102. package/dist/render/table.js +6 -5
  103. package/dist/render/text.d.ts +1 -1
  104. package/dist/render/text.js +7 -4
  105. package/dist/render/tree.d.ts +2 -2
  106. package/dist/render/tree.js +5 -3
  107. package/dist/render/types.d.ts +2 -0
  108. package/dist/render/types.js +1 -0
  109. package/dist/shared/@outfitter/cli-0ggcy7fa.js +20 -0
  110. package/dist/shared/@outfitter/cli-0psys2vm.js +7 -0
  111. package/dist/shared/@outfitter/cli-1bghjef6.js +352 -0
  112. package/dist/shared/@outfitter/cli-1kwbnt86.d.ts +45 -0
  113. package/dist/shared/@outfitter/cli-2g8bx1aq.d.ts +50 -0
  114. package/dist/shared/@outfitter/cli-34fqr7bp.js +37 -0
  115. package/dist/shared/@outfitter/cli-3b7ed3rm.d.ts +97 -0
  116. package/dist/shared/@outfitter/cli-3dxmmy4c.d.ts +20 -0
  117. package/dist/shared/@outfitter/cli-3f12z5kf.d.ts +83 -0
  118. package/dist/shared/@outfitter/cli-3t2zaenc.d.ts +59 -0
  119. package/dist/shared/@outfitter/{cli-dds0qqvm.d.ts → cli-4cb5g831.d.ts} +2 -0
  120. package/dist/shared/@outfitter/cli-4w2a1rfy.d.ts +23 -0
  121. package/dist/shared/@outfitter/cli-4x6pqnez.js +20 -0
  122. package/dist/shared/@outfitter/cli-671sxkhj.js +146 -0
  123. package/dist/shared/@outfitter/cli-6bztk73z.d.ts +51 -0
  124. package/dist/shared/@outfitter/cli-6fxffp8k.js +1 -0
  125. package/dist/shared/@outfitter/cli-6j9qynm8.js +118 -0
  126. package/dist/shared/@outfitter/cli-6m988kh0.d.ts +61 -0
  127. package/dist/shared/@outfitter/cli-74ba31gz.js +134 -0
  128. package/dist/shared/@outfitter/cli-7gnrb8cr.js +214 -0
  129. package/dist/shared/@outfitter/cli-7nm6edvh.d.ts +17 -0
  130. package/dist/shared/@outfitter/cli-85fg2vr5.js +123 -0
  131. package/dist/shared/@outfitter/cli-8a8xrzhy.js +20 -0
  132. package/dist/shared/@outfitter/cli-8bwaw3pz.js +7 -0
  133. package/dist/shared/@outfitter/cli-8rx4g3s5.d.ts +41 -0
  134. package/dist/shared/@outfitter/cli-8xsmsbbd.d.ts +223 -0
  135. package/dist/shared/@outfitter/cli-96b2p4td.d.ts +56 -0
  136. package/dist/shared/@outfitter/cli-9khk3cbq.d.ts +190 -0
  137. package/dist/shared/@outfitter/cli-9mtjjykw.js +67 -0
  138. package/dist/shared/@outfitter/{cli-ag0w4pk0.js → cli-9nbyj2bt.js} +60 -21
  139. package/dist/shared/@outfitter/{cli-azzk8a1d.js → cli-afhjqmg3.js} +7 -3
  140. package/dist/shared/@outfitter/cli-an9j0h80.js +117 -0
  141. package/dist/shared/@outfitter/cli-ay411nbr.js +122 -0
  142. package/dist/shared/@outfitter/cli-b0tzqgnf.d.ts +132 -0
  143. package/dist/shared/@outfitter/cli-b5c2k0d7.js +39 -0
  144. package/dist/shared/@outfitter/cli-b5epywry.js +1 -0
  145. package/dist/shared/@outfitter/cli-bcmcaz1b.js +23 -0
  146. package/dist/shared/@outfitter/cli-bf3vma4q.js +61 -0
  147. package/dist/shared/@outfitter/cli-cf1xexgn.d.ts +53 -0
  148. package/dist/shared/@outfitter/cli-cs45xd6q.js +59 -0
  149. package/dist/shared/@outfitter/cli-d7jpshq5.d.ts +128 -0
  150. package/dist/shared/@outfitter/{cli-jbj78ac5.js → cli-d9ad0rqj.js} +6 -1
  151. package/dist/shared/@outfitter/cli-daw296mv.js +61 -0
  152. package/dist/shared/@outfitter/cli-e5ms1y0x.d.ts +91 -0
  153. package/dist/shared/@outfitter/cli-e73v3qqy.d.ts +93 -0
  154. package/dist/shared/@outfitter/cli-en6zn6sj.js +1 -0
  155. package/dist/shared/@outfitter/cli-ep2cvtk8.js +48 -0
  156. package/dist/shared/@outfitter/cli-f75h8e94.js +7 -0
  157. package/dist/shared/@outfitter/cli-fakncnjp.d.ts +106 -0
  158. package/dist/shared/@outfitter/cli-feb5j90n.js +94 -0
  159. package/dist/shared/@outfitter/cli-h20jc0bs.d.ts +66 -0
  160. package/dist/shared/@outfitter/cli-hnpbqmc8.d.ts +328 -0
  161. package/dist/shared/@outfitter/cli-j4n8gaf3.js +95 -0
  162. package/dist/shared/@outfitter/cli-jejfypgf.js +85 -0
  163. package/dist/shared/@outfitter/{cli-wqc652mx.js → cli-jhcdwvpn.js} +8 -8
  164. package/dist/shared/@outfitter/{cli-v9mjsvjh.js → cli-jjemfdta.js} +13 -46
  165. package/dist/shared/@outfitter/cli-kc84wmch.js +267 -0
  166. package/dist/shared/@outfitter/cli-ktqme80d.js +7 -0
  167. package/dist/shared/@outfitter/cli-mq0jp15z.js +1 -0
  168. package/dist/shared/@outfitter/cli-mymyavvj.d.ts +26 -0
  169. package/dist/shared/@outfitter/cli-n17gt1dz.js +19 -0
  170. package/dist/shared/@outfitter/cli-n9dbh0hp.js +51 -0
  171. package/dist/shared/@outfitter/cli-nvvc92c8.js +128 -0
  172. package/dist/shared/@outfitter/cli-p1m5dhrs.js +169 -0
  173. package/dist/shared/@outfitter/cli-p38sfxyk.js +25 -0
  174. package/dist/shared/@outfitter/cli-p3dqm1vd.js +22 -0
  175. package/dist/shared/@outfitter/cli-p9j1phge.js +20 -0
  176. package/dist/shared/@outfitter/cli-pkxmzavm.js +62 -0
  177. package/dist/shared/@outfitter/cli-q8r6jarq.d.ts +24 -0
  178. package/dist/shared/@outfitter/{cli-2y3kxew8.d.ts → cli-qj83y5wj.d.ts} +22 -9
  179. package/dist/shared/@outfitter/cli-qjfc3j11.d.ts +112 -0
  180. package/dist/shared/@outfitter/cli-qp4cbhqr.js +70 -0
  181. package/dist/shared/@outfitter/cli-s0kkx9m1.d.ts +164 -0
  182. package/dist/shared/@outfitter/cli-snxj55n6.js +43 -0
  183. package/dist/shared/@outfitter/cli-swwxvjvm.d.ts +24 -0
  184. package/dist/shared/@outfitter/cli-sx67mmfx.d.ts +98 -0
  185. package/dist/shared/@outfitter/cli-tarpsa8a.js +30 -0
  186. package/dist/shared/@outfitter/cli-thvzhjd1.js +126 -0
  187. package/dist/shared/@outfitter/cli-tqewy503.d.ts +36 -0
  188. package/dist/shared/@outfitter/cli-tvw1xrdj.js +20 -0
  189. package/dist/shared/@outfitter/cli-v1tzwxkt.js +32 -0
  190. package/dist/shared/@outfitter/cli-vd60dj65.js +1 -0
  191. package/dist/shared/@outfitter/cli-vp88gxev.js +279 -0
  192. package/dist/shared/@outfitter/cli-vstbkzky.d.ts +74 -0
  193. package/dist/shared/@outfitter/cli-vtg0sqk2.d.ts +54 -0
  194. package/dist/shared/@outfitter/cli-w5y3xepp.js +20 -0
  195. package/dist/shared/@outfitter/cli-x4cavvc0.js +1 -0
  196. package/dist/shared/@outfitter/cli-xep6v2c0.js +52 -0
  197. package/dist/shared/@outfitter/cli-xg5y5fhk.js +86 -0
  198. package/dist/shared/@outfitter/{cli-n51t773m.d.ts → cli-xsaheemc.d.ts} +44 -4
  199. package/dist/shared/@outfitter/cli-xvqtqjxk.js +82 -0
  200. package/dist/shared/@outfitter/cli-y25tt8nc.d.ts +48 -0
  201. package/dist/streaming/ansi.d.ts +2 -0
  202. package/dist/streaming/ansi.js +8 -0
  203. package/dist/streaming/index.d.ts +4 -0
  204. package/dist/streaming/index.js +17 -0
  205. package/dist/streaming/spinner.d.ts +3 -0
  206. package/dist/streaming/spinner.js +10 -0
  207. package/dist/streaming/writer.d.ts +2 -0
  208. package/dist/streaming/writer.js +9 -0
  209. package/dist/table/index.d.ts +4 -0
  210. package/dist/table/index.js +13 -0
  211. package/dist/terminal/detection.js +5 -2
  212. package/dist/terminal/index.js +6 -2
  213. package/dist/theme/context.d.ts +9 -0
  214. package/dist/theme/context.js +14 -0
  215. package/dist/theme/create.d.ts +8 -0
  216. package/dist/theme/create.js +12 -0
  217. package/dist/theme/index.d.ts +17 -0
  218. package/dist/theme/index.js +42 -0
  219. package/dist/theme/presets/bold.d.ts +8 -0
  220. package/dist/theme/presets/bold.js +12 -0
  221. package/dist/theme/presets/default.d.ts +8 -0
  222. package/dist/theme/presets/default.js +11 -0
  223. package/dist/theme/presets/index.d.ts +12 -0
  224. package/dist/theme/presets/index.js +24 -0
  225. package/dist/theme/presets/minimal.d.ts +8 -0
  226. package/dist/theme/presets/minimal.js +12 -0
  227. package/dist/theme/presets/rounded.d.ts +8 -0
  228. package/dist/theme/presets/rounded.js +12 -0
  229. package/dist/theme/resolve.d.ts +8 -0
  230. package/dist/theme/resolve.js +11 -0
  231. package/dist/theme/types.d.ts +7 -0
  232. package/dist/theme/types.js +1 -0
  233. package/dist/tree/index.d.ts +3 -0
  234. package/dist/tree/index.js +11 -0
  235. package/dist/types.js +1 -1
  236. package/package.json +168 -54
  237. package/dist/shared/@outfitter/cli-2vs2gxa8.js +0 -429
  238. package/dist/shared/@outfitter/cli-2yq94zst.d.ts +0 -39
  239. package/dist/shared/@outfitter/cli-6xc869x1.js +0 -26
  240. package/dist/shared/@outfitter/cli-7km1e58p.js +0 -85
  241. package/dist/shared/@outfitter/cli-8r0bnyyx.js +0 -43
  242. package/dist/shared/@outfitter/cli-afecwfrn.d.ts +0 -13
  243. package/dist/shared/@outfitter/cli-bt423m6y.js +0 -4
  244. package/dist/shared/@outfitter/cli-d4fegbad.d.ts +0 -66
  245. package/dist/shared/@outfitter/cli-e0ecw3x1.js +0 -64
  246. package/dist/shared/@outfitter/cli-fheaaa6b.js +0 -25
  247. package/dist/shared/@outfitter/cli-j361wp3g.d.ts +0 -41
  248. package/dist/shared/@outfitter/cli-p0m2fc51.js +0 -172
  249. package/dist/shared/@outfitter/cli-tyajr8qa.d.ts +0 -63
  250. package/dist/shared/@outfitter/cli-zs6jy1am.d.ts +0 -164
package/dist/input.d.ts CHANGED
@@ -1,3 +1,164 @@
1
- import { collectIds, confirmDestructive, expandFileArg, normalizeId, parseFilter, parseGlob, parseKeyValue, parseRange, parseSortSpec } from "./shared/@outfitter/cli-zs6jy1am";
2
- import "./shared/@outfitter/cli-ttt7r0j7";
1
+ import { CollectIdsOptions, ConfirmDestructiveOptions, ExpandFileOptions, FilterExpression, KeyValuePair, NormalizeIdOptions, ParseGlobOptions, Range, SortCriteria } from "./shared/@outfitter/cli-ttt7r0j7";
2
+ import { CancelledError, ValidationError } from "@outfitter/contracts";
3
+ import { Result } from "better-result";
4
+ /**
5
+ * Collect IDs from various input formats.
6
+ *
7
+ * Handles space-separated, comma-separated, repeated flags, @file, and stdin.
8
+ *
9
+ * @param input - Raw input from CLI arguments
10
+ * @param options - Collection options
11
+ * @returns Array of collected IDs
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * // All these produce the same result:
16
+ * // wm show id1 id2 id3
17
+ * // wm show id1,id2,id3
18
+ * // wm show --ids id1 --ids id2
19
+ * // wm show @ids.txt
20
+ * const ids = await collectIds(args.ids, {
21
+ * allowFile: true,
22
+ * allowStdin: true,
23
+ * });
24
+ * ```
25
+ */
26
+ declare function collectIds(input: string | readonly string[], options?: CollectIdsOptions): Promise<string[]>;
27
+ /**
28
+ * Expand @file references to file contents.
29
+ *
30
+ * If the input starts with @, reads the file and returns its contents.
31
+ * Otherwise, returns the input unchanged.
32
+ *
33
+ * @param input - Raw input that may be a @file reference
34
+ * @param options - Expansion options
35
+ * @returns File contents or original input
36
+ *
37
+ * @example
38
+ * ```typescript
39
+ * // wm create @template.md
40
+ * const content = await expandFileArg(args.content);
41
+ * ```
42
+ */
43
+ declare function expandFileArg(input: string, options?: ExpandFileOptions): Promise<string>;
44
+ /**
45
+ * Parse and expand glob patterns.
46
+ *
47
+ * Uses Bun.Glob with workspace constraints.
48
+ *
49
+ * @param pattern - Glob pattern to expand
50
+ * @param options - Glob options
51
+ * @returns Array of matched file paths
52
+ *
53
+ * @example
54
+ * ```typescript
55
+ * // wm index "src/**\/*.ts"
56
+ * const files = await parseGlob(args.pattern, {
57
+ * cwd: workspaceRoot,
58
+ * ignore: ["node_modules/**"],
59
+ * });
60
+ * ```
61
+ */
62
+ declare function parseGlob(pattern: string, options?: ParseGlobOptions): Promise<string[]>;
63
+ /**
64
+ * Parse key=value pairs from CLI input.
65
+ *
66
+ * @param input - Raw input containing key=value pairs
67
+ * @returns Array of parsed key-value pairs
68
+ *
69
+ * @example
70
+ * ```typescript
71
+ * // --set key=value --set key2=value2
72
+ * // --set key=value,key2=value2
73
+ * const pairs = parseKeyValue(args.set);
74
+ * // => [{ key: "key", value: "value" }, { key: "key2", value: "value2" }]
75
+ * ```
76
+ */
77
+ declare function parseKeyValue(input: string | readonly string[]): Result<KeyValuePair[], InstanceType<typeof ValidationError>>;
78
+ /**
79
+ * Parse range inputs (numeric or date).
80
+ *
81
+ * @param input - Range string (e.g., "1-10" or "2024-01-01..2024-12-31")
82
+ * @param type - Type of range to parse
83
+ * @returns Parsed range
84
+ *
85
+ * @example
86
+ * ```typescript
87
+ * parseRange("1-10", "number");
88
+ * // => Result<{ type: "number", min: 1, max: 10 }, ValidationError>
89
+ *
90
+ * parseRange("2024-01-01..2024-12-31", "date");
91
+ * // => Result<{ type: "date", start: Date, end: Date }, ValidationError>
92
+ * ```
93
+ */
94
+ declare function parseRange(input: string, type: "number" | "date"): Result<Range, InstanceType<typeof ValidationError>>;
95
+ /**
96
+ * Parse filter expressions from CLI input.
97
+ *
98
+ * @param input - Filter string (e.g., "status:active,priority:high")
99
+ * @returns Array of parsed filter expressions
100
+ *
101
+ * @example
102
+ * ```typescript
103
+ * parseFilter("status:active,priority:high");
104
+ * // => Result<[
105
+ * // { field: "status", value: "active" },
106
+ * // { field: "priority", value: "high" }
107
+ * // ], ValidationError>
108
+ * ```
109
+ */
110
+ declare function parseFilter(input: string): Result<FilterExpression[], InstanceType<typeof ValidationError>>;
111
+ /**
112
+ * Parse sort specification from CLI input.
113
+ *
114
+ * @param input - Sort string (e.g., "modified:desc,title:asc")
115
+ * @returns Array of parsed sort criteria
116
+ *
117
+ * @example
118
+ * ```typescript
119
+ * parseSortSpec("modified:desc,title:asc");
120
+ * // => Result<[
121
+ * // { field: "modified", direction: "desc" },
122
+ * // { field: "title", direction: "asc" }
123
+ * // ], ValidationError>
124
+ * ```
125
+ */
126
+ declare function parseSortSpec(input: string): Result<SortCriteria[], InstanceType<typeof ValidationError>>;
127
+ /**
128
+ * Normalize an identifier (trim, lowercase where appropriate).
129
+ *
130
+ * @param input - Raw identifier input
131
+ * @param options - Normalization options
132
+ * @returns Normalized identifier
133
+ *
134
+ * @example
135
+ * ```typescript
136
+ * normalizeId(" MY-ID ", { lowercase: true, trim: true });
137
+ * // => Result<"my-id", ValidationError>
138
+ * ```
139
+ */
140
+ declare function normalizeId(input: string, options?: NormalizeIdOptions): Result<string, InstanceType<typeof ValidationError>>;
141
+ /**
142
+ * Prompt for confirmation before destructive operations.
143
+ *
144
+ * Respects --yes flag for non-interactive mode.
145
+ *
146
+ * @param options - Confirmation options
147
+ * @returns Whether the user confirmed
148
+ *
149
+ * @example
150
+ * ```typescript
151
+ * const confirmed = await confirmDestructive({
152
+ * message: "Delete 5 notes?",
153
+ * bypassFlag: flags.yes,
154
+ * itemCount: 5,
155
+ * });
156
+ *
157
+ * if (confirmed.isErr()) {
158
+ * // User cancelled
159
+ * process.exit(0);
160
+ * }
161
+ * ```
162
+ */
163
+ declare function confirmDestructive(options: ConfirmDestructiveOptions): Promise<Result<boolean, InstanceType<typeof CancelledError>>>;
3
164
  export { parseSortSpec, parseRange, parseKeyValue, parseGlob, parseFilter, normalizeId, expandFileArg, confirmDestructive, collectIds };
package/dist/input.js CHANGED
@@ -1,16 +1,430 @@
1
1
  // @bun
2
2
  import {
3
- collectIds,
4
- confirmDestructive,
5
- expandFileArg,
6
- normalizeId,
7
- parseFilter,
8
- parseGlob,
9
- parseKeyValue,
10
- parseRange,
11
- parseSortSpec
12
- } from "./shared/@outfitter/cli-2vs2gxa8.js";
13
- import"./shared/@outfitter/cli-bt423m6y.js";
3
+ __require
4
+ } from "./shared/@outfitter/cli-v1tzwxkt.js";
5
+
6
+ // packages/cli/src/input.ts
7
+ import path from "path";
8
+ import { CancelledError, ValidationError } from "@outfitter/contracts";
9
+ import { Err, Ok } from "better-result";
10
+ function isSecurePath(filePath, allowAbsolute = false) {
11
+ if (filePath.includes("\x00")) {
12
+ return false;
13
+ }
14
+ if (filePath.includes("..")) {
15
+ return false;
16
+ }
17
+ const normalized = path.normalize(filePath);
18
+ if (!allowAbsolute && path.isAbsolute(normalized)) {
19
+ return false;
20
+ }
21
+ return true;
22
+ }
23
+ function isSecureGlobPattern(pattern) {
24
+ if (pattern.startsWith("..")) {
25
+ return false;
26
+ }
27
+ if (pattern.includes("/../")) {
28
+ return false;
29
+ }
30
+ return true;
31
+ }
32
+ function isWithinWorkspace(resolvedPath, workspaceRoot) {
33
+ const normalizedPath = path.normalize(resolvedPath);
34
+ const normalizedRoot = path.normalize(workspaceRoot);
35
+ return normalizedPath === normalizedRoot || normalizedPath.startsWith(normalizedRoot + path.sep);
36
+ }
37
+ async function readStdin() {
38
+ const chunks = [];
39
+ for await (const chunk of process.stdin) {
40
+ if (typeof chunk === "string") {
41
+ chunks.push(chunk);
42
+ } else if (Buffer.isBuffer(chunk)) {
43
+ chunks.push(chunk.toString("utf-8"));
44
+ } else if (chunk instanceof Uint8Array) {
45
+ chunks.push(Buffer.from(chunk).toString("utf-8"));
46
+ }
47
+ }
48
+ return chunks.join("");
49
+ }
50
+ function splitIds(input) {
51
+ return input.split(",").flatMap((part) => part.trim().split(/\s+/)).map((id) => id.trim()).filter(Boolean);
52
+ }
53
+ async function isDirectory(path2) {
54
+ try {
55
+ const result = await Bun.$`test -d ${path2}`.quiet();
56
+ return result.exitCode === 0;
57
+ } catch {
58
+ return false;
59
+ }
60
+ }
61
+ async function isFile(path2) {
62
+ try {
63
+ const result = await Bun.$`test -f ${path2}`.quiet();
64
+ return result.exitCode === 0;
65
+ } catch {
66
+ return false;
67
+ }
68
+ }
69
+ async function collectIds(input, options) {
70
+ const { allowFile = true, allowStdin = true } = options ?? {};
71
+ const ids = [];
72
+ const inputs = Array.isArray(input) ? input : [input];
73
+ for (const item of inputs) {
74
+ if (!item)
75
+ continue;
76
+ if (item.startsWith("@")) {
77
+ const filePath = item.slice(1);
78
+ if (filePath === "-") {
79
+ if (!allowStdin) {
80
+ throw new Error("Reading from stdin is not allowed");
81
+ }
82
+ const stdinContent = await readStdin();
83
+ const stdinIds = stdinContent.split(`
84
+ `).map((line) => line.trim()).filter(Boolean);
85
+ ids.push(...stdinIds);
86
+ } else {
87
+ if (!allowFile) {
88
+ throw new Error("File references are not allowed");
89
+ }
90
+ if (!isSecurePath(filePath, true)) {
91
+ throw new Error(`Security error: path traversal not allowed: ${filePath}`);
92
+ }
93
+ const file = Bun.file(filePath);
94
+ const exists = await file.exists();
95
+ if (!exists) {
96
+ throw new Error(`File not found: ${filePath}`);
97
+ }
98
+ const content = await file.text();
99
+ const fileIds = content.split(`
100
+ `).map((line) => line.trim()).filter(Boolean);
101
+ ids.push(...fileIds);
102
+ }
103
+ } else {
104
+ ids.push(...splitIds(item));
105
+ }
106
+ }
107
+ return [...new Set(ids)];
108
+ }
109
+ async function expandFileArg(input, options) {
110
+ const {
111
+ encoding: _encoding = "utf-8",
112
+ maxSize,
113
+ trim = false
114
+ } = options ?? {};
115
+ if (!input.startsWith("@")) {
116
+ return input;
117
+ }
118
+ const filePath = input.slice(1);
119
+ if (filePath === "-") {
120
+ let content2 = await readStdin();
121
+ if (trim) {
122
+ content2 = content2.trim();
123
+ }
124
+ return content2;
125
+ }
126
+ if (!isSecurePath(filePath, true)) {
127
+ throw new Error(`Security error: path traversal not allowed: ${filePath}`);
128
+ }
129
+ const file = Bun.file(filePath);
130
+ const exists = await file.exists();
131
+ if (!exists) {
132
+ throw new Error(`File not found: ${filePath}`);
133
+ }
134
+ if (maxSize !== undefined) {
135
+ const size = file.size;
136
+ if (size > maxSize) {
137
+ throw new Error(`File exceeds maximum size of ${maxSize} bytes`);
138
+ }
139
+ }
140
+ let content = await file.text();
141
+ if (trim) {
142
+ content = content.trim();
143
+ }
144
+ return content;
145
+ }
146
+ async function parseGlob(pattern, options) {
147
+ const {
148
+ cwd = process.cwd(),
149
+ ignore = [],
150
+ onlyFiles = false,
151
+ onlyDirectories = false,
152
+ followSymlinks = false
153
+ } = options ?? {};
154
+ if (!isSecureGlobPattern(pattern)) {
155
+ throw new Error(`Security error: glob pattern may escape workspace: ${pattern}`);
156
+ }
157
+ const resolvedCwd = path.resolve(cwd);
158
+ const glob = new Bun.Glob(pattern);
159
+ const matches = [];
160
+ const scanOptions = {
161
+ cwd,
162
+ followSymlinks,
163
+ onlyFiles: onlyFiles === true
164
+ };
165
+ for await (const match of glob.scan(scanOptions)) {
166
+ const fullPath = path.resolve(cwd, match);
167
+ if (!isWithinWorkspace(fullPath, resolvedCwd)) {
168
+ continue;
169
+ }
170
+ let shouldIgnore = false;
171
+ for (const ignorePattern of ignore) {
172
+ const ignoreGlob = new Bun.Glob(ignorePattern);
173
+ if (ignoreGlob.match(match)) {
174
+ shouldIgnore = true;
175
+ break;
176
+ }
177
+ }
178
+ if (shouldIgnore)
179
+ continue;
180
+ if (onlyDirectories) {
181
+ const isDir = await isDirectory(fullPath);
182
+ if (!isDir)
183
+ continue;
184
+ }
185
+ if (onlyFiles) {
186
+ const isF = await isFile(fullPath);
187
+ if (!isF)
188
+ continue;
189
+ }
190
+ matches.push(match);
191
+ }
192
+ return matches;
193
+ }
194
+ function parseKeyValue(input) {
195
+ const pairs = [];
196
+ const inputs = Array.isArray(input) ? input : [input];
197
+ for (const item of inputs) {
198
+ if (!item)
199
+ continue;
200
+ const parts = item.split(",");
201
+ for (const part of parts) {
202
+ const trimmed = part.trim();
203
+ if (!trimmed)
204
+ continue;
205
+ const eqIndex = trimmed.indexOf("=");
206
+ if (eqIndex === -1) {
207
+ return new Err(new ValidationError({
208
+ message: `Missing '=' in key-value pair: ${trimmed}`
209
+ }));
210
+ }
211
+ const key = trimmed.slice(0, eqIndex).trim();
212
+ const value = trimmed.slice(eqIndex + 1);
213
+ if (!key) {
214
+ return new Err(new ValidationError({ message: "Empty key in key-value pair" }));
215
+ }
216
+ pairs.push({ key, value });
217
+ }
218
+ }
219
+ return new Ok(pairs);
220
+ }
221
+ function parseRange(input, type) {
222
+ const trimmed = input.trim();
223
+ if (type === "date") {
224
+ const parts = trimmed.split("..");
225
+ if (parts.length === 1) {
226
+ const dateStr = parts[0];
227
+ if (dateStr === undefined) {
228
+ return new Err(new ValidationError({ message: "Empty date input" }));
229
+ }
230
+ const date = new Date(dateStr.trim());
231
+ if (Number.isNaN(date.getTime())) {
232
+ return new Err(new ValidationError({ message: `Invalid date format: ${dateStr}` }));
233
+ }
234
+ return new Ok({ type: "date", start: date, end: date });
235
+ }
236
+ if (parts.length === 2) {
237
+ const startStr = parts[0];
238
+ const endStr = parts[1];
239
+ if (startStr === undefined || endStr === undefined) {
240
+ return new Err(new ValidationError({ message: "Invalid date range format" }));
241
+ }
242
+ const start = new Date(startStr.trim());
243
+ const end = new Date(endStr.trim());
244
+ if (Number.isNaN(start.getTime())) {
245
+ return new Err(new ValidationError({ message: `Invalid date format: ${startStr}` }));
246
+ }
247
+ if (Number.isNaN(end.getTime())) {
248
+ return new Err(new ValidationError({ message: `Invalid date format: ${endStr}` }));
249
+ }
250
+ if (start.getTime() > end.getTime()) {
251
+ return new Err(new ValidationError({
252
+ message: "Start date must be before or equal to end date"
253
+ }));
254
+ }
255
+ return new Ok({ type: "date", start, end });
256
+ }
257
+ return new Err(new ValidationError({ message: `Invalid date range format: ${input}` }));
258
+ }
259
+ const singleNum = Number(trimmed);
260
+ if (!(Number.isNaN(singleNum) || trimmed.includes("-", trimmed.startsWith("-") ? 1 : 0))) {
261
+ return new Ok({ type: "number", min: singleNum, max: singleNum });
262
+ }
263
+ let separatorIndex = -1;
264
+ for (let i = 1;i < trimmed.length; i++) {
265
+ const char = trimmed[i];
266
+ const prevChar = trimmed[i - 1];
267
+ if (char === "-" && prevChar !== undefined && /[\d\s]/.test(prevChar)) {
268
+ separatorIndex = i;
269
+ break;
270
+ }
271
+ }
272
+ if (separatorIndex === -1) {
273
+ return new Err(new ValidationError({ message: `Invalid numeric range format: ${input}` }));
274
+ }
275
+ const minStr = trimmed.slice(0, separatorIndex).trim();
276
+ const maxStr = trimmed.slice(separatorIndex + 1).trim();
277
+ const min = Number(minStr);
278
+ const max = Number(maxStr);
279
+ if (Number.isNaN(min)) {
280
+ return new Err(new ValidationError({ message: `Invalid number: ${minStr}` }));
281
+ }
282
+ if (Number.isNaN(max)) {
283
+ return new Err(new ValidationError({ message: `Invalid number: ${maxStr}` }));
284
+ }
285
+ if (min > max) {
286
+ return new Err(new ValidationError({ message: "Min must be less than or equal to max" }));
287
+ }
288
+ return new Ok({ type: "number", min, max });
289
+ }
290
+ function parseFilter(input) {
291
+ const trimmed = input.trim();
292
+ if (!trimmed) {
293
+ return new Ok([]);
294
+ }
295
+ const filters = [];
296
+ const parts = trimmed.split(",");
297
+ for (const part of parts) {
298
+ let partTrimmed = part.trim();
299
+ if (!partTrimmed)
300
+ continue;
301
+ let isNegated = false;
302
+ if (partTrimmed.startsWith("!")) {
303
+ isNegated = true;
304
+ partTrimmed = partTrimmed.slice(1).trim();
305
+ }
306
+ const colonIndex = partTrimmed.indexOf(":");
307
+ if (colonIndex === -1) {
308
+ return new Err(new ValidationError({
309
+ message: `Missing ':' in filter expression: ${part.trim()}`
310
+ }));
311
+ }
312
+ const field = partTrimmed.slice(0, colonIndex).trim();
313
+ let value = partTrimmed.slice(colonIndex + 1).trim();
314
+ let operator;
315
+ if (isNegated) {
316
+ operator = "ne";
317
+ } else if (value.startsWith(">=")) {
318
+ operator = "gte";
319
+ value = value.slice(2).trim();
320
+ } else if (value.startsWith("<=")) {
321
+ operator = "lte";
322
+ value = value.slice(2).trim();
323
+ } else if (value.startsWith(">")) {
324
+ operator = "gt";
325
+ value = value.slice(1).trim();
326
+ } else if (value.startsWith("<")) {
327
+ operator = "lt";
328
+ value = value.slice(1).trim();
329
+ } else if (value.startsWith("~")) {
330
+ operator = "contains";
331
+ value = value.slice(1).trim();
332
+ }
333
+ const filter = { field, value };
334
+ if (operator) {
335
+ filter.operator = operator;
336
+ }
337
+ filters.push(filter);
338
+ }
339
+ return new Ok(filters);
340
+ }
341
+ function parseSortSpec(input) {
342
+ const trimmed = input.trim();
343
+ if (!trimmed) {
344
+ return new Ok([]);
345
+ }
346
+ const criteria = [];
347
+ const parts = trimmed.split(",");
348
+ for (const part of parts) {
349
+ const partTrimmed = part.trim();
350
+ if (!partTrimmed)
351
+ continue;
352
+ const colonIndex = partTrimmed.indexOf(":");
353
+ if (colonIndex === -1) {
354
+ criteria.push({ field: partTrimmed, direction: "asc" });
355
+ } else {
356
+ const field = partTrimmed.slice(0, colonIndex).trim();
357
+ const direction = partTrimmed.slice(colonIndex + 1).trim().toLowerCase();
358
+ if (direction !== "asc" && direction !== "desc") {
359
+ return new Err(new ValidationError({
360
+ message: `Invalid sort direction: ${direction}. Must be 'asc' or 'desc'.`
361
+ }));
362
+ }
363
+ criteria.push({ field, direction });
364
+ }
365
+ }
366
+ return new Ok(criteria);
367
+ }
368
+ function normalizeId(input, options) {
369
+ const {
370
+ trim = false,
371
+ lowercase = false,
372
+ minLength,
373
+ maxLength,
374
+ pattern
375
+ } = options ?? {};
376
+ let normalized = input;
377
+ if (trim) {
378
+ normalized = normalized.trim();
379
+ }
380
+ if (lowercase) {
381
+ normalized = normalized.toLowerCase();
382
+ }
383
+ if (minLength !== undefined && normalized.length < minLength) {
384
+ return new Err(new ValidationError({
385
+ message: `ID must be at least ${minLength} characters long`,
386
+ field: "id"
387
+ }));
388
+ }
389
+ if (maxLength !== undefined && normalized.length > maxLength) {
390
+ return new Err(new ValidationError({
391
+ message: `ID must be at most ${maxLength} characters long`,
392
+ field: "id"
393
+ }));
394
+ }
395
+ if (pattern && !pattern.test(normalized)) {
396
+ return new Err(new ValidationError({
397
+ message: `ID does not match required pattern: ${pattern.source}`,
398
+ field: "id"
399
+ }));
400
+ }
401
+ return new Ok(normalized);
402
+ }
403
+ async function confirmDestructive(options) {
404
+ const { message, bypassFlag = false, itemCount } = options;
405
+ if (bypassFlag) {
406
+ return new Ok(true);
407
+ }
408
+ const isTTY = process.stdout.isTTY;
409
+ const isDumbTerminal = process.env["TERM"] === "dumb";
410
+ if (!isTTY || isDumbTerminal) {
411
+ return new Err(new CancelledError({
412
+ message: "Cannot prompt for confirmation in non-interactive mode. Use --yes to bypass."
413
+ }));
414
+ }
415
+ let promptMessage = message;
416
+ if (itemCount !== undefined) {
417
+ promptMessage = `${message} (${itemCount} items)`;
418
+ }
419
+ const { confirm, isCancel } = await import("@clack/prompts");
420
+ const response = await confirm({ message: promptMessage });
421
+ if (isCancel(response) || response === false) {
422
+ return new Err(new CancelledError({
423
+ message: "Operation cancelled by user."
424
+ }));
425
+ }
426
+ return new Ok(true);
427
+ }
14
428
  export {
15
429
  parseSortSpec,
16
430
  parseRange,
@@ -0,0 +1,3 @@
1
+ import "../shared/@outfitter/cli-yef5b9ds";
2
+ import { ListItem, ListOptions, ListStyle, NestedListItem, renderList } from "../shared/@outfitter/cli-b0tzqgnf";
3
+ export { renderList, NestedListItem, ListStyle, ListOptions, ListItem };
@@ -0,0 +1,9 @@
1
+ // @bun
2
+ import"../shared/@outfitter/cli-en6zn6sj.js";
3
+ import {
4
+ renderList
5
+ } from "../shared/@outfitter/cli-xg5y5fhk.js";
6
+ import"../shared/@outfitter/cli-v1tzwxkt.js";
7
+ export {
8
+ renderList
9
+ };
package/dist/output.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  exitWithError,
4
4
  output
5
5
  } from "./shared/@outfitter/cli-zact3325.js";
6
- import"./shared/@outfitter/cli-bt423m6y.js";
6
+ import"./shared/@outfitter/cli-v1tzwxkt.js";
7
7
  export {
8
8
  output,
9
9
  exitWithError
@@ -1,3 +1,63 @@
1
- import { clearCursor, loadCursor, saveCursor } from "./shared/@outfitter/cli-tyajr8qa";
2
- import "./shared/@outfitter/cli-ttt7r0j7";
1
+ import { CursorOptions, PaginationState } from "./shared/@outfitter/cli-ttt7r0j7";
2
+ /**
3
+ * Load persisted pagination state for a command.
4
+ *
5
+ * @param options - Cursor options specifying command and context
6
+ * @returns The pagination state if it exists, undefined otherwise
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * const state = loadCursor({
11
+ * command: "list",
12
+ * toolName: "waymark",
13
+ * });
14
+ *
15
+ * if (state) {
16
+ * // Continue from last position
17
+ * const results = await listNotes({ cursor: state.cursor });
18
+ * }
19
+ * ```
20
+ */
21
+ declare function loadCursor(options: CursorOptions): PaginationState | undefined;
22
+ /**
23
+ * Save pagination state for a command.
24
+ *
25
+ * The cursor is persisted to XDG state directory, scoped by
26
+ * tool name, command, and optional context.
27
+ *
28
+ * @param cursor - The cursor string to persist
29
+ * @param options - Cursor options specifying command and context
30
+ *
31
+ * @example
32
+ * ```typescript
33
+ * const results = await listNotes({ limit: 20 });
34
+ *
35
+ * if (results.hasMore) {
36
+ * saveCursor(results.cursor, {
37
+ * command: "list",
38
+ * toolName: "waymark",
39
+ * });
40
+ * }
41
+ * ```
42
+ */
43
+ declare function saveCursor(cursor: string, options: CursorOptions): void;
44
+ /**
45
+ * Clear persisted pagination state for a command.
46
+ *
47
+ * Called when --reset flag is passed or when pagination completes.
48
+ *
49
+ * @param options - Cursor options specifying command and context
50
+ *
51
+ * @example
52
+ * ```typescript
53
+ * // User passed --reset flag
54
+ * if (flags.reset) {
55
+ * clearCursor({
56
+ * command: "list",
57
+ * toolName: "waymark",
58
+ * });
59
+ * }
60
+ * ```
61
+ */
62
+ declare function clearCursor(options: CursorOptions): void;
3
63
  export { saveCursor, loadCursor, clearCursor };