commandmate 0.2.2 → 0.2.3

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.
Files changed (123) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-build-manifest.json +48 -52
  3. package/.next/app-path-routes-manifest.json +1 -1
  4. package/.next/build-manifest.json +7 -7
  5. package/.next/cache/.tsbuildinfo +1 -1
  6. package/.next/cache/config.json +3 -3
  7. package/.next/cache/webpack/client-production/0.pack +0 -0
  8. package/.next/cache/webpack/client-production/1.pack +0 -0
  9. package/.next/cache/webpack/client-production/2.pack +0 -0
  10. package/.next/cache/webpack/client-production/index.pack +0 -0
  11. package/.next/cache/webpack/client-production/index.pack.old +0 -0
  12. package/.next/cache/webpack/edge-server-production/index.pack +0 -0
  13. package/.next/cache/webpack/server-production/0.pack +0 -0
  14. package/.next/cache/webpack/server-production/index.pack +0 -0
  15. package/.next/next-server.js.nft.json +1 -1
  16. package/.next/prerender-manifest.json +1 -1
  17. package/.next/required-server-files.json +1 -1
  18. package/.next/routes-manifest.json +1 -1
  19. package/.next/server/app/_not-found/page.js +1 -1
  20. package/.next/server/app/_not-found/page.js.nft.json +1 -1
  21. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  22. package/.next/server/app/api/repositories/route.js +1 -1
  23. package/.next/server/app/api/worktrees/[id]/current-output/route.js +1 -1
  24. package/.next/server/app/api/worktrees/[id]/logs/[filename]/route.js +1 -1
  25. package/.next/server/app/api/worktrees/[id]/logs/route.js +4 -4
  26. package/.next/server/app/api/worktrees/[id]/route.js +1 -1
  27. package/.next/server/app/api/worktrees/route.js +1 -1
  28. package/.next/server/app/page.js +2 -4
  29. package/.next/server/app/page.js.nft.json +1 -1
  30. package/.next/server/app/page_client-reference-manifest.js +1 -1
  31. package/.next/server/app/worktrees/[id]/files/[...path]/page.js +1 -1
  32. package/.next/server/app/worktrees/[id]/files/[...path]/page.js.nft.json +1 -1
  33. package/.next/server/app/worktrees/[id]/files/[...path]/page_client-reference-manifest.js +1 -1
  34. package/.next/server/app/worktrees/[id]/page.js +3 -15
  35. package/.next/server/app/worktrees/[id]/page.js.nft.json +1 -1
  36. package/.next/server/app/worktrees/[id]/page_client-reference-manifest.js +1 -1
  37. package/.next/server/app/worktrees/[id]/terminal/page.js +3 -3
  38. package/.next/server/app/worktrees/[id]/terminal/page.js.nft.json +1 -1
  39. package/.next/server/app/worktrees/[id]/terminal/page_client-reference-manifest.js +1 -1
  40. package/.next/server/app-paths-manifest.json +13 -14
  41. package/.next/server/chunks/1287.js +4 -0
  42. package/.next/server/chunks/2683.js +1 -0
  43. package/.next/server/chunks/3348.js +1 -0
  44. package/.next/server/chunks/369.js +1 -0
  45. package/.next/server/chunks/3860.js +1 -0
  46. package/.next/server/chunks/4559.js +1 -0
  47. package/.next/server/chunks/4704.js +35 -0
  48. package/.next/server/chunks/5781.js +1 -0
  49. package/.next/server/chunks/5823.js +1 -0
  50. package/.next/server/chunks/5853.js +1 -0
  51. package/.next/server/chunks/6837.js +1 -0
  52. package/.next/server/chunks/7266.js +1 -0
  53. package/.next/server/chunks/7458.js +1 -0
  54. package/.next/server/chunks/7536.js +1 -1
  55. package/.next/server/chunks/8705.js +1 -0
  56. package/.next/server/chunks/8744.js +1 -0
  57. package/.next/server/chunks/9367.js +1 -1
  58. package/.next/server/chunks/9582.js +1 -0
  59. package/.next/server/functions-config-manifest.json +1 -1
  60. package/.next/server/middleware-build-manifest.js +1 -1
  61. package/.next/server/pages/500.html +1 -1
  62. package/.next/server/pages-manifest.json +1 -1
  63. package/.next/server/server-reference-manifest.json +1 -1
  64. package/.next/static/chunks/1038-3509435b68c0967e.js +1 -0
  65. package/.next/static/chunks/216-f18f4a9d8b04a91e.js +1 -0
  66. package/.next/static/chunks/2330-0299b9879f4977d2.js +1 -0
  67. package/.next/static/chunks/4733-db0112b08802aaa7.js +1 -0
  68. package/.next/static/chunks/6140-389f1951062dcf4f.js +1 -0
  69. package/.next/static/chunks/{816-c254f4e2406e696a.js → 816-bb41b20a51ae924a.js} +1 -1
  70. package/.next/static/chunks/8216-00e20326f32abd12.js +1 -0
  71. package/.next/static/chunks/9234-b0304101384ca079.js +3 -0
  72. package/.next/static/chunks/app/layout-07755491d5d57242.js +1 -0
  73. package/.next/static/chunks/app/page-792c0577dc44e5e5.js +1 -0
  74. package/.next/static/chunks/app/worktrees/[id]/files/[...path]/page-ce9ac3658f2b7d91.js +1 -0
  75. package/.next/static/chunks/app/worktrees/[id]/page-9d77c6f755d08086.js +1 -0
  76. package/.next/static/chunks/app/worktrees/[id]/terminal/page-5d85a7e508ce36d3.js +1 -0
  77. package/.next/static/chunks/{webpack-4f85dcef6279c6ee.js → webpack-e6531fcf859d9451.js} +1 -1
  78. package/.next/static/css/4eca30cb81bc52b4.css +3 -0
  79. package/.next/trace +5 -5
  80. package/README.md +84 -82
  81. package/dist/server/src/config/auto-yes-config.js +4 -4
  82. package/dist/server/src/config/log-config.js +41 -0
  83. package/dist/server/src/lib/cli-tools/manager.js +0 -6
  84. package/dist/server/src/lib/log-manager.js +2 -6
  85. package/dist/server/src/lib/prompt-detector.js +80 -23
  86. package/dist/server/src/lib/response-poller.js +29 -43
  87. package/package.json +2 -1
  88. package/.next/server/app/_not-found.html +0 -1
  89. package/.next/server/app/_not-found.meta +0 -6
  90. package/.next/server/app/_not-found.rsc +0 -10
  91. package/.next/server/app/index.html +0 -9
  92. package/.next/server/app/index.meta +0 -5
  93. package/.next/server/app/index.rsc +0 -8
  94. package/.next/server/app/worktrees/[id]/simple-terminal/page.js +0 -4
  95. package/.next/server/app/worktrees/[id]/simple-terminal/page.js.nft.json +0 -1
  96. package/.next/server/app/worktrees/[id]/simple-terminal/page_client-reference-manifest.js +0 -1
  97. package/.next/server/chunks/3053.js +0 -1
  98. package/.next/server/chunks/434.js +0 -1
  99. package/.next/server/chunks/4471.js +0 -2
  100. package/.next/server/chunks/6550.js +0 -1
  101. package/.next/server/chunks/8174.js +0 -23
  102. package/.next/server/chunks/8887.js +0 -1
  103. package/.next/server/pages/404.html +0 -1
  104. package/.next/static/chunks/4343-ebe884a2a80eb033.js +0 -1
  105. package/.next/static/chunks/4851-45df4d388db5623f.js +0 -1
  106. package/.next/static/chunks/6568-c65d7e4d7db7655b.js +0 -1
  107. package/.next/static/chunks/6725-f7607851b7d57eb1.js +0 -1
  108. package/.next/static/chunks/7648-325564a6e12a3257.js +0 -1
  109. package/.next/static/chunks/9325-9e98829c1e75f42f.js +0 -1
  110. package/.next/static/chunks/app/layout-4804cfba519283cf.js +0 -1
  111. package/.next/static/chunks/app/page-3926224c4cdf315b.js +0 -1
  112. package/.next/static/chunks/app/worktrees/[id]/files/[...path]/page-7eb14f8043796805.js +0 -1
  113. package/.next/static/chunks/app/worktrees/[id]/page-912c3c4c66821d99.js +0 -1
  114. package/.next/static/chunks/app/worktrees/[id]/simple-terminal/page-16feb3e86e42f4d1.js +0 -1
  115. package/.next/static/chunks/app/worktrees/[id]/terminal/page-be802baffc84dbd2.js +0 -1
  116. package/.next/static/css/d4b58a1129eff6af.css +0 -3
  117. package/.next/types/app/worktrees/[id]/simple-terminal/page.ts +0 -79
  118. package/dist/server/src/lib/claude-poller.js +0 -341
  119. /package/.next/static/chunks/{2117-d845c2cd62e344a6.js → 2117-e31fa477cb500950.js} +0 -0
  120. /package/.next/static/chunks/app/_not-found/{page-a9d04e58c81115ec.js → page-ac4e4463b39d0cf7.js} +0 -0
  121. /package/.next/static/chunks/{fd9d1056-bbe86e4ae099d5cd.js → fd9d1056-cfdf4f91f13d3485.js} +0 -0
  122. /package/.next/static/{HhG0EHeG9E4wTJ4sqnLdv → rppRTm2sRWa4sZE7ili8A}/_buildManifest.js +0 -0
  123. /package/.next/static/{HhG0EHeG9E4wTJ4sqnLdv → rppRTm2sRWa4sZE7ili8A}/_ssgManifest.js +0 -0
