claude-code-kanban 3.0.0 → 3.1.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/package.json +6 -6
- package/public/app.js +109 -60
- package/public/index.html +17 -2
- package/server.js +6 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-code-kanban",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"description": "A web-based Kanban board for viewing Claude Code tasks with agent teams support",
|
|
5
5
|
"main": "server.js",
|
|
6
6
|
"bin": {
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
},
|
|
17
17
|
"repository": {
|
|
18
18
|
"type": "git",
|
|
19
|
-
"url": "git+https://github.com/NikiforovAll/claude-
|
|
19
|
+
"url": "git+https://github.com/NikiforovAll/claude-code-kanban.git"
|
|
20
20
|
},
|
|
21
21
|
"keywords": [
|
|
22
22
|
"claude",
|
|
@@ -31,16 +31,16 @@
|
|
|
31
31
|
"author": "NikiforovAll",
|
|
32
32
|
"license": "MIT",
|
|
33
33
|
"bugs": {
|
|
34
|
-
"url": "https://github.com/NikiforovAll/claude-
|
|
34
|
+
"url": "https://github.com/NikiforovAll/claude-code-kanban/issues"
|
|
35
35
|
},
|
|
36
|
-
"homepage": "https://github.com/NikiforovAll/claude-
|
|
36
|
+
"homepage": "https://github.com/NikiforovAll/claude-code-kanban#readme",
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"chokidar": "^3.5.3",
|
|
39
39
|
"express": "^4.18.2",
|
|
40
|
-
"open": "^
|
|
40
|
+
"open": "^11.0.0"
|
|
41
41
|
},
|
|
42
42
|
"engines": {
|
|
43
|
-
"node": ">=
|
|
43
|
+
"node": ">=20.0.0"
|
|
44
44
|
},
|
|
45
45
|
"files": [
|
|
46
46
|
"server.js",
|
package/public/app.js
CHANGED
|
@@ -25,7 +25,7 @@ let agentPollInterval = null;
|
|
|
25
25
|
let selectedTaskId = null;
|
|
26
26
|
let selectedSessionId = null;
|
|
27
27
|
let focusZone = 'board'; // 'board' | 'sidebar'
|
|
28
|
-
let appConfig = { marketplaceUrl: null };
|
|
28
|
+
let appConfig = { marketplaceUrl: null, costUrl: null };
|
|
29
29
|
let selectedSessionIdx = -1;
|
|
30
30
|
let selectedSessionKbId = null;
|
|
31
31
|
let sessionJustSelected = false;
|
|
@@ -129,27 +129,33 @@ let lastTasksHash = '';
|
|
|
129
129
|
//#endregion
|
|
130
130
|
|
|
131
131
|
//#region DATA_FETCHING
|
|
132
|
-
async function fetchSessions() {
|
|
132
|
+
async function fetchSessions(includeTasks = true) {
|
|
133
133
|
try {
|
|
134
134
|
const allPinnedIds = new Set([...pinnedSessionIds, ...stickySessionIds]);
|
|
135
135
|
if (revealedPlanSessionId) allPinnedIds.add(revealedPlanSessionId);
|
|
136
136
|
if (revealedStorageSessionId) allPinnedIds.add(revealedStorageSessionId);
|
|
137
137
|
const pinnedParam = allPinnedIds.size > 0 ? `&pinned=${[...allPinnedIds].join(',')}` : '';
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
138
|
+
const sessionsPromise = fetch(`/api/sessions?limit=${sessionLimit}${pinnedParam}`).then((r) => r.json());
|
|
139
|
+
|
|
140
|
+
let newSessions, newTasks;
|
|
141
|
+
if (includeTasks) {
|
|
142
|
+
[newSessions, newTasks] = await Promise.all([sessionsPromise, fetch('/api/tasks/all').then((r) => r.json())]);
|
|
143
|
+
} else {
|
|
144
|
+
newSessions = await sessionsPromise;
|
|
145
|
+
}
|
|
142
146
|
|
|
143
147
|
const sessionsHash = JSON.stringify(newSessions);
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
return;
|
|
148
|
+
if (includeTasks) {
|
|
149
|
+
const tasksHash = JSON.stringify(newTasks);
|
|
150
|
+
if (sessionsHash === lastSessionsHash && tasksHash === lastTasksHash) return;
|
|
151
|
+
lastTasksHash = tasksHash;
|
|
152
|
+
allTasksCache = newTasks;
|
|
153
|
+
} else {
|
|
154
|
+
if (sessionsHash === lastSessionsHash) return;
|
|
147
155
|
}
|
|
148
156
|
lastSessionsHash = sessionsHash;
|
|
149
|
-
lastTasksHash = tasksHash;
|
|
150
157
|
|
|
151
158
|
sessions = newSessions;
|
|
152
|
-
allTasksCache = newTasks;
|
|
153
159
|
renderSessions();
|
|
154
160
|
renderLiveUpdatesFromCache();
|
|
155
161
|
} catch (error) {
|
|
@@ -2792,9 +2798,9 @@ function navigateSession(direction, items) {
|
|
|
2792
2798
|
const restoredIdx = selectedSessionKbId ? items.findIndex((el) => getKbId(el) === selectedSessionKbId) : -1;
|
|
2793
2799
|
newIdx = restoredIdx >= 0 ? restoredIdx : 0;
|
|
2794
2800
|
}
|
|
2795
|
-
if (newIdx
|
|
2796
|
-
|
|
2797
|
-
|
|
2801
|
+
if (newIdx < 0) newIdx = items.length - 1;
|
|
2802
|
+
else if (newIdx >= items.length) newIdx = 0;
|
|
2803
|
+
selectSessionByIndex(newIdx, items);
|
|
2798
2804
|
}
|
|
2799
2805
|
|
|
2800
2806
|
function setGroupCollapsed(header, collapsed) {
|
|
@@ -3975,6 +3981,22 @@ document.addEventListener('keydown', (e) => {
|
|
|
3975
3981
|
toggleScratchpad();
|
|
3976
3982
|
return;
|
|
3977
3983
|
}
|
|
3984
|
+
if (e.key === '$' && !e.ctrlKey && !e.altKey && !e.metaKey) {
|
|
3985
|
+
e.preventDefault();
|
|
3986
|
+
hubNavigate('cost', contextSid ? `?view=detail&session=${encodeURIComponent(contextSid)}` : undefined);
|
|
3987
|
+
return;
|
|
3988
|
+
}
|
|
3989
|
+
if (matchKey(e, 'KeyM')) {
|
|
3990
|
+
e.preventDefault();
|
|
3991
|
+
const mSession = contextSid ? sessions.find((s) => s.id === contextSid) : null;
|
|
3992
|
+
hubNavigate('marketplace', mSession?.project ? `?project=${encodeURIComponent(mSession.project)}` : undefined);
|
|
3993
|
+
return;
|
|
3994
|
+
}
|
|
3995
|
+
if (matchKey(e, 'KeyT')) {
|
|
3996
|
+
e.preventDefault();
|
|
3997
|
+
toggleTheme();
|
|
3998
|
+
return;
|
|
3999
|
+
}
|
|
3978
4000
|
if (e.key === '?' || (e.key === '/' && e.shiftKey)) {
|
|
3979
4001
|
e.preventDefault();
|
|
3980
4002
|
showHelpModal();
|
|
@@ -4043,7 +4065,7 @@ function setupEventSource() {
|
|
|
4043
4065
|
if (isMetadata) {
|
|
4044
4066
|
clearTimeout(metadataRefreshTimer);
|
|
4045
4067
|
metadataRefreshTimer = setTimeout(async () => {
|
|
4046
|
-
fetchSessions().catch((err) => console.error('[SSE] fetchSessions failed:', err));
|
|
4068
|
+
fetchSessions(false).catch((err) => console.error('[SSE] fetchSessions failed:', err));
|
|
4047
4069
|
if (currentSessionId) {
|
|
4048
4070
|
await fetchAgents(currentSessionId);
|
|
4049
4071
|
if (!agentLogMode) fetchMessages(currentSessionId);
|
|
@@ -4084,7 +4106,7 @@ function setupEventSource() {
|
|
|
4084
4106
|
pendingAgentSessionIds.add(data.sessionId);
|
|
4085
4107
|
clearTimeout(agentRefreshTimer);
|
|
4086
4108
|
agentRefreshTimer = setTimeout(() => {
|
|
4087
|
-
fetchSessions().catch((err) => console.error('[SSE] fetchSessions failed:', err));
|
|
4109
|
+
fetchSessions(false).catch((err) => console.error('[SSE] fetchSessions failed:', err));
|
|
4088
4110
|
if (viewMode === 'project' && currentProjectSessionIds.some((id) => pendingAgentSessionIds.has(id))) {
|
|
4089
4111
|
refreshProjectAgents();
|
|
4090
4112
|
} else if (currentSessionId && pendingAgentSessionIds.has(currentSessionId)) {
|
|
@@ -4109,8 +4131,22 @@ function setupEventSource() {
|
|
|
4109
4131
|
};
|
|
4110
4132
|
}
|
|
4111
4133
|
|
|
4112
|
-
//
|
|
4134
|
+
// When the tab becomes visible after being hidden, catch up immediately
|
|
4135
|
+
let _pollMissed = false;
|
|
4136
|
+
document.addEventListener('visibilitychange', () => {
|
|
4137
|
+
if (!document.hidden && _pollMissed) {
|
|
4138
|
+
_pollMissed = false;
|
|
4139
|
+
fetchSessions().catch(() => {});
|
|
4140
|
+
if (currentSessionId) fetchTasks(currentSessionId).catch(() => {});
|
|
4141
|
+
}
|
|
4142
|
+
});
|
|
4143
|
+
|
|
4144
|
+
// Fallback poll every 30s in case SSE silently drops; skip when tab is hidden
|
|
4113
4145
|
setInterval(() => {
|
|
4146
|
+
if (document.hidden) {
|
|
4147
|
+
_pollMissed = true;
|
|
4148
|
+
return;
|
|
4149
|
+
}
|
|
4114
4150
|
fetchSessions().catch(() => {});
|
|
4115
4151
|
}, 30000);
|
|
4116
4152
|
|
|
@@ -4581,7 +4617,6 @@ function updateThemeColor(isLight) {
|
|
|
4581
4617
|
//#endregion
|
|
4582
4618
|
|
|
4583
4619
|
//#region THEME
|
|
4584
|
-
// biome-ignore lint/correctness/noUnusedVariables: used in HTML
|
|
4585
4620
|
function toggleTheme() {
|
|
4586
4621
|
const isCurrentlyLight = document.body.classList.contains('light');
|
|
4587
4622
|
if (isCurrentlyLight) {
|
|
@@ -4941,6 +4976,8 @@ function showInfoModal(session, teamConfig, tasks, planContent) {
|
|
|
4941
4976
|
_infoModalSessionId = session.id;
|
|
4942
4977
|
updateStickyBtnState();
|
|
4943
4978
|
updateDismissBtnState();
|
|
4979
|
+
const costBtn = document.getElementById('session-info-cost-btn');
|
|
4980
|
+
if (costBtn) costBtn.style.display = window.__HUB__?.enabled || appConfig.costUrl ? '' : 'none';
|
|
4944
4981
|
modal.classList.add('visible');
|
|
4945
4982
|
|
|
4946
4983
|
const keyHandler = (e) => {
|
|
@@ -5043,6 +5080,15 @@ function openFolderInEditor(folder, file) {
|
|
|
5043
5080
|
postAndToast('/api/open-folder', body, 'folder');
|
|
5044
5081
|
}
|
|
5045
5082
|
|
|
5083
|
+
// biome-ignore lint/correctness/noUnusedVariables: used in HTML
|
|
5084
|
+
function openCost(sessionId) {
|
|
5085
|
+
if (window.__HUB__?.enabled) {
|
|
5086
|
+
hubNavigate('cost', `?view=detail&session=${encodeURIComponent(sessionId)}`);
|
|
5087
|
+
} else if (appConfig.costUrl) {
|
|
5088
|
+
window.open(`${appConfig.costUrl}?view=detail&session=${encodeURIComponent(sessionId)}`, '_blank');
|
|
5089
|
+
}
|
|
5090
|
+
}
|
|
5091
|
+
|
|
5046
5092
|
// biome-ignore lint/correctness/noUnusedVariables: used in HTML
|
|
5047
5093
|
function openMarketplace(projectPath) {
|
|
5048
5094
|
const params = new URLSearchParams({ project: projectPath });
|
|
@@ -5233,33 +5279,42 @@ if (urlState.search) {
|
|
|
5233
5279
|
document.getElementById('search-clear-btn').classList.add('visible');
|
|
5234
5280
|
}
|
|
5235
5281
|
|
|
5236
|
-
|
|
5237
|
-
|
|
5238
|
-
|
|
5239
|
-
|
|
5240
|
-
|
|
5241
|
-
|
|
5242
|
-
|
|
5243
|
-
|
|
5244
|
-
|
|
5245
|
-
|
|
5246
|
-
|
|
5247
|
-
|
|
5282
|
+
Promise.all([
|
|
5283
|
+
fetch('/hub-config')
|
|
5284
|
+
.then((r) => r.json())
|
|
5285
|
+
.then((cfg) => {
|
|
5286
|
+
if (!cfg.enabled) return;
|
|
5287
|
+
window.__HUB__ = cfg;
|
|
5288
|
+
})
|
|
5289
|
+
.catch(() => {}),
|
|
5290
|
+
fetch('/api/config')
|
|
5291
|
+
.then((r) => r.json())
|
|
5292
|
+
.then((c) => {
|
|
5293
|
+
appConfig = c;
|
|
5294
|
+
})
|
|
5295
|
+
.catch(() => {}),
|
|
5296
|
+
])
|
|
5297
|
+
.then(() => fetchSessions())
|
|
5298
|
+
.then(async () => {
|
|
5299
|
+
if (urlState.projectView) {
|
|
5300
|
+
try {
|
|
5301
|
+
await fetchProjectView(atob(urlState.projectView));
|
|
5302
|
+
} catch (_) {
|
|
5303
|
+
showAllTasks();
|
|
5304
|
+
}
|
|
5305
|
+
} else if (urlState.session) {
|
|
5306
|
+
await fetchTasks(urlState.session);
|
|
5307
|
+
} else {
|
|
5248
5308
|
showAllTasks();
|
|
5249
5309
|
}
|
|
5250
|
-
|
|
5251
|
-
|
|
5252
|
-
|
|
5253
|
-
|
|
5254
|
-
|
|
5255
|
-
|
|
5256
|
-
|
|
5257
|
-
|
|
5258
|
-
requestAnimationFrame(() => {
|
|
5259
|
-
if (currentMessages.length) renderMessages(currentMessages);
|
|
5260
|
-
});
|
|
5261
|
-
}
|
|
5262
|
-
});
|
|
5310
|
+
if (urlState.messages && currentSessionId) {
|
|
5311
|
+
toggleMessagePanel();
|
|
5312
|
+
// Re-render after panel layout settles so scroll dimensions are correct
|
|
5313
|
+
requestAnimationFrame(() => {
|
|
5314
|
+
if (currentMessages.length) renderMessages(currentMessages);
|
|
5315
|
+
});
|
|
5316
|
+
}
|
|
5317
|
+
});
|
|
5263
5318
|
|
|
5264
5319
|
window.addEventListener('popstate', () => {
|
|
5265
5320
|
const s = getUrlState();
|
|
@@ -5282,23 +5337,17 @@ window.addEventListener('popstate', () => {
|
|
|
5282
5337
|
//#endregion
|
|
5283
5338
|
|
|
5284
5339
|
// #region HUB_INTEGRATION
|
|
5285
|
-
(
|
|
5286
|
-
|
|
5287
|
-
|
|
5288
|
-
.
|
|
5289
|
-
|
|
5290
|
-
|
|
5291
|
-
|
|
5292
|
-
|
|
5293
|
-
|
|
5294
|
-
|
|
5295
|
-
|
|
5296
|
-
if (e.altKey && !e.ctrlKey && !e.shiftKey && !e.metaKey && /^[1-9]$/.test(e.key)) {
|
|
5297
|
-
e.preventDefault();
|
|
5298
|
-
window.parent?.postMessage({ type: 'hub:keydown', key: e.key }, '*');
|
|
5299
|
-
}
|
|
5300
|
-
});
|
|
5301
|
-
})();
|
|
5340
|
+
document.addEventListener('keydown', (e) => {
|
|
5341
|
+
if (!window.__HUB__?.enabled) return;
|
|
5342
|
+
if (e.ctrlKey && e.altKey && (e.key === 'ArrowLeft' || e.key === 'ArrowRight')) {
|
|
5343
|
+
e.preventDefault();
|
|
5344
|
+
window.parent?.postMessage({ type: 'hub:keydown', key: e.key }, '*');
|
|
5345
|
+
}
|
|
5346
|
+
if (e.altKey && !e.ctrlKey && !e.shiftKey && !e.metaKey && /^[1-9]$/.test(e.key)) {
|
|
5347
|
+
e.preventDefault();
|
|
5348
|
+
window.parent?.postMessage({ type: 'hub:keydown', key: e.key }, '*');
|
|
5349
|
+
}
|
|
5350
|
+
});
|
|
5302
5351
|
|
|
5303
5352
|
window.hubNavigate = function hubNavigate(app, url) {
|
|
5304
5353
|
if (!window.__HUB__?.enabled) return;
|
package/public/index.html
CHANGED
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
<header class="sidebar-header">
|
|
47
47
|
<div class="logo">
|
|
48
48
|
<div class="logo-mark">
|
|
49
|
-
<svg viewBox="
|
|
49
|
+
<svg viewBox="4 6 16 12" fill="none" stroke="currentColor" stroke-width="2.5">
|
|
50
50
|
<path d="M5 13l4 4L19 7"/>
|
|
51
51
|
</svg>
|
|
52
52
|
</div>
|
|
@@ -183,7 +183,7 @@
|
|
|
183
183
|
<circle cx="12" cy="17" r="0.5" fill="currentColor"/>
|
|
184
184
|
</svg>
|
|
185
185
|
</button>
|
|
186
|
-
<a href="https://github.com/NikiforovAll/claude-
|
|
186
|
+
<a href="https://github.com/NikiforovAll/claude-code-kanban" target="_blank" class="icon-btn" title="View on GitHub" aria-label="View on GitHub">
|
|
187
187
|
<svg viewBox="0 0 24 24" fill="currentColor" width="16" height="16">
|
|
188
188
|
<path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z"/>
|
|
189
189
|
</svg>
|
|
@@ -396,6 +396,18 @@
|
|
|
396
396
|
<td style="padding: 4px 0; color: var(--text-secondary);"><kbd style="background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-family: monospace;">N</kbd></td>
|
|
397
397
|
<td style="padding: 4px 0; color: var(--text-primary);">Toggle scratchpad</td>
|
|
398
398
|
</tr>
|
|
399
|
+
<tr>
|
|
400
|
+
<td style="padding: 4px 0; color: var(--text-secondary);"><kbd style="background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-family: monospace;">T</kbd></td>
|
|
401
|
+
<td style="padding: 4px 0; color: var(--text-primary);">Toggle theme</td>
|
|
402
|
+
</tr>
|
|
403
|
+
<tr>
|
|
404
|
+
<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>
|
|
405
|
+
<td style="padding: 4px 0; color: var(--text-primary);">Jump to cost</td>
|
|
406
|
+
</tr>
|
|
407
|
+
<tr>
|
|
408
|
+
<td style="padding: 4px 0; color: var(--text-secondary);"><kbd style="background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-family: monospace;">M</kbd></td>
|
|
409
|
+
<td style="padding: 4px 0; color: var(--text-primary);">Jump to marketplace</td>
|
|
410
|
+
</tr>
|
|
399
411
|
<tr>
|
|
400
412
|
<td style="padding: 4px 0; color: var(--text-secondary);"><kbd style="background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-family: monospace;">Shift+S</kbd></td>
|
|
401
413
|
<td style="padding: 4px 0; color: var(--text-primary);">Storage manager</td>
|
|
@@ -487,6 +499,9 @@
|
|
|
487
499
|
<button id="session-info-sticky-btn" class="icon-btn" style="display:none" title="Sticky pin — always show at top" onclick="toggleSessionSticky(_infoModalSessionId); updateStickyBtnState()">
|
|
488
500
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2 L15 9 L22 9 L17 14 L19 22 L12 18 L5 22 L7 14 L2 9 L9 9 Z"/></svg>
|
|
489
501
|
</button>
|
|
502
|
+
<button id="session-info-cost-btn" class="icon-btn" style="display:none" title="Open in Cost" onclick="openCost(_infoModalSessionId)">
|
|
503
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M16 8h-6a2 2 0 1 0 0 4h4a2 2 0 1 1 0 4H8"/><path d="M12 18V6"/></svg>
|
|
504
|
+
</button>
|
|
490
505
|
<button class="modal-close" aria-label="Close dialog" onclick="closeTeamModal()">
|
|
491
506
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
492
507
|
<path d="M18 6L6 18M6 6l12 12"/>
|
package/server.js
CHANGED
|
@@ -48,17 +48,18 @@ function getClaudeDir() {
|
|
|
48
48
|
return process.env.CLAUDE_DIR || path.join(os.homedir(), '.claude');
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
function
|
|
52
|
-
const idx = process.argv.findIndex(arg => arg.startsWith(
|
|
51
|
+
function getArgUrl(argName, envName) {
|
|
52
|
+
const idx = process.argv.findIndex(arg => arg.startsWith(`--${argName}`));
|
|
53
53
|
if (idx !== -1) {
|
|
54
54
|
const arg = process.argv[idx];
|
|
55
55
|
if (arg.includes('=')) return arg.split('=').slice(1).join('=');
|
|
56
56
|
if (process.argv[idx + 1]) return process.argv[idx + 1];
|
|
57
57
|
}
|
|
58
|
-
return process.env
|
|
58
|
+
return process.env[envName] || null;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
const MARKETPLACE_URL =
|
|
61
|
+
const MARKETPLACE_URL = getArgUrl('marketplace-url', 'MARKETPLACE_URL');
|
|
62
|
+
const COST_URL = getArgUrl('cost-url', 'COST_URL');
|
|
62
63
|
const CLAUDE_DIR = getClaudeDir();
|
|
63
64
|
const TASKS_DIR = path.join(CLAUDE_DIR, 'tasks');
|
|
64
65
|
const PROJECTS_DIR = path.join(CLAUDE_DIR, 'projects');
|
|
@@ -1276,7 +1277,7 @@ app.get('/api/version', (req, res) => {
|
|
|
1276
1277
|
});
|
|
1277
1278
|
|
|
1278
1279
|
app.get('/api/config', (req, res) => {
|
|
1279
|
-
res.json({ marketplaceUrl: MARKETPLACE_URL });
|
|
1280
|
+
res.json({ marketplaceUrl: MARKETPLACE_URL, costUrl: COST_URL });
|
|
1280
1281
|
});
|
|
1281
1282
|
|
|
1282
1283
|
// API: Get all tasks across all sessions
|