@indigo-gr/claude-code-station 0.4.1 → 0.5.0

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.
@@ -1,47 +1,73 @@
1
1
  # repos.yml スキーマ設計
2
2
 
3
- > ccs v0.2.0 — リポジトリ定義ファイルのフォーマット仕様
3
+ > `version: 1` の形 — ccs が読むリポジトリ定義ファイルの形と、ほかの道具との約束(契約)
4
+
5
+ 本体の正は `bin/ccs-config.ts`(読む・検証する)と `bin/ccs-init.ts`(`ccs init` で書き足す)。この資料と本体が食い違ったら本体に合わせて資料を直す。
4
6
 
5
7
  ## 配置
6
8
 
7
- - パス: `~/.config/ccs/repos.yml`
8
- - 初回 `ccs` 実行時、存在しなければテンプレートと `README.md` を自動生成
9
+ - パス: `$XDG_CONFIG_HOME/ccs/repos.yml`(`XDG_CONFIG_HOME` が無ければ `~/.config/ccs/repos.yml`)
10
+ - ccs を起動するたびに置き場を確かめ、無ければ作る(フォルダは 0700)。`repos.yml` と `README.md` が無ければテンプレートから 0600 で作る
11
+ - 機械で読む口(`ccs doctor`・`ccs list --json` など・`machine-interface.md`)は置き場も `repos.yml` も作らない。`ccs repo add` だけは、`repos.yml` が無い時に最小の形で作る
12
+ - `ccs init` も同じ置き場を作り、場所を出して終わる。`ccs init --auto-discover` は `$HOME` の下の git のリポを探し、選んだ物を `repos.yml` に書き足す(下の「ccs が書く時」)
9
13
 
10
14
  ## トップレベル構造
11
15
 
12
16
  ```yaml
13
- version: 1 # スキーマバージョン(必須、現在 1)
14
- defaults: # 全リポジトリのデフォルト値(任意)
15
- command: "claude"
16
- repos: # リポジトリ定義配列(必須、1件以上)
17
- - name: ClaudeCode
18
- path: ~/.claude
19
- description: Claude Code設定
17
+ version: 1 # スキーマのバージョン(必須・整数の 1 だけ)
18
+ defaults: # 全リポジトリの既定(任意)
19
+ command: "claude" # 起動コマンドの既定
20
+ ui: simple # 一覧の見た目(classic / simple)
21
+ terminal: terminal # ccs open --new-window で開く端末のアプリ(v0.5.0〜)
22
+ update_check: false # 更新の知らせを止める(v0.5.0〜)
23
+ groups_dir: ~/groups # 外のグループの定義を読むフォルダ(v0.5.0〜・既定は off)
24
+ repos: # リポジトリ定義の配列(必須・1 件以上)
25
+ - name: Example Project
26
+ path: ~/projects/example
27
+ description: 見本の項目
20
28
  ...
21
29
  ```
22
30
 
31
+ | キー | 型 | 必須 | 既定 | 説明 |
32
+ |---|---|:---:|---|---|
33
+ | `version` | integer | ✅ | — | `1` だけ受け付ける(文字列の `"1"` はエラー) |
34
+ | `defaults` | object | — | `{}` | 下のキー。中の未知のキーは警告なしで無視する(前のバージョンの ccs が新しいキーで壊れないための前方互換) |
35
+ | `defaults.command` | string | — | `CCS_CMD` → `CCR_CMD` → `"claude"` | `command` を書いていない項目の起動コマンド(優先順は下の「環境変数との優先順位」) |
36
+ | `defaults.ui` | string | — | `"classic"` | 一覧とプレビューの見た目。`classic` か `simple`。ほかの値はエラー。空(YAML の null)は未指定。`simple` は fzf 0.61 以上が要り、古い fzf では `classic` で開く。`--ui=` と `CCS_UI` が勝つ |
37
+ | `defaults.terminal` | string | — | 未指定 | v0.5.0〜。`ccs open --new-window` で開く端末のアプリ。`terminal`(macOS のターミナル)だけ(iTerm2 は確かめてから足す)。ほかの値はエラー。空(YAML の null)は未指定。macOS だけで使う(`machine-interface.md` の 4.5) |
38
+ | `defaults.update_check` | boolean | — | `true` | v0.5.0〜。`false` で更新の確認と知らせを止める(`CCS_NO_UPDATE_CHECK` と同じ)。真偽値だけ(`"false"` などの文字列はエラー) |
39
+ | `defaults.groups_dir` | string | — | 未指定(off) | v0.5.0〜。外のグループの定義(`*.json`)を読むフォルダ。`~` を展開する。`$HOME` の下・シェルのメタ文字不可。ccs はこのフォルダに書かない(`machine-interface.md` の 5 章) |
40
+ | `repos` | array | ✅ | — | 1 件以上の項目(下の表) |
41
+
42
+ トップレベルの未知のキーは、標準エラーに `[ccs] unknown key "<key>" in top-level (ignored)` を出して無視する。
43
+
23
44
  ## `repos[]` エントリのフィールド