package/README.md CHANGED
@@ -1,152 +1,154 @@
1
1
  # CommandMate
2
2
 
3
- > 「入力待ちを見逃さない、開発の相棒。」
4
- > 「軽量。その場で完結。Claude Codeを、どこからでも動かす。」
3
+ [English](./README.md) | [日本語](./docs/ja/README.md)
5
4
 
6
- ![PC表示](./docs/images/screenshot-desktop.png)
5
+ > "Never miss a prompt — your development companion."
6
+ > "Lightweight. Self-contained. Run Claude Code from anywhere."
7
7
 
8
- ## これは何か
8
+ ![Desktop view](./docs/images/screenshot-desktop.png)
9
9
 
10
- Git worktree ごとに Claude Code セッションを管理し、ブラウザから指示を送れる開発コンパニオンツールです。
10
+ ## What is this?
11
11
 
12
- 通勤中・育児中・昼休み――メールに返信する感覚で「次の指示」を出し、個人開発を前に進められます。
12
+ A development companion tool that manages Claude Code sessions per Git worktree and lets you send instructions from your browser.
13
13
 
14
- ## 何ではないか
14
+ During your commute, childcare breaks, or lunch — send the next instruction as easily as replying to an email, and keep your side projects moving forward.
15
15
 
16
- - ターミナルの代替ではありません。Claude Code を**補完**するツールです
17
- - CLI の全機能を再現するものではなく、「入力待ち/未確認を見逃さず、すぐ指示を出す」ことに特化しています
16
+ ## What it is NOT
18
17
 
