GlitchState
状態定義・状態遷移図・状態遷移表を、単一のDSLから一体的に設計・可視化するVS Code拡張機能。
セットアップ
必要なもの
- Node.js 22.12以上
- Corepackとpnpm
- Visual Studio Code
手順
corepack pnpm install --frozen-lockfile で依存をインストールする。
npx --no-install playwright install chromiumでテスト用のChromiumを取得する。
- VS Codeを起動できるデスクトップ環境で
npm run check:productを実行し、プロダクトの検査を行う。
- VS Codeでプロジェクトを開き、
F5でExtension Development Hostを起動する。
.glsのサンプルを開き、コマンドパレットからGlitchState: プレビューを開くを実行する。
使い方
.glsファイルを開き、コマンドパレットからGlitchState: プレビューを開くを実行する。
単一のプレビューに状態定義表、状態遷移図、状態遷移表を上から順に表示する。
状態定義表は色、状態、意味の3列で、色列には指定した色の色見本だけを表示する。
保存前の変更も自動で反映され、別の文書をプレビューする場合は、その文書をアクティブにして同じコマンドを実行する。
State IDLE as "待機" color "#4F46E5":
開始を待つ状態
State RUNNING as "実行中" color "#22C55E":
処理を実行している状態
- 状態ID、状態名、カラー、意味はすべて必須である。
- IDは英字または
_で始まり、以後に英数字または_を使える。
大文字と小文字を区別し、同じ文書内で重複させない。
- 状態名は二重引用符で囲み、空白だけの名前、名前の途中の改行と二重引用符は使えない。
エスケープ構文はなく、同じ表示名の状態は別のIDで定義できる。
- カラーは
#と6桁の16進数字で指定する。
- 意味は次の行から半角空白4個で下げ、1行以上の内容を記述する。
複数行の意味は表でも改行され、空白だけの行は無視する。
- 状態は定義した順に表示する。
状態定義のサンプルから試せる。
構文や定義の誤りはVS CodeのProblemsに表示し、同じ文書の最後の正常な図と両方の表を保持する。
正常な内容をまだ表示していない場合は、解析エラーで表示できないことを案内する。
修正すると保存前でも図、両方の表と診断が更新される。
状態の選択
状態定義表の行をクリックすると、その状態の行、図の状態ノード、状態遷移表の状態列全体を薄い背景で強調する。
選択を示す枠線は付けず、指定カラーと未定義の赤文字、既存の罫線とグループ枠を保つ。
他の状態、グループ全体、矢印、他列の遷移先名は強調しない。
- 選択できる状態は1件で、別の行で切り替え、同じ行の再クリックまたはプレビュー内のEscapeで解除する。
- Tabで状態名に移動し、EnterまたはSpaceで選択と解除を行える。
キーボードフォーカスは下線で示し、フォーカスの移動だけでは選択を変えない。
- 同じ文書に同じ状態IDが残る限り、名前、カラー、意味、順序、グループ所属、イベントと遷移の編集後も選択を保つ。
解析エラーで正常表示を保持している間も選択を保ち、表示中の状態を選択できる。
- 状態IDの削除と変更、状態がなくなった場合、対象文書の切替で解除する。
同じIDの再追加や元の文書への復帰では以前の選択を復元しない。
- プレビューを残した同じURIの文書の再オープンとコマンド再実行ではIDで選択を保ち、プレビューを新しく作った場合は未選択から始める。
- 図と状態遷移表からは選択を切り替えず、選択による自動スクロールと自動ズームは行わない。
基本状態遷移図
状態定義表と状態遷移表の間に、状態名と指定カラーを持つノードを表示する。
遷移のない状態も表示し、状態の定義順を基準に自動配置する。
状態間の遷移は淡い矢印で示し、イベント名と処理のラベルは図に表示しない。
- 同じ遷移元と遷移先を持つ定義は、イベントが異なっていても1本の矢印にまとめる。
- 逆方向の遷移は別の矢印、自状態への遷移は自己ループとして表示する。
- 遷移なしと未定義の組み合わせには矢印を作らない。
- 図の中をドラッグして表示範囲を移動でき、ホイールで拡大縮小できる。
- 図の上部に左から
-、Reset、+、⇩と現在の倍率の%表示がある。
縮小、等倍、拡大はマウスのほか、TabでフォーカスしてEnterまたはSpaceで操作できる。
- 拡大、縮小とResetでは現在の表示中心を保つ。
Resetは100%へ戻す操作で、図全体を収め直す操作ではない。
- 同じ文書のDSL編集では、状態の追加や削除、名前と定義順、グループ所属、分岐や遷移先が変わっても、倍率と表示位置を保つ。
解析エラー中も図を操作でき、修正後は現在の内容へ更新しながら最後の操作後の表示範囲を保つ。
状態0件を経由した再追加、同じURIの再オープンとプレビューコマンドの再実行でも保持する。
- 初めて図を表示するときと別文書へ切り替えるとき、図の表示領域の幅や高さを変えたときは図全体を収める。
元の文書へ戻った場合とプレビューを新しく作った場合は、以前の表示範囲を復元しない。
編集で追加した状態が画面外にある場合は、ドラッグと縮小で確認できる。
- 図がない場合は倍率操作部を表示せず、図の準備中はボタン操作を受け付けない。
⇩の図をエクスポートからPNGまたはSVGを選び、保存先を指定できる。
初期の保存先は対象の.glsと同じ場所、同じ基底名で、選んだ形式の拡張子になる。
- 保存画像は倍率と表示位置に依存しない図全体で、画面外の状態、グループ枠、個別と集約の矢印、自己ループと矢尻も含む。
選択強調を除いた通常のノード背景と、現在のテーマの不透明背景と配色を使い、両表、操作部と案内は含めない。
- 未保存の編集を反映した図と、解析エラーで保持している正常な図を保存できる。
形式と保存先のキャンセルでは書き込まず、保存中に文書と内容が変わった場合は再操作を案内する。
保存操作によって状態選択、倍率と位置、DSLと診断は変わらない。
- ノードの移動、接続編集、図からの状態選択、グループ選択には対応しない。
- 状態がない場合は、図の代わりに案内を表示する。
基本状態遷移表
同じ.glsにイベントと遷移を追加すると、状態遷移図の下に状態遷移表を表示する。
イベントを定義順の行、状態を定義順の列に並べ、状態ヘッダの文字色に状態カラーを使う。
分岐なしの定義済みセルは処理を上段、遷移先の状態名を下段にラベルなしで表示し、定義のない組み合わせは赤文字の未定義で示す。
Event START as "開始"
Event STOP as "停止"
Transition IDLE on START -> RUNNING:
開始を記録する
実行を準備する
Transition RUNNING on STOP -> IDLE:
-
Transition IDLE on STOP -> -:
-
この例は、上の状態定義に追記して使う。
STARTとRUNNINGの組み合わせは未定義である。
IDLEとSTOPは明示的な処理なし、遷移なしであり、上下に-を表示する定義済みセルになる。
- イベントは
Event <ID> as "<イベント名>"で宣言する。
IDと名前の制約は状態と同じで、状態とイベントのIDは別に管理する。
同じ名前のイベントも異なるIDで定義できる。
- 遷移は
Transition <遷移元状態ID> on <イベントID> -> <遷移先>:で宣言する。
参照には宣言済みのIDを使い、状態、イベント、遷移の宣言の前後関係は問わない。
- 処理は意味と同じく半角空白4個で下げた1行以上の本文とする。
本文の非空行が-だけの1行なら処理なしになり、遷移先の-は遷移なしになる。
処理なしの-と他の本文行は混在できず、処理本文自体の省略はできない。
- 自状態のIDを遷移先に指定すると、その状態への明示的な遷移になる。
遷移なしの-とは区別する。
- 同じイベントIDの重複、同じ遷移元状態IDとイベントIDの組み合わせの重複、未宣言IDへの参照は診断する。
- 状態だけの文書も引き続き使える。
状態またはイベントが0件の場合は状態遷移表のセルを作らず、不足する軸を案内する。
- 状態定義表、図、状態遷移表は未保存の編集を同じ解析結果から反映し、エラー中は同じ文書の最後の正常な3表示を保つ。
- イベントの分類は最大3段で、遷移は分岐なしと条件分岐を使える。
状態グループで関連する状態を図上の枠にまとめられる。
処理は実行せず、表示用の文字列として扱う。
基本状態遷移のサンプルで状態とイベントをまとめて確認できる。
イベントの分類
分類の各段の列見出しを文書に1回宣言し、イベントごとに分類経路を指定する。
分類は最大3段で、イベント名は段数に含めない。
EventCategoryHeaders "系統" > "区分" > "種別"
Event START as "開始" in "操作" > "運転" > "開始系"
Event STOP as "停止" in "操作" > "運転"
Event PING as "疎通確認"
- 列見出しと分類値は独立しており、例えば
系統列の値が操作となる。
使用する分類が2段なら、列見出しは系統、区分、イベント、各状態の順となる。
イベントはイベント名の列だけの見出しである。
- 見出しは1件から3件で、使う分類の深さまで指定する。
宣言はイベントの後にも置け、未使用の段の名前を先に指定できる。
未使用の段の列と見出しは表示しない。
- 分類名と見出し名はイベント名と同じく二重引用符で囲み、空白だけの名前、改行、途中の二重引用符とエスケープ構文は使えない。
引用符内の>と空白は名前として保持する。
- イベント行は宣言順を保ち、連続して同じ祖先を持つ分類だけをまとめる。
別の親の同名分類や、離れた分類をまとめるための並べ替えはしない。
- 分類なしと浅い分類も混在でき、不足する段は空欄になる。
分類なしだけなら、見出し宣言が残っていても従来のイベント列だけになる。
- 遷移は分類に関係なく既存のイベントIDを参照する。
分類を変えてもIDを保てば処理と遷移先は変わらず、同じイベントIDを別の分類で重複宣言することはできない。
- 分類と見出しの編集も保存前に反映する。
4段の分類、見出し不足、見出し宣言の重複などはProblemsへ表示し、同じ文書の最後の正常な3表示を保つ。
修正すると現在の内容へ更新し、診断とエラー案内を消す。
イベント分類のサンプルから試せる。
条件分岐
同じ状態とイベントに複数の到達先を定義する場合は、Transition行の矢印と遷移先を省き、共通処理と名前付き分岐を並べる。
Transition IDLE on START:
Common:
要求を記録する
Branch "準備完了" -> RUNNING:
開始する
Branch "それ以外" -> -:
-
Common:を最初に1回、その後に1件以上のBranch "<条件名>" -> <状態IDまたは->:を、半角空白4個で下げて記述する。
Commonと各Branchの処理は、半角空白8個で下げた1行以上の本文とする。
- 共通処理や分岐の処理がない場合も、本文に単独の
-を記述する。
分岐の遷移先の-は遷移なしで、自状態のIDへの遷移とは区別する。
- 条件名は非空白の文字列を二重引用符で囲み、途中の二重引用符と改行、エスケープ構文は使わない。
名前と処理は表示用の文字列で、条件の真偽、実行順、網羅性を評価しない。
それ以外も通常の条件名であり、専用のElse構文や分岐の入れ子は設けない。
- 同じ遷移内で同じ条件名を重複できず、大小文字と引用符内の空白は区別する。
異なる遷移では同じ条件名を使える。
同じ状態IDとイベントIDの組み合わせへ、分岐付きと分岐なしを重ねて定義することはできない。
- 表は共通処理を上部に1回、その下だけを分岐の定義順に左右へ分割して表示する。
隣り合う分岐の境界だけに縦線を引き、条件名、処理、遷移先の状態名を上から順にラベルなしで表示する。
なしはそれぞれ-で示し、分岐数で状態列やイベント行を増やさない。
- 図はすべての分岐の遷移先を反映し、同じ有向ペアは分岐なしや他のイベントと合わせて1本にする。
遷移なしには矢印を作らず、自己遷移は自己ループとし、条件名や処理のラベルは表示しない。
- 既存の矢印付きTransitionとイベント分類はそのまま併用できる。
旧形式の処理に書いたCommon:やBranchは、分岐へ読み替えず文字列として保持する。
- 分岐も保存前に更新する。
不正な構文や参照は該当する宣言行などをProblemsへ表示し、同じ文書の最後の正常な3表示を保つ。
修正すると現在の共通処理と全分岐、図と両表へ更新し、診断とエラー案内を消す。
条件分岐のサンプルは分類付きイベントと分岐なし遷移も含む。
状態グループ
関連する状態IDを、名前付きグループの下に1行1件で指定する。
既存の状態とイベント、遷移はそのまま定義する。
StateGroup WORK as "稼働系":
IDLE
RUNNING
RECOVERING
- グループ名と所属する状態だけを実線の枠で囲み、各状態名と指定カラーを保つ。
所属状態は状態の定義順に並べ、未所属状態を枠に含めない。
- 異なる2状態以上から同じ外部状態への矢印は、グループ枠からその状態への1本にまとめる。
全メンバーが同じ状態へ遷移する必要はなく、イベントと条件分岐、処理の有無によらず判定する。
- 同じ1状態からの複数遷移はグループからの矢印にせず、内部遷移と自己ループは各状態のままにする。
1状態から複数状態への集約は行わず、到達先が別グループでも終点は個々の状態である。
- グループは異なる宣言済み状態2件以上を必要とし、所属行は半角空白4個で下げる。
グループIDと名前の制約は状態と同じで、グループIDは状態とイベントとは別の名前空間である。
グループの入れ子、重複所属、グループIDだけを遷移先として使う記法は設けない。
- 両表の順序と個々の交点、分類と見出し、共通処理と条件分岐は変わらない。
遷移のないメンバーへ共通の遷移先を補わず、未定義は未定義のままである。
- 所属と名前の編集も保存前に反映する。
所属や参照の誤りでは該当行をProblemsへ表示し、同じ文書の正常な3表示を保持する。
修正すると現在の枠と矢印、両表へ更新し、診断とエラー案内を消す。
状態グループのサンプルは、外部への集約と個別矢印、内部遷移と自己ループ、分類と条件分岐を含む。
開発
この節は、OpenSpec を使った開発のためのものである。
OpenSpec の部分を切り離して納品する場合は、納品物からこの節を削除する。
開発に必要なもの
- Node.js 22.12以上、Corepack、pnpm
- git(コミット前のフックで全体検証を実行する)
OpenSpec のグローバル設定
OpenSpec が生成するワークフローは、マシンごとのグローバル設定で決まる。
生成されるファイルを全員で一致させるため、各マシンで最初に1回だけ次を実行する。
npx --no-install openspec config set profile custom
npx --no-install openspec config set workflows '["explore","ff","apply","update","verify","sync","archive"]'
npx --no-install openspec config set delivery skills
Windows PowerShell 5.1 では、2行目が expected array, received string で失敗することがある。
その場合は npx --no-install openspec config profile を実行し、対話の画面で上と同じワークフローと配信方法(skills)を選ぶ。
設定は npx --no-install openspec config list で確認できる。
開発の準備
- セットアップの手順で、プロダクトと開発用の依存を入れる。
- OpenSpecのグローバル設定を行う。
git config core.hooksPath .githooks で、コミット前のフックを有効にする。
npm run check で、全体検証が成功することを確かめる。
プロダクトだけの検査は npm run check:product で実行する。
単体テストは corepack pnpm test、ブラウザーテストは corepack pnpm test:visual、VS Code統合テストは corepack pnpm test:extension で実行する。
初回はnpx --no-install playwright install chromiumでブラウザーテスト用のChromiumを取得する。
単体テストはCore、Extension、Webviewの.test.tsとWebviewの.test.tsxを収集する。
プロダクトの検査にはこれらのテストも含み、VS Codeを起動できるデスクトップ環境で実行する。
統合テストは初回にVS Codeのテスト用バイナリを取得する。
全体検証は、プロダクトの検査と OpenSpec の検査をまとめて実行し、コミットの前にフックで自動で実行される。
AI ツール向けの生成されたファイル(.github/skills/、.claude/skills/、.agents/skills/ のうち、使うツールのもの)はコミットし、手で編集しない。
OpenSpec を更新した後は、npx --no-install openspec update で生成し直す。
参照する文書