24
45
 
25
46
  | フィールド | 型 | 必須 | デフォルト | 説明 |
26
47
  |---|---|:---:|---|---|
27
- | `name` | string | ✅ | — | 一意のキー兼、既定の表示名(fzf行に出る、日本語可)。`label` があれば新規起動行とプレビューは `label` を出す。過去セッションの行は常に `name` |
28
- | `path` | string | ✅* | — | リポジトリのフルパス。`~` 展開あり |
29
- | `description` | string | — | `""` | プレビュー補助情報 |
30
- | `command` | string | — | `defaults.command` or `claude` | 起動コマンド。特殊な場合は丸ごと上書き |
31
- | `cwd` | string | — | `path` | 起動時の作業ディレクトリ(通常は `path` と同じ) |
32
- | `tags` | string[] | — | `[]` | 絞り込み用タグ(例: `["work", "backend"]`) |
33
- | `disabled` | bool | — | `false` | true ならリストから除外 |
34
- | `scan` | bool | — | `true` | false なら状態走査をスキップ(非git含む) |
35
- | `icon` | string | — | `📁` | 表示アイコン(絵文字1文字推奨) |
36
- | `launch` | bool | — | `true` | false なら表示だけのグループ見出し(行の種類 `group:<name>`)。Enter で起動しない・バッジなし・状態走査しない。`command`/`cwd` は使われない。`path` の中のリポがこの下に並ぶ。真偽値のみ(`"false"` などの文字列はエラー) |
37
- | `label` | string | — | `""` | 新規起動行・`‹親›` の表示・プレビュー見出しに `name` の代わりに出す名前。表示専用(シェルメタ文字は可、制御文字は表示時に除去)。空・空白だけなら `name` |
38
- | `custom` | object | — | `{}` | 外部システム連携情報。任意のキー/値ペア(後述) |
39
-
40
- \* `path` は `command` に `cwd:` が含まれる特殊ケースを除き必須。`launch: false` の項目では常に必須(無いとエラー)。
48
+ | `name` | string | ✅ | — | 一意のキー兼、既定の表示名(fzf の行に出る・日本語可)。空はエラー。`label` があれば新規起動の行・`‹親›` の表示・プレビューの見出しは `label` を出す。過去セッションの行は常に `name` |
49
+ | `path` | string | ✅* | `""` | リポジトリのパス。先頭の `~` を展開する。`$HOME` の下に限る |
50
+ | `description` | string | — | `""` | プレビューと一覧の補助の文。空(YAML の null)は未指定(v0.5.0〜。前は文字列の `"null"` になった) |
51
+ | `command` | string | — | `defaults.command` → `CCS_CMD` → `CCR_CMD` → `"claude"` | 起動コマンド。特殊な場合は丸ごと上書き |
52
+ | `cwd` | string | — | `path` | 起動時の作業ディレクトリ(通常は書かない)。`~` の展開と `$HOME` の下の制限は `path` と同じ |
53
+ | `tags` | string[] | — | `[]` | プレビューに出すタグ(例: `["work", "backend"]`)。文字列の配列以外はエラー |
54
+ | `disabled` | bool | — | `false` | true なら一覧に出さず、状態も走査しない。真偽値のみ(v0.5.0〜。`"false"` などの文字列はエラー) |
55
+ | `scan` | bool | — | `true` | false なら状態の走査をしない(git でないフォルダや、Claude Code を起こさない項目)。真偽値のみ(v0.5.0〜。文字列はエラー) |
56
+ | `icon` | string | — | `📁` | 行に出すアイコン(絵文字 1 文字を勧める)。空(YAML の null)は未指定(v0.5.0〜) |
57
+ | `launch` | bool | — | `true` | false なら表示だけのグループ見出し(行の種類 `group:<name>`)。Enter で起動しない・バッジなし・状態を走査しない。`command`/`cwd` は使われない。`path` の中のリポがこの下に並ぶ。真偽値のみ(`"false"` などの文字列はエラー) |
58
+ | `label` | string | — | `""` | 新規起動の行・`‹親›` の表示・プレビューの見出しに `name` の代わりに出す名前。表示専用(シェルのメタ文字は可、制御文字は表示の時に除く)。空(YAML の null)は未指定。空・空白だけなら `name` を出す |
59
+ | `lead` | bool | — | `false` | true ならグループの統括。同じ親の下の兄弟の中で一番上に並ぶ(トップレベルの並びは変えない)。`ui: simple` では 👑 で出る。真偽値のみ(`"true"` などの文字列はエラー) |
60
+ | `custom` | object | — | `{}` | 外部システム連携の情報。任意のキーと値(後述)。ほかの道具が自分の値を置く場所 |
61
+
62
+ \* ccs の検証が `path` を必ず求めるのは `launch: false` の項目だけ(無いとエラー)。契約では、ほかの項目でも `path` を必ず書く(ほかの道具は `path` の無い項目を読めない)。`version: 1` の間は、`path` を省いた `launch: true` の項目もエラーにせず今のまま読む(今の動き: 読む時は何も言わず、起動の時に「`$HOME` の外」の警告を出して、いまいるフォルダで開く)。
63
+
64
+ - `repos[i]` がマッピングでなければエラー。項目の中の未知のキーは、標準エラーに `[ccs] unknown key "<key>" in repos[<i>] (ignored)` を出して無視する
65
+ - `disabled`・`scan` は真偽値で書く(v0.4 までの本体は値を真偽に丸め、`"false"` と書くと true になった。v0.5.0 から `launch`・`lead` と同じくエラーにする)
66
+ - `description`・`icon` は文字列で書く(本体は値を文字列にする。YAML の null は v0.5.0 から未指定として扱う)
41
67
 