19
- ## 想定ユーザー
18
+ - It is not a terminal replacement. It **complements** Claude Code
19
+ - It does not replicate all CLI features — it specializes in "never missing a prompt/confirmation and responding immediately"
20
20
 
21
- Claude Code での開発経験があり、本業の傍らで個人開発を続けたい方。
21
+ ## Target Users
22
22
 
23
- ## 主な機能
23
+ Developers with Claude Code experience who want to continue personal projects alongside their day job.
24
24
 
25
- - **入力待ち/未確認検知** — サイドバーでリアルタイムにステータス表示(idle/ready/running/waiting)
26
- - **ブラウザから指示送信** — スマホ・PCどちらからでもメッセージUIで操作
27
- - **実行履歴・メモ** — ブランチごとの会話履歴を保持、メモ機能付き
28
- - **Markdownログビューア** — Claude の詳細出力をMarkdownで閲覧
29
- - **ファイルビュー** — ワークツリー内のファイルをブラウザから確認
30
- - **Auto Yes モード** — 確認ダイアログ付きで自動承認を制御
31
- - **リポジトリ削除** — 不要になったリポジトリをアプリ管理から解除(実ファイルは削除しません)
32
- - **クローンURL登録** — HTTPS/SSH URLを指定してリポジトリをクローン・登録
33
- - **Claude Code 特化** — Claude Code セッションの管理に最適化
34
- - **レスポンシブUI** — デスクトップは2カラム、モバイルはタブベースで最適表示
25
+ ## Key Features
35
26
 
36
- ### ワークツリー詳細画面(Message / Console / History)
27
+ - **Prompt/confirmation detection** — Real-time status display in the sidebar (idle/ready/running/waiting)
28
+ - **Send instructions from browser** — Operate via message UI from both mobile and desktop
29
+ - **Execution history & notes** — Retains conversation history per branch with note-taking support
30
+ - **Markdown log viewer** — View Claude's detailed output in Markdown format
31
+ - **File viewer** — Browse worktree files from the browser
32
+ - **Auto Yes mode** — Control automatic approval with a confirmation dialog
33
+ - **Repository removal** — Remove repositories from app management (actual files are not deleted)
34
+ - **Clone URL registration** — Clone and register repositories by specifying HTTPS/SSH URLs
35
+ - **Claude Code optimized** — Optimized for Claude Code session management
36
+ - **Responsive UI** — Two-column layout on desktop, tab-based layout on mobile
37
37
 
38
- | PC表示 | スマホ(History) | スマホ(Terminal) |
39
- |--------|-------------------|-------------------|
40
- | ![PC - ワークツリー詳細](./docs/images/screenshot-worktree-desktop.png) | ![スマホ - History](./docs/images/screenshot-worktree-mobile.png) | ![スマホ - Terminal](./docs/images/screenshot-worktree-mobile-terminal.png) |
38
+ ### Worktree Detail View (Message / Console / History)
41
39
 
42
- ### トップ画面(スマホ)
40
+ | Desktop | Mobile (History) | Mobile (Terminal) |
41
+ |---------|-----------------|-------------------|
42
+ | ![Desktop - Worktree detail](./docs/images/screenshot-worktree-desktop.png) | ![Mobile - History](./docs/images/screenshot-worktree-mobile.png) | ![Mobile - Terminal](./docs/images/screenshot-worktree-mobile-terminal.png) |
43
43
 
44
- ![スマホ表示](./docs/images/screenshot-mobile.png)
44
+ ### Top Page (Mobile)
45
+
46
+ ![Mobile view](./docs/images/screenshot-mobile.png)
45
47
 
46
48
  ## Quick Start
47
49
 
48
- ### 前提条件
50
+ ### Prerequisites
49
51
 
50
- - macOS / Linux(tmux 依存のため Windows は非対応)
51
- - Node.js v20+、npmgittmuxopenssl
52
- - Claude CLI(オプション)
52
+ - macOS / Linux (Windows not supported due to tmux dependency)
53
+ - Node.js v20+, npm, git, tmux, openssl
54
+ - Claude CLI (optional)
53
55
 
54
- ### インストール
56
+ ### Installation
55
57
 
56
58
  ```bash
57
59
  npm install -g commandmate
58
60
  ```
59
61
 
60
- ### セットアップと起動
62
+ ### Setup and Launch
61
63
 
62
64
  ```bash
63
- commandmate init # 依存チェック、環境設定、DB初期化
64
- commandmate start --daemon # バックグラウンドで起動
65
+ commandmate init # Dependency check, environment setup, DB initialization
66
+ commandmate start --daemon # Start in background
65
67
  ```
66
68
 
67
- ブラウザで http://localhost:3000 にアクセスしてください。
69
+ Open http://localhost:3000 in your browser.
68
70
 
69
- ### CLI コマンド
71
+ ### CLI Commands
70
72
 
