My own corner of monopam
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

ocaml-claude-skills: wire vlog and tty SKILL.md examples into mdx

Add (mdx ...) stanzas covering each SKILL.md and rewrite the OCaml
blocks against the actual API: API renames (Table.create -> Table.v,
Panel.create -> Panel.v, Panel.create_lines -> Panel.lines, Tree.make
-> Tree.v, Node -> Tree.Node), defer side-effecting top-levels via
let main () so mdx_gen does not exit mid-test, and bind bare
expressions. Shell snippets keep their sh tag with a skip directive
since the placeholder myapp binary is not on PATH.

+98 -92
+58 -47
ocaml-claude-skills/plugins/monopam/skills/tty/SKILL.md
··· 29 29 ```ocaml 30 30 open Tty 31 31 32 - let () = 32 + let print_success () = 33 33 let style = Style.(bold + fg Color.green) in 34 34 Fmt.pr "%a@." (Style.styled style Fmt.string) "Success!" 35 35 ``` ··· 39 39 ```ocaml 40 40 open Tty 41 41 42 - let () = 42 + let print_table () = 43 43 let table = 44 44 Table.( 45 45 of_rows ~border:Border.rounded ··· 53 53 ``` 54 54 55 55 Output: 56 - ``` 56 + 57 + ```text 57 58 ╭───────┬─────╮ 58 59 │ Name │ Age │ 59 60 ├───────┼─────┤ ··· 68 69 open Tty 69 70 70 71 (* Predefined ANSI colors *) 71 - let red = Color.red 72 - let green = Color.green 73 - let bright_blue = Color.bright_blue 72 + let _red = Color.red 73 + let _green = Color.green 74 + let _bright_blue = Color.bright_blue 74 75 75 76 (* RGB colors *) 76 - let orange = Color.rgb 255 165 0 77 + let _orange = Color.rgb 255 165 0 77 78 78 79 (* Hex colors *) 79 - let purple = Color.hex "#8B5CF6" 80 + let _purple = Color.hex "#8B5CF6" 80 81 81 82 (* 256-color palette *) 82 - let color_42 = Color.palette 42 83 + let _color_42 = Color.palette 42 83 84 ``` 84 85 85 86 Available predefined colors: ··· 95 96 96 97 let style = Style.(bold + fg Color.red + underline) 97 98 98 - (* Apply to Fmt formatter *) 99 - Fmt.pr "%a@." (Style.styled style Fmt.string) "Important!" 100 - 101 - (* Apply to Format.formatter *) 102 - Style.pp_styled style "Important!" 99 + let print_important () = 100 + (* Apply to Fmt formatter *) 101 + Fmt.pr "%a@." (Style.styled style Fmt.string) "Important!"; 102 + (* Apply to Format.formatter *) 103 + Style.pp_styled style "Important!" 103 104 ``` 104 105 105 106 Available style attributes: ··· 121 122 text "File not found: " ++ 122 123 styled Style.(fg Color.cyan) "/path/to/file") 123 124 124 - (* Render with ANSI codes *) 125 - Fmt.pr "%a@." Span.render span 126 - 127 - (* Render without ANSI codes *) 128 - Fmt.pr "%a@." Span.render_plain span 125 + let print_span () = 126 + (* Render with ANSI codes *) 127 + Fmt.pr "%a@." Span.render span; 128 + (* Render without ANSI codes *) 129 + Fmt.pr "%a@." Span.render_plain span 129 130 130 131 (* Get display width (excludes ANSI escapes) *) 131 - let width = Span.width span 132 + let _width = Span.width span 132 133 ``` 133 134 134 135 Span constructors: ··· 159 160 ] 160 161 161 162 (* Or build incrementally *) 162 - let table = 163 - Table.create ~border:Border.single columns 163 + let table' = 164 + Table.v ~border:Border.single columns 164 165 |> Table.add_row [ Span.text "Widget"; Span.text "$9.99"; Span.text "In Stock" ] 165 166 |> Table.add_row_strings [ "Gadget"; "$19.99"; "Low" ] 166 167 167 - (* Render *) 168 - Table.pp Format.std_formatter table 168 + let print_tables () = 169 + Table.pp Format.std_formatter table; 170 + Table.pp Format.std_formatter table' 169 171 ``` 170 172 171 173 Column options: ··· 179 181 ```ocaml 180 182 open Tty 181 183 182 - Border.none (* no border *) 183 - Border.ascii (* +--+ | +--+ *) 184 - Border.single (* ┌──┐ │ └──┘ *) 185 - Border.double (* ╔══╗ ║ ╚══╝ *) 186 - Border.rounded (* ╭──╮ │ ╰──╯ *) 187 - Border.heavy (* ┏━━┓ ┃ ┗━━┛ *) 188 - Border.hidden (* spaces, maintains layout *) 184 + let _borders = [ 185 + Border.none; (* no border *) 186 + Border.ascii; (* +--+ | +--+ *) 187 + Border.single; (* ┌──┐ │ └──┘ *) 188 + Border.double; (* ╔══╗ ║ ╚══╝ *) 189 + Border.rounded; (* ╭──╮ │ ╰──╯ *) 190 + Border.heavy; (* ┏━━┓ ┃ ┗━━┛ *) 191 + Border.hidden; (* spaces, maintains layout *) 192 + ] 189 193 190 194 (* Style a border *) 191 - let styled_border = Border.with_style Style.(fg Color.blue) Border.rounded 195 + let _styled_border = Border.with_style Style.(fg Color.blue) Border.rounded 192 196 ``` 193 197 194 198 ## Trees ··· 199 203 (* From a tree type *) 200 204 let tree = 201 205 Tree.of_tree 202 - (Node 206 + (Tree.Node 203 207 ( Span.text "src", 204 208 [ 205 - Node (Span.text "lib", [ Node (Span.text "tty.ml", []) ]); 206 - Node (Span.text "test", [ Node (Span.text "test.ml", []) ]); 209 + Tree.Node (Span.text "lib", [ Tree.Node (Span.text "tty.ml", []) ]); 210 + Tree.Node (Span.text "test", [ Tree.Node (Span.text "test.ml", []) ]); 207 211 ] )) 208 212 209 - Tree.pp Format.std_formatter tree 213 + let print_tree () = Tree.pp Format.std_formatter tree 210 214 ``` 211 215 212 216 Output: 213 - ``` 217 + 218 + ```text 214 219 src 215 220 ├── lib 216 221 │ └── tty.ml ··· 223 228 ```ocaml 224 229 type dir = { name : string; children : dir list } 225 230 226 - let tree = 227 - Tree.make 231 + let root_dir = { 232 + name = "src"; 233 + children = [ { name = "tty.ml"; children = [] } ]; 234 + } 235 + 236 + let custom_tree = 237 + Tree.v 228 238 (fun render dir -> 229 - Node (Span.text dir.name, List.map render dir.children)) 239 + Tree.Node (Span.text dir.name, List.map render dir.children)) 230 240 root_dir 231 241 ``` 232 242 ··· 240 250 open Tty 241 251 242 252 let panel = 243 - Panel.create 253 + Panel.v 244 254 ~border:Border.rounded 245 255 ~title:(Span.styled Style.bold "Status") 246 256 ~subtitle:(Span.text "Updated: 2025-01-29") ··· 248 258 ~width:40 249 259 (Span.text "All systems operational") 250 260 251 - Panel.pp Format.std_formatter panel 261 + let print_panel () = Panel.pp Format.std_formatter panel 252 262 ``` 253 263 254 264 Output: 255 - ``` 265 + 266 + ```text 256 267 ╭─ Status ─────────────────────────────╮ 257 268 │ │ 258 269 │ All systems operational │ ··· 263 274 Multi-line content: 264 275 265 276 ```ocaml 266 - let panel = 267 - Panel.create_lines 277 + let _multi_panel = 278 + Panel.lines 268 279 ~title:(Span.text "Metrics") 269 280 [ 270 281 Span.text "CPU: 45%"; ··· 294 305 ) services in 295 306 let table = Table.of_rows ~border:Border.rounded columns rows in 296 307 297 - let panel = Panel.create 308 + let panel = Panel.v 298 309 ~title:(Span.styled Style.bold "Service Status") 299 310 (Span.text (Table.to_string table)) 300 311 in ··· 308 319 ("cache", `Down, "0h"); 309 320 ]) 310 321 311 - let () = exit (Cmd.eval cmd) 322 + let main () = exit (Cmd.eval cmd) 312 323 ``` 313 324 314 325 ## Tips
+3
ocaml-claude-skills/plugins/monopam/skills/tty/dune
··· 1 + (mdx 2 + (files SKILL.md) 3 + (libraries nox-tty fmt cmdliner))
+34 -45
ocaml-claude-skills/plugins/monopam/skills/vlog/SKILL.md
··· 38 38 let info = Cmd.info "myapp" ~doc:"My application" in 39 39 Cmd.v info Term.(const run $ Vlog.setup "myapp") 40 40 41 - let () = exit (Cmd.eval cmd) 41 + let main () = exit (Cmd.eval cmd) 42 42 ``` 43 43 44 44 ## Command Line Usage 45 45 46 - ```bash 46 + <!-- $MDX skip --> 47 + ```sh 47 48 myapp -q # quiet: errors only 48 49 myapp # default: warnings 49 50 myapp -v # verbose: info level ··· 75 76 76 77 The `--log` option and `$APP_LOG` env var accept RUST_LOG syntax: 77 78 78 - ``` 79 + <!-- $MDX skip --> 80 + ```sh 79 81 level # global level 80 82 level,src:level # global + per-source 81 83 src:level,src:level # per-source only (keeps default) ··· 98 100 99 101 Add custom tags with `--log-tag`: 100 102 101 - ```bash 103 + <!-- $MDX skip --> 104 + ```sh 102 105 myapp --json --log-tag=env=production --log-tag=version=1.2.3 103 106 ``` 104 107 ··· 108 111 109 112 ```ocaml 110 113 (* Use default json-logs reporter *) 111 - Vlog.setup "myapp" 114 + let _ = Vlog.setup "myapp" 112 115 113 116 (* Custom JSON reporter *) 114 - let my_reporter ~app ~base () = 117 + let my_reporter ~app:_ ~base:_ () = 115 118 (* custom implementation *) 116 119 Logs_fmt.reporter () 117 120 118 - Vlog.setup ~json_reporter:(Some my_reporter) "myapp" 121 + let _ = Vlog.setup ~json_reporter:(Some my_reporter) "myapp" 119 122 120 123 (* Disable --json flag entirely *) 121 - Vlog.setup ~json_reporter:None "myapp" 124 + let _ = Vlog.setup ~json_reporter:None "myapp" 122 125 ``` 123 126 124 127 ## Test Setup ··· 127 130 128 131 ```ocaml 129 132 let () = Vlog.setup_test ~level:Logs.Debug () 130 - let () = Alcotest.run "mylib" Test_foo.suite 133 + (* then run your test suite, e.g. Alcotest.run "mylib" suite *) 131 134 ``` 132 135 133 136 Override via `TEST_LOG` environment variable: 134 137 135 - ```bash 138 + <!-- $MDX skip --> 139 + ```sh 136 140 TEST_LOG=warning dune test # reduce noise 137 141 TEST_LOG=warning,conpool:debug dune test # debug specific source 138 142 ``` 139 143 140 144 ## Individual Terms 141 145 142 - For advanced use cases, access individual cmdliner terms: 146 + For advanced use cases, access individual cmdliner terms (signatures 147 + exposed by `Vlog`): 143 148 144 - ```ocaml 145 - val quiet : bool Cmdliner.Term.t 146 - (* Term for -q/--quiet flag *) 147 - 148 - val verbosity : bool list Cmdliner.Term.t 149 - (* Term for -v/--verbose flags. Length indicates verbosity level *) 150 - 151 - val log_term : string -> string option Cmdliner.Term.t 152 - (* Term for --log with environment variable $APP_NAME_LOG *) 153 - 154 - val json : bool Cmdliner.Term.t 155 - (* Term for --json flag *) 156 - 157 - val log_tags : (string * string) list Cmdliner.Term.t 158 - (* Term for --log-tag KEY=VALUE flags *) 159 - 160 - val trace_file : string option Cmdliner.Term.t 161 - (* Term for --trace FILE flag *) 162 - ``` 149 + | Value | Type | Purpose | 150 + |-------|------|---------| 151 + | `Vlog.quiet` | `bool Cmdliner.Term.t` | `-q`/`--quiet` flag | 152 + | `Vlog.verbosity` | `bool list Cmdliner.Term.t` | `-v`/`--verbose` flags; length is the level | 153 + | `Vlog.log_term name` | `string option Cmdliner.Term.t` | `--log` with `$NAME_LOG` env | 154 + | `Vlog.json` | `bool Cmdliner.Term.t` | `--json` flag | 155 + | `Vlog.log_tags` | `(string * string) list Cmdliner.Term.t` | `--log-tag KEY=VALUE` | 156 + | `Vlog.trace_file` | `string option Cmdliner.Term.t` | `--trace FILE` | 163 157 164 158 Example combining individual terms: 165 159 166 160 ```ocaml 167 161 let my_setup = 168 162 let open Cmdliner.Term in 169 - const (fun quiet verbosity log_spec json tags trace_file -> 163 + const (fun _quiet _verbosity _log_spec _json _tags _trace_file -> 170 164 (* custom setup logic *) 171 165 ()) 172 166 $ Vlog.quiet ··· 181 175 182 176 ```ocaml 183 177 (* Parse a log spec string *) 184 - let global, overrides = Vlog.parse_log_spec "info,http:debug" 178 + let _global, _overrides = Vlog.parse_log_spec "info,http:debug" 185 179 (* global = Some Info, overrides = [("http", Some Debug)] *) 186 180 187 181 (* Apply per-source overrides *) 188 - Vlog.apply_source_overrides [("http", Some Logs.Debug)] 182 + let () = Vlog.apply_source_overrides [("http", Some Logs.Debug)] 189 183 190 184 (* Enable/disable *.tracing sources *) 191 - Vlog.configure_tracing_sources ~enable:false 185 + let () = Vlog.configure_tracing_sources ~enable:false 192 186 ``` 193 187 194 188 ## Verbosity Helpers 195 189 196 - ```ocaml 197 - (* Compute log level from flags *) 198 - val level_of_verbosity : quiet:bool -> verbosity:bool list -> Logs.level option 199 - (* quiet=true: Error, verbosity=[]: Warning, [_]: Info, [_;_]+: Debug *) 200 - 201 - (* Check if tracing should be enabled (-vvv) *) 202 - val enable_tracing : verbosity:bool list -> bool 203 - (* Returns true if verbosity >= 3 *) 204 - ``` 190 + | Value | Type | Notes | 191 + |-------|------|-------| 192 + | `Vlog.level_of_verbosity` | `quiet:bool -> verbosity:bool list -> Logs.level option` | quiet=true: Error; verbosity=[]: Warning; `[_]`: Info; `[_;_]+`: Debug | 193 + | `Vlog.enable_tracing` | `verbosity:bool list -> bool` | true when verbosity >= 3 (`-vvv`) | 205 194 206 195 ## Complete CLI Example 207 196 ··· 211 200 let log_src = Logs.Src.create "myapp" 212 201 module Log = (val Logs.src_log log_src : Logs.LOG) 213 202 214 - let run input output = 203 + let run _setup input output = 215 204 Log.info (fun m -> m "Processing %s -> %s" input output); 216 205 (* process files *) 217 206 Log.info (fun m -> m "Done") ··· 226 215 let info = Cmd.info "myapp" ~doc:"Process files" in 227 216 Cmd.v info Term.(const run $ Vlog.setup "myapp" $ input_arg $ output_arg) 228 217 229 - let () = exit (Cmd.eval cmd) 218 + let main () = exit (Cmd.eval cmd) 230 219 ``` 231 220 232 221 ## Comparison with Other Ecosystems
+3
ocaml-claude-skills/plugins/monopam/skills/vlog/dune
··· 1 + (mdx 2 + (files SKILL.md) 3 + (libraries vlog cmdliner logs logs.fmt))