claudeck 1.2.0 → 1.3.1
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/README.md +64 -5
- package/cli.js +53 -4
- package/package.json +3 -2
- package/public/css/core/responsive.css +2 -2
- package/public/css/ui/file-picker.css +243 -17
- package/public/css/ui/messages.css +72 -9
- package/public/css/ui/toolbox.css +43 -0
- package/public/index.html +80 -745
- package/public/js/components/add-project-modal.js +27 -0
- package/public/js/components/agent-modal.js +73 -0
- package/public/js/components/agent-monitor-modal.js +19 -0
- package/public/js/components/bg-confirm-modal.js +22 -0
- package/public/js/components/chain-modal.js +52 -0
- package/public/js/components/cost-dashboard-modal.js +39 -0
- package/public/js/components/dag-editor-modal.js +55 -0
- package/public/js/components/file-picker-modal.js +45 -0
- package/public/js/components/linear-create-modal.js +43 -0
- package/public/js/components/mcp-modal.js +58 -0
- package/public/js/components/orchestrate-modal.js +40 -0
- package/public/js/components/permission-modal.js +30 -0
- package/public/js/components/prompt-modal.js +31 -0
- package/public/js/components/shortcuts-modal.js +45 -0
- package/public/js/components/status-bar.js +97 -0
- package/public/js/components/system-prompt-modal.js +29 -0
- package/public/js/components/telegram-modal.js +84 -0
- package/public/js/components/welcome-overlay.js +60 -0
- package/public/js/components/workflow-modal.js +41 -0
- package/public/js/core/api.js +10 -0
- package/public/js/core/dom.js +3 -2
- package/public/js/core/ws.js +7 -1
- package/public/js/features/attachments.js +226 -23
- package/public/js/features/projects.js +7 -0
- package/public/js/main.js +22 -0
- package/public/js/ui/shortcuts.js +4 -8
- package/public/login.html +470 -0
- package/public/offline.html +300 -168
- package/public/sw.js +10 -2
- package/server/agent-loop.js +1 -0
- package/server/auth.js +141 -0
- package/server/orchestrator.js +1 -0
- package/server/ws-handler.js +2 -0
- package/server.js +14 -3
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
class StatusBar extends HTMLElement {
|
|
2
|
+
connectedCallback() {
|
|
3
|
+
this.innerHTML = `
|
|
4
|
+
<footer class="status-bar" id="status-bar">
|
|
5
|
+
<div class="status-bar-left">
|
|
6
|
+
<span class="sb-item sb-version" id="sb-version" title="Claudeck version"></span>
|
|
7
|
+
<span class="sb-sep"></span>
|
|
8
|
+
<span class="sb-item sb-connection" id="sb-connection" title="Connection status">
|
|
9
|
+
<span class="sb-dot" id="sb-dot"></span>
|
|
10
|
+
<span id="sb-connection-text">connecting</span>
|
|
11
|
+
</span>
|
|
12
|
+
<span class="sb-sep"></span>
|
|
13
|
+
<span class="sb-item sb-branch" id="sb-branch" title="Current git branch">
|
|
14
|
+
<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="6" y1="3" x2="6" y2="15"/><circle cx="18" cy="6" r="3"/><circle cx="6" cy="18" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>
|
|
15
|
+
<span id="sb-branch-name">--</span>
|
|
16
|
+
</span>
|
|
17
|
+
<span class="sb-sep"></span>
|
|
18
|
+
<span class="sb-item sb-project" id="sb-project" title="Current project">
|
|
19
|
+
<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/></svg>
|
|
20
|
+
<span id="sb-project-name">no project</span>
|
|
21
|
+
</span>
|
|
22
|
+
</div>
|
|
23
|
+
<div class="status-bar-center">
|
|
24
|
+
<span class="sb-item sb-activity" id="sb-activity"></span>
|
|
25
|
+
</div>
|
|
26
|
+
<div class="status-bar-right">
|
|
27
|
+
<span class="sb-item sb-bg-sessions hidden" id="sb-bg-sessions" title="Background sessions">
|
|
28
|
+
<span class="sb-bg-dot"></span>
|
|
29
|
+
<span id="sb-bg-count">0</span> bg
|
|
30
|
+
</span>
|
|
31
|
+
<span class="sb-sep sb-bg-sep hidden" id="sb-bg-sep"></span>
|
|
32
|
+
<span class="sb-item sb-tokens hidden" id="sb-streaming-tokens" title="Streaming tokens">
|
|
33
|
+
<span id="sb-tokens-value">~0 tokens</span>
|
|
34
|
+
</span>
|
|
35
|
+
<span class="sb-sep sb-tokens-sep hidden" id="sb-tokens-sep"></span>
|
|
36
|
+
<span class="sb-item sb-context-gauge" id="sb-context-gauge-item">
|
|
37
|
+
<span id="context-gauge" class="context-gauge hidden" title="Session context usage">
|
|
38
|
+
<span class="context-gauge-bar"><span id="context-gauge-fill" class="context-gauge-fill"></span></span>
|
|
39
|
+
<span id="context-gauge-label" class="context-gauge-label">0/200k</span>
|
|
40
|
+
</span>
|
|
41
|
+
</span>
|
|
42
|
+
<span class="sb-sep hidden" id="sb-gauge-sep"></span>
|
|
43
|
+
<span class="sb-item sb-credits" id="sb-credits" title="Credits">
|
|
44
|
+
<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/></svg>
|
|
45
|
+
<div class="sb-credits-popup" id="sb-credits-popup">
|
|
46
|
+
<div class="sb-credits-header">Credits</div>
|
|
47
|
+
<div class="sb-credits-body">
|
|
48
|
+
<div class="sb-credits-row">
|
|
49
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="var(--accent)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>
|
|
50
|
+
<div class="sb-credits-info">
|
|
51
|
+
<span class="sb-credits-role">Creator & Architect</span>
|
|
52
|
+
<span class="sb-credits-name">Hamed Farag</span>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
<div class="sb-credits-divider"></div>
|
|
56
|
+
<div class="sb-credits-row">
|
|
57
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#a78bfa" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2a4 4 0 0 0-4 4c0 2 2 3 2 5h4c0-2 2-3 2-5a4 4 0 0 0-4-4z"/><line x1="10" y1="17" x2="14" y2="17"/><line x1="10" y1="20" x2="14" y2="20"/><line x1="11" y1="23" x2="13" y2="23"/></svg>
|
|
58
|
+
<div class="sb-credits-info">
|
|
59
|
+
<span class="sb-credits-role">AI Assistant</span>
|
|
60
|
+
<span class="sb-credits-name">Claude Code AI</span>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
<div class="sb-credits-sponsor">
|
|
65
|
+
<div class="sb-credits-row">
|
|
66
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#f59e0b" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="7" width="20" height="14" rx="2" ry="2"/><path d="M16 21V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16"/></svg>
|
|
67
|
+
<div class="sb-credits-info">
|
|
68
|
+
<span class="sb-credits-role">Sponsor</span>
|
|
69
|
+
<span class="sb-credits-name">WakeCap</span>
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
<a class="sb-credits-kofi" href="https://ko-fi.com/hamedfarag" target="_blank" rel="noopener noreferrer">
|
|
74
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#ff5e5b" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 8h1a4 4 0 0 1 0 8h-1"/><path d="M2 8h16v9a4 4 0 0 1-4 4H6a4 4 0 0 1-4-4V8z"/><line x1="6" y1="1" x2="6" y2="4"/><line x1="10" y1="1" x2="10" y2="4"/><line x1="14" y1="1" x2="14" y2="4"/></svg>
|
|
75
|
+
<span>Support on Ko-fi</span>
|
|
76
|
+
</a>
|
|
77
|
+
</div>
|
|
78
|
+
</span>
|
|
79
|
+
<span class="sb-sep sb-credits-sep"></span>
|
|
80
|
+
<span class="sb-item sb-cost sb-cost-hint" id="sb-cost">
|
|
81
|
+
<span id="sb-session-cost">$0.00</span>
|
|
82
|
+
<span class="sb-cost-pipe">/</span>
|
|
83
|
+
<span id="sb-total-cost">$0.00</span>
|
|
84
|
+
<div class="sb-hint-popup">
|
|
85
|
+
<div class="sb-hint-header">Session / Total Cost</div>
|
|
86
|
+
<div class="sb-hint-body">
|
|
87
|
+
<p>Every message carries a fixed <strong>~20k token</strong> overhead from the Claude Code SDK — this includes the system prompt (~12-15k), core tool schemas (~4-5k), and environment context (~1k).</p>
|
|
88
|
+
<p>This cost is unavoidable and cannot be reduced. Disabling optional tools in Session settings saves only ~2-3k tokens.</p>
|
|
89
|
+
<p class="sb-hint-dim">Subsequent turns benefit from Anthropic's prompt caching, which significantly reduces the effective cost.</p>
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
</span>
|
|
93
|
+
</div>
|
|
94
|
+
</footer>`;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
customElements.define('claudeck-status-bar', StatusBar);
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
class SystemPromptModal extends HTMLElement {
|
|
2
|
+
connectedCallback() {
|
|
3
|
+
this.innerHTML = `
|
|
4
|
+
<div id="system-prompt-modal" class="modal-overlay hidden">
|
|
5
|
+
<div class="modal">
|
|
6
|
+
<div class="modal-header">
|
|
7
|
+
<h3>System Prompt</h3>
|
|
8
|
+
<button id="sp-modal-close" class="modal-close">×</button>
|
|
9
|
+
</div>
|
|
10
|
+
<form id="system-prompt-form">
|
|
11
|
+
<label for="sp-textarea">Custom instructions for Claude in this project</label>
|
|
12
|
+
<p class="sp-hint">If a <code>CLAUDE.md</code> file exists in the project root, it is automatically included by the SDK — no need to duplicate it here.</p>
|
|
13
|
+
<textarea id="sp-textarea" rows="8" placeholder="e.g., You are an expert in React + TypeScript. This is a monorepo..."></textarea>
|
|
14
|
+
<div class="modal-actions">
|
|
15
|
+
<button type="button" id="sp-clear-btn" class="modal-btn-cancel">Clear</button>
|
|
16
|
+
<button type="button" id="sp-cancel-btn" class="modal-btn-cancel">Cancel</button>
|
|
17
|
+
<button type="submit" class="modal-btn-save">Save</button>
|
|
18
|
+
</div>
|
|
19
|
+
</form>
|
|
20
|
+
</div>
|
|
21
|
+
</div>`;
|
|
22
|
+
|
|
23
|
+
const overlay = this.querySelector('#system-prompt-modal');
|
|
24
|
+
const closeBtn = this.querySelector('#sp-modal-close');
|
|
25
|
+
if (closeBtn) closeBtn.addEventListener('click', () => overlay.classList.add('hidden'));
|
|
26
|
+
if (overlay) overlay.addEventListener('click', (e) => { if (e.target === overlay) overlay.classList.add('hidden'); });
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
customElements.define('claudeck-system-prompt-modal', SystemPromptModal);
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// Web Component: Telegram Settings Modal
|
|
2
|
+
class ClaudeckTelegramModal extends HTMLElement {
|
|
3
|
+
connectedCallback() {
|
|
4
|
+
this.innerHTML = `
|
|
5
|
+
<div id="telegram-modal" class="modal-overlay hidden">
|
|
6
|
+
<div class="modal telegram-modal">
|
|
7
|
+
<div class="modal-header">
|
|
8
|
+
<h2>
|
|
9
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
10
|
+
<path d="M21.2 4.6L2.4 11.2c-.8.3-.8 1.5 0 1.8l4.6 1.7 1.7 5.5c.2.6 1 .8 1.4.3l2.5-2.8 4.8 3.5c.6.4 1.4.1 1.5-.6L21.2 4.6z"/>
|
|
11
|
+
</svg>
|
|
12
|
+
Telegram Notifications
|
|
13
|
+
</h2>
|
|
14
|
+
<button class="modal-close" id="telegram-close">×</button>
|
|
15
|
+
</div>
|
|
16
|
+
<div class="modal-body" style="padding:16px;">
|
|
17
|
+
<div class="telegram-form">
|
|
18
|
+
<label class="telegram-toggle-row">
|
|
19
|
+
<input type="checkbox" id="telegram-enabled">
|
|
20
|
+
<span>Enable Telegram notifications</span>
|
|
21
|
+
</label>
|
|
22
|
+
<div class="telegram-field">
|
|
23
|
+
<label for="telegram-bot-token">Bot Token</label>
|
|
24
|
+
<input type="password" id="telegram-bot-token" placeholder="123456:ABC-DEF..." autocomplete="off">
|
|
25
|
+
</div>
|
|
26
|
+
<div class="telegram-field">
|
|
27
|
+
<label for="telegram-chat-id">Chat ID</label>
|
|
28
|
+
<input type="text" id="telegram-chat-id" placeholder="-100123456789" autocomplete="off">
|
|
29
|
+
</div>
|
|
30
|
+
<div class="telegram-field">
|
|
31
|
+
<label for="telegram-afk-timeout">AFK Approval Timeout (minutes)</label>
|
|
32
|
+
<input type="number" id="telegram-afk-timeout" min="1" max="120" value="15" style="width:80px;">
|
|
33
|
+
</div>
|
|
34
|
+
|
|
35
|
+
<div class="telegram-notify-section">
|
|
36
|
+
<label class="telegram-field-label">Notification Events</label>
|
|
37
|
+
<div class="telegram-notify-grid">
|
|
38
|
+
<label class="telegram-toggle-row"><input type="checkbox" id="tg-notify-session" checked> Session complete</label>
|
|
39
|
+
<label class="telegram-toggle-row"><input type="checkbox" id="tg-notify-workflow" checked> Workflow complete</label>
|
|
40
|
+
<label class="telegram-toggle-row"><input type="checkbox" id="tg-notify-chain" checked> Chain complete</label>
|
|
41
|
+
<label class="telegram-toggle-row"><input type="checkbox" id="tg-notify-agent" checked> Agent complete</label>
|
|
42
|
+
<label class="telegram-toggle-row"><input type="checkbox" id="tg-notify-orchestrator" checked> Orchestrator complete</label>
|
|
43
|
+
<label class="telegram-toggle-row"><input type="checkbox" id="tg-notify-dag" checked> DAG complete</label>
|
|
44
|
+
<label class="telegram-toggle-row"><input type="checkbox" id="tg-notify-errors" checked> Errors & failures</label>
|
|
45
|
+
<label class="telegram-toggle-row"><input type="checkbox" id="tg-notify-permissions" checked> Permission requests (AFK approve/deny)</label>
|
|
46
|
+
<label class="telegram-toggle-row"><input type="checkbox" id="tg-notify-start" checked> Task start</label>
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
<div class="telegram-actions">
|
|
51
|
+
<button class="btn btn-secondary" id="telegram-test-btn">Send Test</button>
|
|
52
|
+
<button class="btn btn-primary" id="telegram-save-btn">Save</button>
|
|
53
|
+
</div>
|
|
54
|
+
<div id="telegram-status" class="telegram-status hidden"></div>
|
|
55
|
+
<details class="telegram-help">
|
|
56
|
+
<summary>Setup instructions</summary>
|
|
57
|
+
<ol>
|
|
58
|
+
<li>Open Telegram and search for <strong>@BotFather</strong></li>
|
|
59
|
+
<li>Send <code>/newbot</code> and follow the prompts to create a bot</li>
|
|
60
|
+
<li>Copy the <strong>Bot Token</strong> and paste it above</li>
|
|
61
|
+
<li>Start a chat with your new bot (send <code>/start</code>)</li>
|
|
62
|
+
<li>To find your <strong>Chat ID</strong>, send a message to the bot, then visit:<br>
|
|
63
|
+
<code>https://api.telegram.org/bot<TOKEN>/getUpdates</code><br>
|
|
64
|
+
Look for <code>"chat":{"id":...</code> in the response</li>
|
|
65
|
+
<li>For group chats, add the bot to the group and use the group's chat ID (starts with <code>-</code>)</li>
|
|
66
|
+
</ol>
|
|
67
|
+
</details>
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
`;
|
|
73
|
+
|
|
74
|
+
const overlay = this.querySelector('#telegram-modal');
|
|
75
|
+
const closeBtn = this.querySelector('#telegram-close');
|
|
76
|
+
|
|
77
|
+
closeBtn.addEventListener('click', () => overlay.classList.add('hidden'));
|
|
78
|
+
overlay.addEventListener('click', (e) => {
|
|
79
|
+
if (e.target === overlay) overlay.classList.add('hidden');
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
customElements.define('claudeck-telegram-modal', ClaudeckTelegramModal);
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
class WelcomeOverlay extends HTMLElement {
|
|
2
|
+
connectedCallback() {
|
|
3
|
+
this.innerHTML = `
|
|
4
|
+
<div id="welcome-overlay" class="welcome-overlay hidden">
|
|
5
|
+
<div class="welcome-container">
|
|
6
|
+
<div class="welcome-mascot">
|
|
7
|
+
<img src="/icons/whaly.png" alt="Whaly" class="welcome-whaly" draggable="false">
|
|
8
|
+
</div>
|
|
9
|
+
<h1 class="welcome-title">Welcome to <span>Claudeck</span></h1>
|
|
10
|
+
<div class="welcome-version">v1.0 · browser-based AI development environment</div>
|
|
11
|
+
<p class="welcome-description">
|
|
12
|
+
Your local command center for Claude Code. Chat with AI, run workflows,
|
|
13
|
+
manage projects, explore files, and orchestrate autonomous agents —
|
|
14
|
+
all from a single interface.
|
|
15
|
+
</p>
|
|
16
|
+
<div class="welcome-features">
|
|
17
|
+
<div class="welcome-feature">
|
|
18
|
+
<div class="welcome-feature-icon">
|
|
19
|
+
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
20
|
+
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>
|
|
21
|
+
</svg>
|
|
22
|
+
</div>
|
|
23
|
+
<div>
|
|
24
|
+
<div class="welcome-feature-title">AI Chat</div>
|
|
25
|
+
<div class="welcome-feature-desc">Stream conversations with Claude, run slash commands, attach files</div>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
<div class="welcome-feature">
|
|
29
|
+
<div class="welcome-feature-icon">
|
|
30
|
+
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
31
|
+
<circle cx="12" cy="12" r="3"/><path d="M12 1v4M12 19v4M4.22 4.22l2.83 2.83M16.95 16.95l2.83 2.83M1 12h4M19 12h4M4.22 19.78l2.83-2.83M16.95 7.05l2.83-2.83"/>
|
|
32
|
+
</svg>
|
|
33
|
+
</div>
|
|
34
|
+
<div>
|
|
35
|
+
<div class="welcome-feature-title">Agents & Workflows</div>
|
|
36
|
+
<div class="welcome-feature-desc">Automate tasks with pre-built or custom agent pipelines</div>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
<div class="welcome-feature">
|
|
40
|
+
<div class="welcome-feature-icon">
|
|
41
|
+
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
42
|
+
<path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/>
|
|
43
|
+
</svg>
|
|
44
|
+
</div>
|
|
45
|
+
<div>
|
|
46
|
+
<div class="welcome-feature-title">Dev Tools</div>
|
|
47
|
+
<div class="welcome-feature-desc">File explorer, Git panel, MCP servers, cost analytics</div>
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
<div class="welcome-actions">
|
|
52
|
+
<button id="welcome-get-started" class="welcome-btn-primary">Get Started</button>
|
|
53
|
+
<button id="welcome-take-tour" class="welcome-btn-secondary">Take a Tour</button>
|
|
54
|
+
</div>
|
|
55
|
+
<div class="welcome-hint">Press <kbd>Enter</kbd> or <kbd>Esc</kbd> to skip</div>
|
|
56
|
+
</div>
|
|
57
|
+
</div>`;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
customElements.define('claudeck-welcome-overlay', WelcomeOverlay);
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
class WorkflowModal extends HTMLElement {
|
|
2
|
+
connectedCallback() {
|
|
3
|
+
this.innerHTML = `
|
|
4
|
+
<div id="wf-modal" class="modal-overlay hidden">
|
|
5
|
+
<div class="modal agent-form-modal">
|
|
6
|
+
<div class="modal-header">
|
|
7
|
+
<h3 id="wf-modal-title">New Workflow</h3>
|
|
8
|
+
<button id="wf-modal-close" class="modal-close">×</button>
|
|
9
|
+
</div>
|
|
10
|
+
<form id="wf-form">
|
|
11
|
+
<div class="af-section">
|
|
12
|
+
<div class="af-section-label">Identity</div>
|
|
13
|
+
<div class="af-field">
|
|
14
|
+
<label for="wf-form-title">Title</label>
|
|
15
|
+
<input id="wf-form-title" type="text" placeholder="e.g. Review PR" required>
|
|
16
|
+
</div>
|
|
17
|
+
<div class="af-field">
|
|
18
|
+
<label for="wf-form-desc">Description</label>
|
|
19
|
+
<input id="wf-form-desc" type="text" placeholder="Short description of this workflow">
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
<div class="af-section">
|
|
23
|
+
<div class="af-section-label">Steps</div>
|
|
24
|
+
<div id="wf-steps-list" class="wf-steps-list"></div>
|
|
25
|
+
<button type="button" id="wf-add-step-btn" class="wf-step-add">+ Add Step</button>
|
|
26
|
+
</div>
|
|
27
|
+
<input id="wf-form-edit-id" type="hidden">
|
|
28
|
+
<div class="modal-actions">
|
|
29
|
+
<button type="button" id="wf-modal-cancel" class="modal-btn-cancel">Cancel</button>
|
|
30
|
+
<button type="submit" class="modal-btn-save">Save Workflow</button>
|
|
31
|
+
</div>
|
|
32
|
+
</form>
|
|
33
|
+
</div>
|
|
34
|
+
</div>`;
|
|
35
|
+
|
|
36
|
+
const overlay = this.querySelector('#wf-modal');
|
|
37
|
+
this.querySelector('#wf-modal-close').addEventListener('click', () => overlay.classList.add('hidden'));
|
|
38
|
+
overlay.addEventListener('click', (e) => { if (e.target === overlay) overlay.classList.add('hidden'); });
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
customElements.define('claudeck-workflow-modal', WorkflowModal);
|
package/public/js/core/api.js
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
// All fetch() calls consolidated into named functions
|
|
2
2
|
|
|
3
|
+
// Global 401 interceptor — redirect to login on auth failure
|
|
4
|
+
const _origFetch = window.fetch;
|
|
5
|
+
window.fetch = async (...args) => {
|
|
6
|
+
const res = await _origFetch(...args);
|
|
7
|
+
if (res.status === 401 && !window.location.pathname.startsWith("/login")) {
|
|
8
|
+
window.location.href = "/login";
|
|
9
|
+
}
|
|
10
|
+
return res;
|
|
11
|
+
};
|
|
12
|
+
|
|
3
13
|
export async function fetchProjects() {
|
|
4
14
|
const res = await fetch("/api/projects");
|
|
5
15
|
return res.json();
|
package/public/js/core/dom.js
CHANGED
|
@@ -99,6 +99,8 @@ export const $ = {
|
|
|
99
99
|
fpSearch: document.getElementById("fp-search"),
|
|
100
100
|
fpList: document.getElementById("fp-list"),
|
|
101
101
|
fpCount: document.getElementById("fp-count"),
|
|
102
|
+
fpSelected: document.getElementById("fp-selected"),
|
|
103
|
+
fpEmpty: document.getElementById("fp-empty"),
|
|
102
104
|
|
|
103
105
|
// Image attachments
|
|
104
106
|
imageBtn: document.getElementById("image-btn"),
|
|
@@ -114,8 +116,7 @@ export const $ = {
|
|
|
114
116
|
modalCloseBtn: document.getElementById("modal-close"),
|
|
115
117
|
modalCancelBtn: document.getElementById("modal-cancel"),
|
|
116
118
|
|
|
117
|
-
// Shortcuts
|
|
118
|
-
shortcutsModal: document.getElementById("shortcuts-modal"),
|
|
119
|
+
// Shortcuts — rendered by <claudeck-shortcuts-modal> web component
|
|
119
120
|
|
|
120
121
|
// Cost dashboard
|
|
121
122
|
costDashboardModal: document.getElementById("cost-dashboard-modal"),
|
package/public/js/core/ws.js
CHANGED
|
@@ -44,7 +44,13 @@ export function connectWebSocket() {
|
|
|
44
44
|
emit("ws:message", msg);
|
|
45
45
|
};
|
|
46
46
|
|
|
47
|
-
ws.onclose = () => {
|
|
47
|
+
ws.onclose = (event) => {
|
|
48
|
+
// Auth rejected — redirect to login instead of reconnecting
|
|
49
|
+
if (event.code === 1008 || event.code === 4401) {
|
|
50
|
+
window.location.href = "/login";
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
48
54
|
const delay = getBackoffDelay();
|
|
49
55
|
backoffAttempt++;
|
|
50
56
|
console.log(`WebSocket disconnected, reconnecting in ${Math.round(delay)}ms (attempt ${backoffAttempt})...`);
|