71
- | コマンド | 説明 |
72
- |---------|------|
73
- | `commandmate init` | 初期設定(対話形式) |
74
- | `commandmate init --defaults` | 初期設定(デフォルト値) |
75
- | `commandmate start --daemon` | バックグラウンド起動 |
76
- | `commandmate start -p 3001` | ポート指定で起動 |
77
- | `commandmate stop` | サーバー停止 |
78
- | `commandmate status` | 状態確認 |
73
+ | Command | Description |
74
+ |---------|-------------|
75
+ | `commandmate init` | Initial setup (interactive) |
76
+ | `commandmate init --defaults` | Initial setup (default values) |
77
+ | `commandmate start --daemon` | Start in background |
78
+ | `commandmate start -p 3001` | Start on a specific port |
79
+ | `commandmate stop` | Stop the server |
80
+ | `commandmate status` | Check status |
79
81
 
80
- 詳しくは [CLI セットアップガイド](./docs/user-guide/cli-setup-guide.md) を参照してください。
82
+ See the [CLI Setup Guide](./docs/en/user-guide/cli-setup-guide.md) for details.
81
83
 
82
- ### モバイルからのアクセス
84
+ ### Mobile Access
83
85
 
84
- `commandmate init` で外部アクセスを有効にすると、`CM_BIND=0.0.0.0` が設定されます。同一LAN内から `http://<PCIP>:3000` にアクセスします。外部公開時はリバースプロキシでの認証を推奨します。詳細は [セキュリティガイド](./docs/security-guide.md) を参照してください。
86
+ Enabling external access via `commandmate init` sets `CM_BIND=0.0.0.0`. Access from the same LAN at `http://<your PC's IP>:3000`. For external access, we recommend authentication via a reverse proxy. See the [Security Guide](./docs/en/security-guide.md) for details.
85
87
 
86
- ## 開発者向けセットアップ
88
+ ## Developer Setup
87
89
 
88
- コントリビューターや開発環境を構築する場合は、git clone を使用してください。
90
+ For contributors or those building a development environment, use git clone.
89
91
 
90
92
  ```bash
91
93
  git clone https://github.com/Kewton/CommandMate.git
92
94
  cd CommandMate
93
- ./scripts/setup.sh # 依存チェック、環境設定、ビルド、起動まで自動実行
95
+ ./scripts/setup.sh # Auto-runs dependency check, env setup, build, and launch
94
96
  ```
95
97
 
96
- ### 手動セットアップ(カスタマイズしたい場合)
98
+ ### Manual Setup (for customization)
97
99
 
98
100
  ```bash
99
101
  git clone https://github.com/Kewton/CommandMate.git
100
102
  cd CommandMate
101
- ./scripts/preflight-check.sh # 依存チェック
103
+ ./scripts/preflight-check.sh # Dependency check
102
104
  npm install
103
- ./scripts/setup-env.sh # 対話式で .env を生成
105
+ ./scripts/setup-env.sh # Interactive .env generation
104
106
  npm run db:init
105
107
  npm run build
106
108
  npm start
107
109
  ```
108
110
 
109
- > **Note**: `./scripts/*` スクリプトは開発環境でのみ使用可能です。グローバルインストール(`npm install -g`)では `commandmate` CLI を使用してください。
111
+ > **Note**: `./scripts/*` scripts are only available in the development environment. For global installs (`npm install -g`), use the `commandmate` CLI.
110
112
 
111
- > **Note**: 旧名称の環境変数(`MCBD_*`)も後方互換性のためサポートされていますが、新名称(`CM_*`)の使用を推奨します。
113
+ > **Note**: Legacy environment variable names (`MCBD_*`) are still supported for backward compatibility, but using the new names (`CM_*`) is recommended.
112
114
 
113
115
  ## FAQ
114
116
 
115
- **Q: どこまでローカルで動く?**
116
- A: アプリ本体・DB・セッションはすべてローカルで完結します。外部通信は Claude CLI 自体の API 呼び出しのみです。
117
+ **Q: Does everything run locally?**
118
+ A: The app, database, and sessions all run entirely locally. The only external communication is the Claude CLI's own API calls.
117
119
 
118
- **Q: 外出先からスマホでアクセスするには?**
119
- A: Cloudflare Tunnel などのトンネリングサービスを活用することで利用できます。室内であればローカル PC と同じ Wi-Fi に接続するだけでスマホから利用可能です。
120
+ **Q: How do I access it from my phone outside the house?**
121
+ A: You can use tunneling services like Cloudflare Tunnel. Within your home, simply connect your phone to the same Wi-Fi as your PC.
120
122
 
121
- **Q: Claude Code の権限はどうなる?**
122
- A: Claude Code 自体の権限設定がそのまま適用されます。本ツールが権限を拡張することはありません。詳しくは [Trust & Safety](./docs/TRUST_AND_SAFETY.md) を参照してください。
123
+ **Q: What about Claude Code's permissions?**
124
+ A: Claude Code's own permission settings apply as-is. This tool does not expand permissions. See [Trust & Safety](./docs/en/TRUST_AND_SAFETY.md) for details.
123
125
 
124
- **Q: Windows で使える?**
125
- A: 現時点では非対応です。tmux に依存しているため macOS / Linux が必要です。WSL2 上での動作は未検証です。
126
+ **Q: Does it work on Windows?**
127
+ A: Not currently supported. macOS / Linux is required due to the tmux dependency. WSL2 has not been tested.
126
128
 
127
- **Q: Claude Code 以外の CLI ツールに対応している?**
128
- A: Claude Code Codex CLI に対応しています。Strategy パターンによる拡張可能な設計のため、今後他のツールも追加可能です。
129
+ **Q: Does it support CLI tools other than Claude Code?**
130
+ A: It supports Claude Code and Codex CLI. Thanks to the extensible Strategy pattern design, additional tools can be added in the future.
129
131
 
