@stilero/bankan 1.0.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.
- package/LICENSE +21 -0
- package/README.md +363 -0
- package/bin/bankan.js +148 -0
- package/client/dist/assets/index-BZkAflU1.css +32 -0
- package/client/dist/assets/index-hxSMA1kc.js +48 -0
- package/client/dist/index.html +16 -0
- package/package.json +57 -0
- package/scripts/setup.js +232 -0
- package/server/src/agents.js +401 -0
- package/server/src/config.js +228 -0
- package/server/src/events.js +6 -0
- package/server/src/index.js +774 -0
- package/server/src/orchestrator.js +1193 -0
- package/server/src/paths.js +55 -0
- package/server/src/store.js +287 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Daniele Eliasson
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="docs/images/ban_kan_logo_readme.svg" alt="Ban Kan logo" width="520" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
# Ban Kan
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<strong>Run AI coding agents like a Kanban board.</strong>
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
Plan → Implement → Review → Pull Request
|
|
13
|
+
</p>
|
|
14
|
+
|
|
15
|
+
<p align="center">
|
|
16
|
+
The control center for managing many AI coding agents in one simple UI.
|
|
17
|
+
</p>
|
|
18
|
+
|
|
19
|
+
<p align="center">
|
|
20
|
+
Bring order to parallel AI development without leaving your local workflow.
|
|
21
|
+
</p>
|
|
22
|
+
|
|
23
|
+
<p align="center">
|
|
24
|
+
<img src="docs/images/bankan_screenshot.png" alt="Ban Kan dashboard showing backlog, planning, implementation, review, and done columns" width="1200" />
|
|
25
|
+
</p>
|
|
26
|
+
|
|
27
|
+
<p align="center">
|
|
28
|
+
<a href="https://github.com/stilero/bankan/actions/workflows/ci.yml">CI</a>
|
|
29
|
+
·
|
|
30
|
+
<a href="https://github.com/stilero/bankan">GitHub</a>
|
|
31
|
+
·
|
|
32
|
+
<a href="https://github.com/stilero/bankan/issues">Issues</a>
|
|
33
|
+
</p>
|
|
34
|
+
|
|
35
|
+
<p align="center">
|
|
36
|
+
⭐ If Ban Kan helps you ship faster, please consider starring the repo.
|
|
37
|
+
</p>
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## What Is Ban Kan
|
|
42
|
+
|
|
43
|
+
Ban Kan is a **local control center for AI coding agents** that work across real repositories.
|
|
44
|
+
|
|
45
|
+
Instead of one long AI chat trying to do everything, tasks move through a structured pipeline inspired by a Kanban board:
|
|
46
|
+
|
|
47
|
+
Backlog → Planning → Implementation → Review → Done
|
|
48
|
+
|
|
49
|
+
Each stage can use different agents, prompts, and concurrency settings. Developers keep full visibility and control over what is happening at every step.
|
|
50
|
+
|
|
51
|
+
Ban Kan combines:
|
|
52
|
+
|
|
53
|
+
- structured workflows
|
|
54
|
+
- parallel agent execution
|
|
55
|
+
- human approvals
|
|
56
|
+
- local repository access
|
|
57
|
+
- optional pull request automation
|
|
58
|
+
|
|
59
|
+
All in one dashboard.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Why Ban Kan Exists
|
|
64
|
+
|
|
65
|
+
Most AI coding workflows eventually break down in the same way:
|
|
66
|
+
|
|
67
|
+
- one giant prompt tries to do planning, coding, and review
|
|
68
|
+
- context grows and token usage explodes
|
|
69
|
+
- agents overwrite each other’s work
|
|
70
|
+
- there is no clear review stage
|
|
71
|
+
- parallel development becomes chaos
|
|
72
|
+
|
|
73
|
+
Ban Kan fixes this with a model developers already understand:
|
|
74
|
+
|
|
75
|
+
**a Kanban board with specialized AI agents.**
|
|
76
|
+
|
|
77
|
+
Each stage has a clear responsibility, and tasks move forward only when the previous step succeeds.
|
|
78
|
+
|
|
79
|
+
<table>
|
|
80
|
+
<tr>
|
|
81
|
+
<td align="center" width="50%">
|
|
82
|
+
<img src="docs/images/before_claude_windows.png" alt="Four separate Claude Code terminal windows used to coordinate parallel agent work before Ban Kan" width="100%" />
|
|
83
|
+
<br />
|
|
84
|
+
<strong>Before Ban Kan</strong>
|
|
85
|
+
<br />
|
|
86
|
+
Managing multiple agents means juggling separate terminal windows and fragmented context.
|
|
87
|
+
</td>
|
|
88
|
+
<td align="center" width="50%">
|
|
89
|
+
<img src="docs/images/bankan_multi_tasks.png" alt="Ban Kan dashboard showing multiple tasks and agent output in one coordinated interface" width="100%" />
|
|
90
|
+
<br />
|
|
91
|
+
<strong>With Ban Kan</strong>
|
|
92
|
+
<br />
|
|
93
|
+
Tasks, agent stages, approvals, and live output stay visible in one shared dashboard.
|
|
94
|
+
</td>
|
|
95
|
+
</tr>
|
|
96
|
+
</table>
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Built for Agile Development
|
|
101
|
+
|
|
102
|
+
Ban Kan fits naturally into Agile workflows where work is organized as stories.
|
|
103
|
+
|
|
104
|
+
Each story moves through a structured lifecycle that mirrors how real development teams operate:
|
|
105
|
+
|
|
106
|
+
```mermaid
|
|
107
|
+
flowchart LR
|
|
108
|
+
A[Story / Task Created] --> B[Planning Agent]
|
|
109
|
+
B --> C[Implementation Agent]
|
|
110
|
+
C --> D[Review Agent]
|
|
111
|
+
D --> E[Done / Pull Request]
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
This structure makes Ban Kan especially useful when working with:
|
|
115
|
+
|
|
116
|
+
- Agile user stories
|
|
117
|
+
- sprint backlogs
|
|
118
|
+
- feature tasks
|
|
119
|
+
- incremental development
|
|
120
|
+
|
|
121
|
+
Instead of one AI trying to solve everything in a single prompt, each stage has a clear responsibility — just like in a real Agile team.
|
|
122
|
+
|
|
123
|
+
Developers plan the story, agents implement the work, reviewers validate the result, and the change moves forward when it meets quality gates.
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## What It Looks Like In Practice
|
|
128
|
+
|
|
129
|
+
Example story: **Add Stripe payments**
|
|
130
|
+
|
|
131
|
+
Below is the same task moving through Ban Kan's workflow from creation to completion.
|
|
132
|
+
|
|
133
|
+
### 1. Create the task
|
|
134
|
+
|
|
135
|
+
<p align="center">
|
|
136
|
+
<img src="docs/images/workflow/add_task.png" alt="Ban Kan add task modal used to create the Stripe payments task" />
|
|
137
|
+
</p>
|
|
138
|
+
|
|
139
|
+
The developer creates a task in the dashboard and defines the story to be planned and executed.
|
|
140
|
+
|
|
141
|
+
### 2. Planning starts
|
|
142
|
+
|
|
143
|
+
<p align="center">
|
|
144
|
+
<img src="docs/images/workflow/planning_stage_started.png" alt="Ban Kan planning stage showing the Stripe payments task as planning starts" />
|
|
145
|
+
</p>
|
|
146
|
+
|
|
147
|
+
The planner agent picks up the task, analyzes the repository, and prepares an implementation plan.
|
|
148
|
+
|
|
149
|
+
### 3. Review and approve the plan
|
|
150
|
+
|
|
151
|
+
<p align="center">
|
|
152
|
+
<img src="docs/images/workflow/planning_approve_plan.png" alt="Ban Kan planning stage showing an approval-ready plan for the Stripe payments task" />
|
|
153
|
+
</p>
|
|
154
|
+
|
|
155
|
+
The generated plan is shown in the dashboard so the developer can approve it before any code is written.
|
|
156
|
+
|
|
157
|
+
### 4. Implementation runs
|
|
158
|
+
|
|
159
|
+
<p align="center">
|
|
160
|
+
<img src="docs/images/workflow/implementing_task.png" alt="Ban Kan implementation stage showing the Stripe payments task being actively worked on by an agent" />
|
|
161
|
+
</p>
|
|
162
|
+
|
|
163
|
+
After approval, the implementor agent creates its workspace, writes the code, and reports progress live in the UI.
|
|
164
|
+
|
|
165
|
+
### 5. Review stage
|
|
166
|
+
|
|
167
|
+
<p align="center">
|
|
168
|
+
<img src="docs/images/workflow/review_stage.png" alt="Ban Kan review stage showing the Stripe payments task being validated by a reviewer agent" />
|
|
169
|
+
</p>
|
|
170
|
+
|
|
171
|
+
The reviewer agent validates the implementation, checks for issues, and decides whether the task is ready to move forward.
|
|
172
|
+
|
|
173
|
+
### 6. Done / ready for PR
|
|
174
|
+
|
|
175
|
+
<p align="center">
|
|
176
|
+
<img src="docs/images/workflow/done_stage.png" alt="Ban Kan done stage showing the Stripe payments task completed and ready for pull request creation" />
|
|
177
|
+
</p>
|
|
178
|
+
|
|
179
|
+
Once review passes, the task moves to Done and can be used as the basis for a pull request.
|
|
180
|
+
|
|
181
|
+
Multiple tasks can move through these stages simultaneously with different agents assigned to each step.
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## Installation
|
|
186
|
+
|
|
187
|
+
### Run instantly
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
npx bankan
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Install globally
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
npm install -g bankan
|
|
197
|
+
bankan
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Run from source
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
git clone https://github.com/stilero/bankan.git
|
|
204
|
+
cd bankan
|
|
205
|
+
|
|
206
|
+
npm run install:all
|
|
207
|
+
npm run setup
|
|
208
|
+
npm run dev
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Ban Kan starts a local server, opens your browser automatically, and serves the dashboard from the same process.
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## Requirements
|
|
216
|
+
|
|
217
|
+
- Node.js >= 18
|
|
218
|
+
- git
|
|
219
|
+
- One AI CLI tool:
|
|
220
|
+
- claude
|
|
221
|
+
- codex
|
|
222
|
+
- Native build tools for node-pty
|
|
223
|
+
|
|
224
|
+
macOS: Xcode Command Line Tools
|
|
225
|
+
Linux: build-essential
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## Quick Start
|
|
230
|
+
|
|
231
|
+
1. Launch Ban Kan
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
bankan
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
2. Complete the setup wizard
|
|
238
|
+
|
|
239
|
+
3. Add one or more local repositories
|
|
240
|
+
|
|
241
|
+
4. Create a task in the dashboard
|
|
242
|
+
|
|
243
|
+
5. Approve the generated plan
|
|
244
|
+
|
|
245
|
+
6. Watch agents implement and review the change
|
|
246
|
+
|
|
247
|
+
7. Optionally create a pull request
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## How It Works
|
|
252
|
+
|
|
253
|
+
```mermaid
|
|
254
|
+
flowchart TD
|
|
255
|
+
A[Developer creates task] --> B[Planner agent analyzes repository]
|
|
256
|
+
B --> C[Plan generated]
|
|
257
|
+
C --> D{Approve plan?}
|
|
258
|
+
D -->|Yes| E[Implementor writes code]
|
|
259
|
+
D -->|No| F[Revise plan]
|
|
260
|
+
E --> G[Reviewer validates changes]
|
|
261
|
+
G --> H{Review passed?}
|
|
262
|
+
H -->|Yes| I[Done / PR created]
|
|
263
|
+
H -->|No| E
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
Multiple tasks can run in parallel across different agents.
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## Key Features
|
|
271
|
+
|
|
272
|
+
### Parallel AI agents
|
|
273
|
+
Run multiple planning, implementation, and review agents simultaneously.
|
|
274
|
+
|
|
275
|
+
### Local-first workflow
|
|
276
|
+
Repositories stay on your machine. Agents operate directly on local clones and workspaces.
|
|
277
|
+
|
|
278
|
+
### Human approval gates
|
|
279
|
+
Developers approve plans before implementation begins.
|
|
280
|
+
|
|
281
|
+
### Live agent terminals
|
|
282
|
+
Open the terminal of any running agent and take control when needed.
|
|
283
|
+
|
|
284
|
+
### VS Code workspace support
|
|
285
|
+
Open a task workspace directly from the dashboard.
|
|
286
|
+
|
|
287
|
+
### PR automation
|
|
288
|
+
Configure GitHub settings to automatically create pull requests.
|
|
289
|
+
|
|
290
|
+
### Real-time dashboard
|
|
291
|
+
Track:
|
|
292
|
+
|
|
293
|
+
- active tasks
|
|
294
|
+
- blocked tasks
|
|
295
|
+
- agent activity
|
|
296
|
+
- context usage
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
## CLI
|
|
301
|
+
|
|
302
|
+
Ban Kan keeps the CLI intentionally simple.
|
|
303
|
+
|
|
304
|
+
```bash
|
|
305
|
+
bankan --port 3005
|
|
306
|
+
bankan --no-open
|
|
307
|
+
bankan --help
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
Options:
|
|
311
|
+
|
|
312
|
+
- `--port` bind to a specific port
|
|
313
|
+
- `--no-open` start without opening a browser
|
|
314
|
+
|
|
315
|
+
Most workflows happen inside the dashboard after launch.
|
|
316
|
+
|
|
317
|
+
---
|
|
318
|
+
|
|
319
|
+
## Architecture
|
|
320
|
+
|
|
321
|
+
Ban Kan includes:
|
|
322
|
+
|
|
323
|
+
- Node / Express backend orchestration
|
|
324
|
+
- WebSocket communication for live updates
|
|
325
|
+
- React dashboard built with Vite
|
|
326
|
+
- CLI launcher that starts the local app
|
|
327
|
+
- Configurable planner, implementor, and reviewer agent pools
|
|
328
|
+
|
|
329
|
+
---
|
|
330
|
+
|
|
331
|
+
## Development
|
|
332
|
+
|
|
333
|
+
```bash
|
|
334
|
+
npm run setup
|
|
335
|
+
npm run dev
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
Useful scripts:
|
|
339
|
+
|
|
340
|
+
- `npm run build` – build client bundle
|
|
341
|
+
- `npm run dev` – run server + Vite client
|
|
342
|
+
- `npm run setup` – interactive setup wizard
|
|
343
|
+
- `npm run install:all` – install all dependencies
|
|
344
|
+
|
|
345
|
+
---
|
|
346
|
+
|
|
347
|
+
## Contributing
|
|
348
|
+
|
|
349
|
+
Contributions are welcome.
|
|
350
|
+
|
|
351
|
+
1. Fork the repository
|
|
352
|
+
2. Open an issue before starting work
|
|
353
|
+
3. Create a focused branch
|
|
354
|
+
4. Make your changes
|
|
355
|
+
5. Submit a pull request
|
|
356
|
+
|
|
357
|
+
Screenshots are appreciated for UI updates.
|
|
358
|
+
|
|
359
|
+
---
|
|
360
|
+
|
|
361
|
+
## License
|
|
362
|
+
|
|
363
|
+
MIT
|
package/bin/bankan.js
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { existsSync } from 'node:fs';
|
|
4
|
+
import net from 'node:net';
|
|
5
|
+
import { spawn, execFileSync } from 'node:child_process';
|
|
6
|
+
import { dirname, join } from 'node:path';
|
|
7
|
+
import { fileURLToPath } from 'node:url';
|
|
8
|
+
|
|
9
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
const ROOT_DIR = join(__dirname, '..');
|
|
11
|
+
|
|
12
|
+
function parseArgs(argv) {
|
|
13
|
+
const args = { noOpen: false, port: null };
|
|
14
|
+
|
|
15
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
16
|
+
const arg = argv[i];
|
|
17
|
+
|
|
18
|
+
if (arg === '--no-open') {
|
|
19
|
+
args.noOpen = true;
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (arg === '--help' || arg === '-h') {
|
|
24
|
+
args.help = true;
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (arg === '--port' || arg === '-p') {
|
|
29
|
+
const value = argv[i + 1];
|
|
30
|
+
if (!value || !/^\d+$/.test(value)) {
|
|
31
|
+
throw new Error('`--port` expects a numeric value.');
|
|
32
|
+
}
|
|
33
|
+
args.port = parseInt(value, 10);
|
|
34
|
+
i += 1;
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
throw new Error(`Unknown argument: ${arg}`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return args;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function printHelp() {
|
|
45
|
+
process.stdout.write(`Ban Kan\n\nUsage:\n bankan [--port <number>] [--no-open]\n`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function isPortAvailable(port, host) {
|
|
49
|
+
return new Promise((resolve) => {
|
|
50
|
+
const tester = net.createServer();
|
|
51
|
+
tester.once('error', () => resolve(false));
|
|
52
|
+
tester.once('listening', () => {
|
|
53
|
+
tester.close(() => resolve(true));
|
|
54
|
+
});
|
|
55
|
+
tester.listen(port, host);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function findAvailablePort(preferredPort, host, { exact = false } = {}) {
|
|
60
|
+
if (exact) {
|
|
61
|
+
const available = await isPortAvailable(preferredPort, host);
|
|
62
|
+
if (!available) {
|
|
63
|
+
throw new Error(`Port ${preferredPort} is already in use.`);
|
|
64
|
+
}
|
|
65
|
+
return preferredPort;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
for (let port = preferredPort; port < preferredPort + 20; port += 1) {
|
|
69
|
+
if (await isPortAvailable(port, host)) {
|
|
70
|
+
return port;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
throw new Error(`Unable to find an open port near ${preferredPort}.`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function openBrowser(url) {
|
|
78
|
+
if (process.platform === 'darwin') {
|
|
79
|
+
spawn('open', [url], { detached: true, stdio: 'ignore' }).unref();
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (process.platform === 'win32') {
|
|
84
|
+
spawn('cmd', ['/c', 'start', '', url], { detached: true, stdio: 'ignore' }).unref();
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
spawn('xdg-open', [url], { detached: true, stdio: 'ignore' }).unref();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function runSetup() {
|
|
92
|
+
execFileSync(process.execPath, [join(ROOT_DIR, 'scripts', 'setup.js')], {
|
|
93
|
+
env: process.env,
|
|
94
|
+
stdio: 'inherit',
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async function main() {
|
|
99
|
+
const args = parseArgs(process.argv.slice(2));
|
|
100
|
+
if (args.help) {
|
|
101
|
+
printHelp();
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
process.env.BANKAN_RUNTIME_MODE = 'packaged';
|
|
106
|
+
|
|
107
|
+
const { getRuntimePaths } = await import('../server/src/paths.js');
|
|
108
|
+
const runtimePaths = getRuntimePaths();
|
|
109
|
+
|
|
110
|
+
if (!existsSync(runtimePaths.clientDistDir)) {
|
|
111
|
+
throw new Error('Built client assets are missing. Rebuild the package before publishing.');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (!existsSync(runtimePaths.envFile) && !existsSync(runtimePaths.settingsFile)) {
|
|
115
|
+
runSetup();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const { default: config } = await import('../server/src/config.js');
|
|
119
|
+
const { startServer } = await import('../server/src/index.js');
|
|
120
|
+
|
|
121
|
+
const host = '127.0.0.1';
|
|
122
|
+
const preferredPort = args.port ?? config.PORT;
|
|
123
|
+
const port = await findAvailablePort(preferredPort, host, { exact: args.port !== null });
|
|
124
|
+
const { server, port: resolvedPort } = await startServer({ port, host });
|
|
125
|
+
const url = `http://${host}:${resolvedPort}`;
|
|
126
|
+
|
|
127
|
+
process.stdout.write(`Ban Kan available at ${url}\n`);
|
|
128
|
+
|
|
129
|
+
if (!args.noOpen) {
|
|
130
|
+
try {
|
|
131
|
+
openBrowser(url);
|
|
132
|
+
} catch (err) {
|
|
133
|
+
process.stderr.write(`Failed to open browser automatically: ${err.message}\n`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const shutdown = () => {
|
|
138
|
+
server.close(() => process.exit(0));
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
process.on('SIGINT', shutdown);
|
|
142
|
+
process.on('SIGTERM', shutdown);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
main().catch((err) => {
|
|
146
|
+
process.stderr.write(`${err.message}\n`);
|
|
147
|
+
process.exit(1);
|
|
148
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2014 The xterm.js authors. All rights reserved.
|
|
3
|
+
* Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
|
|
4
|
+
* https://github.com/chjj/term.js
|
|
5
|
+
* @license MIT
|
|
6
|
+
*
|
|
7
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
* in the Software without restriction, including without limitation the rights
|
|
10
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
* furnished to do so, subject to the following conditions:
|
|
13
|
+
*
|
|
14
|
+
* The above copyright notice and this permission notice shall be included in
|
|
15
|
+
* all copies or substantial portions of the Software.
|
|
16
|
+
*
|
|
17
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
23
|
+
* THE SOFTWARE.
|
|
24
|
+
*
|
|
25
|
+
* Originally forked from (with the author's permission):
|
|
26
|
+
* Fabrice Bellard's javascript vt100 for jslinux:
|
|
27
|
+
* http://bellard.org/jslinux/
|
|
28
|
+
* Copyright (c) 2011 Fabrice Bellard
|
|
29
|
+
* The original design remains. The terminal itself
|
|
30
|
+
* has been extended to include xterm CSI codes, among
|
|
31
|
+
* other features.
|
|
32
|
+
*/.xterm{cursor:text;position:relative;user-select:none;-ms-user-select:none;-webkit-user-select:none}.xterm.focus,.xterm:focus{outline:none}.xterm .xterm-helpers{position:absolute;top:0;z-index:5}.xterm .xterm-helper-textarea{padding:0;border:0;margin:0;position:absolute;opacity:0;left:-9999em;top:0;width:0;height:0;z-index:-5;white-space:nowrap;overflow:hidden;resize:none}.xterm .composition-view{background:#000;color:#fff;display:none;position:absolute;white-space:nowrap;z-index:1}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{background-color:#000;overflow-y:scroll;cursor:default;position:absolute;right:0;left:0;top:0;bottom:0}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;left:0;top:0}.xterm .xterm-scroll-area{visibility:hidden}.xterm-char-measure-element{display:inline-block;visibility:hidden;position:absolute;top:0;left:-9999em;line-height:normal}.xterm.enable-mouse-events{cursor:default}.xterm.xterm-cursor-pointer,.xterm .xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility:not(.debug),.xterm .xterm-message{position:absolute;left:0;top:0;bottom:0;right:0;z-index:10;color:transparent;pointer-events:none}.xterm .xterm-accessibility-tree:not(.debug) *::selection{color:transparent}.xterm .xterm-accessibility-tree{-webkit-user-select:text;user-select:text;white-space:pre}.xterm .live-region{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}.xterm-dim{opacity:1!important}.xterm-underline-1{text-decoration:underline}.xterm-underline-2{text-decoration:double underline}.xterm-underline-3{text-decoration:wavy underline}.xterm-underline-4{text-decoration:dotted underline}.xterm-underline-5{text-decoration:dashed underline}.xterm-overline{text-decoration:overline}.xterm-overline.xterm-underline-1{text-decoration:overline underline}.xterm-overline.xterm-underline-2{text-decoration:overline double underline}.xterm-overline.xterm-underline-3{text-decoration:overline wavy underline}.xterm-overline.xterm-underline-4{text-decoration:overline dotted underline}.xterm-overline.xterm-underline-5{text-decoration:overline dashed underline}.xterm-strikethrough{text-decoration:line-through}.xterm-screen .xterm-decoration-container .xterm-decoration{z-index:6;position:absolute}.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer{z-index:7}.xterm-decoration-overview-ruler{z-index:8;position:absolute;top:0;right:0;pointer-events:none}.xterm-decoration-top{z-index:2;position:relative}:root{--bg: #0C0C0E;--bg1: #111114;--bg2: #16161A;--bg3: #1C1C22;--border: #252530;--border2: #2E2E3C;--amber: #F5A623;--steel2: #6AABDB;--green: #3DDC84;--red: #FF4D4D;--yellow: #FFD166;--purple: #A78BFA;--blue: #60A5FA;--text: #E8E8F0;--text2: #9090A8;--text3: #50505E;--font-mono: "DM Mono", monospace;--font-head: "Syne", sans-serif}*,*:before,*:after{box-sizing:border-box;margin:0;padding:0}html,body,#root{height:100%;overflow:hidden}body{font-family:var(--font-mono);font-size:13px;color:var(--text);background:var(--bg);-webkit-font-smoothing:antialiased}::-webkit-scrollbar{width:6px;height:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--border2);border-radius:3px}::-webkit-scrollbar-thumb:hover{background:var(--text3)}@keyframes card-enter{0%{opacity:0;transform:translate(-12px) scale(.97)}to{opacity:1;transform:translate(0) scale(1)}}@keyframes pulse{0%,to{opacity:1}50%{opacity:.4}}@keyframes fade-in{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}@keyframes toast-in{0%{opacity:0;transform:translate(100px)}to{opacity:1;transform:translate(0)}}button{font-family:var(--font-mono);cursor:pointer;border:none;background:none;color:var(--text);font-size:12px}input,textarea,select{font-family:var(--font-mono);font-size:13px;color:var(--text);background:var(--bg);border:1px solid var(--border);border-radius:4px;padding:8px 12px;outline:none}input:focus,textarea:focus,select:focus{border-color:var(--amber)}select option{color:var(--text);background:var(--bg1)}
|