洪 民憙 (Hong Minhee) 
@hongminhee@hollo.social
CLIパーサーの新しい記事を書きました。--reporterの値によって--output-fileが必須になったり禁止になったり…そういう関係、型で表現できたら楽じゃないですか?


@hongminhee@hollo.social · 986 following · 1354 followers
An intersectionalist, feminist, and socialist living in Seoul (UTC+09:00). @tokolovesme's spouse. Who's behind @fedify, @hollo, and @botkit. Write some free software in #TypeScript, #Haskell, #Rust, & #Python. They/them.
서울에 사는 交叉女性主義者이자 社會主義者. 金剛兔(@tokolovesme)의 配偶者. @fedify, @hollo, @botkit 메인테이너. #TypeScript, #Haskell, #Rust, #Python 等으로 自由 소프트웨어 만듦.
| Website | GitHub | Blog | Hackers' Pub |
|---|---|---|---|

@hongminhee@hollo.social
CLIパーサーの新しい記事を書きました。--reporterの値によって--output-fileが必須になったり禁止になったり…そういう関係、型で表現できたら楽じゃないですか?
@jdv_jazz@mastodon.nl
Cannonball Adderley & The Bossa Rio Sextet - Batida Diferentes (Feat. Sergio Mendes)
#JazzDeVille #Jazz #NowPlaying #CannonballAdderleyTheBossaRioSextet
@omasanori@mstdn.maud.io · Reply to Masanori Ogino 𓀁's post
先に書いておくと、RDFのシリアライズ形式は必ずしもXMLでなければならないわけではなく、Turtleなど、JSONくらい《軽い》文法もあります。
@omasanori@mstdn.maud.io
そんなことをしたら流行ってないのは承知の上で、JSON-LDではなくRDFを使ったActivityPubの世界をみたいかも。

@hongminhee@hollo.social
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.
@hongminhee@hackers.pub
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.
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.
import { conditional, object } from "@optique/core/constructs";
import { option } from "@optique/core/primitives";
import { choice, string } from "@optique/core/valueparser";
const parser = conditional(
option("--reporter", choice(["console", "junit", "html"])),
{
console: object({}),
junit: object({ outputFile: option("--output-file", string()) }),
html: object({ outputFile: option("--output-file", string()) }),
}
);
// Result type: ["console", {}] | ["junit", { outputFile: string }] | ...
Key features:
[discriminator, branchValue] for clear type narrowingThe 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.
See the conditional() documentation for more details and examples.
passThrough() 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.
import { object } from "@optique/core/constructs";
import { option, passThrough } from "@optique/core/primitives";
const parser = object({
debug: option("--debug"),
extra: passThrough(),
});
// mycli --debug --foo=bar --baz=qux
// → { debug: true, extra: ["--foo=bar", "--baz=qux"] }
Key features:
"equalsOnly" (default, safest), "nextToken" (captures --opt val pairs), and "greedy" (captures all remaining tokens)-- options terminator in "equalsOnly" and "nextToken" modesobject(), subcommands, and other combinatorsThis feature is designed for building Docker-like CLIs, build tool wrappers, or any tool that proxies commands to another process.
See the passThrough() documentation for usage patterns and best practices.
The new @optique/logtape package provides seamless integration with LogTape, enabling you to configure logging through command-line arguments with various parsing strategies.
# Deno
deno add --jsr @optique/logtape @logtape/logtape
# npm
npm add @optique/logtape @logtape/logtape
Quick start with the loggingOptions() preset:
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 levelslogLevel() value parser: Explicit --log-level=debug option for direct level selectionlogOutput() parser: Log output destination with - for console or file path for file outputSee the LogTape integration documentation for complete examples and configuration options.
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.
# Deno
deno add jsr:@optique/core
# npm
npm add @optique/core
# pnpm
pnpm add @optique/core
# Yarn
yarn add @optique/core
# Bun
bun add @optique/core
For the LogTape integration:
# Deno
deno add --jsr @optique/logtape @logtape/logtape
# npm
npm add @optique/logtape @logtape/logtape
# pnpm
pnpm add @optique/logtape @logtape/logtape
# Yarn
yarn add @optique/logtape @logtape/logtape
# Bun
bun add @optique/logtape @logtape/logtape
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.
@hongminhee@hackers.pub
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.
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.
import { conditional, object } from "@optique/core/constructs";
import { option } from "@optique/core/primitives";
import { choice, string } from "@optique/core/valueparser";
const parser = conditional(
option("--reporter", choice(["console", "junit", "html"])),
{
console: object({}),
junit: object({ outputFile: option("--output-file", string()) }),
html: object({ outputFile: option("--output-file", string()) }),
}
);
// Result type: ["console", {}] | ["junit", { outputFile: string }] | ...
Key features:
[discriminator, branchValue] for clear type narrowingThe 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.
See the conditional() documentation for more details and examples.
passThrough() 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.
import { object } from "@optique/core/constructs";
import { option, passThrough } from "@optique/core/primitives";
const parser = object({
debug: option("--debug"),
extra: passThrough(),
});
// mycli --debug --foo=bar --baz=qux
// → { debug: true, extra: ["--foo=bar", "--baz=qux"] }
Key features:
"equalsOnly" (default, safest), "nextToken" (captures --opt val pairs), and "greedy" (captures all remaining tokens)-- options terminator in "equalsOnly" and "nextToken" modesobject(), subcommands, and other combinatorsThis feature is designed for building Docker-like CLIs, build tool wrappers, or any tool that proxies commands to another process.
See the passThrough() documentation for usage patterns and best practices.
The new @optique/logtape package provides seamless integration with LogTape, enabling you to configure logging through command-line arguments with various parsing strategies.
# Deno
deno add --jsr @optique/logtape @logtape/logtape
# npm
npm add @optique/logtape @logtape/logtape
Quick start with the loggingOptions() preset:
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 levelslogLevel() value parser: Explicit --log-level=debug option for direct level selectionlogOutput() parser: Log output destination with - for console or file path for file outputSee the LogTape integration documentation for complete examples and configuration options.
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.
# Deno
deno add jsr:@optique/core
# npm
npm add @optique/core
# pnpm
pnpm add @optique/core
# Yarn
yarn add @optique/core
# Bun
bun add @optique/core
For the LogTape integration:
# Deno
deno add --jsr @optique/logtape @logtape/logtape
# npm
npm add @optique/logtape @logtape/logtape
# pnpm
pnpm add @optique/logtape @logtape/logtape
# Yarn
yarn add @optique/logtape @logtape/logtape
# Bun
bun add @optique/logtape @logtape/logtape
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.

