aizuchi 0.4.0 → 0.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,211 +1,273 @@
1
+ English | [日本語](README.ja.md)
2
+
1
3
  # AIzuchi
2
4
 
3
- **AI進捗管理カンバンダッシュボード**(npm / CLI 名: `aizuchi`)
5
+ **A local kanban dashboard for the work you delegate to AI coding agents** (npm / CLI name: `aizuchi`)
4
6
 
5
- CLI AI コーディングエージェント(Claude Code 等)に作業を委任するプロジェクトで、人間が
6
- ブラウザ上のカンバンボードからタスクの進捗を一望・操作するためのローカル専用ツールです。
7
- タスクは `.kanban/` 配下のプレーンテキスト(Markdown + YAML frontmatter)が唯一の正で、
8
- AI も人間も通常のファイル読み書きだけで参加できます。
7
+ You hand work to a CLI-based AI coding agent (Claude Code and the like), then watch and steer its
8
+ progress on a kanban board in your browser. Tasks are plain text under `.kanban/`
9
+ (Markdown + YAML frontmatter) — that file is the single source of truth, and both the AI and you
10
+ take part by simply reading and writing files.
9
11
 
10
- 「相槌(あいづち)」=対話せずに通じ合う、AI との意思疎通を表す命名です。
12
+ The name comes from *aizuchi* (相槌) — the small back-channel cues that let two people stay in sync
13
+ without spelling everything out: the quiet understanding between you and your AI.
11
14
 
12
- - **ローカル限定**: `127.0.0.1` のみにバインドし、外部送信・テレメトリは一切しません。
13
- - **ファイルが唯一の正**: DB を使いません。git 管理でき、サーバー停止中も読めます。
14
- - **規約ベースの AI 連携**: AI は専用 API なしで、ファイル読み書きだけで参加します。
15
+ - **Local only** — binds to `127.0.0.1` only. No outbound requests, no telemetry, ever.
16
+ - **Files are the source of truth** — no database. Everything is git-trackable and still readable
17
+ while the server is stopped.
18
+ - **Convention-based AI integration** — the AI needs no special API or SDK; it joins by reading and
19
+ writing the same files you do.
15
20
 
16
- 変更履歴は [CHANGELOG.md](CHANGELOG.md) を参照してください。
21
+ See [CHANGELOG.md](CHANGELOG.md) for the version history.
17
22
 
18
- ## 必要環境
23
+ ## Requirements
19
24
 
20
- - Node.js **20.1 以上**(`fs.readdir` `recursive` を使うため)
21
- - macOS / Linux / WSLWindows ネイティブはベストエフォート)
25
+ - Node.js **20.1 or newer** (uses the `recursive` option of `fs.readdir`)
26
+ - macOS / Linux / WSL (native Windows is best-effort)
22
27
 
23
- ## クイックスタート
28
+ ## Quick start
24
29
 
25
30
  ```bash
26
- # 対象プロジェクトのディレクトリ直下で実行する
27
- npx aizuchi init # .kanban/ を生成 + CLAUDE.md へ運用規約をマーカー区切りで追記
28
- npx aizuchi # = servehttp://127.0.0.1:5151 でボードを起動(Ctrl+C で終了)
31
+ # Run from the root of the project you want to manage
32
+ npx aizuchi init # creates .kanban/ and appends the operating rules to CLAUDE.md (marker-delimited)
33
+ npx aizuchi # = serve. Opens the board at http://127.0.0.1:5151 (Ctrl+C to stop)
29
34
 
30
- # 複数プロジェクトをまとめて見る(read-only 集約・既定ポート 5152
31
- npx aizuchi overview <dir...> # 例: npx aizuchi overview ~/proj-a ~/proj-b
35
+ # View several projects at once (read-only aggregation, default port 5152)
36
+ npx aizuchi overview <dir...> # e.g. npx aizuchi overview ~/proj-a ~/proj-b
32
37
  ```
33
38
 