130
- **Q: 複数人で使える?**
131
- A: 現時点では個人利用を想定しています。複数人での同時利用は未対応です。
132
+ **Q: Can multiple people use it?**
133
+ A: Currently designed for individual use. Simultaneous multi-user access is not supported.
132
134
 
133
- ## ドキュメント
135
+ ## Documentation
134
136
 
135
- | ドキュメント | 説明 |
136
- |-------------|------|
137
- | [CLI セットアップガイド](./docs/user-guide/cli-setup-guide.md) | インストールと初期設定 |
138
- | [Webアプリ操作ガイド](./docs/user-guide/webapp-guide.md) | Webアプリの基本操作 |
139
- | [クイックスタート](./docs/user-guide/quick-start.md) | Claude Codeコマンドの使い方 |
140
- | [コンセプト](./docs/concept.md) | ビジョンと解決する課題 |
141
- | [アーキテクチャ](./docs/architecture.md) | システム設計 |
142
- | [デプロイガイド](./docs/DEPLOYMENT.md) | 本番環境構築手順 |
143
- | [移行ガイド](./docs/migration-to-commandmate.md) | MyCodeBranchDesk からの移行手順 |
144
- | [UI/UXガイド](./docs/UI_UX_GUIDE.md) | UI実装の詳細 |
145
- | [Trust & Safety](./docs/TRUST_AND_SAFETY.md) | セキュリティと権限の考え方 |
137
+ | Document | Description |
138
+ |----------|-------------|
139
+ | [CLI Setup Guide](./docs/en/user-guide/cli-setup-guide.md) | Installation and initial setup |
140
+ | [Web App Guide](./docs/en/user-guide/webapp-guide.md) | Basic web app operations |
141
+ | [Quick Start](./docs/en/user-guide/quick-start.md) | Using Claude Code commands |
142
+ | [Concept](./docs/en/concept.md) | Vision and problems solved |
143
+ | [Architecture](./docs/en/architecture.md) | System design |
144
+ | [Deployment Guide](./docs/en/DEPLOYMENT.md) | Production environment setup |
145
+ | [Migration Guide](./docs/en/migration-to-commandmate.md) | Migrating from MyCodeBranchDesk |
146
+ | [UI/UX Guide](./docs/en/UI_UX_GUIDE.md) | UI implementation details |
147
+ | [Trust & Safety](./docs/en/TRUST_AND_SAFETY.md) | Security and permissions |
146
148
 
147
149
  ## Contributing
148
150
 
149
- バグ報告・機能提案・ドキュメント改善を歓迎します。詳しくは [CONTRIBUTING.md](./CONTRIBUTING.md) を参照してください。
151
+ Bug reports, feature suggestions, and documentation improvements are welcome. See [CONTRIBUTING.md](./CONTRIBUTING.md) for details.
150
152
 
151
153
  ## License
152
154
 
@@ -16,11 +16,11 @@ exports.formatTimeRemaining = formatTimeRemaining;
16
16
  exports.ALLOWED_DURATIONS = [3600000, 10800000, 28800000];
17
17
  /** Default Auto-Yes duration (1 hour = 3600000ms) */
18
18
  exports.DEFAULT_AUTO_YES_DURATION = 3600000;
19
- /** UI display labels for each duration value */
19
+ /** i18n translation keys for each duration value */
20
20
  exports.DURATION_LABELS = {
21
- 3600000: '1時間',
22
- 10800000: '3時間',
23
- 28800000: '8時間',
21
+ 3600000: 'autoYes.durations.1h',
22
+ 10800000: 'autoYes.durations.3h',
23
+ 28800000: 'autoYes.durations.8h',
24
24
  };
25
25
  /**
26
26
  * Type guard: check whether a value is a valid AutoYesDuration.
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ /**
3
+ * Log Directory Configuration
4
+ * Issue #11: Centralized LOG_DIR constant
5
+ *
6
+ * Eliminates duplicate LOG_DIR definitions previously found in:
7
+ * - src/lib/log-manager.ts
8
+ * - src/app/api/worktrees/[id]/logs/[filename]/route.ts
9
+ *
10
+ * Dependency chain: log-config.ts -> env.ts -> db-path-resolver.ts (no circular dependency)
11
+ *
12
+ * @module log-config
13
+ */
14
+ var __importDefault = (this && this.__importDefault) || function (mod) {
15
+ return (mod && mod.__esModule) ? mod : { "default": mod };
16
+ };
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.getLogDir = getLogDir;
19
+ const path_1 = __importDefault(require("path"));
20
+ const env_1 = require("../lib/env");
21
+ /**
22
+ * Get the log directory path.
23
+ *
24
+ * Resolution order:
25
+ * 1. CM_LOG_DIR environment variable (with MCBD_LOG_DIR fallback via getEnvByKey)
26
+ * 2. Default: `${process.cwd()}/data/logs`
27
+ *
28
+ * @returns Absolute path to the log directory
29
+ *
30
+ * @example
31
+ * ```typescript
32
+ * import { getLogDir } from '../config/log-config';
33
+ *
34
+ * const logDir = getLogDir();
35
+ * // => '/path/to/project/data/logs' (default)
36
+ * // => '/custom/log/dir' (when CM_LOG_DIR is set)
37
+ * ```
38
+ */
39
+ function getLogDir() {
40
+ return (0, env_1.getEnvByKey)('CM_LOG_DIR') || path_1.default.join(process.cwd(), 'data', 'logs');
41
+ }
@@ -9,7 +9,6 @@ const claude_1 = require("./claude");
9
9
  const codex_1 = require("./codex");