42
68
  ### `custom` フィールド(外部システム連携)
43
69
 
44
- ユーザー固有の連携情報を自由に保持できる。プレビューペインで「連携バッジ」として表示され、未入力なら表示しない。
70
+ ユーザー固有の連携情報を自由に保持できる。プレビューに「連携バッジ」として出し、無い・空なら出さない。
45
71
 
46
72
  **よくある例:**
47
73
 
@@ -70,78 +96,97 @@ repos:
70
96
  ```
71
97
 
72
98
  **仕様:**
73
- - `custom` の値は文字列・数値・bool・配列・ネストobject 何でも可(JSON保存)
74
- - 既知キー(後述の組み込み連携)は専用の表示ロジックでバッジ化
75
- - 未知キーは `key: value` の形でそのまま表示
99
+ - `custom` の値は文字列・数値・bool・配列・入れ子の object 何でも可(JSON にして state.db に保存)
100
+ - 既知キー(下の表)は専用の表示でバッジにする
101
+ - 未知キーは「Other」の下に `key: value` の形で出す(値が null なら出さない)
76
102
 
77
- **組み込み既知キー(v0.2.0):**
103
+ **組み込み既知キー:**
78
104
 
79
105
  | キー | 表示 | 備考 |
80
106
  |---|---|---|
81
- | `plane_project_id` | Plane バッジ | `plane_url` あればURL併記 |
82
- | `plane_url` | — | バッジリンク用 |
107
+ | `plane_project_id` | Plane バッジ | |
108
+ | `plane_url` | — | 補助のキー(単独では出さない) |
83
109
  | `attio_workspace` | Attio バッジ | |
84
110
  | `notion_db` | Notion バッジ | |
85
111
  | `linear_team` | Linear バッジ | |
86
- | `slack_channel` | Slack バッジ | `#` 自動付与 |
112
+ | `slack_channel` | Slack バッジ | `#` を自動で付ける |
87
113
  | `github_repo` | GitHub バッジ | `owner/repo` 形式 |
88
114
  | `figma_file` | Figma バッジ | URL でも ID でも可 |
89
115
 
90
- **未知キーの扱い:**
91
- - そのまま `key: value` 形式で「Other Integrations」セクションに表示
92
- - 将来需要が高まったキーは組み込み既知キーに昇格
93
-
94
- **バリデーション:**
95
- - `custom` がobjectでない → エラー
96
- - 中身の型は問わない(ユーザー責任)
97
- - シークレット混入注意(APIキー等は書かない、URL/IDのみ推奨)
116
+ **検証:**
117
+ - `custom` が object でない → エラー
118
+ - JSON にして 64,000 文字を超える → エラー
119
+ - 中身の型は問わない(ユーザーの責任)
120
+ - 秘密の値を混ぜない(API キーなどは書かない。URL・ID だけを勧める)
98
121
 