34
- - `init` は既存ファイルを壊しません。既に `.kanban/` があれば安全に中断します。
35
- CLAUDE.md は末尾にマーカー(`<!-- aizuchi:begin -->`〜`<!-- aizuchi:end -->`)区切りで追記し、
36
- 再実行時は同区間だけを置き換えます(冪等)。撤去は `.kanban/` 削除とマーカー区間削除だけで完了します。
37
- - `--port <番号>` でポート変更、`--member <ID>` で AI のメンバー ID 指定(config.members に未登録なら
38
- `ai` 種別で追加)、`--yes` で確認プロンプト省略。
39
- - `overview` は各 dir `.kanban` を読み取り専用で集約表示します(編集・起票・D&D なし)。
40
- `.kanban` の無い dir や同一 dir の重複指定は明確なエラーで起動を拒否します。既定ポートは
41
- serve(5151)と衝突しない 5152 で、`--port <番号>` で変更できます。
42
- - `127.0.0.1` 以外にはバインドせず、外部へのネットワーク送信は一切行いません。
43
-
44
- ## できること
45
-
46
- ブラウザのボードで AI への委任を一望・操作します。エディタや AI がファイルを書き換えると、
47
- watcher → SSE で開いているボードへ約 1 秒以内に反映されます(ライブ更新)。
48
- UI 表示言語は英語 / 日本語(en / ja・既定 en)を切り替えられます。
49
-
50
- ### ボード運用
51
-
52
- - **ドラッグ&ドロップ**: カラム移動で frontmatter の `status` / `updated` だけをピンポイント書換(本文は保全)。
53
- Pending へ移すと種別(decision / external / dependency)と理由を尋ねるダイアログが出ます。
54
- - **検索フィルタ**: タイトル / ラベル / 担当でカードを絞り込み。
55
- - **Saved Views(保存済みビュー)**: 絞り込み条件を config に名前付きで保存し、chip からワンクリックで適用。
56
- - **新着ハイライト**: 画面を見ていない間に AI が動かしたタスク(status 変化 / 作業ログ追記 / 新規)を
57
- カードのハイライトと「新着」バッジで可視化。カードを開くと既読化、ヘッダから一括既読も可能。
58
- - **停滞バッジ**: 一定期間更新が止まったタスクにバッジを表示(閾値は status 別に設定可能)。
59
- - **差し戻し(やり直しを依頼)**: カード / 詳細から理由を添えて `todo` へ戻し、作業ログに記録。
60
- 直近の差し戻し理由は再依頼の指示コピーに自動で載ります。
61
- - **複数選択の一括指示コピー**: 複数選択モードでカードを選び、依存関係のトポロジカル順に並べた
62
- 1 つの指示文へまとめてクリップボードへコピー(AI へのバッチ委任を 1 操作で)。
63
- - **ドラッグ横パン**: カラムの空白部分を掴んで横スクロール(カード等のインタラクティブ要素からの操作は除外)。
64
-
65
- ### 見通し
66
-
67
- - **クリティカルパス**: `depends_on` DAG をトポロジカル深さで列配置し、クリティカルパスを強調。
68
- 循環は検出して警告し、再編成の指示コピーも提供。
69
- - **マイルストーン**: 予定表(milestone 別・done/total 付き)と対応履歴(月別)の 2 ペイン表示。
70
- - **日次ダイジェスト**: 日付別に作業ログをまとめて表示。
71
- - **統計**: 完了数推移 / サイクルタイム / ステータス滞留 / member 別完了数 / ボトルネック /
72
- 停滞中(静かな)タスクの一覧。
73
-
74
- ### 管理と健全性
75
-
76
- - **アーカイブ検索 + 復元**: done タスクを archive へ退避し、一覧・検索・プレビュー。
77
- 「ボードに戻す」で `tasks/` へ復元(unarchive)。
78
- - **ごみ箱(.trash 退避 + 復元)**: タスクを破壊的に書き換える直前に旧版を `.kanban/.trash/`
79
- 自動退避する安全網。一覧・現行との差分プレビュー・復元が可能(誤上書きからの回復)。
80
- - **AI 設定ファイル管理**: `aiConfigPaths` で許可したファイル(CLAUDE.md / settings 等)を
81
- GUI から編集(JSON 構文チェック・`.bak` バックアップ・パーミッション保全)。
82
- - **git 履歴連携(read-only)**: 詳細パネルのコミットタブで、タスク ID を含むコミット履歴を表示。
83
- `git log` read-only で実行するだけで、fetch / pull 等の外部通信はしません。
84
-
85
- ### AI 連携規約 + CLI
86
-
87
- - **規約ベースの連携**: `init` が CLAUDE.md に運用規約(着手 / 進捗 / 完了 / ブロック / 起票 / 書式)を
88
- マーカー区切りで追記。AI は専用 API なしでファイルを読み書きするだけで参加できます。
89
- - **提案ワークフロー**: `aiTaskCreation` `proposal` のとき、AI 起票は `proposed` で入り、
90
- 承認 / 却下を経て `todo` へ。モード違反は警告で検知。
91
- - **AI 用 CLI(必須でない安全弁)**: 書込系 `aizuchi task add / move <id> <status> / done <id> /
92
- block <id> --type --reason / log <id> "msg" / comment <id> "msg" / revise <id> --reason` と、
93
- 読取系 `list [--status S] [--assignee M] / show <id> / next`(着手可能なタスクを依存解決順に提示)を提供。
94
- いずれも既存のスキーマ検証・採番直列化・行置換検証を再利用します(生ファイル編集も従来どおり可・`--json` 対応)。
95
-
96
- ### そのほか
97
-
98
- - **複数案件横断 overview**: `aizuchi overview <dir...>` で複数 `.kanban` read-only 集約表示。
99
- - **コマンドパレット ⌘K**: ビュー切替 / タスク検索ジャンプ / 起票 / 設定を 1 操作で。
100
- - **タスク詳細**: Markdown プレビュー / 本文編集(保存時に競合検知 → 行差分提示)/
101
- 作業ログ・やりとり(双方向コメント)のタイムライン。
102
- - **警告バナー**: 壊れた frontmatter・重複 ID・未登録メンバー・不正な config を表示(ボードは落ちません)。
103
-
104
- ## 開発
39
+ - `init` never clobbers existing files. If `.kanban/` already exists, it stops safely.
40
+ It appends to CLAUDE.md inside markers (`<!-- aizuchi:begin -->` … `<!-- aizuchi:end -->`) and on
41
+ re-run replaces only that section (idempotent). To remove it, delete `.kanban/` and the marked
42
+ section that's all.
43
+ - `--port <n>` changes the port, `--member <id>` sets the AI's member ID (added with the `ai` kind
44
+ if it isn't already in `config.members`), and `--yes` skips the confirmation prompt.
45
+ - `overview` aggregates each directory's `.kanban` read-only (no editing, no creating tasks, no
46
+ drag & drop). Directories without a `.kanban`, or the same directory passed twice, are rejected
47
+ with a clear error at startup. The default port is 5152 so it doesn't collide with `serve`
48
+ (5151); change it with `--port <n>`.
49
+ - It binds to `127.0.0.1` only and makes no outbound network requests whatsoever.
50
+
51
+ ## What it does
52
+
53
+ The board lets you see and steer everything you've delegated to the AI. When your editor or the AI
54
+ rewrites a file, the change reaches any open board within about a second (live updates via
55
+ watcher → SSE). The UI language can be switched between English and Japanese (`en` / `ja`, default
56
+ `en`).
57
+
58
+ ### Board operations
59
+
60
+ - **Drag & drop** moving a card between columns pinpoint-writes only the `status` / `updated`
61
+ frontmatter fields (the body is preserved). Moving to Pending opens a dialog asking for the
62
+ block kind (decision / external / dependency) and a reason.
63
+ - **Search filter** narrow cards by title, label, or assignee.
64
+ - **Saved views** store filter conditions by name in the config and apply them in one click from
65
+ a chip.
66
+ - **"Assigned to me" filter** — pick yourself (a member) in the header to narrow the board, in one
67
+ tap, to just the tasks coming your way: ones assigned to you, ones that `@mention` you in the body,
68
+ and ones you created that are awaiting approval (`proposed`). Handy for checking your own queue
69
+ first thing in the morning when several people / AIs are working at once. The choice is stored in
70
+ this browser only and never touches the task files.
71
+ - **Pin / focus** — pin a task you want to keep an eye on from its card or detail with 📌, and it
72
+ stays at the top of Home. Pins to tasks that become done or archived hide themselves automatically.
73
+ Separate from the auto-computed critical path, you can always see the tasks you chose to watch. The
74
+ pin set is kept in this browser only.
75
+ - **New-activity highlight** — tasks the AI moved while you weren't looking (status change, new work
76
+ log entry, brand-new task) are surfaced with a card highlight and a "new" badge. Opening a card
77
+ marks it read; the header offers mark-all-read.
78
+ - **Stale badge** — a badge appears on tasks that haven't been updated for a while (the threshold is
79
+ configurable per status).
80
+ - **Send back (ask for a redo)** — from a card or its detail, return a task to `todo` with a reason
81
+ that's recorded in the work log. The most recent send-back reason is auto-included in the
82
+ re-delegation instruction copy.
83
+ - **Quick comment from a card** add a one-line comment straight to the exchanges (two-way
84
+ comments) section from a card, without opening the detail panel, so the back-and-forth with the AI
85
+ gets one step faster.
86
+ - **Batch instruction copy for multiple selections** — in multi-select mode, pick several cards and
87
+ copy a single instruction that orders them topologically by dependency, so you can batch-delegate
88
+ to the AI in one action.
89
+ - **Drag-to-pan** — grab the empty area of a column to scroll horizontally (interactions starting
90
+ from cards and other interactive elements are excluded).
91
+
92
+ ### Visibility
93
+
94
+ - **Critical path** lays out the `depends_on` DAG in columns by topological depth and highlights
95
+ the critical path. Cycles are detected and warned about, with a reorganization instruction copy
96
+ provided.
97
+ - **Milestones** a two-pane view of the schedule (per milestone, with done/total) and the history
98
+ of completed work (by month).
99
+ - **Daily digest** — work-log entries grouped and shown by date.
100
+ - **Stats** — completion-count trend, cycle time, time-in-status, completions by member,
101
+ bottlenecks, and a list of stalled (quiet) tasks.
102
+ - **AI activity heatmap** — the stats view also aggregates work-log timestamps into a weekday × hour
103
+ heatmap, so you can see at a glance when the AI tends to be working (display only).
104
+
105
+ ### Management and health
106
+
107
+ - **Archive search + restore** move done tasks into the archive to list, search, and preview.
108
+ "Return to board" restores them to `tasks/` (unarchive).
109
+ - **Trash (.trash backup + restore)** — a safety net that automatically backs up the old version to
110
+ `.kanban/.trash/` just before a task is destructively rewritten. You can list, preview the diff
111
+ against the current version, and restore (recovery from accidental overwrites).
112
+ - **Permanent task deletion** — the task detail offers "Delete permanently" (archive stays the
113
+ primary choice; delete is separated out as a dangerous operation, with a confirmation). A task
114
+ being deleted is always backed up to the trash (`.kanban/.trash`) before it is removed, so it can
115
+ be restored later. If the backup fails, the deletion is aborted (to prevent irreversible loss).
116
+ - **AI config file management** — edit files allowed via `aiConfigPaths` (CLAUDE.md, settings, etc.)
117
+ from the GUI, with JSON syntax checking, a `.bak` backup, and permission preservation.
118
+ - **Git history integration (read-only)** — the commits tab in the detail panel shows commit history
119
+ that mentions the task ID. It only runs `git log` read-only — no fetch, pull, or other outbound
120
+ communication.
121
+
122
+ ### AI integration rules + CLI
123
+
124
+ - **Convention-based integration** — `init` appends the operating rules (start / progress / done /
125
+ block / create / format) to CLAUDE.md inside markers. The AI takes part by reading and writing
126
+ files, with no special API needed.
127
+ - **Proposal workflow** — when `aiTaskCreation` is `proposal`, AI-created tasks enter as `proposed`
128
+ and reach `todo` only after approval / rejection. Mode violations are surfaced as warnings.
129
+ - **AI-facing CLI (an optional safety valve)** — write commands `aizuchi task add / move <id> <status> /
130
+ done <id> / block <id> --type --reason / log <id> "msg" / comment <id> "msg" / revise <id> --reason`,
131
+ plus read commands `list [--status S] [--assignee M] / show <id> / next` (proposes the next
132
+ actionable tasks in dependency-resolved order). All of these reuse the existing schema validation,
133
+ serialized ID numbering, and line-replacement checks (editing raw files directly still works too;
134
+ `--json` is supported).
135
+
136
+ ### Also
137
+
138
+ - **Cross-project overview** — `aizuchi overview <dir...>` aggregates multiple `.kanban` directories
139
+ read-only.
140
+ - **Command palette ⌘K** — switch views, jump to a task by search, create a task, and open settings
141
+ in one action.
142
+ - **Task detail** — Markdown preview, body editing (conflict detection on save → line-diff prompt),
143
+ and a timeline of the work log and exchanges (two-way comments).
144
+ - **Warning banner** — surfaces broken frontmatter, duplicate IDs, unregistered members, and invalid
145
+ config (the board stays up).
146
+
147
+ ## Development
105
148
 