10
10
  const gemini_1 = require("./gemini");
11
11
  const response_poller_1 = require("../response-poller");
12
- const claude_poller_1 = require("../claude-poller");
13
12
  /**
14
13
  * CLI Tool Manager (Singleton)
15
14
  * Provides centralized access to all CLI tools
@@ -160,11 +159,6 @@ class CLIToolManager {
160
159
  stopPollers(worktreeId, cliToolId) {
161
160
  // Stop response-poller for all tools
162
161
  (0, response_poller_1.stopPolling)(worktreeId, cliToolId);
163
- // claude-poller is Claude-specific
164
- if (cliToolId === 'claude') {
165
- (0, claude_poller_1.stopPolling)(worktreeId);
166
- }
167
- // Future: Add other tool-specific pollers here if needed
168
162
  }
169
163
  }
170
164
  exports.CLIToolManager = CLIToolManager;
@@ -16,11 +16,7 @@ exports.cleanupOldLogs = cleanupOldLogs;
16
16
  const promises_1 = __importDefault(require("fs/promises"));
17
17
  const path_1 = __importDefault(require("path"));
18
18
  const date_fns_1 = require("date-fns");
19
- const env_1 = require("./env");
20
- /**
21
- * Log directory configuration (with fallback support - Issue #76)
22
- */
23
- const LOG_DIR = (0, env_1.getEnvByKey)('CM_LOG_DIR') || path_1.default.join(process.cwd(), 'data', 'logs');
19
+ const log_config_1 = require("../config/log-config");
24
20
  /**
25
21
  * Get log directory for a CLI tool
26
22
  *
@@ -28,7 +24,7 @@ const LOG_DIR = (0, env_1.getEnvByKey)('CM_LOG_DIR') || path_1.default.join(proc
28
24
  * @returns Log directory path
29
25
  */
30
26
  function getCliToolLogDir(cliToolId = 'claude') {
31
- return path_1.default.join(LOG_DIR, cliToolId);
27
+ return path_1.default.join((0, log_config_1.getLogDir)(), cliToolId);
32
28
  }