99
122
  ## バリデーションルール
100
123
 
101
- | ルール | エラー例 |
102
- |---|---|
103
- | `version` は整数、現在サポートは `1` のみ | `unsupported version: 2` |
104
- | `name` はユニーク | `duplicate name: "ClaudeCode"` |
105
- | `path` 存在チェック | `path not found: ~/projects/foo`(警告扱い、disabled 推奨) |
106
- | `path` は `$HOME` 配下必須 | `path outside $HOME: /etc/foo`(セキュリティ) |
107
- | `name` に shell metachar 不可 (`;&\|<>$\`"'\\` + 全制御文字 = `SHELL_METACHARS`、audit NEW-3。`path`/`cwd`/`command` と同一ポリシー) | `~/.config/ccs/repos.yml: repos[0].name contains shell metacharacter(s) or control char(s): "..."` |
108
- | `command` に shell metachar 不可 (`;&\|<>$\`"'\\` + 制御文字) | `~/.config/ccs/repos.yml: repos[0].command contains shell metacharacter(s): "claude;..."` |
109
- | `defaults.command`(CCS_CMD/CCR_CMD 由来含む)もロード時に同検証(レビューA-6) | `~/.config/ccs/repos.yml: defaults.command (resolved from defaults.command / CCS_CMD / CCR_CMD) contains shell metacharacter(s): "..."` |
110
- | `custom` のJSONサイズ 64KB 上限 | `~/.config/ccs/repos.yml: repos[0].custom exceeds 64KB JSON size limit` |
111
- | `disabled: true` の場合 scan/command 無視 | — |
112
- | `launch` は真偽値のみ(`Boolean()` で丸めない: `"false"` が true になるのを防ぐ) | `~/.config/ccs/repos.yml: repos[0].launch must be true or false (got "false")` |
113
- | `launch: false` は `path` 必須 | `~/.config/ccs/repos.yml: repos[0].path is required when launch is false` |
114
- | `label` は文字列のみ(空の `label:` = YAML の null は未指定扱い) | `~/.config/ccs/repos.yml: repos[0].label must be a string` |
124
+ エラーは `ConfigError` で、文の先頭に `repos.yml` のフルパスが付く(下の表では `<repos.yml>` と書く)。警告は標準エラーに出し、読むのは続ける。
125
+
126
+ | ルール | 種類 | 出る文の例 |
127
+ |---|---|---|
128
+ | トップレベルはマッピング | エラー | `<repos.yml>: top-level must be a mapping/object` |
129
+ | YAML として読めること | エラー | `<repos.yml>: YAML parse error: ...` |
130
+ | `version` は整数の `1` だけ | エラー | `<repos.yml>: unsupported version: 2, only 1 is supported` |
131
+ | `defaults` は object | エラー | `<repos.yml>: defaults must be an object` |
132
+ | `defaults.command` は文字列 | エラー | `<repos.yml>: defaults.command must be a string` |
133
+ | `defaults.ui` は `classic` か `simple` | エラー | `<repos.yml>: defaults.ui must be one of classic / simple (got "fancy")` |
134
+ | `defaults.terminal` は `terminal` だけ(v0.5.0〜) | エラー | `<repos.yml>: defaults.terminal must be one of terminal (got "x")` |
135
+ | `defaults.update_check` は真偽値のみ(v0.5.0〜) | エラー | `<repos.yml>: defaults.update_check must be true or false (got "false")` |
136
+ | `defaults.groups_dir` は文字列・`$HOME` の下・シェルのメタ文字不可(v0.5.0〜) | エラー | `<repos.yml>: defaults.groups_dir "/etc" is outside $HOME (security)` |
137
+ | 解決した既定のコマンド(`defaults.command` / `CCS_CMD` / `CCR_CMD` 由来)にシェルのメタ文字不可 | エラー | `<repos.yml>: defaults.command (resolved from defaults.command / CCS_CMD / CCR_CMD) contains shell metacharacter(s): "..."` |
138
+ | `repos` は 1 件以上の配列 | エラー | `<repos.yml>: repos must be a non-empty array` |
139
+ | `name` は空でない文字列 | エラー | `<repos.yml>: repos[0].name is required and must be a non-empty string` |
140
+ | `name` にシェルのメタ文字・制御文字不可(`SHELL_METACHARS`。`path`/`cwd`/`command` と同じ) | エラー | `<repos.yml>: repos[0].name contains shell metacharacter(s) or control char(s): "..."` |
141
+ | `name` は一意 | エラー | `<repos.yml>: duplicate name "foo" at indexes [0, 2]` |
142
+ | `launch` は真偽値のみ | エラー | `<repos.yml>: repos[0].launch must be true or false (got "false")` |
143
+ | `launch: false` は `path` 必須 | エラー | `<repos.yml>: repos[0].path is required when launch is false` |
144
+ | `path`・`cwd`・`command` は文字列 | エラー | `<repos.yml>: repos[0].path must be a string` |
145
+ | `path`・`cwd` は `$HOME` の下(書いたままの形と、実在する時はシンボリックリンクを解いた先の両方) | エラー | `<repos.yml>: repos[0].path "/etc/foo" is outside $HOME (security)` |
146
+ | `path`・`cwd`(展開した後)・`command`(継いだ値を含む)にシェルのメタ文字不可 | エラー | `<repos.yml>: repos[0].command contains shell metacharacter(s): "claude;..."` |
147
+ | `path` が無い(`disabled: true` の時は確かめない) | 警告 | `[ccs] path not found: ~/projects/foo (repos[0] "foo") — set disabled: true to silence` |
148
+ | `label` は文字列のみ(空の `label:` = YAML の null は未指定) | エラー | `<repos.yml>: repos[0].label must be a string` |
149
+ | `lead` は真偽値のみ | エラー | `<repos.yml>: repos[0].lead must be true or false (got "true")` |
150
+ | `disabled`・`scan` は真偽値のみ(v0.5.0〜) | エラー | `<repos.yml>: repos[0].disabled must be true or false (got "false")` |
151
+ | `description`・`icon` の YAML の null は未指定(v0.5.0〜) | — | — |
152
+ | `tags` は文字列の配列 | エラー | `<repos.yml>: repos[0].tags must be an array of strings` |
153
+ | `custom` は object | エラー | `<repos.yml>: repos[0].custom must be an object` |
154
+ | `custom` は JSON にして 64,000 文字まで | エラー | `<repos.yml>: repos[0].custom exceeds the 64KB limit (measured as 64,000 characters of JSON; got 70000)`(v0.5.0〜。前の文は `exceeds 64KB JSON size limit (got 70000 bytes)` で、数えているのは文字数) |
155
+ | 未知のキー(トップレベルと `repos[i]`) | 警告 | `[ccs] unknown key "foo" in repos[0] (ignored)` |
156
+ | 未知のキー(`defaults` の中) | 黙って無視 | —(前方互換) |
157
+ | `disabled: true` の項目は一覧に出さず、走査も `path` の確認もしない | — | — |
158
+
159
+ `SHELL_METACHARS` は `` ;&|<>$`"'\ `` と、改行・CR を含む全部の制御文字(U+0000〜U+001F)。
115
160
 
116
161
  ## 例1: シンプル
117
162
 
118
163
  ```yaml