106
149
  ```bash
107
- npm install # 依存インストール
108
- npm run dev # 開発: Vite + API 1 プロセスで起動(http://127.0.0.1:5173 など)
109
- npm run build # web dist/web にビルド + server/shared dist にコンパイル
110
- npm run serve # ビルド済み dist 1 プロセスで配信(= node dist/bin/aizuchi.js serve
150
+ npm install # install dependencies
151
+ npm run dev # dev: Vite + API in a single process (e.g. http://127.0.0.1:5173)
152
+ npm run build # build web into dist/web + compile server/shared into dist
153
+ npm run serve # serve the built dist in one process (= node dist/bin/aizuchi.js serve)
111
154
  npm test # vitest
112
- npm run typecheck # tscserver)+ tsc -p web/tsconfig.jsonweb
155
+ npm run typecheck # tsc (server) + tsc -p web/tsconfig.json (web)
113
156
  ```
114
157
 
115
- - 開発時は Vite `configureServer` Hono アプリをマウントし、`npm run dev` 一発で SPA と API の
116
- 両方が立ち上がります(proxy concurrently も不要)。
117
- - 別プロジェクトを開発対象にしたい場合は `AIZUCHI_DEV_ROOT=/path/to/project npm run dev`。
158
+ - In development, the Hono app is mounted onto Vite's `configureServer`, so `npm run dev` brings up
159
+ both the SPA and the API at once (no proxy, no concurrently).
160
+ - To develop against a different target project, use `AIZUCHI_DEV_ROOT=/path/to/project npm run dev`.
118
161
 
