coding-tool-x 3.5.10 → 3.5.11

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.
@@ -5,7 +5,7 @@
5
5
  <link rel="icon" href="/favicon.ico">
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
7
  <title>CC-TOOL - ClaudeCode增强工作助手</title>
8
- <script type="module" crossorigin src="/assets/index-BnyNm74G.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-CTeg1xG-.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="/assets/markdown-BNJfEgCA.js">
10
10
  <link rel="modulepreload" crossorigin href="/assets/vue-vendor-B5RqjEjQ.js">
11
11
  <link rel="modulepreload" crossorigin href="/assets/naive-ui-DM897mIP.js">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "coding-tool-x",
3
- "version": "3.5.10",
3
+ "version": "3.5.11",
4
4
  "description": "Vibe Coding 增强工作助手 - 智能会话管理、动态渠道切换、全局搜索、实时监控",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -201,6 +201,10 @@ module.exports = (config) => {
201
201
  res.json(channel);
202
202
  broadcastSchedulerState('codex', getSchedulerState('codex'));
203
203
  } catch (err) {
204
+ if (err?.message === 'Channel not found') {
205
+ console.warn(`[Codex Channels API] Ignored update for missing channel: ${req.params.channelId}`);
206
+ return res.status(404).json({ error: 'Channel not found' });
207
+ }
204
208
  console.error('[Codex Channels API] Failed to update channel:', err);
205
209
  res.status(500).json({ error: err.message });
206
210
  }
@@ -61,6 +61,31 @@ function resolveActiveChannel(channels, activeChannelId = null) {
61
61
  || null;
62
62
  }
63
63
 
64
+ function recoverChannelAfterMissingUpdate(previousChannel) {
65
+ const { channels } = getChannels();
66
+ const allChannels = Array.isArray(channels) ? channels : [];
67
+ const enabledChannels = allChannels.filter(channel => channel.enabled !== false);
68
+
69
+ const previousProviderKey = String(previousChannel?.providerKey || '').trim();
70
+ if (previousProviderKey) {
71
+ const sameProvider = enabledChannels.find(channel => channel.providerKey === previousProviderKey);
72
+ if (sameProvider) {
73
+ return sameProvider;
74
+ }
75
+ }
76
+
77
+ if (allChannels.length > 0) {
78
+ return resolveActiveChannel(allChannels, null);
79
+ }
80
+
81
+ const refreshedEnabledChannels = getEnabledChannels();
82
+ if (Array.isArray(refreshedEnabledChannels) && refreshedEnabledChannels.length > 0) {
83
+ return refreshedEnabledChannels[0];
84
+ }
85
+
86
+ return null;
87
+ }
88
+
64
89
  // 保存激活渠道ID
65
90
  function saveActiveChannelId(channelId) {
66
91
  ensureStorageDirMigrated();
@@ -149,7 +174,23 @@ router.post('/start', async (req, res) => {
149
174
  });
150
175
  }
151
176
 
152
- currentChannel = markChannelAsRecentlyUsed(currentChannel.id);
177
+ try {
178
+ currentChannel = markChannelAsRecentlyUsed(currentChannel.id) || currentChannel;
179
+ } catch (error) {
180
+ if (error?.message !== 'Channel not found') {
181
+ throw error;
182
+ }
183
+
184
+ const recoveredChannel = recoverChannelAfterMissingUpdate(currentChannel);
185
+ if (!recoveredChannel) {
186
+ return res.status(400).json({
187
+ error: 'No enabled Codex channel found. Please create and enable a channel first.'
188
+ });
189
+ }
190
+
191
+ currentChannel = recoveredChannel;
192
+ console.warn(`[Codex Proxy] Active channel disappeared before startup, falling back to ${currentChannel.name} (${currentChannel.id})`);
193
+ }
153
194
 
154
195
  // 3. 保存当前激活渠道ID(用于代理模式)
155
196
  saveActiveChannelId(currentChannel.id);