119
164
  version: 1
120
165
  repos:
121
- - name: ClaudeCode
122
- path: ~/.claude
123
- description: Claude Code設定
166
+ - name: dotfiles
167
+ path: ~/dotfiles
168
+ description: 手元の設定
124
169
  - name: My Project
125
170
  path: ~/projects/my-project
126
171
  description: Main development repository
127
172
  tags: [work]
128
173
  ```
129
174
 
130
- ## 例2: 特殊コマンド対応(CMS dev server起動など)
175
+ ## 例2: 特殊コマンド対応(CMS の dev server 起動など)
131
176
 
132
177
  ```yaml
133
178
  version: 1
134
179
  defaults:
135
180
  command: "claude"
136
181
  repos:
137
- - name: ClaudeCode
138
- path: ~/.claude
182
+ - name: dotfiles
183
+ path: ~/dotfiles
139
184
 
140
185
  - name: CMS (dev server)
141
186
  path: ~/sites/blog-cms
142
187
  command: "npm run develop"
143
188
  icon: "🚀"
144
- scan: false # Claude起動じゃないので状態走査不要
189
+ scan: false # Claude Code を起こさないので状態の走査は要らない
145
190
  tags: [dev-server]
146
191
 
147
192
  - name: personal-notes
@@ -150,12 +195,12 @@ repos:
150
195
  disabled: true # 今は使わない
151
196
  ```
152
197
 
153
- ## 例3: 1Passwordラッパー付き(CCR_CMD互換)
198
+ ## 例3: ラッパー経由の起動
154
199
 
155
200
  ```yaml