@hongminhee@hollo.social · Reply to Carlana :v_trans:'s post
@carlana Haha, maybe, but I haven't heard of these word yet!
@krosylight@fosstodon.org
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...
@firesidefedi@social.firesidefedi.live
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 .
https://www.euractiv.com/news/x-blocks-eu-commissions-advertising-account-after-e120-million-fine/

@hongminhee@hollo.social
韓国語でクィア(queer)を意味する言葉に、(「一般」ではないという意味で)「二般」という言葉が有るのですが、本当によくできた言葉だと思います。

@hongminhee@hollo.social · Reply to 洪 民憙 (Hong Minhee) :nonbinary:'s post
오늘 liftIO 2025에서 發表한 〈Optique: TypeScript의 타입 推論으로 CLI 有效性 檢査를 代替하기〉의 發表 資料를 共有합니다! 들어주신 모든 분들께 感謝 드립니다.

@hongminhee@hollo.social

@hongminhee@hollo.social · Reply to Jaeyeol Lee (a.k.a. kodingwarrior) :vim:'s post
@kodingwarrior 아니면 버티컬 마우스는 어떠세요? 저는 버티컬 마우스랑 같이 써요. ABKO에서 나오는 이런 거 하나 싸게 사시면… (저도 저거 쓰고 있습니다.)
@hongminhee@hackers.pub
내일은 liftIO 2025에서 발표… 떨린다…
@kodingwarrior@hackers.pub
여기에 뒤늦게 올리지만 2차 모집도 진행중입니다! 이번엔 12월 15일(월)까지....!!
RE: https://hackers.pub/@kodingwarrior/019abed2-f2e0-79fe-ada8-6b150ae0d840
@kodingwarrior@hackers.pub
Hackers' Public @ Seoul 송년 네트워킹 밋업은 발표보다 대화, 형식보다 연결을 중심으로 진행됩니다. 라이트닝 토크도 지원받습니다. 만들었던 것·배운 것·고민했던 이야기를 자유롭게 얘기해보도록 해요.
많은 관심 부탁드립니다~

@hongminhee@hollo.social · Reply to Jaeyeol Lee (a.k.a. kodingwarrior) :vim:'s post
@kodingwarrior 麻婆丼 먹고 싶네요…
@yihyunjoon@hackers.pub · Reply to 洪 民憙 (Hong Minhee) :nonbinary:'s post
@hongminhee 저요저요~
@bgl@hackers.pub · Reply to 洪 民憙 (Hong Minhee) :nonbinary:'s post
@hongminhee 저 가요~

@hongminhee@hollo.social · Reply to 초무's post
@2chanhaeng I'm not interested in ergo keyboards… 😂

@hongminhee@hollo.social
이番 週 土曜日에 liftIO 2025에 오시는 분 계신가요?

@hongminhee@hollo.social · Reply to wwj's post

@hongminhee@hollo.social
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…

@hongminhee@hollo.social · Reply to radioactivestardust's post
@bookstardust @dokuwiki Okay, I'm looking into it!

@hongminhee@hollo.social · Reply to Christian Westrom's post
@wildwestrom 귀찮음…? 😂

@hongminhee@hollo.social
올해를 마무리하는 블로그 글을 쓰고 있는데, 올해 뭔가 한 게 많긴 하구나…
@juergen_hubert@mementomori.social
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

@hongminhee@hollo.social
겨울 되니까 意欲 全般이 다 低下된다… 오늘도 別 거 안 하고 時間만 보냈네… 😩

@hongminhee@hollo.social
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.
@TypeScript@fosstodon.org
We've got some updates on TypeScript 7! The new native port
- can type-check any project
- supports --build and --incremental
- has rich editor features implemented
- is still 10x faster
and is ready for you to try today!
https://devblogs.microsoft.com/typescript/progress-on-typescript-7-december-2025/

@hongminhee@hollo.social
12月中旬、弟と一緒に、1ヶ月間の出張に行っている妻に会いに東京へ行くことにした。