Hello! I'm Hong Minhee (洪 民憙), an open source software engineer in my late 30s, living in Seoul, Korea. I'm bisexual and non-binary (they/them), and an enthusiastic advocate of free/open source software and the fediverse.
I work full-time on @fedify, an ActivityPub server framework in TypeScript, funded by @sovtechfund. I'm also the creator of @hollo, a single-user ActivityPub microblog; @botkit, an ActivityPub bot framework; Hackers' Pub, a fediverse platform for software developers; and LogTape, a logging library for JavaScript and TypeScript.
I have a long interest in East Asian languages (CJK) and Unicode. I post mostly in English here, though occasionally in Japanese or in mixed-script Korean (國漢文混用體), a traditional writing style that interleaves Chinese characters with the native Korean alphabet. Wanting to write in that style was actually one of the reasons I joined the fediverse. Feel free to talk to me in English, Korean, Japanese, or even Literary Chinese!
安寧하세요! 저는 서울에 살고 있는 30代 後半의 오픈 소스 소프트웨어 엔지니어 洪民憙입니다. 兩性愛者(bisexual)이자 논바이너리(non-binary)이며, 自由·오픈 소스 소프트웨어(F/OSS)와 聯合宇宙(fediverse)의 熱烈한 支持者이기도 합니다.
STF(@sovtechfund)의 支援을 받아 TypeScript用 ActivityPub 서버 프레임워크 @fedify 開發에 專業으로 任하고 있습니다. 그 外에도 싱글 유저用 ActivityPub 마이크로블로그 @hollo, ActivityPub 봇 프레임워크 @botkit, 소프트웨어 開發者를 위한 聯合宇宙 플랫폼 Hackers' Pub, JavaScript·TypeScript用 로깅 라이브러리 LogTape 等의 製作者이기도 합니다.
東아시아 言語(이른바 CJK)와 Unicode에도 關心이 많습니다. 이 計定에서는 主로 英語로 포스팅하지만, 때때로 日本語나 國漢文混用體 韓國語로도 씁니다. 聯合宇宙에 오게 된 動機 中 하나가 바로 國漢文混用體로 글을 쓰고 싶었기 때문이기도 하고요. 韓國語, 英語, 日本語, 아니면 漢文으로도 말을 걸어주세요!
Released Optique 0.8.0, a type-safe CLI parser for TypeScript.
This version adds conditional() for branching based on a discriminator option, passThrough() for forwarding unknown options to underlying tools, and a new @optique/logtape package for configuring LogTape via CLI.
We're excited to announce Optique 0.8.0! This release introduces powerful new features for building sophisticated CLI applications: the conditional() combinator for discriminated union patterns, the passThrough() parser for wrapper tools, and the new @optique/logtape package for seamless logging configuration.
Optique is a type-safe combinatorial CLI parser for TypeScript, providing a functional approach to building command-line interfaces with composable parsers and full type inference.
New conditional parsing with conditional()
Ever needed to enable different sets of options based on a discriminator value? The new conditional() combinator makes this pattern first-class. It creates discriminated unions where certain options only become valid when a specific discriminator value is selected.
Explicit discriminator option determines which branch is selected
Tuple result [discriminator, branchValue] for clear type narrowing
Optional default branch for when discriminator is not provided
Clear error messages indicating which options are required for each discriminator value
The conditional() parser provides a more structured alternative to or() for discriminated union patterns. Use it when you have an explicit discriminator option that determines which set of options is valid.
Building wrapper CLI tools that need to forward unrecognized options to an underlying tool? The new passThrough() parser enables legitimate wrapper/proxy patterns by capturing unknown options without validation errors.
The new @optique/logtape package provides seamless integration with LogTape, enabling you to configure logging through command-line arguments with various parsing strategies.
import { loggingOptions, createLoggingConfig } from "@optique/logtape";import { object } from "@optique/core/constructs";import { parse } from "@optique/core/parser";import { configure } from "@logtape/logtape";const parser = object({ logging: loggingOptions({ level: "verbosity" }),});const args = ["-vv", "--log-output=-"];const result = parse(parser, args);if (result.success) { const config = await createLoggingConfig(result.value.logging); await configure(config);}
The package offers multiple approaches to control log verbosity:
verbosity() parser: The classic -v/-vv/-vvv pattern where each flag increases verbosity (no flags → "warning", -v → "info", -vv → "debug", -vvv → "trace")
debug() parser: Simple --debug/-d flag that toggles between normal and debug levels
logLevel() value parser: Explicit --log-level=debug option for direct level selection
logOutput() parser: Log output destination with - for console or file path for file output
Fixed an issue where the integer() value parser rejected negative integers when using type: "number". The regex pattern has been updated from /^\d+$/ to /^-?\d+$/ to correctly handle values like -42. Note that type: "bigint" already accepted negative integers, so this change brings consistency between the two types.
Optique 0.8.0 continues our focus on making CLI development more expressive and type-safe. The conditional() combinator brings discriminated union patterns to the forefront, passThrough() enables new wrapper tool use cases, and the LogTape integration makes logging configuration a breeze.
As always, all new features maintain full backward compatibility—your existing parsers continue to work unchanged.
We're grateful to the community for feedback and suggestions. If you have ideas for future improvements or encounter any issues, please let us know through GitHub Issues. For more information about Optique and its features, visit the documentation or check out the full changelog.
We're excited to announce Optique 0.8.0! This release introduces powerful new features for building sophisticated CLI applications: the conditional() combinator for discriminated union patterns, the passThrough() parser for wrapper tools, and the new @optique/logtape package for seamless logging configuration.
Optique is a type-safe combinatorial CLI parser for TypeScript, providing a functional approach to building command-line interfaces with composable parsers and full type inference.
New conditional parsing with conditional()
Ever needed to enable different sets of options based on a discriminator value? The new conditional() combinator makes this pattern first-class. It creates discriminated unions where certain options only become valid when a specific discriminator value is selected.
Explicit discriminator option determines which branch is selected
Tuple result [discriminator, branchValue] for clear type narrowing
Optional default branch for when discriminator is not provided
Clear error messages indicating which options are required for each discriminator value
The conditional() parser provides a more structured alternative to or() for discriminated union patterns. Use it when you have an explicit discriminator option that determines which set of options is valid.
Building wrapper CLI tools that need to forward unrecognized options to an underlying tool? The new passThrough() parser enables legitimate wrapper/proxy patterns by capturing unknown options without validation errors.
The new @optique/logtape package provides seamless integration with LogTape, enabling you to configure logging through command-line arguments with various parsing strategies.
import { loggingOptions, createLoggingConfig } from "@optique/logtape";import { object } from "@optique/core/constructs";import { parse } from "@optique/core/parser";import { configure } from "@logtape/logtape";const parser = object({ logging: loggingOptions({ level: "verbosity" }),});const args = ["-vv", "--log-output=-"];const result = parse(parser, args);if (result.success) { const config = await createLoggingConfig(result.value.logging); await configure(config);}
The package offers multiple approaches to control log verbosity:
verbosity() parser: The classic -v/-vv/-vvv pattern where each flag increases verbosity (no flags → "warning", -v → "info", -vv → "debug", -vvv → "trace")
debug() parser: Simple --debug/-d flag that toggles between normal and debug levels
logLevel() value parser: Explicit --log-level=debug option for direct level selection
logOutput() parser: Log output destination with - for console or file path for file output
Fixed an issue where the integer() value parser rejected negative integers when using type: "number". The regex pattern has been updated from /^\d+$/ to /^-?\d+$/ to correctly handle values like -42. Note that type: "bigint" already accepted negative integers, so this change brings consistency between the two types.
Optique 0.8.0 continues our focus on making CLI development more expressive and type-safe. The conditional() combinator brings discriminated union patterns to the forefront, passThrough() enables new wrapper tool use cases, and the LogTape integration makes logging configuration a breeze.
As always, all new features maintain full backward compatibility—your existing parsers continue to work unchanged.
We're grateful to the community for feedback and suggestions. If you have ideas for future improvements or encounter any issues, please let us know through GitHub Issues. For more information about Optique and its features, visit the documentation or check out the full changelog.
As a multi language speaker I'd love to have some built-in language selector in the web browser for each website. This feature shouldn't be part of the website but rather the browser...
EU Commission's X account has been removed after the EU fined X for transparency failures at the tune $150,000,000. I hope someone at the EU is paying attention to X's behavior as well as our growing community here on the #fediverse .
Lately, I've been wanting to get a new, full aluminum keyboard with an HHKB layout. I'm holding back though, since I already have so many keyboards at home…
I think I have identified a fairly significant flaw in how the #Fediverse currently operates. Hear me out.
The Fediverse currently consists of all sorts of different systems - #Mastodon, #Friendica , #Pixelfed , #PeerTube, #BookWyrm , and so forth. And while they are all connected via the #ActivityPub protocol, they all have different functionalities and different ways of presenting themselves. Which is as it should be, because Diversity Is Our Strength(TM).
However, it is here that the ActivityPub-based interactivity hits its limits - for usually, you can either experience the relevant system as it was intended, or you can interact with it, but not both - _unless_ you have an account on the same system (though not necessarily on the same instance).
Let's say that you are a Mastodon user who looks at another person's BookWyrm page. You scroll through their books, posts, and comments. Then you see some comment you want to comment on yourself, but can you do so?
Not directly. You need to figure out the URL of their comment, and then copy and paste that comment into the search bar of your Mastodon instance. Then it will show up in the same format as a Mastodon post, and you can interact with it - boost it, like it, comment on it.
Sure, it works, but it's a whole lot of tedious effort.
Or you can search for the user account in Mastodon and scroll through all their posts and comments as if they were a Mastodon user - and thus, you will miss out on all the unique user interface features of BookWyrm.
So what is missing?
Well, Mastodon already has an "Open original page" feature when looking at someone's post. What we need is an "Open original page AND AUTHENTICATE" feature. This way, the target instance (whatever software they are using) could acknowledge the viewer as an external user who could nevertheless fully interact with the local user interface, including the ability to boost, like, and make comments.
This is something that should be theoretically possible to implement, right? #FediHelp
ALT text detailsA Mastodon menu that pops up when clicking on another user's post, showing the options:
"Expand this post
Open original page
Copy link to post"
I asked Nano Banana to draw an ad poster for a fictional McDonald's menu item called the “McBook,” and this is the image that was generated.
ALT text detailsA satirical advertisement poster showing a McDonald's meal where the burger has been replaced by an open laptop designed to look like a cheeseburger. The laptop lid is a sesame seed bun with a yellow Golden Arches logo, the keyboard area is a beef patty with lettuce and cheese, and green wires act as garnish. It rests on a tray with french fries and a drink in a McDonald's booth. Text on the poster reads “McBook. Served Hot.” and “I'm lovin' it. Powered by the M-Series Chip.”