156
201
  version: 1
157
202
  defaults:
158
- command: "opr claude" # 全リポジトリで opr ラッパー経由
203
+ command: "my-wrapper claude" # 全リポジトリでラッパー経由
159
204
  repos:
160
205
  - name: Startup MVP
161
206
  path: ~/work/startup-mvp
@@ -163,17 +208,41 @@ repos:
163
208
  path: ~/projects/my-project
164
209
  ```
165
210
 
211
+ ## 例4: グループ見出しと統括
212
+
213
+ ```yaml
214
+ version: 1
215
+ defaults:
216
+ command: "claude"
217
+ ui: simple
218
+ repos:
219
+ - name: studio
220
+ path: ~/studio
221
+ launch: false # 見出しだけ。Enter で起動しない
222
+ label: Studio
223
+ - name: studio-hq
224
+ path: ~/studio/hq
225
+ lead: true # 兄弟の中で一番上・simple では 👑
226
+ label: HQ
227
+ - name: studio-web
228
+ path: ~/studio/web
229
+ ```
230
+
166
231
  ## 環境変数との優先順位
167
232
 
168
- `repos[].command` > `defaults.command` > `CCS_CMD` 環境変数 > `"claude"`
233
+ 起動コマンド: `repos[].command` > `defaults.command` > `CCS_CMD` 環境変数 > `CCR_CMD` 環境変数 > `"claude"`
169
234
 
170
- **設計意図**: per-repo の明示的指定(`command:` フィールド)が常に最優先。`CCS_CMD` env は「全リポジトリ共通のラッパー(例: `opr claude`)を `defaults.command` 未指定時に注入したい」用途のフォールバックとして機能する。CMS 起動のような特殊コマンドが env で踏み潰されるのを防ぐため、env を最弱に置く。
235
+ **設計意図**: 項目ごとの明示(`command:`)が常に最優先。`CCS_CMD` は「全リポジトリ共通のラッパー(例: `my-wrapper claude`)を、`defaults.command` が無い時に入れたい」用のフォールバック。CMS 起動のような特殊コマンドが環境変数で潰れないよう、環境変数を一番弱くする。
171
236
 
172
- ccr v0.1.3 の `CCR_CMD` は `CCS_CMD` にリネーム(移行ガイドで明記、CCR_CMD指定時は警告ログ + 暫定honor)。
237
+ 旧名の `CCR_CMD` は、`CCS_CMD` が無い時だけ使い、標準エラーに改名を勧める警告を 1 回出す。
173
238
 
174
239
  **Security note**: `CCS_CMD` / `CCR_CMD` env values are subject to the same shell metacharacter rejection as `command:` in YAML. If env-sourced value contains any forbidden character, `loadConfig()` throws `ConfigError` before launch.
175
240
 
176
- **未マッピングセッションへの適用(レビューA-8)**: repos.yml に登録されていない cwd のセッション(fzf 上で `❓` 表示)も、この優先順位の `defaults.command` 以降のチェーンに従う。scan 時に解決済みフォールバックが state.db の `meta.defaults_command` に保存され、ccs-list が RESUME 行の起動コマンドとして使用する(旧実装はハードコードの `"claude"` 固定だった)。
241
+ **登録の無いセッションへの適用**: `repos.yml` に登録されていない cwd のセッション(fzf 上で `❓` 表示)も、`defaults.command` から後の優先順に従う。走査の時に解決した既定が state.db の `meta.defaults_command` に保存され、一覧が過去セッションの行の起動コマンドに使う。
242
+
243
+ 見た目: `--ui=` フラグ > `CCS_UI` 環境変数 > `defaults.ui` > `classic`
244
+
245
+ 更新の確認: `CCS_NO_UPDATE_CHECK` が空でない → 止める > `defaults.update_check: false` → 止める > 確かめる(設定の `true` は環境変数の「止める」に勝たない)
177
246
 
178
247
  ## JSON Schema(抜粋)
179
248
 
@@ -187,7 +256,11 @@ ccr v0.1.3 の `CCR_CMD` は `CCS_CMD` にリネーム(移行ガイドで明
187
256
  "defaults": {
188
257
  "type": "object",
189
258
  "properties": {
190
- "command": { "type": "string" }
259
+ "command": { "type": "string" },
260
+ "ui": { "enum": ["classic", "simple", null] },
261
+ "terminal": { "enum": ["terminal", null] },
262
+ "update_check": { "type": "boolean" },
263
+ "groups_dir": { "type": "string", "pattern": "^[^;&|<>$`\"'\\\\\\u0000-\\u001f]+$" }
191
264
  }
