@aion0/forge 0.2.10 → 0.2.12

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/CLAUDE.md CHANGED
@@ -1,44 +1,43 @@
1
1
  ## Project: Forge (@aion0/forge)
2
2
 
3
- ### Dev Commands
3
+ ### Scripts
4
4
  ```bash
5
- # Development (hot-reload)
6
- pnpm dev
7
-
8
- # Production (local)
9
- pnpm build && pnpm start
10
-
11
- # Publish to npm (bump version in package.json first)
12
- npm login
13
- npm publish --access public --otp=<code>
14
-
15
- # Install globally from local source (for testing)
16
- npm install -g /Users/zliu/IdeaProjects/my-workflow
17
-
18
- # Install from npm
19
- npm install -g @aion0/forge
20
-
21
- # Run via npm global install
22
- forge-server # foreground (default port 3000)
23
- forge-server --dev # dev mode
24
- forge-server --background # background, logs to ~/.forge/forge.log
25
- forge-server --stop # stop background server
26
- forge-server --restart # stop + start (safe for remote)
27
- forge-server --rebuild # force rebuild
28
- forge-server --port 4000 # custom web port
29
- forge-server --terminal-port 4001 # custom terminal port
30
- forge-server --dir ~/.forge-staging # custom data directory
31
-
32
- # CLI
33
- forge # help
34
- forge password # show today's login password
35
- forge tasks # list tasks
5
+ # ── Start ──
6
+ ./start.sh # production (kill old processes → build → start)
7
+ ./start.sh dev # development (hot-reload)
8
+ forge server start # production via npm link/install
9
+ forge server start --dev # dev mode
10
+ forge server start --background # background, logs to ~/.forge/forge.log
11
+ forge server stop # stop background server
12
+ forge server restart # stop + start (safe for remote)
13
+ forge server rebuild # force rebuild
14
+ forge server start --port 4000 --terminal-port 4001 --dir ~/.forge-staging
15
+ forge server start --reset-terminal # kill terminal server (loses tmux attach)
16
+ forge --version # show version
17
+
18
+ # ── Test ──
19
+ ./dev-test.sh # test instance (port 4000, data ~/.forge-test)
20
+
21
+ # ── Install ──
22
+ ./install.sh # install from npm
23
+ ./install.sh --local # install from local source (npm link + build)
24
+
25
+ # ── Publish ──
26
+ ./publish.sh # bump patch version, commit, tag
27
+ ./publish.sh minor # bump minor
28
+ ./publish.sh 1.0.0 # explicit version
29
+ npm login && npm publish --access public --otp=<code>
30
+
31
+ # ── Monitor ──
32
+ ./check-forge-status.sh # show process status + tmux sessions
33
+
34
+ # ── CLI ──
35
+ forge # help
36
+ forge --version # show version
37
+ forge password # show today's login password
38
+ forge tasks # list tasks
36
39
  forge task <project> "prompt" # submit task
37
-
38
- # Terminal server runs on port 3001 (auto-started by Next.js)
39
- # Data directory: ~/.forge/
40
- # Config: ~/.forge/settings.yaml
41
- # Env: ~/.forge/.env.local
40
+ forge watch <id> # live stream task output
42
41
  ```
43
42
 
44
43
  ### Key Paths
@@ -46,7 +45,12 @@ forge task <project> "prompt" # submit task
46
45
  - npm package: `@aion0/forge`
47
46
  - GitHub: `github.com/aiwatching/forge`
48
47
 
48
+ ### Architecture
49
+ - `forge-server.mjs` starts: Next.js + terminal-standalone + telegram-standalone
50
+ - `pnpm dev` / `start.sh dev` starts: Next.js (init.ts spawns terminal + telegram)
51
+ - `FORGE_EXTERNAL_SERVICES=1` → init.ts skips spawning (forge-server manages them)
52
+
49
53
  ## Obsidian Vault
50
54
  Location: /Users/zliu/MyDocuments/obsidian-project/Projects/Bastion
51
55
  When I ask about my notes, use bash to search and read files from this directory.
52
- Example: find /Users/zliu/MyDocuments/obsidian-project -name "*.md" | head -20
56
+ Example: find /Users/zliu/MyDocuments/obsidian-project -name "*.md" | head -20
package/README.md CHANGED
@@ -1,73 +1,72 @@
1
1
  <p align="center">