33
29
  /**
34
30
  * Ensure log directory exists
@@ -8,6 +8,40 @@ exports.detectPrompt = detectPrompt;
8
8
  exports.getAnswerInput = getAnswerInput;
9
9
  const logger_1 = require("./logger");
10
10
  const logger = (0, logger_1.createLogger)('prompt-detector');
11
+ /**
12
+ * Maximum number of lines to retain in rawContent.
13
+ * Tail lines are preserved (instruction text typically appears just before the prompt).
14
+ * @see truncateRawContent
15
+ */
16
+ const RAW_CONTENT_MAX_LINES = 200;
17
+ /**
18
+ * Maximum number of characters to retain in rawContent.
19
+ * Tail characters are preserved.
20
+ * @see truncateRawContent
21
+ */
22
+ const RAW_CONTENT_MAX_CHARS = 5000;
23
+ /**
24
+ * Truncate raw content to fit within size limits.
25
+ * Preserves the tail (end) of the content since instruction text
26
+ * typically appears just before the prompt at the end of output.
27
+ *
28
+ * Security: No regular expressions used -- no ReDoS risk. [SF-S4-002]
29
+ * String.split('\n') and String.slice() are literal string operations only.
30
+ *
31
+ * @param content - The content to truncate
32
+ * @returns Truncated content (last RAW_CONTENT_MAX_LINES lines, max RAW_CONTENT_MAX_CHARS characters)
33
+ */
34
+ function truncateRawContent(content) {
35
+ const lines = content.split('\n');
36
+ const truncatedLines = lines.length > RAW_CONTENT_MAX_LINES
37
+ ? lines.slice(-RAW_CONTENT_MAX_LINES)
38
+ : lines;
39
+ let result = truncatedLines.join('\n');
40
+ if (result.length > RAW_CONTENT_MAX_CHARS) {
41
+ result = result.slice(-RAW_CONTENT_MAX_CHARS);
42
+ }
43
+ return result;
44
+ }
11
45
  /**
12
46
  * Yes/no pattern definitions for data-driven matching.
13
47
  * Each entry defines a regex pattern and its associated default option.
@@ -27,6 +61,32 @@ const YES_NO_PATTERNS = [
27
61
  // (yes/no) - no default
28
62
  { regex: /^(.+)\s+\(yes\/no\)\s*$/m },
29
63
  ];
64
+ /**
65
+ * Creates a yes/no prompt detection result.
66
+ * Centralizes the repeated construction of yes_no PromptDetectionResult objects
67
+ * used by both YES_NO_PATTERNS matching and Approve pattern matching.
68
+ *
69
+ * @param question - The question text
70
+ * @param cleanContent - The clean content string
71
+ * @param rawContent - The raw content string (last 20 lines, trimmed)
72
+ * @param defaultOption - Optional default option ('yes' or 'no')
73
+ * @returns PromptDetectionResult with isPrompt: true and yes_no prompt data
74
+ */
75
+ function yesNoPromptResult(question, cleanContent, rawContent, defaultOption) {
76
+ return {
77
+ isPrompt: true,
78
+ promptData: {
79
+ type: 'yes_no',
80
+ question,
81
+ options: ['yes', 'no'],
82
+ status: 'pending',
83
+ ...(defaultOption !== undefined && { defaultOption }),
84
+ instructionText: rawContent,
85
+ },
86
+ cleanContent,
87
+ rawContent,
88
+ };
89
+ }
30
90
  /**
31
91
  * Detect if output contains an interactive prompt
32
92
  *
@@ -51,7 +111,8 @@ const YES_NO_PATTERNS = [
51
111
  function detectPrompt(output, options) {
52
112
  logger.debug('detectPrompt:start', { outputLength: output.length });
53
113
  const lines = output.split('\n');
54
- const lastLines = lines.slice(-10).join('\n');
114
+ // [SF-003] [MF-S2-001] Expanded from 10 to 20 lines for rawContent coverage
115
+ const lastLines = lines.slice(-20).join('\n');
55
116
  // Pattern 0: Multiple choice (numbered options with ❯ indicator)
56
117
  // Example:
57
118
  // Do you want to proceed?
@@ -68,21 +129,12 @@ function detectPrompt(output, options) {
68
129
  return multipleChoiceResult;
69
130
  }
70
131
  // Patterns 1-4: Yes/no patterns (data-driven matching)
132
+ const trimmedLastLines = lastLines.trim();
71
133
  for (const pattern of YES_NO_PATTERNS) {
72
134
  const match = lastLines.match(pattern.regex);
73
135
  if (match) {
74
136
  const question = match[1].trim();
75
- return {
76
- isPrompt: true,
77
- promptData: {
78
- type: 'yes_no',
79
- question,
80
- options: ['yes', 'no'],
81
- status: 'pending',
82
- ...(pattern.defaultOption !== undefined && { defaultOption: pattern.defaultOption }),
83
- },
84
- cleanContent: question,
85
- };
137
+ return yesNoPromptResult(question, question, trimmedLastLines, pattern.defaultOption);
86
138
  }
87
139
  }
88
140
  // Pattern 5: Approve?
@@ -93,16 +145,7 @@ function detectPrompt(output, options) {
93
145
  const content = approveMatch[1].trim();
94
146
  // If there's content before "Approve?", include it in the question
95
147
  const question = content ? `${content} Approve?` : 'Approve?';
96
- return {
97
- isPrompt: true,
98
- promptData: {
99
- type: 'yes_no',
100
- question: question,
101
- options: ['yes', 'no'],
102
- status: 'pending',
103
- },
104
- cleanContent: content || 'Approve?',
105
- };
148
+ return yesNoPromptResult(question, content || 'Approve?', trimmedLastLines);
106
149
  }
107
150
  // No prompt detected
108
151
  logger.debug('detectPrompt:complete', { isPrompt: false });
@@ -272,7 +315,7 @@ function isContinuationLine(rawLine, line) {
272
315
  // the question line would be misclassified as a continuation line, causing
273
316
  // questionEndIndex to remain -1 and Layer 5 SEC-001 to block detection.
274
317
  const endsWithQuestion = line.endsWith('?') || line.endsWith('\uff1f');
275
- const hasLeadingSpaces = rawLine.match(/^\s{2,}[^\d]/) && !rawLine.match(/^\s*\d+\./) && !endsWithQuestion;
318
+ const hasLeadingSpaces = /^\s{2,}[^\d]/.test(rawLine) && !/^\s*\d+\./.test(rawLine) && !endsWithQuestion;
276
319
  // Short fragment (< 5 chars, excluding question-ending lines)
277
320
  const isShortFragment = line.length < 5 && !endsWithQuestion;
278
321
  // Path string continuation: lines starting with / or ~, or alphanumeric-only fragments (2+ chars)
@@ -414,6 +457,18 @@ function detectMultipleChoicePrompt(output, options) {
414
457
  // No clear question found - use a generic one
415
458
  question = 'Please select an option:';
416
459
  }
460
+ // Extract instruction text: full prompt block (context before question through all options/descriptions)
461
+ // Captures the complete AskUserQuestion block including option descriptions and navigation hints.
462
+ let instructionText;
463
+ if (questionEndIndex >= 0) {
464
+ const contextStart = Math.max(0, questionEndIndex - 19);
465
+ const blockLines = lines.slice(contextStart, effectiveEnd)
466
+ .map(l => l.trimEnd());
467
+ const joined = blockLines.join('\n').trim();
468
+ if (joined.length > 0) {
469
+ instructionText = joined;
470
+ }
471
+ }
417
472
  return {
418
473
  isPrompt: true,
419
474
  promptData: {
@@ -430,8 +485,10 @@ function detectMultipleChoicePrompt(output, options) {
430
485
  };
431
486
  }),
432
487
  status: 'pending',
488
+ instructionText,
433
489
  },
434
490
  cleanContent: question.trim(),
491
+ rawContent: truncateRawContent(output.trim()), // Issue #235: complete prompt output (truncated) [MF-001]
435
492
  };
436
493
  }
437
494
  /**
@@ -53,6 +53,25 @@ const MAX_POLLING_DURATION = 5 * 60 * 1000;
53
53
  * @constant
54
54
  */
55
55
  const RESPONSE_THINKING_TAIL_LINE_COUNT = 5;