192
265
  },
193
266
  "repos": {
@@ -197,26 +270,102 @@ ccr v0.1.3 の `CCR_CMD` は `CCS_CMD` にリネーム(移行ガイドで明
197
270
  "type": "object",
198
271
  "required": ["name"],
199
272
  "properties": {
200
- "name": { "type": "string", "pattern": "^[^\\t\\n\\\\]+$" },
273
+ "name": { "type": "string", "minLength": 1, "pattern": "^[^;&|<>$`\"'\\\\\\u0000-\\u001f]+$" },
201
274
  "path": { "type": "string" },
202
- "description": { "type": "string" },
275
+ "description": { "type": ["string", "null"] },
203
276
  "command": { "type": "string" },
204
277
  "cwd": { "type": "string" },
205
278
  "tags": { "type": "array", "items": { "type": "string" } },
206
279
  "disabled": { "type": "boolean" },
207
280
  "scan": { "type": "boolean" },
208
- "icon": { "type": "string", "maxLength": 4 },
281
+ "icon": { "type": ["string", "null"] },
282
+ "launch": { "type": "boolean" },
283
+ "label": { "type": ["string", "null"] },
284
+ "lead": { "type": "boolean" },
209
285
  "custom": { "type": "object", "additionalProperties": true }
210
- }
286
+ },
287
+ "if": { "properties": { "launch": { "const": false } }, "required": ["launch"] },
288
+ "then": { "required": ["path"] }
211
289
  }
212
290
  }
213
291
  }
214
292
  }