@@ -836,6 +836,7 @@ function sliceCodexContentByUserMessage(content, afterUserMessageNumber) {
836
836
  const { lines, eol, hasTrailingEol } = splitTextPreserveEol(content);
837
837
  const keptLines = [];
838
838
  let matchedUserMessages = 0;
839
+ let targetUserReached = false;
839
840
 
840
841
  for (const line of lines) {
841
842
  if (!line.trim()) {
@@ -851,23 +852,32 @@ function sliceCodexContentByUserMessage(content, afterUserMessageNumber) {
851
852
  continue;
852
853
  }
853
854
 
854
- keptLines.push(line);
855
-
856
855
  if (parsed?.type !== 'response_item' || !parsed?.payload) {
856
+ keptLines.push(line);
857
857
  continue;
858
858
  }
859
859
 
860
860
  const preview = extractCodexPreviewFromResponseItem(parsed.payload);
861
861
  if (!preview) {
862
+ keptLines.push(line);
862
863
  continue;
863
864
  }
864
865
 
866
+ if (targetUserReached) {
867
+ return joinTextPreserveEol(keptLines, eol, hasTrailingEol);
868
+ }
869
+
865
870
  matchedUserMessages += 1;
871
+ keptLines.push(line);
866
872
  if (matchedUserMessages >= afterUserMessageNumber) {
867
- return joinTextPreserveEol(keptLines, eol, hasTrailingEol);
873
+ targetUserReached = true;
868
874
  }
869
875
  }
870
876
 
877
+ if (targetUserReached) {
878
+ return joinTextPreserveEol(keptLines, eol, hasTrailingEol);
879
+ }
880
+
871
881
  throw new Error(`afterUserMessageNumber ${afterUserMessageNumber} exceeds available user messages (${matchedUserMessages})`);
872
882
  }
873
883
 
@@ -622,21 +622,29 @@ function forkSession(sessionId, options = {}) {
622
622
  let truncatedMessages = sourceMessages;
623
623
  if (Number.isInteger(options.afterUserMessageNumber) && options.afterUserMessageNumber > 0) {
624
624
  let matchedUserMessages = 0;
625
- let stopIndex = -1;
625
+ let targetUserIndex = -1;
626
626
  for (let index = 0; index < sourceMessages.length; index += 1) {
627
627
  if (sourceMessages[index]?.type !== 'user') continue;
628
628
  matchedUserMessages += 1;
629
629
  if (matchedUserMessages >= options.afterUserMessageNumber) {
630
- stopIndex = index;
630
+ targetUserIndex = index;
631
631
  break;
632
632
  }
633
633
  }
634
634
 
635
- if (stopIndex < 0) {
635
+ if (targetUserIndex < 0) {
636
636
  throw new Error(`afterUserMessageNumber ${options.afterUserMessageNumber} exceeds available user messages (${matchedUserMessages})`);
637
637
  }
638
638
 
639
- truncatedMessages = sourceMessages.slice(0, stopIndex + 1);
639
+ let nextUserIndex = sourceMessages.length;
640
+ for (let index = targetUserIndex + 1; index < sourceMessages.length; index += 1) {
641
+ if (sourceMessages[index]?.type === 'user') {
642
+ nextUserIndex = index;
643
+ break;
644
+ }
645
+ }
646
+
647
+ truncatedMessages = sourceMessages.slice(0, nextUserIndex);
640
648
  }
641
649
 
642
650
  // 生成新的会话 ID
@@ -135,6 +135,7 @@ function sliceClaudeSessionContentByUserMessage(content, afterUserMessageNumber)
135
135
  const { lines, eol, hasTrailingEol } = splitTextPreserveEol(content);
136
136
  const keptLines = [];
137
137
  let matchedUserMessages = 0;
138
+ let targetUserReached = false;
138
139
 
139
140
  for (const line of lines) {
140
141
  if (!line.trim()) {
@@ -150,23 +151,32 @@ function sliceClaudeSessionContentByUserMessage(content, afterUserMessageNumber)
150
151
  continue;
151
152
  }
152
153
 
153
- keptLines.push(line);
154
-
155
154
  if (json.type !== 'user') {
155
+ keptLines.push(line);
156
156
  continue;
157
157
  }
158
158
 
159
159
  const userText = getClaudeForkMessageText(json.message?.content);
160
160
  if (!userText) {
161
+ keptLines.push(line);
161
162
  continue;
162
163
  }
163
164
 
165
+ if (targetUserReached) {
166
+ return joinTextPreserveEol(keptLines, eol, hasTrailingEol);
167
+ }
168
+
164
169
  matchedUserMessages += 1;
170
+ keptLines.push(line);
165
171
  if (matchedUserMessages >= afterUserMessageNumber) {
166
- return joinTextPreserveEol(keptLines, eol, hasTrailingEol);
172
+ targetUserReached = true;
167
173
  }
168
174
  }
169
175
 
176
+ if (targetUserReached) {
177
+ return joinTextPreserveEol(keptLines, eol, hasTrailingEol);
178
+ }
179
+
170
180
  throw new Error(`afterUserMessageNumber ${afterUserMessageNumber} exceeds available user messages (${matchedUserMessages})`);
171
181
  }
172
182
 
@@ -1 +0,0 @@
1
- .session-list-container[data-v-80557dc6]{width:100%;height:100%;display:flex;flex-direction:column;box-sizing:border-box}.header[data-v-80557dc6]{flex-shrink:0;padding:24px 24px 16px;background:var(--bg-primary);border-bottom:1px solid var(--border-primary)}.content[data-v-80557dc6]{flex:1;overflow-y:auto;overflow-x:hidden;padding:16px 24px 24px}.sessions-list[data-v-80557dc6]{position:relative;overflow:hidden}.back-button[data-v-80557dc6]{flex-shrink:0;margin-right:12px}.title-bar[data-v-80557dc6]{display:flex;align-items:center;gap:16px}.title-section[data-v-80557dc6]{flex:1;min-width:0}.title-with-count[data-v-80557dc6]{display:flex;align-items:center;gap:8px;margin-bottom:2px;flex-wrap:wrap}.title-section h2[data-v-80557dc6]{margin:0;font-size:20px}.session-count[data-v-80557dc6]{font-size:14px;color:#666}.total-size-tag[data-v-80557dc6]{margin-left:8px}.project-path[data-v-80557dc6]{font-size:13px;display:block;color:#666;margin-bottom:2px}.header-actions[data-v-80557dc6]{display:flex;align-items:center;gap:12px;margin-left:4px}.search-input[data-v-80557dc6]{width:320px;flex-shrink:0}.loading-container[data-v-80557dc6]{display:flex;justify-content:center;align-items:center;min-height:400px}.session-item[data-v-80557dc6]{display:flex;align-items:center;gap:12px;padding:16px;background:var(--bg-primary);border:1px solid var(--border-primary);border-radius:8px;margin-bottom:8px;transition:all .2s;cursor:pointer}.session-item[data-v-80557dc6]:hover{border-color:#18a058;box-shadow:0 2px 8px #18a0581a}.session-item-selection-mode[data-v-80557dc6]{cursor:default}.session-item-selected[data-v-80557dc6]{border-color:#18a058;box-shadow:0 0 0 2px #18a0581f;background:#18a0580a}.drag-handle[data-v-80557dc6]{cursor:move;width:24px;height:24px;padding:4px;opacity:.4;transition:all .2s;flex-shrink:0;display:flex;align-items:center;justify-content:center}.session-item:hover .drag-handle[data-v-80557dc6]{opacity:1;background-color:#18a0581a;border-radius:4px}.selection-checkbox[data-v-80557dc6]{width:24px;min-width:24px;display:flex;align-items:center;justify-content:center}.session-left[data-v-80557dc6]{flex:1;display:flex;align-items:center;gap:16px;min-width:0}.session-icon[data-v-80557dc6]{flex-shrink:0}.session-info[data-v-80557dc6]{flex:1;min-width:0}.session-header[data-v-80557dc6]{display:flex;align-items:center;margin-bottom:6px}.session-title-row[data-v-80557dc6]{display:flex;align-items:center;gap:8px}.session-title[data-v-80557dc6]{font-size:15px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex-shrink:1;min-width:0}.session-meta[data-v-80557dc6]{display:flex;align-items:center;gap:8px;margin-bottom:6px;font-size:13px}.session-message[data-v-80557dc6]{display:block;max-width:600px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:13px}.session-message-empty[data-v-80557dc6]{font-style:italic;opacity:.5}.session-right[data-v-80557dc6]{display:flex;flex-direction:column;justify-content:flex-start;align-items:flex-end;min-width:280px;flex-shrink:0;gap:12px}.session-tags-area[data-v-80557dc6]{min-height:24px;display:flex;align-items:flex-start;justify-content:flex-end}.session-actions[data-v-80557dc6]{display:flex;align-items:center;margin-top:auto}.ghost[data-v-80557dc6]{opacity:.4}.chosen[data-v-80557dc6]{box-shadow:0 4px 16px #00000026}.search-result-item[data-v-80557dc6]{margin-bottom:16px;padding:12px;border:1px solid var(--border-primary);border-radius:6px;background:var(--bg-elevated)}.search-result-header[data-v-80557dc6]{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px}.search-result-title[data-v-80557dc6]{display:flex;align-items:center;gap:8px}.search-match[data-v-80557dc6]{display:flex;align-items:flex-start;gap:8px;margin-top:6px;padding:6px;background:var(--bg-secondary);border-radius:4px}.search-match-text[data-v-80557dc6]{flex:1;line-height:1.6}