56
+ /**
57
+ * Gemini auth/loading state indicators that should not be treated as complete responses.
58
+ * Braille spinner characters are shared with CLAUDE_SPINNER_CHARS in cli-patterns.ts.
59
+ * Extracted to module level for clarity and to avoid re-creation on each call.
60
+ */
61
+ const GEMINI_LOADING_INDICATORS = [
62
+ 'Waiting for auth',
63
+ '\u280b', '\u2819', '\u2839', '\u2838', '\u283c', '\u2834', '\u2826', '\u2827', '\u2807', '\u280f',
64
+ ];
65
+ /**
66
+ * Creates an incomplete extraction result with empty response.
67
+ * Centralizes the repeated pattern of returning an in-progress/incomplete state.
68
+ *
69
+ * @param lineCount - Current line count for state tracking
70
+ * @returns ExtractionResult with empty response and isComplete: false
71
+ */
72
+ function incompleteResult(lineCount) {
73
+ return { response: '', isComplete: false, lineCount };
74
+ }
56
75
  /**
57
76
  * Active pollers map: "worktreeId:cliToolId" -> NodeJS.Timeout
58
77
  */
@@ -335,11 +354,7 @@ function extractResponse(output, lastCapturedLine, cliToolId) {
335
354
  // Prevents false blocking when completed thinking summaries appear in the response body.
336
355
  const responseTailLines = response.split('\n').slice(-RESPONSE_THINKING_TAIL_LINE_COUNT).join('\n');
337
356
  if (thinkingPattern.test(responseTailLines)) {
338
- return {
339
- response: '',
340
- isComplete: false,
341
- lineCount: totalLines,
342
- };
357
+ return incompleteResult(totalLines);
343
358
  }
344
359
  // CRITICAL FIX: Detect and skip Claude Code startup banner/screen
345
360
  // The startup screen contains: ASCII art logo, version info, prompt, separator
@@ -366,20 +381,12 @@ function extractResponse(output, lastCapturedLine, cliToolId) {
366
381
  !/^─+$/.test(trimmed);
367
382
  });
368
383
  if (contentLines.length === 0) {
369
- return {
370
- response: '',
371
- isComplete: false,
372
- lineCount: totalLines,
373
- };
384
+ return incompleteResult(totalLines);
374
385
  }
375
386
  }
376
387
  else if ((hasBannerArt || hasVersionInfo || hasStartupTips || hasProjectInit) && response.length < 2000) {
377
388
  // No user prompt found, but has banner characteristics - likely initial startup
378
- return {
379
- response: '',
380
- isComplete: false,
381
- lineCount: totalLines,
382
- };
389
+ return incompleteResult(totalLines);
383
390
  }
384
391
  }
385
392
  // Gemini-specific check: ensure response contains actual content (✦ marker)
@@ -388,31 +395,13 @@ function extractResponse(output, lastCapturedLine, cliToolId) {
388
395
  const bannerCharCount = (response.match(/[░███]/g) || []).length;
389
396
  const totalChars = response.length;
390
397
  if (bannerCharCount > totalChars * 0.3) {
391
- return {
392
- response: '',
393
- isComplete: false,
394
- lineCount: totalLines,
395
- };
398
+ return incompleteResult(totalLines);
396
399
  }
397
- // Check for auth/loading states that should not be treated as complete responses.
398
- // Braille spinner characters are shared with CLAUDE_SPINNER_CHARS in cli-patterns.ts.
399
- const LOADING_INDICATORS = [
400
- 'Waiting for auth',
401
- '⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏',
402
- ];
403
- if (LOADING_INDICATORS.some(indicator => response.includes(indicator))) {
404
- return {
405
- response: '',
406
- isComplete: false,
407
- lineCount: totalLines,
408
- };
400
+ if (GEMINI_LOADING_INDICATORS.some(indicator => response.includes(indicator))) {
401
+ return incompleteResult(totalLines);
409
402
  }
410
403
  if (!response.includes('✦') && response.length < 10) {
411
- return {
412
- response: '',
413
- isComplete: false,
414
- lineCount: totalLines,
415
- };
404
+ return incompleteResult(totalLines);
416
405
  }
417
406
  }
418
407
  return {
@@ -460,11 +449,7 @@ function extractResponse(output, lastCapturedLine, cliToolId) {
460
449
  };
461
450
  }
462
451
  // Response not yet complete (or is in thinking state)
463
- return {
464
- response: '',
465
- isComplete: false,
466
- lineCount: totalLines,
467
- };
452
+ return incompleteResult(totalLines);
468
453
  }
469
454
  /**
470
455
  * Check for CLI tool response once
@@ -533,7 +518,8 @@ async function checkForResponse(worktreeId, cliToolId) {
533
518
  const message = (0, db_1.createMessage)(db, {
534
519
  worktreeId,
535
520
  role: 'assistant',
536
- content: promptDetection.cleanContent,
521
+ // Issue #235: rawContent優先でDB保存 (rawContent contains complete prompt output)
522
+ content: promptDetection.rawContent || promptDetection.cleanContent,
537
523
  messageType: 'prompt',
538
524
  promptData: promptDetection.promptData,
539
525
  timestamp: new Date(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "commandmate",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "Git worktree management with Claude CLI and tmux sessions",
5
5
  "repository": {
6
6
  "type": "git",
@@ -48,6 +48,7 @@
48
48
  "lucide-react": "^0.554.0",
49
49
  "mermaid": "^11.12.2",
50
50
  "next": "^14.2.35",
51
+ "next-intl": "^4.8.2",
51
52
  "postcss": "^8.5.6",
52
53
  "react": "^18.3.0",
53
54
  "react-dom": "^18.3.0",