215
293
  ```
216
294
 
217
- ## 将来拡張(v0.3.0以降・未実装)
295
+ 抜粋で表せない検証(`name` の一意・`path`/`cwd`/`defaults.groups_dir` が `$HOME` の下・展開した後の `path`/`cwd` と継いだ `command` のメタ文字・`custom` の大きさ)は上の「バリデーションルール」が正。未知のキーは Schema でも拒まない(ccs は警告して無視する)。
296
+
297
+ ## 契約(ほかの道具との約束)
298
+
299
+ `repos.yml` は ccs のほかに、ほかの道具(hook・スクリプト・入れる手順)も「プロジェクトの一覧の正」として読み、書く。変える時に読む側が壊れないよう、ここに約束を置く。
300
+
301
+ ### 頼ってよいキー
302
+
303
+ まず頼ってよい物(`version: 1` の間、意味を変えない・消さない):
304
+
305
+ | キー | 約束 |
306
+ |---|---|
307
+ | `version` | 整数の `1` |
308
+ | `repos[].name` | 項目の一意のキー(同じ名前は ccs がエラーにする) |
309
+ | `repos[].path` | リポのパス。`$HOME` の下。先頭の `~` を `$HOME` に展開して読む |
310
+ | `repos[].description` | 説明の文 |
311
+ | `defaults.command` | 起動コマンドの既定 |
312
+ | `defaults.ui` | `classic` か `simple` |
313
+
314
+ 次に頼ってよい物: `repos[].launch`・`repos[].lead`・`repos[].label`・`repos[].disabled`・`repos[].custom`(意味は上の表)。
315
+
316
+ v0.5.0 で足した物(足すだけの変更): `defaults.terminal`・`defaults.update_check`・`defaults.groups_dir`。前のバージョンの ccs は `defaults` の中の未知のキーを黙って無視するので、書いても壊れない。
317
+
318
+ ほかの道具が `repos.yml` を直に読まずに済むよう、ccs は同じ検証を通した結果を `ccs list --json` で出す(`machine-interface.md` の 2.2)。
319
+
320
+ ### `version: 1` の間の変え方
321
+
322
+ - 足すだけ。キーの意味を変えない・消さない
323
+ - 読む側は未知のキーを無視する(ccs はトップレベルと項目の中は警告を出して、`defaults` の中は黙って無視する)
324
+ - ほかの道具が自分の値を置く場所は `repos[].custom`(ccs は中身の型を問わず、プレビューに出すだけ)。トップレベルや項目の直下に自分のキーを足さない
325
+ - 壊す変更(キーの意味を変える・消す・必須を足す)は `version: 2` にし、両方を読める移る期間を置く
326
+
327
+ ### 勧める書き方
328
+
329
+ - ブロックの形で書く(`repos: [{name: …, path: …}]` のような 1 行の形にしない)
330
+ - 各項目の直下に `name:` と `path:` を書く(`- name:` で始め、次の行に `path:`)。YAML のパーサを使わず行で読む読む側でも、`name:` と `path:` を引ける
331
+ - `path` は `~/…` か `$HOME` の下のフルパスで書く。`$HOME` そのものは `~/`(`~` だけは YAML の null になり、引用符なしで書けない)
332
+ - ccs が書く時(初回のテンプレート・`ccs init --auto-discover` の書き足し・`ccs repo add`・`ccs repo remove`・`ccs config set`)は、必ずこの形で書く。書き足しは元のファイルのコメントと書き方を残し(例外: 行の終わりのコメントの前の空白は 1 つに揃う)、`.bak` を残し、書いた後の検証に落ちたら元に戻す(手順は `machine-interface.md` の 3 章)
333
+ - `repos:` が 1 行の形(`repos: [ … ]`)の時、ccs は項目を書き足さずに断る(`ccs init --auto-discover` は終了コード 1・`ccs repo add` は 6・どちらも理由の語 `flow_style_repos`・ファイルを書き換えない)。`ccs init --auto-discover` の書き足しは、ほかの検査より先に断る(`repos: []` も)。1 行の形のまま足すと、行で読む道具が新しい項目を読めないため
334
+ - ccs が書く `name`・`path` は、YAML で引用符なしに書ける値だけ(`machine-interface.md` の 1.6)
335
+
336
+ ### 最小の形の見本
337
+
338
+ 入れる手順などが書く最小の `repos.yml`。ccs はこの形を `version: 1` の間読み続ける(値は架空)。
339
+
340
+ ```yaml
341
+ version: 1
342
+ defaults:
343
+ command: "claude"
344
+ ui: simple
345
+ repos:
346
+ - name: example
347
+ path: ~/projects/example
348
+ ```
349
+
350
+ ### `repos.yml` のほかに約束に入る事
218
351
 
219
- - `group`: リポジトリのグループ化(fzfヘッダーでグループ切替)
220
- - `env`: リポジトリ毎の環境変数注入
352
+ - `ccs --version`(`-v` も同じ): 標準出力に `ccs v<バージョン>` の 1 行を出し、exit 0。バージョンは配った `package.json` の `version`(読めない置き方では `0.0.0-dev`)
353
+ - 起動の形: コマンドの名前は `ccs`。`ccs init`・`ccs init --auto-discover`・`--version`。v0.5.0 から、最初の引数が `doctor`・`list`・`sessions`・`repo`・`config`・`open` の時は ccs の口になる(前は起動するコマンドに渡っていた。渡したい時は `ccs --new doctor` のように前にフラグを置く)。Claude Code は、選んだ項目のフォルダ(`cwd`、無ければ `path`)へ cd し、上の優先順で決めたコマンドで起こす。過去セッションの再開はそのコマンドに `--resume <UUID>` を付ける。ccs が知らないフラグはそのコマンドに渡す
354
+ - Node の下限: `package.json` の `engines.node`
355
+ - 機械で読む口(コマンド・JSON の形・終了コード・理由の語)の約束は `machine-interface.md`
356
+
357
+ 上の物を変えるバージョンは、出す前に読む側に知らせる。壊す変更は、読む側が替え終えてから出す。
358
+
359
+ ### 約束の外
360
+
361
+ - 画面の言葉と並び(一覧・プレビュー・警告の文。`ui: simple` と `classic` のどちらも)
362
+ - キーの割り当て(Enter・Ctrl-Y など)
363
+ - state.db のスキーマ(`sqlite-schema.md` は設計の記録で、約束ではない)
364
+
365
+ ## 将来拡張(未実装の案)
366
+
367
+ - `env`: リポジトリごとの環境変数の注入
221
368
  - `post_launch`: 起動後に実行するフック
222
- - `priority`: ソート重み(上に出したいリポジトリ)
369
+ - `priority`: 並びの重み(上に出したいリポジトリ)
370
+
371
+ グループ化(fzf のヘッダーでの切り替え)の案は、`launch: false` の見出しと `path` での入れ子・`lead` で形を変えて入った。足す時は上の「`version: 1` の間の変え方」に従う。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indigo-gr/claude-code-station",
3
- "version": "0.4.1",
3
+ "version": "0.5.0",
4
4
  "description": "Claude Code Station — fzf-powered launcher and session picker for Claude Code with multi-repo support and SQLite-backed state cache",
5
5
  "type": "module",
6
6
  "bin": {