@co0ontty/wand 1.5.5 → 1.5.7
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.
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import { EventEmitter } from "node:events";
|
|
2
2
|
import { WandStorage } from "./storage.js";
|
|
3
|
-
import { ExecutionMode, SessionSnapshot, WandConfig } from "./types.js";
|
|
4
|
-
export
|
|
5
|
-
type: "output" | "status" | "started" | "ended" | "usage" | "task" | "notification";
|
|
6
|
-
sessionId: string;
|
|
7
|
-
data?: unknown;
|
|
8
|
-
}
|
|
3
|
+
import { ExecutionMode, ProcessEventHandler, SessionSnapshot, WandConfig } from "./types.js";
|
|
4
|
+
export type { ProcessEvent, ProcessEventHandler } from "./types.js";
|
|
9
5
|
/** Human-readable task information for the UI */
|
|
10
6
|
export interface TaskInfo {
|
|
11
7
|
title: string;
|
|
@@ -17,7 +13,6 @@ export declare class SessionInputError extends Error {
|
|
|
17
13
|
readonly sessionStatus?: SessionSnapshot["status"] | undefined;
|
|
18
14
|
constructor(message: string, code: "SESSION_NOT_FOUND" | "SESSION_NOT_RUNNING" | "SESSION_NO_PTY", sessionId: string, sessionStatus?: SessionSnapshot["status"] | undefined);
|
|
19
15
|
}
|
|
20
|
-
export type ProcessEventHandler = (event: ProcessEvent) => void;
|
|
21
16
|
/** A Claude Code session discovered by scanning ~/.claude/projects/ directories. */
|
|
22
17
|
export interface ClaudeHistorySession {
|
|
23
18
|
claudeSessionId: string;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { WandStorage } from "./storage.js";
|
|
2
|
-
import { ExecutionMode, SessionRunner, SessionSnapshot, WandConfig } from "./types.js";
|
|
3
|
-
import { ProcessEvent } from "./ws-broadcast.js";
|
|
2
|
+
import { ExecutionMode, ProcessEvent, SessionRunner, SessionSnapshot, WandConfig } from "./types.js";
|
|
4
3
|
interface CreateStructuredSessionOptions {
|
|
5
4
|
cwd: string;
|
|
6
5
|
mode: ExecutionMode;
|
package/dist/types.d.ts
CHANGED
|
@@ -8,6 +8,13 @@ export type EscalationScope = "write_file" | "run_command" | "network" | "outsid
|
|
|
8
8
|
export type EscalationRunner = "json" | "pty";
|
|
9
9
|
export type EscalationResolution = "approve_once" | "approve_turn" | "deny" | "fallback_manual";
|
|
10
10
|
export type EscalationSource = "tool_permission_request" | "sandbox_hard_block" | "workspace_policy_limit" | "cli_capability_limit" | "unknown";
|
|
11
|
+
/** WebSocket / ProcessManager event envelope used throughout the app. */
|
|
12
|
+
export interface ProcessEvent {
|
|
13
|
+
type: "output" | "status" | "started" | "ended" | "usage" | "task" | "notification";
|
|
14
|
+
sessionId: string;
|
|
15
|
+
data?: unknown;
|
|
16
|
+
}
|
|
17
|
+
export type ProcessEventHandler = (event: ProcessEvent) => void;
|
|
11
18
|
export interface EscalationRequest {
|
|
12
19
|
requestId: string;
|
|
13
20
|
scope: EscalationScope;
|
|
@@ -804,31 +804,50 @@
|
|
|
804
804
|
|
|
805
805
|
// General config tab
|
|
806
806
|
'<div class="settings-panel" id="settings-tab-general">' +
|
|
807
|
-
'<div class="field">' +
|
|
808
|
-
'<
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
'<
|
|
813
|
-
|
|
807
|
+
'<div class="field-row">' +
|
|
808
|
+
'<div class="field">' +
|
|
809
|
+
'<label class="field-label" for="cfg-host">监听地址 (host)</label>' +
|
|
810
|
+
'<input id="cfg-host" type="text" class="field-input" placeholder="127.0.0.1" />' +
|
|
811
|
+
'</div>' +
|
|
812
|
+
'<div class="field">' +
|
|
813
|
+
'<label class="field-label" for="cfg-port">端口 (port)</label>' +
|
|
814
|
+
'<input id="cfg-port" type="number" class="field-input" placeholder="8443" min="1" max="65535" />' +
|
|
815
|
+
'</div>' +
|
|
814
816
|
'</div>' +
|
|
815
817
|
'<div class="field field-inline">' +
|
|
816
|
-
'<label class="field-label" for="cfg-https">启用 HTTPS</label>' +
|
|
817
818
|
'<input id="cfg-https" type="checkbox" class="field-checkbox" />' +
|
|
819
|
+
'<label class="field-label" for="cfg-https">启用 HTTPS</label>' +
|
|
818
820
|
'</div>' +
|
|
819
|
-
'<div class="field">' +
|
|
820
|
-
'<
|
|
821
|
-
|
|
822
|
-
'<
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
821
|
+
'<div class="field-row">' +
|
|
822
|
+
'<div class="field">' +
|
|
823
|
+
'<label class="field-label" for="cfg-mode">默认执行模式</label>' +
|
|
824
|
+
'<select id="cfg-mode" class="field-input">' +
|
|
825
|
+
'<option value="default">default</option>' +
|
|
826
|
+
'<option value="assist">assist</option>' +
|
|
827
|
+
'<option value="agent">agent</option>' +
|
|
828
|
+
'<option value="agent-max">agent-max</option>' +
|
|
829
|
+
'<option value="auto-edit">auto-edit</option>' +
|
|
830
|
+
'<option value="full-access">full-access</option>' +
|
|
831
|
+
'<option value="native">native</option>' +
|
|
832
|
+
'<option value="managed">managed</option>' +
|
|
833
|
+
'</select>' +
|
|
834
|
+
'</div>' +
|
|
835
|
+
'<div class="field">' +
|
|
836
|
+
'<label class="field-label" for="cfg-language">回复语言</label>' +
|
|
837
|
+
'<select id="cfg-language" class="field-input">' +
|
|
838
|
+
'<option value="">自动(不指定)</option>' +
|
|
839
|
+
'<option value="中文">中文</option>' +
|
|
840
|
+
'<option value="English">English</option>' +
|
|
841
|
+
'<option value="日本語">日本語</option>' +
|
|
842
|
+
'<option value="한국어">한국어</option>' +
|
|
843
|
+
'<option value="Español">Español</option>' +
|
|
844
|
+
'<option value="Français">Français</option>' +
|
|
845
|
+
'<option value="Deutsch">Deutsch</option>' +
|
|
846
|
+
'<option value="Русский">Русский</option>' +
|
|
847
|
+
'</select>' +
|
|
848
|
+
'</div>' +
|
|
831
849
|
'</div>' +
|
|
850
|
+
'<p class="field-hint" style="margin-top:-4px;">设置回复语言后,Claude 将尽量使用指定语言回复。</p>' +
|
|
832
851
|
'<div class="field">' +
|
|
833
852
|
'<label class="field-label" for="cfg-cwd">默认工作目录</label>' +
|
|
834
853
|
'<input id="cfg-cwd" type="text" class="field-input" placeholder="/home/user" />' +
|
|
@@ -837,52 +856,40 @@
|
|
|
837
856
|
'<label class="field-label" for="cfg-shell">Shell</label>' +
|
|
838
857
|
'<input id="cfg-shell" type="text" class="field-input" placeholder="/bin/bash" />' +
|
|
839
858
|
'</div>' +
|
|
840
|
-
'<div class="field">' +
|
|
841
|
-
'<label class="field-label" for="cfg-language">回复语言</label>' +
|
|
842
|
-
'<select id="cfg-language" class="field-input">' +
|
|
843
|
-
'<option value="">自动(不指定)</option>' +
|
|
844
|
-
'<option value="中文">中文</option>' +
|
|
845
|
-
'<option value="English">English</option>' +
|
|
846
|
-
'<option value="日本語">日本語</option>' +
|
|
847
|
-
'<option value="한국어">한국어</option>' +
|
|
848
|
-
'<option value="Español">Español</option>' +
|
|
849
|
-
'<option value="Français">Français</option>' +
|
|
850
|
-
'<option value="Deutsch">Deutsch</option>' +
|
|
851
|
-
'<option value="Русский">Русский</option>' +
|
|
852
|
-
'</select>' +
|
|
853
|
-
'<p class="hint" style="margin-top:4px;margin-bottom:0;">设置后,Claude 将尽量使用指定语言回复。</p>' +
|
|
854
|
-
'</div>' +
|
|
855
859
|
'<button id="save-config-button" class="btn btn-primary btn-block">保存配置</button>' +
|
|
856
860
|
'<p id="config-message" class="hint hidden"></p>' +
|
|
857
861
|
'</div>' +
|
|
858
862
|
|
|
859
863
|
// Security tab
|
|
860
864
|
'<div class="settings-panel" id="settings-tab-security">' +
|
|
861
|
-
'<
|
|
862
|
-
|
|
863
|
-
'<
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
'<
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
'<h3 class="settings-section-title">SSL 证书</h3>' +
|
|
875
|
-
'<p class="settings-hint" id="cert-status">加载中...</p>' +
|
|
876
|
-
'<div class="field">' +
|
|
877
|
-
'<label class="field-label" for="cert-key-file">私钥文件 (.key)</label>' +
|
|
878
|
-
'<input id="cert-key-file" type="file" class="field-input field-file" accept=".key,.pem" />' +
|
|
865
|
+
'<div class="settings-card">' +
|
|
866
|
+
'<h3 class="settings-section-title">\ud83d\udd12 修改密码</h3>' +
|
|
867
|
+
'<div class="field">' +
|
|
868
|
+
'<label class="field-label" for="new-password">新密码</label>' +
|
|
869
|
+
'<input id="new-password" type="password" class="field-input" placeholder="输入新密码(至少 6 个字符)" autocomplete="new-password" />' +
|
|
870
|
+
'</div>' +
|
|
871
|
+
'<div class="field">' +
|
|
872
|
+
'<label class="field-label" for="confirm-password">确认密码</label>' +
|
|
873
|
+
'<input id="confirm-password" type="password" class="field-input" placeholder="再次输入新密码" autocomplete="new-password" />' +
|
|
874
|
+
'</div>' +
|
|
875
|
+
'<button id="save-password-button" class="btn btn-primary btn-block">保存密码</button>' +
|
|
876
|
+
'<p id="settings-error" class="error-message hidden"></p>' +
|
|
877
|
+
'<p id="settings-success" class="hint hidden" style="color: var(--success);"></p>' +
|
|
879
878
|
'</div>' +
|
|
880
|
-
'<div class="
|
|
881
|
-
'<
|
|
882
|
-
'<
|
|
879
|
+
'<div class="settings-card">' +
|
|
880
|
+
'<h3 class="settings-section-title">\ud83d\udd10 SSL 证书</h3>' +
|
|
881
|
+
'<p class="settings-hint" id="cert-status">加载中...</p>' +
|
|
882
|
+
'<div class="field">' +
|
|
883
|
+
'<label class="field-label" for="cert-key-file">私钥文件 (.key)</label>' +
|
|
884
|
+
'<input id="cert-key-file" type="file" class="field-input field-file" accept=".key,.pem" />' +
|
|
885
|
+
'</div>' +
|
|
886
|
+
'<div class="field">' +
|
|
887
|
+
'<label class="field-label" for="cert-cert-file">证书文件 (.crt/.pem)</label>' +
|
|
888
|
+
'<input id="cert-cert-file" type="file" class="field-input field-file" accept=".crt,.pem,.cert" />' +
|
|
889
|
+
'</div>' +
|
|
890
|
+
'<button id="upload-cert-button" class="btn btn-primary btn-block">上传证书</button>' +
|
|
891
|
+
'<p id="cert-message" class="hint hidden"></p>' +
|
|
883
892
|
'</div>' +
|
|
884
|
-
'<button id="upload-cert-button" class="btn btn-primary btn-block">上传证书</button>' +
|
|
885
|
-
'<p id="cert-message" class="hint hidden"></p>' +
|
|
886
893
|
'</div>' +
|
|
887
894
|
|
|
888
895
|
// Command presets tab
|
|
@@ -3943,15 +3950,23 @@
|
|
|
3943
3950
|
function selectSession(id) {
|
|
3944
3951
|
var foundSession = state.sessions.find(function(item) { return item.id === id; });
|
|
3945
3952
|
console.log("[WAND] selectSession id:", id, "found:", !!foundSession, "sessionKind:", foundSession && foundSession.sessionKind, "runner:", foundSession && foundSession.runner, "isStructured:", isStructuredSession(foundSession));
|
|
3953
|
+
if (!foundSession) {
|
|
3954
|
+
console.warn("[WAND] selectSession: session not found, skipping", id);
|
|
3955
|
+
return;
|
|
3956
|
+
}
|
|
3946
3957
|
state.selectedId = id;
|
|
3947
3958
|
persistSelectedId();
|
|
3959
|
+
// Clear queued inputs from the previous session to prevent cross-session leaks
|
|
3960
|
+
state.messageQueue = [];
|
|
3961
|
+
state.pendingMessages = [];
|
|
3962
|
+
updateQueueCounter();
|
|
3948
3963
|
resetChatRenderCache();
|
|
3949
3964
|
state.currentMessages = [];
|
|
3950
3965
|
if (chatRenderTimer) { clearTimeout(chatRenderTimer); chatRenderTimer = null; }
|
|
3951
3966
|
// Reset todo progress bar
|
|
3952
3967
|
var todoEl = document.getElementById("todo-progress");
|
|
3953
3968
|
if (todoEl) todoEl.classList.add("hidden");
|
|
3954
|
-
var session =
|
|
3969
|
+
var session = foundSession;
|
|
3955
3970
|
state.preferredCommand = getPreferredTool();
|
|
3956
3971
|
state.chatMode = getSafeModeForTool("claude", session && session.mode ? session.mode : state.chatMode);
|
|
3957
3972
|
if (state.terminalInteractive && session && session.status !== "running") {
|
|
@@ -4010,6 +4025,8 @@
|
|
|
4010
4025
|
var focusTrapHandler = null;
|
|
4011
4026
|
|
|
4012
4027
|
function openSessionModal() {
|
|
4028
|
+
// Close settings modal first if open (mutual exclusion)
|
|
4029
|
+
closeSettingsModal();
|
|
4013
4030
|
state.modalOpen = true;
|
|
4014
4031
|
state.sessionsDrawerOpen = false;
|
|
4015
4032
|
updateDrawerState();
|
|
@@ -4084,6 +4101,8 @@
|
|
|
4084
4101
|
}
|
|
4085
4102
|
|
|
4086
4103
|
function openSettingsModal() {
|
|
4104
|
+
// Close session modal first if open (mutual exclusion)
|
|
4105
|
+
closeSessionModal();
|
|
4087
4106
|
var modal = document.getElementById("settings-modal");
|
|
4088
4107
|
if (modal) {
|
|
4089
4108
|
modal.classList.remove("hidden");
|
|
@@ -4240,7 +4259,7 @@
|
|
|
4240
4259
|
'<span class="preset-detail">' + escapeHtml(p.command) + (p.mode ? ' (' + escapeHtml(p.mode) + ')' : '') + '</span>' +
|
|
4241
4260
|
'</div>';
|
|
4242
4261
|
}
|
|
4243
|
-
if (!html) html = '<
|
|
4262
|
+
if (!html) html = '<div class="empty-state-compact"><span class="empty-icon">\u2699</span><span>\u6ca1\u6709\u547d\u4ee4\u9884\u8bbe</span><span class="hint">\u5728 config.json \u7684 commandPresets \u4e2d\u914d\u7f6e</span></div>';
|
|
4244
4263
|
presetsList.innerHTML = html;
|
|
4245
4264
|
}
|
|
4246
4265
|
})
|
|
@@ -4542,7 +4561,10 @@
|
|
|
4542
4561
|
});
|
|
4543
4562
|
}
|
|
4544
4563
|
|
|
4564
|
+
var _sessionCreating = false;
|
|
4565
|
+
|
|
4545
4566
|
function runCommand() {
|
|
4567
|
+
if (_sessionCreating) return;
|
|
4546
4568
|
var cwdEl = document.getElementById("cwd");
|
|
4547
4569
|
var errorEl = document.getElementById("modal-error");
|
|
4548
4570
|
var command = getPreferredTool();
|
|
@@ -4564,6 +4586,7 @@
|
|
|
4564
4586
|
|
|
4565
4587
|
function startStructuredSessionFromModal(cwd, mode, errorEl) {
|
|
4566
4588
|
console.log("[WAND] startStructuredSessionFromModal cwd:", cwd, "mode:", mode);
|
|
4589
|
+
_sessionCreating = true;
|
|
4567
4590
|
state.modeValue = mode;
|
|
4568
4591
|
state.chatMode = mode;
|
|
4569
4592
|
state.sessionTool = "claude";
|
|
@@ -4579,11 +4602,13 @@
|
|
|
4579
4602
|
.then(function() { focusInputBox(true); })
|
|
4580
4603
|
.catch(function(error) {
|
|
4581
4604
|
showError(errorEl, (error && error.message) || "无法启动结构化会话,请确认 Claude 已正确安装。");
|
|
4582
|
-
})
|
|
4605
|
+
})
|
|
4606
|
+
.finally(function() { _sessionCreating = false; });
|
|
4583
4607
|
}
|
|
4584
4608
|
|
|
4585
4609
|
function runPtyCommandFromModal(command, cwd, mode, errorEl) {
|
|
4586
4610
|
console.log("[WAND] runPtyCommandFromModal command:", command, "cwd:", cwd, "mode:", mode);
|
|
4611
|
+
_sessionCreating = true;
|
|
4587
4612
|
state.modeValue = mode;
|
|
4588
4613
|
state.chatMode = mode;
|
|
4589
4614
|
state.sessionTool = command;
|
|
@@ -4626,7 +4651,8 @@
|
|
|
4626
4651
|
})
|
|
4627
4652
|
.catch(function() {
|
|
4628
4653
|
showError(errorEl, "无法启动会话,请确认 Claude 已正确安装。");
|
|
4629
|
-
})
|
|
4654
|
+
})
|
|
4655
|
+
.finally(function() { _sessionCreating = false; });
|
|
4630
4656
|
}
|
|
4631
4657
|
|
|
4632
4658
|
function initBlankChatCwd() {
|
|
@@ -6012,9 +6038,12 @@
|
|
|
6012
6038
|
});
|
|
6013
6039
|
}
|
|
6014
6040
|
|
|
6041
|
+
var _resumeInProgress = false;
|
|
6042
|
+
|
|
6015
6043
|
function resumeSession(sessionId, errorEl) {
|
|
6016
6044
|
console.log("[WAND] resumeSession sessionId:", sessionId);
|
|
6017
|
-
if (!sessionId) return Promise.resolve(null);
|
|
6045
|
+
if (!sessionId || _resumeInProgress) return Promise.resolve(null);
|
|
6046
|
+
_resumeInProgress = true;
|
|
6018
6047
|
return fetch("/api/sessions/" + encodeURIComponent(sessionId) + "/resume", {
|
|
6019
6048
|
method: "POST",
|
|
6020
6049
|
headers: { "Content-Type": "application/json" },
|
|
@@ -6040,7 +6069,8 @@
|
|
|
6040
6069
|
if (errorEl) showError(errorEl, message);
|
|
6041
6070
|
else showToast(message, "error");
|
|
6042
6071
|
return null;
|
|
6043
|
-
})
|
|
6072
|
+
})
|
|
6073
|
+
.finally(function() { _resumeInProgress = false; });
|
|
6044
6074
|
}
|
|
6045
6075
|
|
|
6046
6076
|
function resumeClaudeSessionById(claudeSessionId, errorEl) {
|
|
@@ -8177,12 +8207,16 @@
|
|
|
8177
8207
|
smartScrollToBottom(chatMessages);
|
|
8178
8208
|
});
|
|
8179
8209
|
} else if (msgCount === existingCount && outputHash !== prevHash) {
|
|
8180
|
-
// Same message count but content changed (streaming update).
|
|
8181
|
-
//
|
|
8210
|
+
// Same message count but content changed (streaming update).
|
|
8211
|
+
// Optimization: only re-render the newest N messages (column-reverse: first children)
|
|
8212
|
+
// that actually differ, starting from the top (newest). Most streaming updates only
|
|
8213
|
+
// touch the latest assistant turn, so we can skip scanning all older messages.
|
|
8182
8214
|
var existingEls = Array.from(chatMessages.querySelectorAll(".chat-message"));
|
|
8183
8215
|
var reversedMessages = messages.slice().reverse();
|
|
8184
8216
|
var replacedAny = false;
|
|
8185
|
-
|
|
8217
|
+
// Scan from newest (index 0 in reversed) up to MAX_STREAMING_SCAN messages
|
|
8218
|
+
var MAX_STREAMING_SCAN = Math.min(4, reversedMessages.length, existingEls.length);
|
|
8219
|
+
for (var mi = 0; mi < MAX_STREAMING_SCAN; mi++) {
|
|
8186
8220
|
var currentEl = existingEls[mi];
|
|
8187
8221
|
var tmpWrap = document.createElement("div");
|
|
8188
8222
|
var srOrigIdx = reversedMessages.length - 1 - mi;
|
|
@@ -8193,8 +8227,16 @@
|
|
|
8193
8227
|
chatMessages.replaceChild(replacementEl, currentEl);
|
|
8194
8228
|
attachCopyHandler(replacementEl);
|
|
8195
8229
|
replacedAny = true;
|
|
8230
|
+
} else if (mi > 0) {
|
|
8231
|
+
// Once we hit an unchanged older message, stop scanning
|
|
8232
|
+
break;
|
|
8196
8233
|
}
|
|
8197
8234
|
}
|
|
8235
|
+
// Fallback: if hash changed but no visible diff found in the top N messages,
|
|
8236
|
+
// the change is deeper — trigger a full render to avoid stale display.
|
|
8237
|
+
if (!replacedAny && reversedMessages.length > MAX_STREAMING_SCAN) {
|
|
8238
|
+
fullRenderChat();
|
|
8239
|
+
}
|
|
8198
8240
|
if (replacedAny) {
|
|
8199
8241
|
requestAnimationFrame(function() {
|
|
8200
8242
|
smartScrollToBottom(chatMessages);
|
|
@@ -4802,7 +4802,7 @@
|
|
|
4802
4802
|
.modal-backdrop {
|
|
4803
4803
|
position: fixed;
|
|
4804
4804
|
inset: 0;
|
|
4805
|
-
z-index:
|
|
4805
|
+
z-index: 500;
|
|
4806
4806
|
background: rgba(42, 28, 18, 0.52);
|
|
4807
4807
|
backdrop-filter: blur(12px);
|
|
4808
4808
|
-webkit-backdrop-filter: blur(12px);
|
|
@@ -5684,6 +5684,7 @@
|
|
|
5684
5684
|
.modal { max-height: 80vh; }
|
|
5685
5685
|
.modal-header { padding: 8px 10px; min-height: 36px; }
|
|
5686
5686
|
.modal-body { padding: 8px 10px; }
|
|
5687
|
+
.field-row { grid-template-columns: 1fr; gap: 0; }
|
|
5687
5688
|
|
|
5688
5689
|
.btn { min-height: 36px; padding: 8px 12px; }
|
|
5689
5690
|
.btn-sm { min-height: 28px; padding: 4px 8px; }
|
|
@@ -6287,18 +6288,21 @@
|
|
|
6287
6288
|
background: none;
|
|
6288
6289
|
border: none;
|
|
6289
6290
|
border-bottom: 2px solid transparent;
|
|
6291
|
+
border-radius: var(--radius-sm) var(--radius-sm) 0 0;
|
|
6290
6292
|
cursor: pointer;
|
|
6291
|
-
transition: color 0.15s, border-color 0.15s;
|
|
6293
|
+
transition: color 0.15s, border-color 0.15s, background 0.15s;
|
|
6292
6294
|
white-space: nowrap;
|
|
6293
6295
|
}
|
|
6294
6296
|
|
|
6295
6297
|
.settings-tab:hover {
|
|
6296
6298
|
color: var(--text-primary);
|
|
6299
|
+
background: rgba(197, 101, 61, 0.06);
|
|
6297
6300
|
}
|
|
6298
6301
|
|
|
6299
6302
|
.settings-tab.active {
|
|
6300
6303
|
color: var(--accent);
|
|
6301
6304
|
border-bottom-color: var(--accent);
|
|
6305
|
+
background: var(--accent-muted);
|
|
6302
6306
|
}
|
|
6303
6307
|
|
|
6304
6308
|
.settings-panel {
|
|
@@ -6312,8 +6316,11 @@
|
|
|
6312
6316
|
.settings-about-info {
|
|
6313
6317
|
display: flex;
|
|
6314
6318
|
flex-direction: column;
|
|
6315
|
-
gap:
|
|
6319
|
+
gap: 0;
|
|
6316
6320
|
margin-bottom: 18px;
|
|
6321
|
+
background: var(--bg-secondary);
|
|
6322
|
+
border-radius: var(--radius-md);
|
|
6323
|
+
padding: 2px 14px;
|
|
6317
6324
|
}
|
|
6318
6325
|
|
|
6319
6326
|
.settings-about-row {
|
|
@@ -6321,6 +6328,12 @@
|
|
|
6321
6328
|
justify-content: space-between;
|
|
6322
6329
|
align-items: center;
|
|
6323
6330
|
font-size: 0.8125rem;
|
|
6331
|
+
padding: 9px 0;
|
|
6332
|
+
border-bottom: 1px solid var(--border-subtle);
|
|
6333
|
+
}
|
|
6334
|
+
|
|
6335
|
+
.settings-about-row:last-child {
|
|
6336
|
+
border-bottom: none;
|
|
6324
6337
|
}
|
|
6325
6338
|
|
|
6326
6339
|
.settings-label {
|
|
@@ -6356,8 +6369,8 @@
|
|
|
6356
6369
|
.settings-section-title {
|
|
6357
6370
|
font-size: 0.8125rem;
|
|
6358
6371
|
font-weight: 600;
|
|
6359
|
-
color: var(--
|
|
6360
|
-
margin
|
|
6372
|
+
color: var(--text-primary);
|
|
6373
|
+
margin: 0 0 12px 0;
|
|
6361
6374
|
letter-spacing: 0.02em;
|
|
6362
6375
|
}
|
|
6363
6376
|
|
|
@@ -6367,13 +6380,6 @@
|
|
|
6367
6380
|
margin-top: 10px;
|
|
6368
6381
|
}
|
|
6369
6382
|
|
|
6370
|
-
.settings-section-title {
|
|
6371
|
-
font-size: 0.875rem;
|
|
6372
|
-
font-weight: 600;
|
|
6373
|
-
color: var(--text-primary);
|
|
6374
|
-
margin: 0 0 12px 0;
|
|
6375
|
-
}
|
|
6376
|
-
|
|
6377
6383
|
.settings-divider {
|
|
6378
6384
|
border: none;
|
|
6379
6385
|
border-top: 1px solid var(--border-subtle);
|
|
@@ -6397,6 +6403,49 @@
|
|
|
6397
6403
|
margin-bottom: 0;
|
|
6398
6404
|
}
|
|
6399
6405
|
|
|
6406
|
+
.field-row {
|
|
6407
|
+
display: grid;
|
|
6408
|
+
grid-template-columns: 1fr 1fr;
|
|
6409
|
+
gap: 12px;
|
|
6410
|
+
margin-bottom: 14px;
|
|
6411
|
+
}
|
|
6412
|
+
.field-row .field {
|
|
6413
|
+
margin-bottom: 0;
|
|
6414
|
+
}
|
|
6415
|
+
|
|
6416
|
+
.settings-card {
|
|
6417
|
+
background: var(--bg-secondary);
|
|
6418
|
+
border-radius: var(--radius-md);
|
|
6419
|
+
padding: 16px;
|
|
6420
|
+
margin-bottom: 14px;
|
|
6421
|
+
}
|
|
6422
|
+
.settings-card .field:last-of-type {
|
|
6423
|
+
margin-bottom: 12px;
|
|
6424
|
+
}
|
|
6425
|
+
.settings-card .settings-section-title {
|
|
6426
|
+
margin-top: 0;
|
|
6427
|
+
}
|
|
6428
|
+
.settings-card .field-input {
|
|
6429
|
+
background: rgba(255, 255, 255, 0.6);
|
|
6430
|
+
}
|
|
6431
|
+
.settings-card .btn-block {
|
|
6432
|
+
margin-bottom: 0;
|
|
6433
|
+
}
|
|
6434
|
+
|
|
6435
|
+
.empty-state-compact {
|
|
6436
|
+
display: flex;
|
|
6437
|
+
flex-direction: column;
|
|
6438
|
+
align-items: center;
|
|
6439
|
+
gap: 6px;
|
|
6440
|
+
padding: 32px 16px;
|
|
6441
|
+
color: var(--text-muted);
|
|
6442
|
+
font-size: 0.8125rem;
|
|
6443
|
+
}
|
|
6444
|
+
.empty-state-compact .empty-icon {
|
|
6445
|
+
font-size: 1.5rem;
|
|
6446
|
+
opacity: 0.5;
|
|
6447
|
+
}
|
|
6448
|
+
|
|
6400
6449
|
.field-checkbox {
|
|
6401
6450
|
width: 18px;
|
|
6402
6451
|
height: 18px;
|
package/dist/ws-broadcast.d.ts
CHANGED
|
@@ -3,12 +3,8 @@
|
|
|
3
3
|
* Handles debounced output events, backpressure control, and client subscriptions.
|
|
4
4
|
*/
|
|
5
5
|
import { WebSocketServer } from "ws";
|
|
6
|
-
import type { SessionSnapshot } from "./types.js";
|
|
7
|
-
export
|
|
8
|
-
type: "output" | "status" | "started" | "ended" | "usage" | "task" | "notification";
|
|
9
|
-
sessionId: string;
|
|
10
|
-
data?: unknown;
|
|
11
|
-
}
|
|
6
|
+
import type { SessionSnapshot, ProcessEvent } from "./types.js";
|
|
7
|
+
export type { ProcessEvent } from "./types.js";
|
|
12
8
|
export declare class WsBroadcastManager {
|
|
13
9
|
private wss;
|
|
14
10
|
private clients;
|