2
- <img src="app/icon.svg" width="80" height="80" alt="Forge">
2
+ <img src="app/icon.svg" width="80" height="80" alt="Forge - Self-hosted Vibe Coding Platform">
3
3
  </p>
4
4
 
5
5
  <h1 align="center">Forge</h1>
6
6
 
7
7
  <p align="center">
8
- <strong>Self-hosted Vibe Coding platform — browser terminal, task orchestration, remote access</strong>
8
+ <strong>Self-hosted Vibe Coding platform for Claude Code — browser terminal, AI task orchestration, remote access from any device</strong>
9
9
  </p>
10
10
 
11
11
  <p align="center">
12
- <a href="https://www.npmjs.com/package/@aion0/forge"><img src="https://img.shields.io/npm/v/@aion0/forge" alt="npm"></a>
13
- <a href="https://github.com/aiwatching/forge/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/@aion0/forge" alt="license"></a>
14
- <a href="https://github.com/aiwatching/forge"><img src="https://img.shields.io/github/stars/aiwatching/forge?style=social" alt="stars"></a>
12
+ <a href="https://www.npmjs.com/package/@aion0/forge"><img src="https://img.shields.io/npm/v/@aion0/forge" alt="npm version"></a>
13
+ <a href="https://github.com/aiwatching/forge/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/@aion0/forge" alt="MIT license"></a>
14
+ <a href="https://github.com/aiwatching/forge"><img src="https://img.shields.io/github/stars/aiwatching/forge?style=social" alt="GitHub stars"></a>
15
15
  </p>
16
16
 
17
17
  <p align="center">
18
- <a href="#installation">Install</a> · <a href="#features">Features</a> · <a href="#quick-start">Quick Start</a> · <a href="#telegram-bot">Telegram</a> · <a href="#configuration">Config</a> · <a href="#roadmap">Roadmap</a>
18
+ <a href="#installation">Install</a> · <a href="#features">Features</a> · <a href="#quick-start">Quick Start</a> · <a href="#telegram-bot">Telegram</a> · <a href="#scripts">Scripts</a> · <a href="#configuration">Config</a> · <a href="#roadmap">Roadmap</a>
19
19
  </p>
20
20
 
21
21
  ---
22
22
 
