cc-viewer 1.9.13 → 1.9.15
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/dist/assets/App-BCDnm2Lh.js +2 -0
- package/dist/assets/App-CCnPkf2_.css +1 -0
- package/dist/assets/{MdxEditorPanel-Db1nmcJV.js → MdxEditorPanel-DRLFmdU5.js} +1 -1
- package/dist/assets/Mobile-C8VJqBwa.js +1 -0
- package/dist/assets/{ProxyStatsModal-Ch1BH0Kp.js → ProxyStatsModal-Ba1E1lu4.js} +1 -1
- package/dist/assets/{index-CAiC6cw-.js → index-Sp3JYYKo.js} +2 -2
- package/dist/assets/seqResourceLoaders-BUfjTaCV.css +41 -0
- package/dist/assets/seqResourceLoaders-CHmtPDFO.js +2 -0
- package/dist/index.html +1 -1
- package/node_modules/@ccv/core/src/contentFilter.js +3 -0
- package/node_modules/@ccv/core/src/context-rules.js +6 -2
- package/node_modules/@ccv/core/src/queued-prompt.js +66 -0
- package/node_modules/@ccv/core/src/v2-transcript-normalizer.js +78 -14
- package/package.json +1 -1
- package/server/lib/chat-queue.js +350 -120
- package/server/lib/model-system-prompts.js +4 -1
- package/server/lib/scheduled-task-executor.js +3 -1
- package/server/lib/sdk-manager.js +282 -68
- package/server/lib/v2/conversation-store.js +15 -11
- package/server/lib/v2/v2-writer.js +1 -1
- package/server/lib/view-root.js +4 -4
- package/server/pty-manager.js +8 -8
- package/server/routes/files-content.js +108 -14
- package/server/routes/files-fs.js +122 -36
- package/server/routes/resume.js +1 -1
- package/server/routes/sdk-context.js +13 -2
- package/server/server.js +128 -28
- package/server/system-prompt-templates/presets/kimi-k3.md +4 -0
- package/dist/assets/App-BzOM1_y-.js +0 -2
- package/dist/assets/App-DU5jmGrx.css +0 -1
- package/dist/assets/Mobile-rjfABa-U.js +0 -1
- package/dist/assets/seqResourceLoaders-CxUFE36z.css +0 -41
- package/dist/assets/seqResourceLoaders-Ds8-_QA3.js +0 -2
package/server/server.js
CHANGED
|
@@ -1738,7 +1738,7 @@ function registerUpgradeRoute(httpServer, name, match, handle) {
|
|
|
1738
1738
|
async function setupTerminalWebSocket(httpServer) {
|
|
1739
1739
|
try {
|
|
1740
1740
|
const { WebSocketServer } = await import('ws');
|
|
1741
|
-
const { writeToPty, writeToPtySequential, writeToPtyFor, writeToPtySequentialFor, resizePty, onPtyData, onPtyExit, getPtyState, getPtyKind, getOutputBuffer, getCurrentWorkspace, spawnShell, findSafeSliceStart, attachPtyFor, listLivePtys } = await import('./pty-manager.js');
|
|
1741
|
+
const { writeToPty, writeToPtySequential, writeToPtyFor, writeToPtySequentialFor, resizePty, onPtyData, onPtyExit, getPtyState, getPtyKind, getPtyKindFor, getOutputBuffer, getCurrentWorkspace, spawnShell, findSafeSliceStart, attachPtyFor, listLivePtys } = await import('./pty-manager.js');
|
|
1742
1742
|
const {
|
|
1743
1743
|
spawnScratch,
|
|
1744
1744
|
writeScratch,
|
|
@@ -1770,13 +1770,40 @@ async function setupTerminalWebSocket(httpServer) {
|
|
|
1770
1770
|
if (!isSdkMode) {
|
|
1771
1771
|
chatQueue.initChatQueue({
|
|
1772
1772
|
writeToPty,
|
|
1773
|
+
writeToPtyFor,
|
|
1773
1774
|
writeToPtySequential,
|
|
1774
1775
|
writeToPtySequentialFor,
|
|
1775
1776
|
getPtyKind,
|
|
1776
1777
|
isStreaming: () => streamingState.active,
|
|
1777
1778
|
hasPendingApproval: () => pendingAskHooks.size > 0 || pendingPermHooks.size > 0,
|
|
1778
1779
|
hasExternalInjection: () => imCore.anyActiveInjection(),
|
|
1779
|
-
|
|
1780
|
+
hasLivePtyFor: (anchor) => {
|
|
1781
|
+
if (!anchor || typeof anchor !== 'object') return undefined;
|
|
1782
|
+
if (anchor.instanceKey) return getPtyKindFor({ instanceKey: anchor.instanceKey }) === 'claude';
|
|
1783
|
+
if (anchor.project) return listLivePtys().some((pty) => pty.ptyKind === 'claude' && projectKeyForCwd(pty.cwd) === anchor.project);
|
|
1784
|
+
return undefined;
|
|
1785
|
+
},
|
|
1786
|
+
broadcastWs: (msg, item) => {
|
|
1787
|
+
if (msg.type !== 'queue-state') {
|
|
1788
|
+
const scope = item?.anchor || msg.scope;
|
|
1789
|
+
const { scope: _privateScope, ...publicMsg } = msg;
|
|
1790
|
+
broadcastWsMessage(scope ? { ...publicMsg, project: scope.project, instanceKey: scope.instanceKey } : publicMsg);
|
|
1791
|
+
return;
|
|
1792
|
+
}
|
|
1793
|
+
if (!terminalWss) return;
|
|
1794
|
+
terminalWss.clients.forEach((client) => {
|
|
1795
|
+
if (client.readyState !== 1) return;
|
|
1796
|
+
const view = client._ccvViewInstance
|
|
1797
|
+
? { instanceKey: client._ccvViewInstance, project: client._ccvViewProject || undefined }
|
|
1798
|
+
: { project: client._ccvViewProject || _projectName || '' };
|
|
1799
|
+
const items = chatQueue.getSnapshot(view.project || view.instanceKey ? view : null);
|
|
1800
|
+
const project = view.project || _projectName || undefined;
|
|
1801
|
+
const instanceKey = view.instanceKey;
|
|
1802
|
+
const { scope: _privateScope, ...publicMsg } = msg;
|
|
1803
|
+
const payload = { ...publicMsg, items, ...(project ? { project } : {}), ...(instanceKey ? { instanceKey } : {}) };
|
|
1804
|
+
try { client.send(JSON.stringify(payload)); } catch (err) { reportSwallowed('chat-queue.client-send', err); }
|
|
1805
|
+
});
|
|
1806
|
+
},
|
|
1780
1807
|
});
|
|
1781
1808
|
}
|
|
1782
1809
|
const wss = new WebSocketServer({ noServer: true });
|
|
@@ -2143,31 +2170,53 @@ async function setupTerminalWebSocket(httpServer) {
|
|
|
2143
2170
|
// workspace's approval/spinner/queue would pop into the foreground. Filter each
|
|
2144
2171
|
// snapshot by this connection's `_ccvViewProject` (bound view / no ?project= → all).
|
|
2145
2172
|
const _viewProj = ws._ccvViewProject || null;
|
|
2173
|
+
const replayQueueSnapshot = () => {
|
|
2174
|
+
const anchor = ws._ccvViewInstance
|
|
2175
|
+
? { instanceKey: ws._ccvViewInstance, project: ws._ccvViewProject || undefined }
|
|
2176
|
+
: (ws._ccvViewProject ? { project: ws._ccvViewProject } : (isSdkMode ? null : { project: _projectName || undefined }));
|
|
2177
|
+
const items = (isSdkMode && _sdkGetQueueSnapshot)
|
|
2178
|
+
? _sdkGetQueueSnapshot(anchor)
|
|
2179
|
+
: chatQueue.getSnapshot(anchor);
|
|
2180
|
+
if (!Array.isArray(items)) return;
|
|
2181
|
+
const frame = { type: 'queue-state', items };
|
|
2182
|
+
if (ws._ccvViewProject || (!isSdkMode && _projectName)) frame.project = ws._ccvViewProject || _projectName;
|
|
2183
|
+
if (ws._ccvViewInstance) frame.instanceKey = ws._ccvViewInstance;
|
|
2184
|
+
if (_sdkFrameForView(frame)) {
|
|
2185
|
+
try { ws.send(JSON.stringify(frame)); } catch (err) { reportSwallowed('queue.replay-send', err); }
|
|
2186
|
+
}
|
|
2187
|
+
};
|
|
2146
2188
|
const _sdkFrameForView = (frame) => {
|
|
2147
2189
|
if (!frame || typeof frame !== 'object') return true; // no cwd → view-agnostic, replay
|
|
2148
|
-
|
|
2190
|
+
const viewProject = ws._ccvViewProject || null;
|
|
2191
|
+
if (!viewProject) return true; // bound view → all workspaces
|
|
2149
2192
|
// The view stamp is a SANITIZED project key (projectKeyForCwd), so compare against the
|
|
2150
2193
|
// frame's cwd sanitized the same way — a raw basename would silently drop legit frames
|
|
2151
2194
|
// for space/CJK workspace names.
|
|
2152
2195
|
const fproj = (typeof frame.cwd === 'string' && frame.cwd) ? (projectKeyForCwd(frame.cwd) || null) : null;
|
|
2153
|
-
return !fproj || fproj ===
|
|
2196
|
+
return !fproj || fproj === viewProject; // no-cwd frame → replay; else must match
|
|
2154
2197
|
};
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
// 与上面 perm-hook 同理,但快照来自 sdk-manager(_pendingApprovals)。
|
|
2158
|
-
// ask 类带 startedAt/timeoutMs —— 与 ask-hook replay 同款剩余时间重算。
|
|
2159
|
-
if (isSdkMode && _sdkGetPendingApprovals) {
|
|
2198
|
+
const replaySdkPendingApprovals = ({ planOnly = false } = {}) => {
|
|
2199
|
+
if (!_sdkGetPendingApprovals) return;
|
|
2160
2200
|
for (const p of _sdkGetPendingApprovals() || []) {
|
|
2161
2201
|
if (!p || !p.replay || !p.id) continue;
|
|
2202
|
+
if (planOnly && p.kind !== 'plan') continue;
|
|
2162
2203
|
const payload = { ...p.replay };
|
|
2163
|
-
if (!_sdkFrameForView(payload)) continue;
|
|
2204
|
+
if (!_sdkFrameForView(payload)) continue;
|
|
2205
|
+
// The generic replay filter is project-scoped. When an exact instance
|
|
2206
|
+
// is selected, require ownership metadata too instead of guessing from cwd.
|
|
2207
|
+
if (ws._ccvViewInstance && payload.instanceKey !== ws._ccvViewInstance) continue;
|
|
2164
2208
|
if (p.kind === 'ask') {
|
|
2165
|
-
payload.startedAt = now;
|
|
2166
|
-
payload.timeoutMs = p.remainingMs;
|
|
2209
|
+
payload.startedAt = Date.now();
|
|
2210
|
+
payload.timeoutMs = p.remainingMs;
|
|
2167
2211
|
}
|
|
2168
|
-
try { ws.send(JSON.stringify(payload)); } catch {}
|
|
2212
|
+
try { ws.send(JSON.stringify(payload)); } catch (err) { reportSwallowed('sdk.approval-replay', err); }
|
|
2169
2213
|
}
|
|
2170
|
-
}
|
|
2214
|
+
};
|
|
2215
|
+
|
|
2216
|
+
// Replay SDK 模式 pendings(sdk-manager canUseTool 的 ask/plan/perm):
|
|
2217
|
+
// 与上面 perm-hook 同理,但快照来自 sdk-manager(_pendingApprovals)。
|
|
2218
|
+
// ask 类带 startedAt/timeoutMs —— 与 ask-hook replay 同款剩余时间重算。
|
|
2219
|
+
if (isSdkMode) replaySdkPendingApprovals();
|
|
2171
2220
|
|
|
2172
2221
|
// Replay sdk-init snapshot so a refreshed/reconnected page restores slash-command
|
|
2173
2222
|
// surface and model info without waiting for the next session.
|
|
@@ -2203,10 +2252,13 @@ async function setupTerminalWebSocket(httpServer) {
|
|
|
2203
2252
|
}
|
|
2204
2253
|
|
|
2205
2254
|
// Replay the last sdk-context-usage snapshot so a reconnected panel restores the
|
|
2206
|
-
// latest numbers
|
|
2255
|
+
// latest numbers. Anchor by view instance (exact) else view project — same precedence
|
|
2256
|
+
// as sdk-skills — and reject a missing/foreign instance when the viewer is pinned to
|
|
2257
|
+
// one (context-only filter; other replay frames keep project-level semantics).
|
|
2258
|
+
// Null snapshot → no frame, the panel falls back to its HTTP pull.
|
|
2207
2259
|
if (isSdkMode && _sdkGetContextUsageSnapshot) {
|
|
2208
|
-
const cuSnap = _sdkGetContextUsageSnapshot
|
|
2209
|
-
if (cuSnap
|
|
2260
|
+
const cuSnap = sdkContextReplayFrame(_sdkGetContextUsageSnapshot, _viewProj, ws._ccvViewInstance);
|
|
2261
|
+
if (cuSnap) {
|
|
2210
2262
|
try { ws.send(JSON.stringify(cuSnap)); } catch {}
|
|
2211
2263
|
}
|
|
2212
2264
|
}
|
|
@@ -2222,13 +2274,7 @@ async function setupTerminalWebSocket(httpServer) {
|
|
|
2222
2274
|
|
|
2223
2275
|
// Replay the chat-composer busy queue so a refreshed/reconnected page restores the
|
|
2224
2276
|
// floating queued-message bubbles (server is the source of truth in both modes).
|
|
2225
|
-
|
|
2226
|
-
const qItems = (isSdkMode && _sdkGetQueueSnapshot) ? _sdkGetQueueSnapshot() : chatQueue.getSnapshot();
|
|
2227
|
-
if (Array.isArray(qItems) && qItems.length) {
|
|
2228
|
-
const qFrame = { type: 'queue-state', items: qItems };
|
|
2229
|
-
if (_sdkFrameForView(qFrame)) { try { ws.send(JSON.stringify(qFrame)); } catch {} }
|
|
2230
|
-
}
|
|
2231
|
-
}
|
|
2277
|
+
replayQueueSnapshot();
|
|
2232
2278
|
|
|
2233
2279
|
// 兜底重绘标记:claude TUI 在 alternate-screen 下只在收到 SIGWINCH 时重绘整屏。
|
|
2234
2280
|
// 若前端首次 resize 与 PTY 当前尺寸恰好相等,pty.resize noop 不发 SIGWINCH → 前端空白。
|
|
@@ -2384,6 +2430,11 @@ async function setupTerminalWebSocket(httpServer) {
|
|
|
2384
2430
|
}
|
|
2385
2431
|
}
|
|
2386
2432
|
}
|
|
2433
|
+
// View changes use attach rather than a new connection: restore that view's
|
|
2434
|
+
// pending approvals too, so a plan cleared on switch-away can be answered
|
|
2435
|
+
// after switching back instead of waiting for the server timeout.
|
|
2436
|
+
replaySdkPendingApprovals({ planOnly: true });
|
|
2437
|
+
replayQueueSnapshot();
|
|
2387
2438
|
return;
|
|
2388
2439
|
}
|
|
2389
2440
|
} else if (isSdkMode && (msg.type === 'input' || msg.type === 'input-sequential'
|
|
@@ -2494,12 +2545,20 @@ async function setupTerminalWebSocket(httpServer) {
|
|
|
2494
2545
|
let res = null;
|
|
2495
2546
|
try { res = (target || targetInstance) ? attachPtyFor({ project: target || undefined, instanceKey: targetInstance || undefined }) : null; } catch { res = null; }
|
|
2496
2547
|
if (res && res.ok) {
|
|
2548
|
+
ws._ccvViewProject = target || null;
|
|
2549
|
+
ws._ccvViewInstance = targetInstance || null;
|
|
2550
|
+
replayQueueSnapshot();
|
|
2497
2551
|
try { ws.send(JSON.stringify({ type: 'attached', project: target, running: res.running, ptyKind: res.ptyKind, exitCode: res.exitCode })); } catch { }
|
|
2498
2552
|
const snap = getOutputBuffer();
|
|
2499
2553
|
if (snap) {
|
|
2500
2554
|
try { ws.send(JSON.stringify({ type: 'data', data: snap })); } catch { }
|
|
2501
2555
|
}
|
|
2502
2556
|
} else {
|
|
2557
|
+
// The queue belongs to the view, not to a live PTY. A history view or
|
|
2558
|
+
// a dead instance still needs its own queue snapshot after re-stamping.
|
|
2559
|
+
ws._ccvViewProject = target || null;
|
|
2560
|
+
ws._ccvViewInstance = targetInstance || null;
|
|
2561
|
+
replayQueueSnapshot();
|
|
2503
2562
|
// Multi-instance: surface an ambiguous project-name attach (with the live
|
|
2504
2563
|
// candidates) so the client re-issues with an instanceKey instead of silently
|
|
2505
2564
|
// pinning an arbitrary same-cwd process.
|
|
@@ -2722,6 +2781,14 @@ async function setupTerminalWebSocket(httpServer) {
|
|
|
2722
2781
|
try { ws.send(cmsg); } catch {}
|
|
2723
2782
|
}
|
|
2724
2783
|
}
|
|
2784
|
+
} else if (msg.type === 'sdk-plan-auto-cancel') {
|
|
2785
|
+
// Cancellation stops the automatic timers on other viewers too. It is
|
|
2786
|
+
// not an approval/denial: the plan remains pending for manual review.
|
|
2787
|
+
if (_sdkResolveApproval && msg.id) broadcastWsMessage({
|
|
2788
|
+
type: 'sdk-plan-auto-cancel', id: msg.id,
|
|
2789
|
+
cwd: msg.cwd || null, project: msg.project || null,
|
|
2790
|
+
instanceKey: msg.instanceKey || null,
|
|
2791
|
+
});
|
|
2725
2792
|
} else if (msg.type === 'sdk-plan-answer') {
|
|
2726
2793
|
// Plan approval in SDK mode
|
|
2727
2794
|
if (_sdkResolveApproval) {
|
|
@@ -2772,7 +2839,7 @@ async function setupTerminalWebSocket(httpServer) {
|
|
|
2772
2839
|
});
|
|
2773
2840
|
}
|
|
2774
2841
|
} else {
|
|
2775
|
-
const _qAnchor = { project: typeof msg.project === 'string'
|
|
2842
|
+
const _qAnchor = { project: (typeof msg.project === 'string' && msg.project) || _projectName || undefined, sessionId: typeof msg.sessionId === 'string' ? msg.sessionId : undefined, instanceKey: typeof msg.instanceKey === 'string' ? msg.instanceKey : undefined };
|
|
2776
2843
|
const _anchorArg = (_qAnchor.project || _qAnchor.sessionId || _qAnchor.instanceKey) ? _qAnchor : undefined;
|
|
2777
2844
|
try { chatQueue.enqueue(msg.text, _anchorArg); } catch (err) { reportSwallowed('server.queue-message', err); }
|
|
2778
2845
|
}
|
|
@@ -2790,7 +2857,8 @@ async function setupTerminalWebSocket(httpServer) {
|
|
|
2790
2857
|
catch (err) { reportSwallowed('server.queue-send-now', err); }
|
|
2791
2858
|
}
|
|
2792
2859
|
} else {
|
|
2793
|
-
|
|
2860
|
+
const qAnchor = { project: typeof msg.project === 'string' ? msg.project : undefined, instanceKey: typeof msg.instanceKey === 'string' ? msg.instanceKey : undefined };
|
|
2861
|
+
try { chatQueue.sendNow(qid, qAnchor); } catch (err) { reportSwallowed('server.queue-send-now', err); }
|
|
2794
2862
|
}
|
|
2795
2863
|
}
|
|
2796
2864
|
} else if (msg.type === 'queue-remove') {
|
|
@@ -2799,7 +2867,8 @@ async function setupTerminalWebSocket(httpServer) {
|
|
|
2799
2867
|
if (isSdkMode) {
|
|
2800
2868
|
if (_sdkRemoveQueued) { const qAnchor = ((typeof msg.project === 'string' && msg.project) || (typeof msg.instanceKey === 'string' && msg.instanceKey)) ? { project: msg.project, instanceKey: typeof msg.instanceKey === 'string' ? msg.instanceKey : undefined } : undefined; try { _sdkRemoveQueued(qid, qAnchor); } catch (err) { reportSwallowed('server.queue-remove', err); } }
|
|
2801
2869
|
} else {
|
|
2802
|
-
|
|
2870
|
+
const qAnchor = { project: typeof msg.project === 'string' ? msg.project : undefined, instanceKey: typeof msg.instanceKey === 'string' ? msg.instanceKey : undefined };
|
|
2871
|
+
try { chatQueue.remove(qid, qAnchor); } catch (err) { reportSwallowed('server.queue-remove', err); }
|
|
2803
2872
|
}
|
|
2804
2873
|
}
|
|
2805
2874
|
} else if (msg.type === 'queue-clear') {
|
|
@@ -2808,7 +2877,8 @@ async function setupTerminalWebSocket(httpServer) {
|
|
|
2808
2877
|
if (isSdkMode) {
|
|
2809
2878
|
if (_sdkClearQueued) { const qAnchor = ((typeof msg.project === 'string' && msg.project) || (typeof msg.instanceKey === 'string' && msg.instanceKey)) ? { project: msg.project, instanceKey: typeof msg.instanceKey === 'string' ? msg.instanceKey : undefined } : undefined; try { _sdkClearQueued(qAnchor); } catch (err) { reportSwallowed('server.queue-clear', err); } }
|
|
2810
2879
|
} else {
|
|
2811
|
-
|
|
2880
|
+
const qAnchor = { project: typeof msg.project === 'string' ? msg.project : undefined, sessionId: typeof msg.sessionId === 'string' ? msg.sessionId : undefined, instanceKey: typeof msg.instanceKey === 'string' ? msg.instanceKey : undefined };
|
|
2881
|
+
try { chatQueue.clear(qAnchor.project || qAnchor.sessionId || qAnchor.instanceKey ? qAnchor : undefined); } catch (err) { reportSwallowed('server.queue-clear', err); }
|
|
2812
2882
|
}
|
|
2813
2883
|
} else if (msg.type === 'queue-suppress') {
|
|
2814
2884
|
// PTY Stop pressed: park the queue — the coming turn-end must not auto-drain it.
|
|
@@ -3595,6 +3665,36 @@ export function broadcastWsMessage(msg) { if (terminalWss) {
|
|
|
3595
3665
|
}
|
|
3596
3666
|
}
|
|
3597
3667
|
|
|
3668
|
+
/**
|
|
3669
|
+
* Context-usage reconnect replay. CONTEXT-ONLY: unlike the generic `_sdkFrameForView`
|
|
3670
|
+
* (project-scoped, shared by init/session-state/queue/MCP/approval replay), a viewer
|
|
3671
|
+
* pinned to an exact instance also requires the replayed frame to carry THAT instanceKey
|
|
3672
|
+
* — otherwise a same-basename twin's snapshot could repaint the wrong panel. Anchor
|
|
3673
|
+
* precedence matches sdk-skills: exact viewed instance, else viewed project, else no
|
|
3674
|
+
* anchor (active session). Unknown/ambiguous anchors resolve to a null snapshot → no
|
|
3675
|
+
* frame; never fall back to the active session. The project check reuses
|
|
3676
|
+
* projectKeyForCwd so sanitized names (spaces/CJK) still match.
|
|
3677
|
+
*/
|
|
3678
|
+
export function sdkContextReplayFrame(getSnapshot, viewProject, viewInstance) {
|
|
3679
|
+
if (typeof getSnapshot !== 'function') return null;
|
|
3680
|
+
const anchor = viewInstance
|
|
3681
|
+
? { instanceKey: viewInstance }
|
|
3682
|
+
: (viewProject ? { project: viewProject } : null);
|
|
3683
|
+
const frame = anchor ? getSnapshot(anchor) : getSnapshot();
|
|
3684
|
+
if (!frame || typeof frame !== 'object') return null;
|
|
3685
|
+
if (viewInstance) {
|
|
3686
|
+
const frameInstance = (typeof frame.instanceKey === 'string' && frame.instanceKey) ? frame.instanceKey : null;
|
|
3687
|
+
if (frameInstance !== viewInstance) return null; // missing or foreign instance
|
|
3688
|
+
}
|
|
3689
|
+
if (viewProject) {
|
|
3690
|
+
const frameProject = (typeof frame.cwd === 'string' && frame.cwd)
|
|
3691
|
+
? (projectKeyForCwd(frame.cwd) || null)
|
|
3692
|
+
: null;
|
|
3693
|
+
if (frameProject && frameProject !== viewProject) return null;
|
|
3694
|
+
}
|
|
3695
|
+
return frame;
|
|
3696
|
+
}
|
|
3697
|
+
|
|
3598
3698
|
/**
|
|
3599
3699
|
* Close open approval modals on every client after a server-side drain of canUseTool
|
|
3600
3700
|
* approvals (sdk-interrupt Stop, or queue-send-now interrupting a turn mid-approval).
|
|
@@ -10,6 +10,10 @@ You are ${model.name}, an interactive coding agent that helps users with softwar
|
|
|
10
10
|
|
|
11
11
|
IMPORTANT: Never generate or guess URLs unless you are confident they help the user with programming. Prefer URLs the user provides or ones found in local files.
|
|
12
12
|
|
|
13
|
+
# Choosing skills
|
|
14
|
+
- At the skill-selection entry point, skip `claude-api` and the skill whose display title is "Building LLM-Powered Applications with Claude": they are the same Anthropic-only API skill, so treat the identifier and title as aliases. Do not invoke it or read its documentation unless the task explicitly requires Claude/Anthropic SDK or API integration. This applies even when Claude Code automatically recommends or triggers it.
|
|
15
|
+
- Working on model-name recognition, model logos, aliases, or context-window classification in an existing project is local application code, NOT LLM API integration. Do not load `claude-api` for these tasks merely because the code mentions models, Claude, or model IDs. Locate the local matcher and its tests first; for a genuinely unrelated skill, do not load it just to determine that it is unrelated.
|
|
16
|
+
|
|
13
17
|
# Doing tasks
|
|
14
18
|
- Read the relevant files before acting or answering; ground every claim and change in code you have actually looked at.
|
|
15
19
|
- Before your first tool call, output a one-sentence action plan; then act.
|