119
- ## 構成
162
+ ## Architecture
120
163
 
121
164
  ```
122
- ┌──────────── 1 プロセス (Node.js) ────────────┐
123
- ブラウザ ──HTTP──▶│ 静的配信 (dist/web) REST API SSE
165
+ ┌──────────── single process (Node.js) ───────┐
166
+ browser ──HTTP──▶│ static serve (dist/web) REST API SSE
124
167
  (React SPA) ◀SSE─│ server/static.ts server/app.ts events │──watch/read/write──▶ .kanban/
125
- │ chokidar watcher (server/watcher) │ (プレーンテキスト)
168
+ │ chokidar watcher (server/watcher) │ (plain text)
126
169
  └────────────────────────────────────────────┘ ▲
127
- AI / 人間が直接編集 or CLI
170
+ AI / human edit directly or via the CLI
128
171
  ```
129
172
 
130
173
  ```
131
174
  aizuchi/
132
- ├── bin/aizuchi.ts # CLI エントリ(init / serve / task / overview)。dist/bin/aizuchi.js にコンパイル
133
- ├── server/ # Hono アプリ・watcher・静的配信・ファイル I/O
134
- │ ├── app.ts # REST APIboard / tasks / events)+ Host 検証 + onError
135
- │ ├── overview.ts # 複数 .kanban の read-only 集約(aizuchi overview・既定ポート 5152
136
- │ ├── board.ts # .kanban 読込・zod 検証・警告生成
137
- │ ├── watcher.ts # chokidar(debounce 200ms)→ SSE
138
- │ ├── static.ts # ビルド済み SPA の配信(トラバーサル拒否)
175
+ ├── bin/aizuchi.ts # CLI entry (init / serve / task / overview). Compiled to dist/bin/aizuchi.js
176
+ ├── server/ # Hono app, watcher, static serving, file I/O
177
+ │ ├── app.ts # REST API (board / tasks / events) + Host validation + onError
178
+ │ ├── overview.ts # read-only aggregation of multiple .kanban (aizuchi overview, default port 5152)
179
+ │ ├── board.ts # .kanban loading, zod validation, warning generation
180
+ │ ├── watcher.ts # chokidar (200ms debounce) → SSE
181
+ │ ├── static.ts # serving the built SPA (traversal rejected)
139
182
  │ └── lib/ # task-file / pinpoint / id / fs-safe / time / git / trash / task-ops
140
- ├── web/ # Vite + React SPA(ビルド成果物を dist/web に同梱)
183
+ ├── web/ # Vite + React SPA (build output bundled into dist/web)
141
184
  │ └── src/ # App / useBoard / components / lib
142
- ├── shared/ # task / config zod スキーマ・型・行 LCS diff(server / web 共有)
143
- ├── templates/ # config.json / claude-rules.mdinit が生成)
144
- └── docs/ # decisions.md ほか
185
+ ├── shared/ # zod schemas, types, and line LCS diff for task / config (shared by server / web)
186
+ ├── templates/ # config.json / claude-rules.md (generated by init)
187
+ └── docs/ # decisions.md and others
145
188
  ```