23
- Forge turns [Claude Code](https://docs.anthropic.com/en/docs/claude-code) into a full web-based vibe coding platform. Open your browser, start coding with AI from anywhere — your iPad, phone, or any device with a browser.
23
+ ## What is Forge?
24
24
 
25
- **No API keys required.** Runs on your existing Claude Code CLI subscription. Your code stays on your machine.
25
+ Forge is a self-hosted web platform that turns [Claude Code](https://docs.anthropic.com/en/docs/claude-code) into a remote-accessible vibe coding environment. It provides a persistent browser-based terminal (powered by tmux), background AI task orchestration, one-click Cloudflare Tunnel for remote access, and a Telegram bot for mobile control.
26
+
27
+ **Use cases:**
28
+ - Vibe code from your iPad, phone, or any browser — Claude Code runs on your machine, you access it from anywhere
29
+ - Submit AI coding tasks that run in the background while you sleep
30
+ - Chain multiple Claude Code instances into automated pipelines (design → implement → review → deploy)
31
+ - Browse and search your Obsidian notes with an AI assistant
32
+
33
+ **No API keys required.** Forge uses your existing Claude Code CLI subscription. Your code never leaves your machine.
26
34
 
27
35
  ## Features
28
36
 
29
- | Feature | Description |
37
+ | Feature | What it does |
30
38
  |---------|-------------|
31
- | **Vibe Coding** | Browser-based tmux terminal. Multiple tabs, persistent sessions that survive refresh, browser close, and server restart |
32
- | **Remote Access** | One-click Cloudflare Tunnel secure public URL, zero config, no account needed |
33
- | **Task Queue** | Submit tasks to Claude Code in the background. Live streaming output, cost tracking, session continuity |
34
- | **Docs Viewer** | Render Obsidian vaults / markdown directories with a dedicated Claude Console |
35
- | **Project Manager** | Browse projects, view files, git status, commit, push, pull all from the browser |
36
- | **Demo Preview** | Preview local dev servers through the tunnel with a dedicated Cloudflare URL |
37
- | **Telegram Bot** | Submit tasks, check status, control tunnel, take notes all from your phone |
38
- | **File Browser** | Code viewer with syntax highlighting, git changes, diff view, multi-repo support |
39
- | **YAML Workflows** | Define multi-step flows that chain Claude Code tasks together |
40
- | **CLI** | Full command-line interface for task management |
39
+ | **Vibe Coding** | Browser-based tmux terminal with multiple tabs. Sessions persist across page refresh, browser close, and server restart. Access from any device via Cloudflare Tunnel. |
40
+ | **AI Task Queue** | Submit prompts to Claude Code that run in the background. Live streaming output, cost tracking, session continuity across tasks. Supports `--dangerously-skip-permissions` for fully autonomous operation. |
41
+ | **Pipeline Engine** | Define multi-step DAG workflows in YAML. Chain Claude Code tasks with dependencies, output passing between steps, conditional routing, and parallel execution. Visual drag-and-drop editor included. |
42
+ | **Remote Access** | One-click Cloudflare Tunnel generates a secure public URL. Zero config, no Cloudflare account needed. Auto-health-check with reconnection. |
43
+ | **Docs Viewer** | Render Obsidian vaults and markdown directories in the browser. Built-in Claude Console for AI-assisted note-taking and research. Image support. |
44
+ | **Project Manager** | Browse project files, view code with syntax highlighting, git status/commit/push/pull, commit history — all from the browser. Multi-repo support. |
45
+ | **Demo Preview** | Preview local dev servers (Vite, Next.js, etc.) through dedicated Cloudflare Tunnel URLs. Multiple simultaneous previews supported. |
46
+ | **Telegram Bot** | Create tasks, check status, control tunnel, take notes, get AI session summaries — all from your phone. Whitelist-protected. |
47
+ | **CLI** | Full command-line interface: `forge task`, `forge watch`, `forge status`, `forge password`, and more. |
48
+ | **Monitor** | Real-time dashboard showing process status (Next.js, Terminal, Telegram, Tunnel), tmux sessions, and system uptime. |
41
49
 
42
50
  ## Installation
43
51
 
44
- ### npm (recommended)
45
-
46
52
  ```bash
47
53
  npm install -g @aion0/forge
48
- forge-server
54
+ forge server start
49
55
  ```
50
56
 
57
+ Open `http://localhost:3000` — a login password is printed in the console.
58
+
51
59
  ### From source
52
60
 
53
61
  ```bash
54
62
  git clone https://github.com/aiwatching/forge.git
55
63
  cd forge
56
64
  pnpm install
57
- pnpm dev
65
+ ./start.sh # production
66
+ ./start.sh dev # development with hot-reload
58
67
  ```
59
68
 
60
- ### Options
61
-
62
- ```bash
63
- forge-server # Production (auto-builds if needed)
64
- forge-server --dev # Development with hot-reload
65
- forge-server --background # Run in background, logs to ~/.forge/forge.log
66
- forge-server --stop # Stop background server
67
- forge-server --rebuild # Force rebuild
68
- ```
69
-
70
- ## Prerequisites
69
+ ### Prerequisites
71
70
 
72
71
  - **Node.js** >= 20
73
72
  - **tmux** — `brew install tmux` (macOS) / `apt install tmux` (Linux)
@@ -75,68 +74,133 @@ forge-server --rebuild # Force rebuild
75
74
 
76
75
  ## Quick Start
77
76
 
78
- 1. **Start Forge**
79
-
80
- ```bash
81
- forge-server
82
- ```
83
-
84
- 2. **Open browser** → `http://localhost:3000`
85
-
86
- 3. **Log in** — password is auto-generated and printed in the console:
87
-
88
- ```
89
- [init] Login password: a7x9k2 (valid today)
90
- ```
91
-
92
- Forgot it? Run `forge password`
93
-
94
- 4. **Configure projects** — Settings → add your project directories
95
-
96
- 5. **Start vibe coding** — open a terminal tab, run `claude`, and go
77
+ 1. **Start Forge** — `forge server start` or `./start.sh`
78
+ 2. **Open browser** — `http://localhost:3000`
79
+ 3. **Log in** — set an admin password in Settings. Run `forge password` for info.
80
+ 4. **Configure** — Settings → add project directories and (optionally) Telegram bot token
81
+ 5. **Start coding** — Open a terminal tab, run `claude`, and vibe
97
82
 
98
83
  ## Remote Access
99
84
 
100
- Access Forge from anywhere — your phone, iPad, or another computer:
85
+ Access Forge from anywhere — iPad, phone, coffee shop:
101
86
 
102
87
  1. Click the **tunnel button** in the header
103
- 2. Forge auto-downloads `cloudflared` and creates a temporary public URL
104
- 3. Open the URL on any device — protected by the daily login password
88
+ 2. A temporary Cloudflare URL is generated (no account needed)
89
+ 3. Open it on any device — requires admin password + session code (2FA)
105
90
 
106
- > The tunnel URL changes each time. Use the Telegram `/tunnel_password` command to get it on your phone.
91
+ Health checks run every 60 seconds. If the tunnel drops, it auto-restarts and notifies you via Telegram.
107
92
 
108
93
  ## Telegram Bot
109
94
 
110
- Control Forge from your phone. Create a bot via [@BotFather](https://t.me/botfather), add the token in Settings.
95
+ Mobile-first control for Forge. Create a bot via [@BotFather](https://t.me/botfather), add the token in Settings.
111
96
 
112
97
  | Command | Description |
113
98
  |---------|-------------|
114
99
  | `/task` | Create a task (interactive project picker) |
115
100
  | `/tasks` | List tasks with quick-action numbers |
116
- | `/peek` | AI summary of a Claude session |
101
+ | `/sessions` | AI summary of Claude Code sessions |
117
102
  | `/docs` | Docs session summary or file search |
118
- | `/note` | Quick note — sent to Docs Claude |
119
- | `/tunnel_start` | Start Cloudflare Tunnel |
103
+ | `/note` | Quick note — sent to Docs Claude for filing |
104
+ | `/tunnel_start <admin_pw>` | Start Cloudflare Tunnel |
120
105
  | `/tunnel_stop` | Stop tunnel |
121
- | `/tunnel_password <pw>` | Get login password + tunnel URL |
106
+ | `/tunnel_code <admin_pw>` | Get session code for remote login |
107
+ | `/watch` | Monitor session / list watchers |
108
+
109
+ Whitelist-protected — only configured Chat IDs can interact. Supports multiple users (comma-separated IDs).
110
+
111
+ ## Pipeline Engine
112
+
113
+ Define multi-step AI workflows in YAML. Each step runs Claude Code autonomously, with outputs passed to downstream steps.
114
+
115
+ ```yaml
116
+ name: feature-build
117
+ description: "Design → Implement → Review"
118
+ input:
119
+ requirement: "Feature description"
120
+ vars:
121
+ project: my-app
122
+ nodes:
123
+ architect:
124
+ project: "{{vars.project}}"
125
+ prompt: "Analyze: {{input.requirement}}. Output a design doc."
126
+ outputs:
127
+ - name: design
128
+ extract: result
129
+ implement:
130
+ project: "{{vars.project}}"
131
+ depends_on: [architect]
132
+ prompt: "Implement: {{nodes.architect.outputs.design}}"
133
+ outputs:
134
+ - name: diff
135
+ extract: git_diff
136
+ review:
137
+ depends_on: [implement]
138
+ project: "{{vars.project}}"
139
+ prompt: "Review: {{nodes.implement.outputs.diff}}"
140
+ ```
122
141
 
123
- Whitelist-protected only configured Chat IDs can interact with the bot.
142
+ Features: DAG execution, parallel nodes, conditional routing, loop protection, Telegram notifications per step, visual editor.
124
143
 
125
144
  ## CLI
126
145
 
146
+ All commands are unified under `forge`:
147
+
127
148
  ```bash
149
+ # Server management
150
+ forge server start # Start server (foreground)
151
+ forge server start --background # Start in background
152
+ forge server start --dev # Development mode with hot-reload
153
+ forge server start --port 4000 # Custom port
154
+ forge server stop # Stop server
155
+ forge server restart # Restart (safe for remote use)
156
+ forge server rebuild # Force rebuild
157
+
158
+ # Tasks
128
159
  forge task <project> <prompt> # Submit a task
129
- forge tasks [status] # List tasks
130
- forge watch <id> # Live stream output
131
- forge status <id> # Task details + result
160
+ forge tasks [status] # List tasks (running|queued|done|failed)
161
+ forge watch <id> # Live stream task output
132
162
  forge cancel <id> # Cancel a task
133
163
  forge retry <id> # Retry a failed task
164
+
165
+ # Workflows
134
166
  forge run <flow-name> # Run a YAML workflow
135
- forge projects # List projects
167
+ forge flows # List available workflows
168
+
169
+ # Status & Info
170
+ forge status # Show process status + tmux sessions
171
+ forge status <id> # Show task details
136
172
  forge password # Show login password
173
+ forge projects # List configured projects
174
+ forge -v # Show version
175
+
176
+ # Package management
177
+ forge upgrade # Update to latest npm version
178
+ forge uninstall # Stop server + uninstall (data preserved in ~/.forge)
137
179
  ```
138
180
 
139
- Shortcuts: `t`=task, `ls`=tasks, `w`=watch, `s`=status, `f`=flows, `p`=projects, `pw`=password
181
+ Shortcuts: `t`=task, `ls`=tasks, `w`=watch, `s`=status, `l`=log, `f`=flows, `p`=projects, `pw`=password
182
+
183
+ ### Server start options
184
+
185
+ ```bash
186
+ forge server start --port 4000 # Custom web port (default: 3000)
187
+ forge server start --terminal-port 4001 # Custom terminal port (default: 3001)
188
+ forge server start --dir ~/.forge-test # Custom data directory
189
+ forge server start --background # Run in background
190
+ forge server start --reset-terminal # Kill terminal server on start
191
+ ```
192
+
193
+ ### Development scripts
194
+
195
+ ```bash
196
+ ./start.sh # kill old processes → build → start (production)
197
+ ./start.sh dev # development with hot-reload
198
+ ./dev-test.sh # test instance on port 4000 (separate data dir)
199
+ ./install.sh # install from npm
200
+ ./install.sh --local # install from local source
201
+ ./publish.sh # bump version → commit → tag → ready to publish
202
+ ./check-forge-status.sh # show all forge processes + tmux sessions
203
+ ```
140
204
 
141
205
  ## Configuration
142
206
 
@@ -144,14 +208,16 @@ All data lives in `~/.forge/`:
144
208
 
145
209
  ```
146
210
  ~/.forge/
147
- ├── .env.local # Environment variables (optional)
211
+ ├── .env.local # Environment variables (AUTH_SECRET, API keys)
148
212
  ├── settings.yaml # Main configuration
149
- ├── password.json # Daily auto-generated password
150
- ├── data.db # SQLite database
213
+ ├── session-code.json # Session code for remote login 2FA
214
+ ├── data.db # SQLite database (tasks, sessions)
151
215
  ├── terminal-state.json # Terminal tab layout
216
+ ├── tunnel-state.json # Tunnel process state
152
217
  ├── preview.json # Demo preview config
218
+ ├── pipelines/ # Pipeline execution state
153
219
  ├── flows/ # YAML workflow definitions
154
- └── bin/ # Auto-downloaded binaries
220
+ └── bin/ # Auto-downloaded binaries (cloudflared)
155
221
  ```
156
222
 
157
223
  <details>
@@ -166,9 +232,13 @@ claudePath: claude
166
232
  tunnelAutoStart: false
167
233
  telegramBotToken: ""
168
234
  telegramChatId: "" # Comma-separated for multiple users
169
- telegramTunnelPassword: ""
235
+ telegramTunnelPassword: "" # Admin password (encrypted)
170
236
  notifyOnComplete: true
171
237
  notifyOnFailure: true
238
+ taskModel: default # default / sonnet / opus / haiku
239
+ pipelineModel: default
240
+ telegramModel: sonnet
241
+ skipPermissions: false # Add --dangerously-skip-permissions to terminal claude invocations
172
242
  ```
173
243
 
174
244
  </details>
@@ -190,45 +260,41 @@ AUTH_SECRET=<random-string>
190
260
  ## Architecture
191
261
 
192
262
  ```
193
- ┌──────────────────────────────────────────────────┐
194
- │ Web Dashboard (Next.js 16 + React 19)
195
- ┌─────────┐ ┌──────┐ ┌────────┐ ┌───────────┐ │
196
- │ Vibe Docs │Projects│ │Demo │ │
197
- Coding │ │ │ │ │ │Preview │ │
198
- └─────────┘ └──────┘ └────────┘ └───────────┘ │
199
- ├──────────────────────────────────────────────────┤
200
- API Layer (Next.js Route Handlers)
201
- ├───────────┬───────────┬──────────────────────────┤
202
- │ Claude │ Task │ Telegram Bot │
203
- │ Code │ Runner │ + Notifications │
204
- │ Process │ (Queue) │ │
205
- ├───────────┴───────────┴──────────────────────────┤
206
- │ SQLite · Terminal Server · Cloudflare Tunnel │
207
- └──────────────────────────────────────────────────┘
263
+ forge-server.mjs (single process)
264
+ ├── Next.js (web dashboard + API)
265
+ ├── Vibe Coding (xterm.js + tmux)
266
+ ├── Docs Viewer (markdown + Claude Console)
267
+ ├── Project Manager (files + git)
268
+ ├── Task Queue (background Claude Code)
269
+ │ ├── Pipeline Engine (DAG workflows)
270
+ ├── Demo Preview (tunnel proxy)
271
+ │ └── Monitor (process status)
272
+ ├── terminal-standalone.ts (WebSocket → tmux)
273
+ ├── telegram-standalone.ts (Telegram Bot API polling)
274
+ └── cloudflared (Cloudflare Tunnel, on demand)
208
275
  ```
209
276
 
210
277
  ## Tech Stack
211
278
 
212
279
  | Layer | Technology |
213
280
  |-------|-----------|
214
- | Frontend | Next.js 16, React 19, Tailwind CSS 4, xterm.js |
281
+ | Frontend | Next.js 16, React 19, Tailwind CSS 4, xterm.js, ReactFlow |
215
282
  | Backend | Next.js Route Handlers, SQLite (better-sqlite3) |
216
283
  | Terminal | node-pty, tmux, WebSocket |
217
- | Auth | NextAuth v5 (daily rotating password + OAuth) |
284
+ | Auth | NextAuth v5 (admin password + session code 2FA + OAuth) |
218
285
  | Tunnel | Cloudflare cloudflared (zero-config) |
219
286
  | Bot | Telegram Bot API |
287
+ | Pipeline | YAML-based DAG engine with visual editor |
220
288
 
221
289
  ## Troubleshooting
222
290
 
223
291
  <details>
224
292
  <summary><strong>macOS: "fork failed: Device not configured"</strong></summary>
225
293
 
226
- PTY device limit exhausted. Increase it:
294
+ PTY device limit exhausted:
227
295
 
228
296
  ```bash
229
297
  sudo sysctl kern.tty.ptmx_max=2048
230
-
231
- # Permanent
232
298
  echo 'kern.tty.ptmx_max=2048' | sudo tee -a /etc/sysctl.conf
233
299
  ```
234
300
 
@@ -237,7 +303,7 @@ echo 'kern.tty.ptmx_max=2048' | sudo tee -a /etc/sysctl.conf
237
303
  <details>
238
304
  <summary><strong>Session cookie invalid after restart</strong></summary>
239
305
 
240
- Fix the AUTH_SECRET so it persists:
306
+ Fix AUTH_SECRET so it persists across restarts:
241
307
 
242
308
  ```bash
243
309
  echo "AUTH_SECRET=$(openssl rand -hex 32)" >> ~/.forge/.env.local
@@ -245,13 +311,25 @@ echo "AUTH_SECRET=$(openssl rand -hex 32)" >> ~/.forge/.env.local
245
311
 
246
312
  </details>
247
313
 
314
+ <details>
315
+ <summary><strong>Orphan processes after Ctrl+C</strong></summary>
316
+
317
+ Use `./start.sh` or `forge server start` which clean up old processes on start. Or manually:
318
+
319
+ ```bash
320
+ ./check-forge-status.sh # see what's running
321
+ pkill -f 'telegram-standalone|terminal-standalone|next-server|cloudflared'
322
+ ```
323
+
324
+ </details>
325
+
248
326
  ## Roadmap
249
327
 
250
- - [ ] **Multi-Agent Workflow** — DAG-based pipelines where multiple Claude Code instances collaborate ([design doc](docs/roadmap-multi-agent-workflow.md))
251
- - [ ] Pipeline UI — DAG visualization with real-time node status
328
+ - [ ] **Multi-Agent Collaboration** — Real-time message channels between concurrent Claude Code instances ([design doc](docs/roadmap-multi-agent-workflow.md))
252
329
  - [ ] Additional bot platforms — Discord, Slack
253
330
  - [ ] Excalidraw rendering in Docs viewer
254
- - [ ] Multi-model chat (Anthropic, OpenAI, Google, xAI)
331
+ - [ ] Multi-model chat with API keys (Anthropic, OpenAI, Google, xAI)
332
+ - [ ] Plugin system for custom integrations
255
333
 
256
334
  ## Contributing
257
335
 
@@ -1,15 +1,62 @@
1
1
  import { NextResponse } from 'next/server';
2
- import { loadSettings, saveSettings, type Settings } from '@/lib/settings';
2
+ import { loadSettings, loadSettingsMasked, saveSettings, type Settings } from '@/lib/settings';
3
3
  import { restartTelegramBot } from '@/lib/init';
4
+ import { SECRET_FIELDS } from '@/lib/crypto';
5
+ import { verifyAdmin } from '@/lib/password';
4
6
 
5
7
  export async function GET() {
6
- return NextResponse.json(loadSettings());
8
+ return NextResponse.json(loadSettingsMasked());
7
9
  }
8
10
 
9
11
  export async function PUT(req: Request) {
10
- const body = await req.json() as Settings;
11
- saveSettings(body);
12
- // Restart Telegram bot in case token/chatId changed
12
+ const body = await req.json();
13
+
14
+ // Handle secret field updates separately
15
+ if (body._secretUpdate) {
16
+ const { field, adminPassword, newValue } = body._secretUpdate as {
17
+ field: string;
18
+ adminPassword: string;
19
+ newValue: string;
20
+ };
21
+
22
+ // Validate field name
23
+ if (!SECRET_FIELDS.includes(field as any)) {
24
+ return NextResponse.json({ ok: false, error: 'Invalid field' }, { status: 400 });
25
+ }
26
+
27
+ // Verify admin password
28
+ if (!verifyAdmin(adminPassword)) {
29
+ return NextResponse.json({ ok: false, error: 'Wrong password' }, { status: 403 });
30
+ }
31
+
32
+ // Update the specific field
33
+ const current = loadSettings();
34
+ (current as any)[field] = newValue;
35
+ saveSettings(current);
36
+
37
+ // Restart Telegram bot if token changed
38
+ if (field === 'telegramBotToken') {
39
+ restartTelegramBot();
40
+ }
41
+
42
+ return NextResponse.json({ ok: true });
43
+ }
44
+
45
+ // Normal settings update — strip masked secrets so we don't overwrite with placeholder
46
+ const settings = loadSettings();
47
+ const updated = body as Settings;
48
+
49
+ for (const field of SECRET_FIELDS) {
50
+ // Keep existing encrypted value if frontend sent masked placeholder
51
+ if (updated[field] === '••••••••' || updated[field] === '') {
52
+ updated[field] = settings[field];
53
+ }
54
+ }
55
+
56
+ // Remove internal fields
57
+ delete (updated as any)._secretStatus;
58
+
59
+ saveSettings(updated);
13
60
  restartTelegramBot();
14
61
  return NextResponse.json({ ok: true });
15
62
  }
@@ -1,18 +1,26 @@
1
1
  import { NextResponse } from 'next/server';
2
2
  import { startTunnel, stopTunnel, getTunnelStatus } from '@/lib/cloudflared';
3
+ import { verifyAdmin } from '@/lib/password';
3
4
 
4
5
  export async function GET() {
5
6
  return NextResponse.json(getTunnelStatus());
6
7
  }
7
8
 
8
9
  export async function POST(req: Request) {
9
- const { action } = await req.json() as { action: 'start' | 'stop' };
10
+ const body = await req.json() as { action: 'start' | 'stop'; password?: string };
10
11
 
11
- if (action === 'stop') {
12
+ if (body.action === 'start') {
13
+ if (!body.password || !verifyAdmin(body.password)) {
14
+ return NextResponse.json({ ok: false, error: 'Wrong password' }, { status: 403 });
15
+ }
16
+ const result = await startTunnel();
17
+ return NextResponse.json({ ok: !result.error, ...getTunnelStatus() });
18
+ }
19
+
20
+ if (body.action === 'stop') {
12
21
  stopTunnel();
13
22
  return NextResponse.json({ ok: true, ...getTunnelStatus() });
14
23
  }
15
24
 
16
- const result = await startTunnel();
17
- return NextResponse.json({ ok: !result.error, ...getTunnelStatus() });
25
+ return NextResponse.json({ ok: false, error: 'Invalid action' }, { status: 400 });
18
26
  }