はじめに
先日、Excel ブックを生成 AI 向け Markdown に変換する xlsx2md という Single-file Web App を作りました。
もともとの xlsx2md は、xlsx2md.html をブラウザで開いて使う GUI 中心のアプリです。そこに今回、Node から実行できる CLI を追加しました。つまり、画面から使うだけでなく、バッチ的にも利用できるようにしようとしたわけです。
今回も使ったのは OpenAI GPT-5.4 です。しかも今回も、前回の本体開発と同様に、私はソースコードも Markdown も一切手で編集していません。基本的に対話だけで、実装、整理、テスト、README 更新まで進めています。なお、今回の CLI 追加で私が実際に入力した内容は、後方の Appendix に載せておきました。お急ぎの方は、先に末尾の Appendix を見てもらっても構いません。これだけの会話で CLI が追加されるというのは、AI駆動開発にあまり接していない方には意外性があるかも、と思い記事を書き残します。
xlsx2md の Node CLI で何ができて、どう使うのかは別記事に分けました。この記事では、CLI 追加の途中でどのような対話をし、どこで方針を決め、どこで軌道修正したのかに絞って書きます。
- 初出: 2026-03-21
- 更新: 2026-03-21
題材は GUI アプリへの CLI 追加だった
出発点の xlsx2md は、ブラウザでローカルに .xlsx を読み込み、Markdown や ZIP を保存する Single-file Web App でした。
今回ここに Node CLI を追加しました。この記事では、その追加をどう対話で進めたかに絞って書きます。
最初の入力はかなり素朴でした。
README読んで。このアプリっていまはGUIだよね。これにバッチインタフェースって足すのって可能?
ここで面白いのは、最初から厳密な設計指示を出したわけではないことです。というかマルっと書いてますね。まず可能かどうかを聞き、そのあとで必要なら既存構造を整理できるかを聞く、という順番で進めています。進めていくのは生成AIですけれどね。
GUI 前提の構造について、中身を見ていくと、UI 層と変換コアが完全に一体化しているわけではなく、ほんのりとはわかれていました。そこで、いきなり CLI を足すのではなく、まずは構造整理から入ることになりました。
先行して大きめのリファクタリングからはじめた
今回の対応で主要だったのはリファクタリングです。GUI 用のコードにそのまま CLI の分岐を足し始めるより、共通コアを使い回せる形へ寄せるほうが、保守性や拡張性において有利だと思っています。加えて生成AIのトークン消費削減にも有利と思っています。
ソースコードが整理されれば、CLIを追加するのは実は簡単な作業だったのです。
その流れは、かなりはっきり入力にも出ています。
core.ts に残している大きな globalThis フォールバックを削る をお願いします。
残っている globalThis.__xlsx2md... への二重公開を段階的に減らしていく、をお願いします。
おおよその実施事項は以下のようなものです。
- browser 前提の依存を少しずつ切り離すこと
- モジュール取得を
globalThis直参照中心の形から整理すること - browser / Node / CLI から同じ変換コアを呼べる形へ寄せること
実際には、モジュールレジストリの導入、Node runtime の追加、core 周辺の依存整理、README の見直し、CLI テストの追加まで進めました。
つまり、今回の流れは、リファクタリングによって構造化を進め、ソースコードの見通しを改善したうえで、おまけのように Node から呼べる入口を追加した、というほうが実態に近いです。
生成AI が大きい CLI を作ろうとしたので止めた
CLI を追加するときに、生成AIが何でもできる大きなコマンドにしようとして、実際に複数入力対応の方向で作業を進め始めました。ですが、その段階でいったん止めて、UNIX 的な思想に沿って、役割を絞った CLI に寄せるよう指示しました。
この方針転換は、入力ログを見るとかなり生々しいです。
ちょっとまって。UNIX原則的には小さい方がいいよ。複数入力やめて。
UNIX原則に基づき、CLIはなるべく小さく、を基本としたいです。mdに記述必要あれば妥当な箇所に記載してください。
その結果、最終的な方針はかなり明快になりました。
- 1 回につき 1 つの workbook を処理する
- Markdown と ZIP を出力できる
- オプションは少数に絞る
-
--helpとエラーメッセージは英語にする
ここで印象的だったのは、生成AIが私の思想とは違う実装を行うことがあり得る、ということです。まあ、当たり前ですね。そして、よりベターな選択肢が人間側の指示する方であるならば、そうした方向の違いについては人間が止めてコントロールしなくてはならない、ということです。
人間が持っていた判断
リアルな発話については Appendix を参照してください。
印象的だったのは、CLI の追加そのものだけでなく、途中で入れた構造整理、README の更新、小さい CLI テストの追加、エラーメッセージの改善まで、対話だけでかなり広く進められたことです。
もちろん、人間の仕事が無いわけではありません。そして今回の例で言うと、人間の仕事は、何を目指すか、CLI をどの程度まで大きくするか、UNIX 的に小さく保つか、リファクタリングはどこまでやるのか、といった判断を持つことです。
今回で特に印象的だったのは、「GUI アプリに CLI を足す」という、少し構造に踏み込んだ作業であっても、対話の積み重ねだけで進められたことです。基本的には「続けて」とかでいいのですが、たまに 3 択のようなものが出てきて人間が選択したり、あるいは作業を止めさせて方針転換させたり、そういったことが人間の担当なのだとしみじみ思いました。
実際、入力の多くはかなり短いです。
続けて
よし。OK
ただ、その短い入力の裏で、方向付けや停止判断は人間が持っています。ここがコード補完ではないAI駆動開発ならではのポイントだと思っています。
今回も、ソースコードや Markdown を手で編集せず、基本的には対話だけで実装、整理、テスト、文書更新まで進められました。前回の本体開発に続いて、このやり方が機能追加や構造整理にも十分使えることを、あらためて確認できました。まあ、自動テストがたくさん揃った状態でのリファクタリングが主体だったこともあると思いますが、こういった作業は生成AIがかなり得意なのだと、よくよく思いました。
まとめ
今回の CLI 追加を通じて、生成AI と対話しながら進める開発は、単なるコード補完ではなく、機能追加、大きめのリファクタリング、README 更新、テスト整備まで含めてかなり広く進められることをあらためて確認できました。
ただし、何を作るか、どこで止めるか、どこまで整理するかは、人間が判断する必要があります。その意味で、AI駆動開発は「全部おまかせ」ではなく、「人間が方針を持ったまま、実装を大きく前に進めるやり方」なのだと思っています。
余談ですが、Claude Code はこれよりずっと自動化されているらしく、そのあたりもいずれ試してみたいと思っています。
後方の Appendix には、今回の CLI 追加で実際に入力した内容をそのまま載せています。TYPO を含めて原文のまま残しているので、本文で触れた流れを、より生の形で追えるはずです。
想定読者
- 生成AI と対話しながら、実際にどのように機能追加やリファクタリングを進めるのか知りたい人
- コード補完ではなく、リアルな AI 駆動開発の進み方に関心がある人
- 人間と生成AIの役割分担をどう置くとよいか気になっている人
実行ページとソースコード
ソースコードは GitHub で公開しており、これをダウンロードして Node CLI を起動できます。
従来のブラウザですぐ試せる Web 画面の実行ページは、次の URL です。
関連記事
-
xlsx2mdに Node CLI を追加した話 - Excelブックを生成AI向けMarkdownに変換する
xlsx2mdを作りました - VS Code + GPT-5.4 と会話しながら、アプリ開発をかなり広い範囲で進めた話
Appendix
実際のユーザー入力メモ
TYPO を含めて、今回の CLI 追加で実際に入力した内容をそのまま載せています。そして、今回のリファクタリングと CLI 機能追加について私がやったのは、この会話を入力したことと Git / GitHub 操作だけです。おまけで言うと、「また、その出漁kは版管理する?しない?」のような TYPO もあります。恥ずかしいですがそのまま残しています。そして、これで動作する生成AIはすごいです。
- README読んで。このアプリっていまはGUIだよね。これにバッチインタフェースって足すのって可能?
- そもそもCLI・バッチ対応できるように既存実装をせいるすることって可能?
- すごな、進めて。
- 進めて。
- いいね、続けて
- すごいね。進めて。
- すごいね。そしてそうなんだね。続けて。
- はい。すばらしいです。続けて。
- core.ts に残している大きな globalThis フォールバックを削る をお願いします。
- 残っている globalThis.__xlsx2md... への二重公開を段階的に減らしていく、をお願いします。
- さて、続きはなんだい?
- 2
- 前者
- いいですね。進めて。
- module-registry.ts に残っている globalKeys ベースの互換ロジックを整理する
ts 側に残る globalThis.__xlsx2md... 文字列参照をさらに削る > 続けて - 残っている __xlsx2mdModuleRegistry 参照の書き方を共通 helper 化して、各 TS ファイル冒頭の重複を減らす段階です。 > お願いします。
- ちなみに、今動かすと、ブラウザで
getXlsx2mdModuleRegistry is not definedのエラーが大量に発生します。意図通り? - いえいえ、直してくれてありがとう。さて、戻って、続きの作業しよう。
- このままなら次は relsParser / formulaReferenceUtils / sheetMarkdown / formulaEngine / sheetAssets / worksheetParser / workbookLoader / formulaLegacy / formulaAst あたりの alias 化です。 >お願い。
- core.ts 内の alias 群を module-registry-access.ts 側へさらに寄せて、共通の typed accessor にする
- core.ts でまだ残る型引数の長い呼び出しを、さらに束ねた accessor にする > これって、効果的?もうおおよそ終わっている?
- core.ts でまだ残る型引数の長い呼び出しを、さらに束ねた accessor にする > これやって!
- もうおおよそリファクタリング系はOKかな?
- よし。OK
- CLI/バッチの実用機能に戻る > お願い。
- 続けて
- ちょっとまって。UNIX原則的には小さい方がいいよ。複数入力やめて。
- UNIX原則に基づき、CLIはなるべく小さく、を基本としたいです。mdに記述必要あれば妥当な箇所に記載してください。
- いまって CLI ってどういうインタフェース? ZIP のみ? 出力オプションについて、Include shape details in Markdown ってすでにある?まだない?
- README の CLI 節へ --include-shape-details と --output-mode の使用例も追記できます。 >おねがい。
- さて、CLI的に、他にやるべきことは?
- README に CLI オプション一覧を短く明記する
今は使用例中心なので、--summary、--output-mode、--include-shape-details、--no-header-row などを1行ずつ並べると把握しやすいです。 > おねがい - --help の出力を README と揃える
現状は概ね揃っていますが、README を見なくても CLI 単体で迷わない状態にしておく価値があります。 > お願い - 失敗時メッセージの粒度を少し整える
いまは入力ファイル名付きで十分実用的です。さらにやるなら「読み込み失敗」「変換失敗」「書き込み失敗」を分ける程度で十分です。 > やって - CLI テストを少しだけ増やす > やって。
- exit code の扱いを README に書く
成功は 0、失敗は 1 と明記するだけでも、バッチ利用時に親切です。 > やって - ちなみに、CLIのエラーメッセージがあればそれは英語だよね?
- OK. すばらしい。CLI作るシリーズは、一旦完了かな?
- リポジトリルートに、table-basic-sample01.mdとxlsx2md-basic-sample01.mdがあるんだけれど、これテストしたらできるの?
- ええと、テストするのはOKというか喜ばしい。ただ、出力フォルダをルートでは無いところにして。Nodeの場合、こういう出力はどこにする?また、その出漁kは版管理する?しない?
- 進めて。
- 必要なちいさいテストは追加済みかな
- md関連で更新すべきところは更新済みかな?