146
189
 
147
- ## データ仕様(抜粋)
190
+ ## Data model (excerpt)
148
191
 
149
- - タスク = `.kanban/tasks/<ID>.md`(1 タスク 1 ファイル、**ID=ファイル名**)。
192
+ - A task = `.kanban/tasks/<ID>.md` (one task per file, **ID = filename**).
150
193
  - frontmatter: `id` / `title` / `status` / `assignee` / `created_by` / `priority` / `labels` /
151
- `blocked_type` / `blocked_reason` / `depends_on` / `milestone` / `created` / `updated`。
152
- - `status`: `proposed` / `backlog` / `todo` / `in_progress` / `pending` / `done`。
153
- - 日時は ISO 8601(タイムゾーン付き、例: `2026-06-10T10:00:00+09:00`)。UTC へ変換しません。
154
- - 設定は `.kanban/config.json`(プロジェクト名・ID 接頭辞・ポート・メンバー・カラム・マイルストーン・
155
- タスクテンプレート・保存済みビュー・停滞閾値・言語 ほか)。設定ゼロでも既定値で動作します。
156
-
157
- 各フィールドの enum 値・必須条件など完全な frontmatter スキーマは、`aizuchi init` が `CLAUDE.md` に追記する運用規約(frontmatter スキーマ表)に記載されます。init 後すぐ手元で確認できます。
158
-
159
- ## 手動確認チェックリスト(受け入れ基準 / DoD)
160
-
161
- `npm run build` 後に対象プロジェクトで `node dist/bin/aizuchi.js init` → `... serve` を実行し、ブラウザで確認します。
162
-
163
- - [ ] **init**: `node bin/aizuchi.js init` で `.kanban/`(config.json・tasks/・archive/・README)が生成され、
164
- CLAUDE.md にマーカーコメント区切りで運用規約が追記される(既存があれば末尾追記、再実行は同区間のみ置換、
165
- 既存 `.kanban/` があれば安全に中断)。
166
- - [ ] **serve**: `node bin/aizuchi.js serve` で `http://127.0.0.1:5151` にボードが表示される。127.0.0.1 以外に
167
- バインドしない。
168
- - [ ] **起票**: 追加モーダルからタスクを作成すると `tasks/TASK-00X.md` が生成され、ID が連番になる
169
- (起票者は members から選択、その ID `created_by` に入る)。
170
- - [ ] **D&D**: カラム移動で frontmatter `status` / `updated` だけが変わる(`git diff` で本文保全を確認)。
171
- - [ ] **ライブ反映**: エディタで直接タスクファイルを書き換えると 1 秒以内にボードへ反映される。
172
- - [ ] **保留表示**: pending カードに保留種別(色分けバッジ)と理由が表示され、in_progress カードに
173
- 「最終更新 ◯分前」が表示される。
174
- - [ ] **警告**: frontmatter を壊したファイルを置くと警告バナーに表示され、ボード自体は落ちない。
175
- - [ ] **詳細**: タスク詳細でプレビュー・編集・作業ログのタイムラインが使える。保存時に外部変更と競合したら
176
- 上書き確認(差分提示)が出る。
177
- - [ ] **アーカイブ / ごみ箱**: done をアーカイブ アーカイブビューから復元できる。破壊的書換の前に
178
- `.kanban/.trash/` へ退避され、ごみ箱から復元できる。
179
- - [ ] **ネットワーク**: 動作中、外部へのネットワーク通信が一切発生しない。
180
- - [ ] **終了**: ブラウザでボードを開いたまま `Ctrl+C` serve が速やかに終了する。
181
- - [ ] **再現性**: README の手順だけで第三者が環境構築〜起動まで再現できる。
182
-
183
- ## アクセシビリティ
184
-
185
- キーボードとスクリーンリーダーでの操作を考慮しています。
186
-
187
- - **キーボード操作**: フォームやボタンは Tab で移動・操作できます。コマンドパレット(⌘K / Ctrl+K)から
188
- ビュー切替・タスク検索ジャンプ・起票・設定をキーボードだけで実行できます。
189
- - **キーボードでのカード移動**: カードにフォーカスして **Space で掴み**、矢印キーでカラム間を移動、
190
- 再度 Space で確定(Enter はカード詳細を開く)。ポインタ D&D と同じ status 更新経路・Pending 行きは保留ダイアログを起動。
191
- - **モーダル**: 開いた時に内部へフォーカスを移し、Tab / Shift+Tab はダイアログ内をループ(focus trap)、
192
- Escape で閉じ、閉じたら元の要素へフォーカスを戻します。
193
- - **ARIA / 役割**: カラムやカード、ツールバー、ダイアログに `role` と `aria-label` を付与しています。
194
-
195
- ## 技術スタック
194
+ `blocked_type` / `blocked_reason` / `depends_on` / `milestone` / `created` / `updated`.
195
+ - `status`: `proposed` / `backlog` / `todo` / `in_progress` / `pending` / `done`.
196
+ - Timestamps are ISO 8601 (with timezone, e.g. `2026-06-10T10:00:00+09:00`). They are not converted
197
+ to UTC.
198
+ - Configuration lives in `.kanban/config.json` (project name, ID prefix, port, members, columns,
199
+ milestones, task template, saved views, stale thresholds, language, and more). It works on
200
+ defaults with zero configuration.
201
+
202
+ The complete frontmatter schema — including each field's enum values and required conditions — is
203
+ recorded in the operating rules (the frontmatter schema table) that `aizuchi init` appends to
204
+ `CLAUDE.md`. You can check it right after init.
205
+
206
+ ## Manual verification checklist (acceptance criteria / DoD)
207
+
208
+ After `npm run build`, run `node dist/bin/aizuchi.js init` → `... serve` in the target project and
209
+ verify in the browser.
210
+
211
+ - [ ] **init**: `node bin/aizuchi.js init` generates `.kanban/` (config.json, tasks/, archive/,
212
+ README) and appends the operating rules to CLAUDE.md inside marker comments (append at the end
213
+ if one exists, re-run replaces only that section, stop safely if `.kanban/` already exists).
214
+ - [ ] **serve**: `node bin/aizuchi.js serve` shows the board at `http://127.0.0.1:5151`. It does not
215
+ bind to anything other than 127.0.0.1.
216
+ - [ ] **create**: creating a task from the add modal generates `tasks/TASK-00X.md` with a sequential
217
+ ID (the creator is chosen from members, and that ID goes into `created_by`).
218
+ - [ ] **drag & drop**: moving between columns changes only the `status` / `updated` frontmatter
219
+ (confirm the body is preserved with `git diff`).
220
+ - [ ] **live updates**: editing a task file directly in your editor is reflected on the board within
221
+ a second.
222
+ - [ ] **block display**: a pending card shows the block kind (color-coded badge) and reason, and an
223
+ in_progress card shows "last updated N minutes ago".
224
+ - [ ] **warnings**: placing a file with broken frontmatter shows up in the warning banner without
225
+ crashing the board.
226
+ - [ ] **detail**: the task detail offers preview, editing, and a work-log timeline. If a save
227
+ conflicts with an external change, an overwrite confirmation (with a diff) appears.
228
+ - [ ] **archive / trash**: archive a done task → restore it from the archive view. Before a
229
+ destructive rewrite the old version is backed up to `.kanban/.trash/` and can be restored from
230
+ the trash.
231
+ - [ ] **network**: no outbound network communication occurs at all while running.
232
+ - [ ] **shutdown**: with the board open in the browser, `Ctrl+C` stops serve promptly.
233
+ - [ ] **reproducibility**: a third party can go from setup to launch using only this README.
234
+
235
+ ## Accessibility
236
+
237
+ Keyboard and screen-reader operation is taken into account.
238
+
239
+ - **Keyboard operation** — forms and buttons can be reached and operated with Tab. The command
240
+ palette (⌘K / Ctrl+K) lets you switch views, jump to a task by search, create a task, and open
241
+ settings entirely from the keyboard.
242
+ - **Moving cards with the keyboard** — focus a card, **grab it with Space**, move between columns
243
+ with the arrow keys, and confirm with Space again (Enter opens the card detail). It uses the same
244
+ status-update path as pointer drag & drop, and moving to Pending triggers the block dialog.
245
+ - **Modals** — focus moves inside on open, Tab / Shift+Tab loop within the dialog (focus trap),
246
+ Escape closes it, and focus returns to the original element after closing.
247
+ - **ARIA / roles** — columns, cards, the toolbar, and dialogs carry `role` and `aria-label`.
248
+
249
+ ## Tech stack
196
250
 
