claude-code-kanban 1.11.0 → 1.12.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 +1 -1
- package/README.md +25 -105
- package/package.json +1 -1
- package/public/index.html +181 -6
- package/server.js +9 -0
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -1,55 +1,27 @@
|
|
|
1
1
|
# Claude Code Kanban
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/claude-code-kanban)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
[](https://www.npmjs.com/package/claude-code-kanban)
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
> Watch Claude Code think, in real time.
|
|
6
8
|
|
|
7
|
-

|
|
8
10
|
|
|
9
|
-
|
|
11
|
+

|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
## Features
|
|
12
14
|
|
|
13
|
-
- **
|
|
14
|
-
- **
|
|
15
|
-
- **
|
|
16
|
-
- **
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
### Observation-Focused Design
|
|
21
|
-
Claude Code controls task state — the viewer shows you what's happening:
|
|
22
|
-
- **Real-time status** — See tasks move through Pending → In Progress → Completed as Claude works
|
|
23
|
-
- **Active session detection** — Indicators show which sessions have in-progress tasks
|
|
24
|
-
- **Task dependencies** — Visualise blockedBy/blocks relationships to understand the critical path
|
|
25
|
-
- **Live activity feed** — Real-time stream of all in-progress tasks across every session
|
|
26
|
-
|
|
27
|
-
### Agent Teams Support
|
|
28
|
-
- **Team detection** — Automatically detects team sessions with multiple agents
|
|
29
|
-
- **Owner filtering** — Filter Kanban board by team member with color-coded agent indicators
|
|
30
|
-
- **Member count badges** — See how many agents are working in each session
|
|
31
|
-
|
|
32
|
-
### Cleanup Operations
|
|
33
|
-
- **Delete tasks** — Remove tasks with the delete button or press `D` (includes safety checks for dependencies)
|
|
34
|
-
- **Bulk delete** — Delete all tasks in a session at once
|
|
35
|
-
|
|
36
|
-
### Session Management
|
|
37
|
-
View and organize your Claude Code sessions:
|
|
38
|
-
- **Session discovery** — Automatically finds all sessions in `~/.claude/tasks/` and `~/.claude/projects/`
|
|
39
|
-
- **View project paths** — See the full filesystem path for each project
|
|
40
|
-
- **Git branch display** — See which branch each session is working on
|
|
41
|
-
- **Fuzzy search** — Search across session names, task descriptions, and project paths with instant filtering
|
|
42
|
-
- **Session filters** — Filter by active/all sessions and by project
|
|
43
|
-
|
|
44
|
-
### Keyboard Shortcuts
|
|
45
|
-
- `?` — Show help with all keyboard shortcuts
|
|
46
|
-
- `D` — Delete the currently selected task (with confirmation and dependency checking)
|
|
47
|
-
- `Esc` — Close detail panel or modals
|
|
15
|
+
- **Real-time updates** — Tasks move through Pending → In Progress → Completed as Claude works
|
|
16
|
+
- **Agent teams** — Color-coded team members, owner filtering, member count badges
|
|
17
|
+
- **Task dependencies** — See blockedBy/blocks relationships and the critical path
|
|
18
|
+
- **Live activity feed** — Stream of all in-progress tasks across every session
|
|
19
|
+
- **Session management** — Fuzzy search, project/branch display, active session indicators
|
|
20
|
+
- **Cleanup** — Delete tasks (with dependency checks) or bulk-delete entire sessions
|
|
21
|
+
- **Keyboard shortcuts** — Press `?` for help
|
|
48
22
|
|
|
49
23
|
## Installation
|
|
50
24
|
|
|
51
|
-
### Quick start
|
|
52
|
-
|
|
53
25
|
```bash
|
|
54
26
|
npx claude-code-kanban
|
|
55
27
|
```
|
|
@@ -63,78 +35,26 @@ npm install -g claude-code-kanban
|
|
|
63
35
|
claude-code-kanban --open
|
|
64
36
|
```
|
|
65
37
|
|
|
66
|
-
### From source
|
|
67
|
-
|
|
68
|
-
```bash
|
|
69
|
-
git clone https://github.com/NikiforovAll/claude-task-viewer.git
|
|
70
|
-
cd claude-task-viewer
|
|
71
|
-
npm install
|
|
72
|
-
npm start
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
## How It Works
|
|
76
|
-
|
|
77
|
-
Claude Code stores tasks in `~/.claude/tasks/`. Each session has its own folder:
|
|
78
|
-
|
|
79
|
-
```
|
|
80
|
-
~/.claude/tasks/
|
|
81
|
-
└── {session-uuid}/
|
|
82
|
-
├── 1.json
|
|
83
|
-
├── 2.json
|
|
84
|
-
└── ...
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
The viewer watches this directory and pushes updates via Server-Sent Events. Changes appear instantly — no polling, no refresh needed.
|
|
88
|
-
|
|
89
|
-
If port 3456 is already in use, the server automatically falls back to a random available port.
|
|
90
|
-
|
|
91
|
-
## Task Structure
|
|
92
|
-
|
|
93
|
-
```json
|
|
94
|
-
{
|
|
95
|
-
"id": "1",
|
|
96
|
-
"subject": "Implement user authentication",
|
|
97
|
-
"description": "Add JWT-based auth with refresh tokens",
|
|
98
|
-
"activeForm": "Setting up auth middleware",
|
|
99
|
-
"status": "in_progress",
|
|
100
|
-
"blocks": ["2", "3"],
|
|
101
|
-
"blockedBy": []
|
|
102
|
-
}
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
- `activeForm` — What Claude is doing right now (shown in Live Updates)
|
|
106
|
-
- `blocks` / `blockedBy` — Task dependency relationships
|
|
107
|
-
|
|
108
38
|
## Configuration
|
|
109
39
|
|
|
110
40
|
```bash
|
|
111
|
-
# Custom port
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
# Open browser automatically
|
|
115
|
-
npx claude-code-kanban --open
|
|
116
|
-
|
|
117
|
-
# Use a different Claude config directory (for multiple accounts)
|
|
118
|
-
npx claude-code-kanban --dir=~/.claude-work
|
|
41
|
+
PORT=8080 npx claude-code-kanban # Custom port
|
|
42
|
+
npx claude-code-kanban --open # Auto-open browser
|
|
43
|
+
npx claude-code-kanban --dir=~/.claude-work # Custom Claude config dir
|
|
119
44
|
```
|
|
120
45
|
|
|
121
|
-
|
|
46
|
+
If port 3456 is in use, the server falls back to a random available port.
|
|
122
47
|
|
|
123
|
-
|
|
124
|
-
|----------|--------|-------------|
|
|
125
|
-
| `/api/sessions` | GET | List all sessions with task counts |
|
|
126
|
-
| `/api/sessions/:id` | GET | Get all tasks for a session |
|
|
127
|
-
| `/api/tasks/all` | GET | Get all tasks across all sessions |
|
|
128
|
-
| `/api/tasks/:session/:task` | DELETE | Delete a task (checks dependencies) |
|
|
129
|
-
| `/api/tasks/:session/:task/note` | POST | Add a note to a task |
|
|
130
|
-
| `/api/teams/:name` | GET | Load team configuration |
|
|
131
|
-
| `/api/events` | GET | SSE stream for live updates |
|
|
48
|
+
## FAQ
|
|
132
49
|
|
|
133
|
-
|
|
50
|
+
**Does this control Claude?**
|
|
51
|
+
No. Claude Code owns all task state. The viewer only observes — it never directs Claude's work.
|
|
134
52
|
|
|
135
|
-
**
|
|
53
|
+
**Does it work with agent teams?**
|
|
54
|
+
Yes. Team sessions are auto-detected with color-coded members and owner filtering.
|
|
136
55
|
|
|
137
|
-
**
|
|
56
|
+
**Does it require Claude Code to be running?**
|
|
57
|
+
No. It reads task files from `~/.claude/tasks/`. You can view past sessions anytime.
|
|
138
58
|
|
|
139
59
|
## License
|
|
140
60
|
|
package/package.json
CHANGED
package/public/index.html
CHANGED
|
@@ -65,15 +65,35 @@
|
|
|
65
65
|
|
|
66
66
|
/* Sidebar */
|
|
67
67
|
.sidebar {
|
|
68
|
-
width: 300px;
|
|
68
|
+
width: var(--sidebar-width, 300px);
|
|
69
69
|
background: var(--bg-surface);
|
|
70
70
|
border-right: 1px solid var(--border);
|
|
71
71
|
box-shadow: 1px 0 12px rgba(0, 0, 0, 0.04);
|
|
72
72
|
display: flex;
|
|
73
73
|
flex-direction: column;
|
|
74
74
|
flex-shrink: 0;
|
|
75
|
+
position: relative;
|
|
76
|
+
overflow: hidden;
|
|
77
|
+
transition: width 0.25s cubic-bezier(0.4, 0, 0.2, 1);
|
|
75
78
|
}
|
|
76
79
|
|
|
80
|
+
.sidebar.collapsed { width: 48px; }
|
|
81
|
+
.sidebar.collapsed .logo-text,
|
|
82
|
+
.sidebar.collapsed .connection,
|
|
83
|
+
.sidebar.collapsed .sidebar-section,
|
|
84
|
+
.sidebar.collapsed .sidebar-footer { display: none; }
|
|
85
|
+
.sidebar.collapsed .sidebar-header {
|
|
86
|
+
padding: 12px;
|
|
87
|
+
display: flex;
|
|
88
|
+
flex-direction: column;
|
|
89
|
+
align-items: center;
|
|
90
|
+
gap: 12px;
|
|
91
|
+
}
|
|
92
|
+
.sidebar.collapsed .sidebar-toggle-btn {
|
|
93
|
+
position: static;
|
|
94
|
+
}
|
|
95
|
+
.sidebar.resizing { transition: none; }
|
|
96
|
+
|
|
77
97
|
.sidebar-header {
|
|
78
98
|
padding: 20px 20px 16px;
|
|
79
99
|
border-bottom: none;
|
|
@@ -81,8 +101,61 @@
|
|
|
81
101
|
background-size: 100% 1px;
|
|
82
102
|
background-repeat: no-repeat;
|
|
83
103
|
background-position: bottom;
|
|
104
|
+
position: relative;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.sidebar-toggle-btn {
|
|
108
|
+
position: absolute;
|
|
109
|
+
top: 20px;
|
|
110
|
+
right: 8px;
|
|
111
|
+
width: 28px;
|
|
112
|
+
height: 28px;
|
|
113
|
+
display: flex;
|
|
114
|
+
align-items: center;
|
|
115
|
+
justify-content: center;
|
|
116
|
+
background: transparent;
|
|
117
|
+
border: 1px solid transparent;
|
|
118
|
+
border-radius: 6px;
|
|
119
|
+
color: var(--text-muted);
|
|
120
|
+
cursor: pointer;
|
|
121
|
+
transition: all 0.15s ease;
|
|
122
|
+
padding: 0;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.sidebar-toggle-btn:hover {
|
|
126
|
+
color: var(--text-secondary);
|
|
127
|
+
background: var(--bg-hover);
|
|
128
|
+
border-color: var(--border);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.sidebar-toggle-btn svg {
|
|
132
|
+
width: 16px;
|
|
133
|
+
height: 16px;
|
|
134
|
+
transition: transform 0.25s ease;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.sidebar.collapsed .sidebar-toggle-btn svg {
|
|
138
|
+
transform: rotate(180deg);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.sidebar-resize-handle {
|
|
142
|
+
position: absolute;
|
|
143
|
+
top: 0;
|
|
144
|
+
right: 0;
|
|
145
|
+
width: 4px;
|
|
146
|
+
height: 100%;
|
|
147
|
+
cursor: col-resize;
|
|
148
|
+
z-index: 10;
|
|
149
|
+
transition: background 0.15s;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.sidebar-resize-handle:hover,
|
|
153
|
+
.sidebar-resize-handle.dragging {
|
|
154
|
+
background: var(--accent-dim);
|
|
84
155
|
}
|
|
85
156
|
|
|
157
|
+
.sidebar.collapsed .sidebar-resize-handle { display: none; }
|
|
158
|
+
|
|
86
159
|
.logo {
|
|
87
160
|
display: flex;
|
|
88
161
|
align-items: center;
|
|
@@ -115,9 +188,9 @@
|
|
|
115
188
|
.connection {
|
|
116
189
|
display: flex;
|
|
117
190
|
align-items: center;
|
|
118
|
-
gap:
|
|
119
|
-
margin-top:
|
|
120
|
-
font-size:
|
|
191
|
+
gap: 5px;
|
|
192
|
+
margin-top: 10px;
|
|
193
|
+
font-size: 10px;
|
|
121
194
|
color: var(--text-tertiary);
|
|
122
195
|
text-transform: uppercase;
|
|
123
196
|
letter-spacing: 0.05em;
|
|
@@ -387,6 +460,7 @@
|
|
|
387
460
|
|
|
388
461
|
/* Footer */
|
|
389
462
|
.sidebar-footer {
|
|
463
|
+
flex-shrink: 0;
|
|
390
464
|
padding: 14px 20px;
|
|
391
465
|
border-top: none;
|
|
392
466
|
background-image: linear-gradient(to right, transparent, var(--border), transparent);
|
|
@@ -616,6 +690,7 @@
|
|
|
616
690
|
display: flex;
|
|
617
691
|
flex-direction: column;
|
|
618
692
|
gap: 8px;
|
|
693
|
+
padding-right: 8px;
|
|
619
694
|
}
|
|
620
695
|
|
|
621
696
|
.column-empty {
|
|
@@ -979,6 +1054,17 @@
|
|
|
979
1054
|
margin-bottom: 0;
|
|
980
1055
|
}
|
|
981
1056
|
|
|
1057
|
+
.detail-desc ol,
|
|
1058
|
+
.detail-desc ul {
|
|
1059
|
+
padding-left: 1.5em;
|
|
1060
|
+
margin: 0 0 12px 0;
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
.detail-desc ol:last-child,
|
|
1064
|
+
.detail-desc ul:last-child {
|
|
1065
|
+
margin-bottom: 0;
|
|
1066
|
+
}
|
|
1067
|
+
|
|
982
1068
|
/* Note form */
|
|
983
1069
|
.note-section {
|
|
984
1070
|
margin-top: 24px;
|
|
@@ -1609,6 +1695,11 @@
|
|
|
1609
1695
|
<span class="connection-dot"></span>
|
|
1610
1696
|
<span>Connecting</span>
|
|
1611
1697
|
</div>
|
|
1698
|
+
<button id="sidebar-toggle" class="sidebar-toggle-btn" onclick="toggleSidebar()" title="Toggle sidebar" aria-label="Toggle sidebar">
|
|
1699
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
1700
|
+
<path d="M15 18l-6-6 6-6"/>
|
|
1701
|
+
</svg>
|
|
1702
|
+
</button>
|
|
1612
1703
|
</header>
|
|
1613
1704
|
|
|
1614
1705
|
<!-- Live Updates -->
|
|
@@ -1667,6 +1758,8 @@
|
|
|
1667
1758
|
<div id="sessions-list" class="sessions-list"></div>
|
|
1668
1759
|
</div>
|
|
1669
1760
|
|
|
1761
|
+
<div class="sidebar-footer" id="sidebar-footer"></div>
|
|
1762
|
+
<div class="sidebar-resize-handle" id="sidebar-resize"></div>
|
|
1670
1763
|
</aside>
|
|
1671
1764
|
|
|
1672
1765
|
<!-- Main -->
|
|
@@ -2119,8 +2212,8 @@
|
|
|
2119
2212
|
<div class="live-item" onclick="openLiveTask('${task.sessionId}', '${task.id}')">
|
|
2120
2213
|
<span class="pulse"></span>
|
|
2121
2214
|
<div class="live-item-content">
|
|
2122
|
-
<div class="live-item-action">${escapeHtml(task.activeForm || task.subject)}</div>
|
|
2123
|
-
<div class="live-item-session"
|
|
2215
|
+
<div class="live-item-action" title="${escapeHtml(task.activeForm || task.subject)}">${escapeHtml(task.activeForm || task.subject)}</div>
|
|
2216
|
+
<div class="live-item-session" title="${escapeHtml(task.sessionName || task.sessionId)}">${escapeHtml(task.sessionName || task.sessionId)}</div>
|
|
2124
2217
|
</div>
|
|
2125
2218
|
</div>
|
|
2126
2219
|
`).join('');
|
|
@@ -2554,6 +2647,10 @@
|
|
|
2554
2647
|
|
|
2555
2648
|
focusZone = zone;
|
|
2556
2649
|
if (zone === 'sidebar') {
|
|
2650
|
+
if (sidebar.classList.contains('collapsed')) {
|
|
2651
|
+
sidebar.classList.remove('collapsed');
|
|
2652
|
+
localStorage.setItem('sidebar-collapsed', false);
|
|
2653
|
+
}
|
|
2557
2654
|
sidebar.classList.add('sidebar-focused');
|
|
2558
2655
|
const items = getSessionItems();
|
|
2559
2656
|
if (selectedSessionIdx < 0 && items.length > 0) {
|
|
@@ -2877,6 +2974,12 @@
|
|
|
2877
2974
|
|
|
2878
2975
|
if (document.querySelector('.modal-overlay.visible')) return;
|
|
2879
2976
|
|
|
2977
|
+
if (e.key === '[') {
|
|
2978
|
+
e.preventDefault();
|
|
2979
|
+
toggleSidebar();
|
|
2980
|
+
return;
|
|
2981
|
+
}
|
|
2982
|
+
|
|
2880
2983
|
// Tab toggles focus zone
|
|
2881
2984
|
if (e.key === 'Tab') {
|
|
2882
2985
|
e.preventDefault();
|
|
@@ -3130,6 +3233,62 @@
|
|
|
3130
3233
|
updateThemeIcon();
|
|
3131
3234
|
}
|
|
3132
3235
|
|
|
3236
|
+
function toggleSidebar() {
|
|
3237
|
+
const sidebar = document.querySelector('.sidebar');
|
|
3238
|
+
const collapsed = sidebar.classList.toggle('collapsed');
|
|
3239
|
+
localStorage.setItem('sidebar-collapsed', collapsed);
|
|
3240
|
+
if (collapsed) {
|
|
3241
|
+
sidebar.style.width = '';
|
|
3242
|
+
} else {
|
|
3243
|
+
const w = getComputedStyle(sidebar).getPropertyValue('--sidebar-width');
|
|
3244
|
+
if (w) sidebar.style.width = w;
|
|
3245
|
+
}
|
|
3246
|
+
}
|
|
3247
|
+
|
|
3248
|
+
function loadSidebarState() {
|
|
3249
|
+
const sidebar = document.querySelector('.sidebar');
|
|
3250
|
+
if (localStorage.getItem('sidebar-collapsed') === 'true') {
|
|
3251
|
+
sidebar.classList.add('collapsed');
|
|
3252
|
+
}
|
|
3253
|
+
const w = localStorage.getItem('sidebar-width');
|
|
3254
|
+
if (w) {
|
|
3255
|
+
sidebar.style.setProperty('--sidebar-width', w);
|
|
3256
|
+
}
|
|
3257
|
+
}
|
|
3258
|
+
|
|
3259
|
+
function initSidebarResize() {
|
|
3260
|
+
const sidebar = document.querySelector('.sidebar');
|
|
3261
|
+
const handle = document.getElementById('sidebar-resize');
|
|
3262
|
+
let startX, startWidth;
|
|
3263
|
+
|
|
3264
|
+
handle.addEventListener('mousedown', (e) => {
|
|
3265
|
+
if (sidebar.classList.contains('collapsed')) return;
|
|
3266
|
+
startX = e.clientX;
|
|
3267
|
+
startWidth = sidebar.offsetWidth;
|
|
3268
|
+
sidebar.classList.add('resizing');
|
|
3269
|
+
handle.classList.add('dragging');
|
|
3270
|
+
document.body.style.userSelect = 'none';
|
|
3271
|
+
document.addEventListener('mousemove', onMove);
|
|
3272
|
+
document.addEventListener('mouseup', onUp);
|
|
3273
|
+
e.preventDefault();
|
|
3274
|
+
});
|
|
3275
|
+
|
|
3276
|
+
function onMove(e) {
|
|
3277
|
+
const w = Math.min(600, Math.max(200, startWidth + e.clientX - startX));
|
|
3278
|
+
sidebar.style.setProperty('--sidebar-width', w + 'px');
|
|
3279
|
+
sidebar.style.width = w + 'px';
|
|
3280
|
+
}
|
|
3281
|
+
|
|
3282
|
+
function onUp() {
|
|
3283
|
+
sidebar.classList.remove('resizing');
|
|
3284
|
+
handle.classList.remove('dragging');
|
|
3285
|
+
document.body.style.userSelect = '';
|
|
3286
|
+
document.removeEventListener('mousemove', onMove);
|
|
3287
|
+
document.removeEventListener('mouseup', onUp);
|
|
3288
|
+
localStorage.setItem('sidebar-width', sidebar.style.getPropertyValue('--sidebar-width'));
|
|
3289
|
+
}
|
|
3290
|
+
}
|
|
3291
|
+
|
|
3133
3292
|
function loadPreferences() {
|
|
3134
3293
|
document.getElementById('session-filter').value = sessionFilter;
|
|
3135
3294
|
document.getElementById('session-limit').value = sessionLimit;
|
|
@@ -3248,8 +3407,20 @@
|
|
|
3248
3407
|
renderKanban();
|
|
3249
3408
|
}
|
|
3250
3409
|
|
|
3410
|
+
// Sync sidebar header height with view header
|
|
3411
|
+
const sidebarHeader = document.querySelector('.sidebar-header');
|
|
3412
|
+
const viewHeader = document.querySelector('.view-header');
|
|
3413
|
+
new ResizeObserver(() => {
|
|
3414
|
+
sidebarHeader.style.height = viewHeader.offsetHeight + 'px';
|
|
3415
|
+
}).observe(viewHeader);
|
|
3416
|
+
|
|
3251
3417
|
// Init
|
|
3252
3418
|
loadTheme();
|
|
3419
|
+
loadSidebarState();
|
|
3420
|
+
initSidebarResize();
|
|
3421
|
+
fetch('/api/version').then(r => r.json()).then(d => {
|
|
3422
|
+
document.getElementById('sidebar-footer').textContent = 'v' + d.version;
|
|
3423
|
+
}).catch(() => {});
|
|
3253
3424
|
|
|
3254
3425
|
const urlState = getUrlState();
|
|
3255
3426
|
sessionFilter = urlState.filter || 'active';
|
|
@@ -3315,6 +3486,10 @@
|
|
|
3315
3486
|
<td style="padding: 4px 0; color: var(--text-secondary);"><kbd style="background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-family: monospace;">Tab</kbd></td>
|
|
3316
3487
|
<td style="padding: 4px 0; color: var(--text-primary);">Toggle sidebar / board focus</td>
|
|
3317
3488
|
</tr>
|
|
3489
|
+
<tr>
|
|
3490
|
+
<td style="padding: 4px 0; color: var(--text-secondary);"><kbd style="background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-family: monospace;">[</kbd></td>
|
|
3491
|
+
<td style="padding: 4px 0; color: var(--text-primary);">Toggle sidebar collapse</td>
|
|
3492
|
+
</tr>
|
|
3318
3493
|
</table>
|
|
3319
3494
|
</div>
|
|
3320
3495
|
<div>
|
package/server.js
CHANGED
|
@@ -329,6 +329,11 @@ app.get('/api/teams/:name', (req, res) => {
|
|
|
329
329
|
res.json(config);
|
|
330
330
|
});
|
|
331
331
|
|
|
332
|
+
app.get('/api/version', (req, res) => {
|
|
333
|
+
const pkg = require('./package.json');
|
|
334
|
+
res.json({ version: pkg.version });
|
|
335
|
+
});
|
|
336
|
+
|
|
332
337
|
// API: Get all tasks across all sessions
|
|
333
338
|
app.get('/api/tasks/all', async (req, res) => {
|
|
334
339
|
try {
|
|
@@ -516,6 +521,10 @@ projectsWatcher.on('all', (event, filePath) => {
|
|
|
516
521
|
}
|
|
517
522
|
});
|
|
518
523
|
|
|
524
|
+
app.use('/api', (req, res) => {
|
|
525
|
+
res.status(404).json({ error: 'Not found' });
|
|
526
|
+
});
|
|
527
|
+
|
|
519
528
|
// Start server
|
|
520
529
|
const server = app.listen(PORT, () => {
|
|
521
530
|
const actualPort = server.address().port;
|