197
251
  Node.js 20.1+ / Hono + @hono/node-server / chokidar / SSE / React 18 + TypeScript + Vite /
198
- @dnd-kit / react-markdown + remark-gfm / gray-matter / zod / CSS Modules / vitest
252
+ @dnd-kit / react-markdown + remark-gfm / gray-matter / zod / CSS Modules / vitest.
253
+
254
+ ### Dependencies added beyond the core stack, and why
255
+
256
+ - **@hono/node-server** — runs Hono on the Node runtime and statically serves the built SPA.
257
+ - **js-yaml (+ @types/js-yaml)** — injects the `JSON_SCHEMA` engine into gray-matter so that
258
+ timestamps with `+09:00` round-trip as strings instead of being turned into `Date` (avoids the
259
+ transitive dependency on gray-matter's bundled, older 3.x).
260
+ - **@vitejs/plugin-react** — enables React (JSX / Fast Refresh) in Vite.
261
+ - **@dnd-kit/utilities** — part of the @dnd-kit family; assists with the D&D CSS transform.
262
+ - **tsx** — runs the TypeScript server directly during development (production uses the compiled JS
263
+ in dist).
264
+ - **typescript / vitest / @types/\*** — the foundation for type safety and testing.
199
265
 
200
- ### 主要スタックに追加した依存とその理由
266
+ ## Repository
201
267
 
202
- - **@hono/node-server** Hono を Node ランタイムで起動し、ビルド済み SPA を静的配信するため
203
- - **js-yaml (+ @types/js-yaml)** — gray-matter に `JSON_SCHEMA` エンジンを注入し、`+09:00` 付き日時を Date 化せず文字列のまま往復させるため(gray-matter 内蔵の旧 3.x に transitive 依存しない)
204
- - **@vitejs/plugin-react** — Vite で React(JSX / Fast Refresh)を使うため
205
- - **@dnd-kit/utilities** — @dnd-kit ファミリ。D&D の CSS transform 補助
206
- - **tsx** — 開発時に TypeScript サーバーを直接実行するため(本番は dist のコンパイル済み JS を使用)
207
- - **typescript / vitest / @types/\*** — 型安全とテストの基盤
268
+ - npm package: `aizuchi`
269
+ - Source & issues: <https://github.com/megaphone-tokyo/AIzuchi>
208
270
 
209
- ## ライセンス
271
+ ## License
210
272
 
211
273
  MIT
@@ -4,7 +4,7 @@ import path from 'node:path';
4
4
  import readline from 'node:readline';
5
5
  import { fileURLToPath, pathToFileURL } from 'node:url';
6
6
  import { serve } from '@hono/node-server';
7
- import { DEFAULT_OVERVIEW_PORT, DEFAULT_PORT } from '../shared/schema.js';
7
+ import { DEFAULT_OVERVIEW_PORT, DEFAULT_PORT, PORT_FALLBACK_ATTEMPTS } from '../shared/schema.js';
8
8
  import { analyzeCriticalPath } from '../shared/critical-path.js';
9
9
  import { createApp } from '../server/app.js';
10
10
  import { loadArchive, loadBoard, loadConfig } from '../server/board.js';
@@ -16,7 +16,7 @@ import { startWatcher } from '../server/watcher.js';
16
16
  /**
17
17
  * AIzuchi CLI (要件 §4.3)。
18
18
  * - init : .kanban/ を生成し、CLAUDE.md へ運用規約をマーカー区切りで追記する (N-9: 冪等)
19
- * - serve: 127.0.0.1 限定でボードを起動する (--port > config > 5151)
19
+ * - serve: 127.0.0.1 限定でボードを起動する (--port > config > 5151。--port 未指定なら使用中時に次の空きへ自動フォールバック)
20
20
  * - overview: 複数 .kanban の read-only 集約を起動する (--port > 5152、波 VII)
21
21
  */
22
22
  export const MARKER_BEGIN = '<!-- aizuchi:begin -->';
@@ -159,28 +159,65 @@ export async function runServe(options) {
159
159
  // .kanban が symlink / 不在: cleanup を skip (containment 外の削除はしない)
160
160
  }
161
161
  const { config } = await loadConfig(cwd);
162
- const port = options.port ?? config.port ?? DEFAULT_PORT;
162
+ // --port を明示したらそのポートに固定 (使用中ならエラー終了)。明示しない場合は
163
+ // config.port → 既定 5151 を起点に、使用中なら順に次の空きへフォールバックする
164
+ // (複数プロジェクトを同時に serve してもポート衝突で止まらないように)。
165
+ // 起点は毎回同じで状態を保存しないため、次回起動時に起点が空いていれば必ず起点で起動する。
166
+ const explicitPort = options.port !== undefined;
167
+ const basePort = options.port ?? config.port ?? DEFAULT_PORT;
168
+ const maxAttempts = explicitPort ? 1 : PORT_FALLBACK_ATTEMPTS;
163
169
  const bus = createEventBus();
164
170
  const { app } = createApp({ projectRoot: cwd, bus });
165
171
  attachStaticAssets(app, path.join(packageRoot(), 'dist', 'web'));
166
172
  const watcher = startWatcher({ kanbanDir, bus });
167
- const { server, boundPort } = await new Promise((resolve, reject) => {
168
- // 127.0.0.1 限定でバインドする (N-1)。0.0.0.0 や LAN IP への変更手段は提供しない。
173
+ // 1 ポートぶんの listen 試行。成功で {server, boundPort}、EADDRINUSE 'busy'、その他は reject
174
+ // 127.0.0.1 限定でバインドする (N-1)。フォールバックで変えるのはポート番号のみ・host は固定。
175
+ const tryListen = (candidate) => new Promise((resolve, reject) => {
176
+ let settled = false;
169
177
  // info.port は実際にバインドされたポート (port=0 のときは OS が選んだ番号が入る)
170
- const created = serve({ fetch: app.fetch, port, hostname: '127.0.0.1' }, (info) => resolve({ server: created, boundPort: info.port }));
178
+ const created = serve({ fetch: app.fetch, port: candidate, hostname: '127.0.0.1' }, (info) => {
179
+ settled = true;
180
+ resolve({ server: created, boundPort: info.port });
181
+ });
171
182
  created.on('error', (error) => {
183
+ if (settled)
184
+ return; // listen 成功後の実行時エラーはここでは扱わない
172
185
  if (error.code === 'EADDRINUSE') {
173
- // 自動でポートを変えず、明確なエラーで終了する (決定済み)
174
- reject(new Error(`ポート ${port} は使用中です。--port <番号> か .kanban/config.json の port で変更してください`));
186
+ try {
187
+ created.close();
188
+ }
189
+ catch {
190
+ /* バインド失敗した server の close 失敗は無視 */
191
+ }
192
+ resolve('busy');
175
193
  }
176
194
  else {
177
195
  reject(error);
178
196
  }
179
197
  });
180
- }).catch(async (error) => {
181
- await watcher.close();
182
- throw error;
183
198
  });
199
+ let listened = null;
200
+ for (let i = 0; i < maxAttempts; i++) {
201
+ const result = await tryListen(basePort + i).catch(async (error) => {
202
+ await watcher.close();
203
+ throw error; // EADDRINUSE 以外 (権限不足など) は即終了
204
+ });
205
+ if (result !== 'busy') {
206
+ listened = result;
207
+ break;
208
+ }
209
+ }
210
+ if (listened === null) {
211
+ await watcher.close();
212
+ if (explicitPort) {
213
+ throw new Error(`ポート ${basePort} は使用中です。別の --port <番号> を指定するか、起動中の AIzuchi を終了してください`);
214
+ }
215
+ throw new Error(`空きポートが見つかりませんでした (${basePort}〜${basePort + maxAttempts - 1} はすべて使用中)。--port <番号> で指定してください`);
216
+ }
217
+ const { server, boundPort } = listened;
218
+ if (!explicitPort && boundPort !== basePort) {
219
+ log(`ポート ${basePort} は使用中のため ${boundPort} で起動しました`);
220
+ }
184
221
  log(`AIzuchi: http://127.0.0.1:${boundPort} (project: ${config.projectName})`);
185
222
  log('終了するには Ctrl+C');
186
223
  return {