@molecule/app-ide-react 1.15.0 → 1.17.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/README.md +193 -7
- package/dist/components/ChatPanel.d.ts +10 -1
- package/dist/components/ChatPanel.d.ts.map +1 -1
- package/dist/components/ChatPanel.js +136 -14
- package/dist/components/ChatPanel.js.map +1 -1
- package/dist/components/MarkdownContent.d.ts.map +1 -1
- package/dist/components/MarkdownContent.js +27 -7
- package/dist/components/MarkdownContent.js.map +1 -1
- package/dist/components/TestStatusBar.d.ts +56 -0
- package/dist/components/TestStatusBar.d.ts.map +1 -0
- package/dist/components/TestStatusBar.js +105 -0
- package/dist/components/TestStatusBar.js.map +1 -0
- package/dist/components/TestsCard.d.ts +15 -2
- package/dist/components/TestsCard.d.ts.map +1 -1
- package/dist/components/TestsCard.js +42 -9
- package/dist/components/TestsCard.js.map +1 -1
- package/dist/components/ToolCallCard.d.ts +7 -1
- package/dist/components/ToolCallCard.d.ts.map +1 -1
- package/dist/components/ToolCallCard.js +516 -161
- package/dist/components/ToolCallCard.js.map +1 -1
- package/dist/components/tests-bar-utilities.d.ts +78 -103
- package/dist/components/tests-bar-utilities.d.ts.map +1 -1
- package/dist/components/tests-bar-utilities.js +130 -201
- package/dist/components/tests-bar-utilities.js.map +1 -1
- package/dist/components/tests-card-utilities.d.ts +78 -2
- package/dist/components/tests-card-utilities.d.ts.map +1 -1
- package/dist/components/tests-card-utilities.js +134 -6
- package/dist/components/tests-card-utilities.js.map +1 -1
- package/dist/components/tool-call-utilities.d.ts +81 -7
- package/dist/components/tool-call-utilities.d.ts.map +1 -1
- package/dist/components/tool-call-utilities.js +146 -6
- package/dist/components/tool-call-utilities.js.map +1 -1
- package/dist/hooks/useTestsBarVisible.d.ts +16 -0
- package/dist/hooks/useTestsBarVisible.d.ts.map +1 -0
- package/dist/hooks/useTestsBarVisible.js +39 -0
- package/dist/hooks/useTestsBarVisible.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +60 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +2 -2
|
@@ -11,6 +11,7 @@ import { Tooltip } from '@molecule/app-ui-react/components/Tooltip.js';
|
|
|
11
11
|
import { timelineSortKey } from '../chatTimelineOrdering.js';
|
|
12
12
|
import { getCustomEventCardFactory } from '../customEventCards.js';
|
|
13
13
|
import { useChatTimestampsVisible, useMinuteNow } from '../hooks/useChatTimestampsVisible.js';
|
|
14
|
+
import { useTestsBarVisible } from '../hooks/useTestsBarVisible.js';
|
|
14
15
|
import { useCoarsePointer, useNarrowViewport } from '../hooks/useViewport.js';
|
|
15
16
|
import { activityFromEvent } from './activity-utilities.js';
|
|
16
17
|
import { ActivityCard } from './ActivityCard.js';
|
|
@@ -44,8 +45,10 @@ import { SettingsCard } from './SettingsCard.js';
|
|
|
44
45
|
import { ShareModal } from './ShareModal.js';
|
|
45
46
|
import { SkillsCard } from './SkillsCard.js';
|
|
46
47
|
import { StreamingIndicator } from './StreamingIndicator.js';
|
|
47
|
-
import {
|
|
48
|
+
import { getTestsBarVisible, parseTestsBarArg, setTestsBarVisible, shouldShowTestsBar, } from './tests-bar-utilities.js';
|
|
49
|
+
import { applyTestRunEvent, buildTestFixMessage, EMPTY_RUN_STATE, failRun, markSkipUnavailable, parseTestCommand, requestSkip, } from './tests-card-utilities.js';
|
|
48
50
|
import { TestsCard } from './TestsCard.js';
|
|
51
|
+
import { TestStatusBar } from './TestStatusBar.js';
|
|
49
52
|
import { TipCard } from './TipCard.js';
|
|
50
53
|
import { ToolCallCard } from './ToolCallCard.js';
|
|
51
54
|
import { UserAvatar } from './UserAvatar.js';
|
|
@@ -973,7 +976,7 @@ AuthorNameButton.displayName = 'AuthorNameButton';
|
|
|
973
976
|
* @returns The rendered message item.
|
|
974
977
|
*/
|
|
975
978
|
const MessageItem = memo(function MessageItem(props) {
|
|
976
|
-
const { msg, sendMessage, handleAskUserResponse, isLoading, streamingStatus, onNavigatePreview, undoneTcIds, handleUndoToggle, onFileOpen, onFileDoubleClick, onFileDiff, handleFileRevert, setInputAndCursorEnd, setModelPicker, chatMode, userAvatar, onProfileClick, currentUserId, discovery, buildUpgradeCta, agentName, canEdit, showTimestamp, } = props;
|
|
979
|
+
const { msg, sendMessage, handleAskUserResponse, isLoading, streamingStatus, onNavigatePreview, undoneTcIds, handleUndoToggle, onFileOpen, onFileDoubleClick, onFileDiff, handleFileRevert, setInputAndCursorEnd, setModelPicker, chatMode, userAvatar, onProfileClick, currentUserId, discovery, buildUpgradeCta, agentName, canEdit, onSkipToolCall, skipToolCallReason, showTimestamp, } = props;
|
|
977
980
|
const cm = getClassMap();
|
|
978
981
|
const themeMode = useThemeMode();
|
|
979
982
|
const isLight = themeMode === 'light';
|
|
@@ -1176,7 +1179,7 @@ const MessageItem = memo(function MessageItem(props) {
|
|
|
1176
1179
|
const tc = msg.toolCalls?.find((c) => c.id === block.id);
|
|
1177
1180
|
if (!tc)
|
|
1178
1181
|
return null;
|
|
1179
|
-
return (_jsx("div", { style: { marginTop: '4px' }, children: _jsx(ToolCallCard, { id: tc.id, name: tc.name, input: tc.input, output: tc.output, status: tc.status, fileDiff: tc.fileDiff, isUndone: undoneTcIds.has(tc.id), onUndoToggle: handleUndoToggle, onFileOpen: onFileOpen, onFileDoubleClick: onFileDoubleClick, onFileDiff: onFileDiff, onFileRevert: canEdit === false ? undefined : handleFileRevert, onAskUserResponse: canEdit === false ? undefined : handleAskUserResponse }) }, tc.id));
|
|
1182
|
+
return (_jsx("div", { style: { marginTop: '4px' }, children: _jsx(ToolCallCard, { id: tc.id, name: tc.name, input: tc.input, output: tc.output, status: tc.status, fileDiff: tc.fileDiff, isUndone: undoneTcIds.has(tc.id), onUndoToggle: handleUndoToggle, onFileOpen: onFileOpen, onFileDoubleClick: onFileDoubleClick, onFileDiff: onFileDiff, onFileRevert: canEdit === false ? undefined : handleFileRevert, onAskUserResponse: canEdit === false ? undefined : handleAskUserResponse, onSkip: onSkipToolCall, skipDisabledReason: skipToolCallReason ?? null }) }, tc.id));
|
|
1180
1183
|
})) : msg.content ? (_jsx(MarkdownContent, { text: msg.content, isStreaming: msg.isStreaming, statusLabel: msg.isStreaming ? streamingStatus : undefined, statusStartedAt: typeof msg.timestamp === 'number' ? msg.timestamp : undefined, onNavigatePreview: onNavigatePreview, hideStreamingIndicator: true })) : null, msg.toolCalls &&
|
|
1181
1184
|
msg.blocks &&
|
|
1182
1185
|
msg.blocks.length > 0 &&
|
|
@@ -1187,10 +1190,10 @@ const MessageItem = memo(function MessageItem(props) {
|
|
|
1187
1190
|
tc.output.status === 'awaiting_response' &&
|
|
1188
1191
|
!msg.blocks.some((b) => b.type === 'tool_call' &&
|
|
1189
1192
|
b.id === tc.id))
|
|
1190
|
-
.map((tc) => (_jsx(ToolCallCard, { id: tc.id, name: tc.name, input: tc.input, output: tc.output, status: tc.status, fileDiff: tc.fileDiff, isUndone: undoneTcIds.has(tc.id), onUndoToggle: handleUndoToggle, onFileOpen: onFileOpen, onFileDoubleClick: onFileDoubleClick, onFileDiff: onFileDiff, onFileRevert: canEdit === false ? undefined : handleFileRevert, onAskUserResponse: canEdit === false ? undefined : handleAskUserResponse }, `orphan-ask-${tc.id}`))), msg.toolCalls &&
|
|
1193
|
+
.map((tc) => (_jsx(ToolCallCard, { id: tc.id, name: tc.name, input: tc.input, output: tc.output, status: tc.status, fileDiff: tc.fileDiff, isUndone: undoneTcIds.has(tc.id), onUndoToggle: handleUndoToggle, onFileOpen: onFileOpen, onFileDoubleClick: onFileDoubleClick, onFileDiff: onFileDiff, onFileRevert: canEdit === false ? undefined : handleFileRevert, onAskUserResponse: canEdit === false ? undefined : handleAskUserResponse, onSkip: onSkipToolCall, skipDisabledReason: skipToolCallReason ?? null }, `orphan-ask-${tc.id}`))), msg.toolCalls &&
|
|
1191
1194
|
msg.toolCalls.length > 0 &&
|
|
1192
1195
|
(!msg.blocks || msg.blocks.length === 0) &&
|
|
1193
|
-
msg.toolCalls.map((tc) => (_jsx(ToolCallCard, { id: tc.id, name: tc.name, input: tc.input, output: tc.output, status: tc.status, fileDiff: tc.fileDiff, isUndone: undoneTcIds.has(tc.id), onUndoToggle: handleUndoToggle, onFileOpen: onFileOpen, onFileDoubleClick: onFileDoubleClick, onFileDiff: onFileDiff, onFileRevert: canEdit === false ? undefined : handleFileRevert, onAskUserResponse: canEdit === false ? undefined : handleAskUserResponse }, tc.id))), msg.aborted && (_jsx("span", { className: cm.cn(cm.textMuted, cm.textSize('xs')), style: { display: 'block', marginTop: 4, fontStyle: 'italic' }, children: t('ide.chat.responseStopped', undefined, {
|
|
1196
|
+
msg.toolCalls.map((tc) => (_jsx(ToolCallCard, { id: tc.id, name: tc.name, input: tc.input, output: tc.output, status: tc.status, fileDiff: tc.fileDiff, isUndone: undoneTcIds.has(tc.id), onUndoToggle: handleUndoToggle, onFileOpen: onFileOpen, onFileDoubleClick: onFileDoubleClick, onFileDiff: onFileDiff, onFileRevert: canEdit === false ? undefined : handleFileRevert, onAskUserResponse: canEdit === false ? undefined : handleAskUserResponse, onSkip: onSkipToolCall, skipDisabledReason: skipToolCallReason ?? null }, tc.id))), msg.aborted && (_jsx("span", { className: cm.cn(cm.textMuted, cm.textSize('xs')), style: { display: 'block', marginTop: 4, fontStyle: 'italic' }, children: t('ide.chat.responseStopped', undefined, {
|
|
1194
1197
|
defaultValue: 'Response stopped',
|
|
1195
1198
|
}) })), msg.loopLimitReached &&
|
|
1196
1199
|
!msg.isStreaming &&
|
|
@@ -1281,7 +1284,7 @@ const MessageItem = memo(function MessageItem(props) {
|
|
|
1281
1284
|
* @param props - Component props (see {@link MessageItemProps}).
|
|
1282
1285
|
* @returns The rendered chat inner component.
|
|
1283
1286
|
*/
|
|
1284
|
-
function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent, isPro, isAnonymous, canEdit, canShare, buildUpgradeCta, buildHelpUpgradeSection, activeFile, openTabs, onFileOpen, onFileDoubleClick, onFileDiff, onFileRevert, onFileChange, onFileDeleted, onCommit, onConversationId, onActivityClick, onRenderError, onProfileClick, currentUserId, onReadyToBuild, awaitingSandboxBoot, onClientAction, onTurnComplete, onLoadingChange, onNavigatePreview, onRegisterPushHandler, onRegisterHistoryReconcile, autoSubmitSignal, openSettingsSignal, onManageCustomModels, modelSelectionSignal, openReportSignal, openShareSignal, initialInputValue, pendingMessage, pendingMessageKey, pendingMessageSuppressUser, pendingMessageUserInitiated, userEditedFile, userEditedFileKey, gitStatusTick: externalGitStatusTick, discovery, userAvatar, agentName = DEFAULT_AGENT_NAME, productName = DEFAULT_PRODUCT_NAME, version, extraCommands, listTests, runTests, canRunTests, testsAvailable,
|
|
1287
|
+
function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent, isPro, isAnonymous, canEdit, canShare, buildUpgradeCta, buildHelpUpgradeSection, activeFile, openTabs, onFileOpen, onFileDoubleClick, onFileDiff, onFileRevert, onFileChange, onFileDeleted, onCommit, onConversationId, onActivityClick, onRenderError, onProfileClick, currentUserId, onReadyToBuild, awaitingSandboxBoot, onClientAction, onTurnComplete, onLoadingChange, onNavigatePreview, onRegisterPushHandler, onRegisterHistoryReconcile, autoSubmitSignal, openSettingsSignal, onManageCustomModels, modelSelectionSignal, openReportSignal, openShareSignal, initialInputValue, pendingMessage, pendingMessageKey, pendingMessageSuppressUser, pendingMessageUserInitiated, userEditedFile, userEditedFileKey, gitStatusTick: externalGitStatusTick, discovery, userAvatar, agentName = DEFAULT_AGENT_NAME, productName = DEFAULT_PRODUCT_NAME, version, extraCommands, listTests, runTests, canRunTests, testsAvailable, skipToolCall,
|
|
1285
1288
|
// feedbackUrl: prop kept for back-compat (callers still pass it), but no longer
|
|
1286
1289
|
// consumed here — its only use was the command-menu footer link removed in P3-21.
|
|
1287
1290
|
}) {
|
|
@@ -1656,6 +1659,8 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
|
|
|
1656
1659
|
const [commitState, setCommitState] = useState(null);
|
|
1657
1660
|
const [pendingFiles, setPendingFiles] = useState(null);
|
|
1658
1661
|
const [commitBarExpanded, setCommitBarExpanded] = useState(false);
|
|
1662
|
+
// The tests strip sits above the commit bar and starts collapsed, like it.
|
|
1663
|
+
const [testsBarExpanded, setTestsBarExpanded] = useState(false);
|
|
1659
1664
|
const [commitCards, setCommitCards] = useState([]);
|
|
1660
1665
|
/** Number of timeline items rendered in the DOM. Increases when user clicks "Show earlier". */
|
|
1661
1666
|
const [maxVisibleItems, setMaxVisibleItems] = useState(60);
|
|
@@ -2600,6 +2605,7 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
|
|
|
2600
2605
|
// The minute clock re-plans which items show a time (see planChatTimestamps),
|
|
2601
2606
|
// so labels advance and runs of identical labels regroup as time passes.
|
|
2602
2607
|
const timestampsVisible = useChatTimestampsVisible();
|
|
2608
|
+
const testsBarVisible = useTestsBarVisible();
|
|
2603
2609
|
const minuteNow = useMinuteNow();
|
|
2604
2610
|
const applyTimestampsVisible = useCallback((visible) => {
|
|
2605
2611
|
setChatTimestampsVisible(visible);
|
|
@@ -2702,7 +2708,7 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
|
|
|
2702
2708
|
durationMs: null,
|
|
2703
2709
|
}));
|
|
2704
2710
|
try {
|
|
2705
|
-
|
|
2711
|
+
const handle = runTests(selection, (event) => {
|
|
2706
2712
|
if (!testsMountedRef.current)
|
|
2707
2713
|
return;
|
|
2708
2714
|
setTestsRun((prev) => applyTestRunEvent(prev, event));
|
|
@@ -2713,6 +2719,12 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
|
|
|
2713
2719
|
void refreshTests();
|
|
2714
2720
|
}
|
|
2715
2721
|
});
|
|
2722
|
+
testsRunHandleRef.current = handle;
|
|
2723
|
+
// Whether a Skip control belongs on screen is decided HERE, by whether
|
|
2724
|
+
// this host's handle serves one — not by the card guessing, and not by
|
|
2725
|
+
// a button that would do nothing when clicked.
|
|
2726
|
+
const skips = typeof handle.skipCurrent === 'function';
|
|
2727
|
+
setTestsRun((prev) => ({ ...prev, skipPending: false, skipUnavailable: !skips }));
|
|
2716
2728
|
}
|
|
2717
2729
|
catch (error) {
|
|
2718
2730
|
logger.warn('Failed to start a test run', { error });
|
|
@@ -2741,8 +2753,64 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
|
|
|
2741
2753
|
const cancelTestsRun = useCallback(() => {
|
|
2742
2754
|
testsRunHandleRef.current?.cancel();
|
|
2743
2755
|
testsRunHandleRef.current = null;
|
|
2744
|
-
setTestsRun((prev) => ({
|
|
2756
|
+
setTestsRun((prev) => ({
|
|
2757
|
+
...prev,
|
|
2758
|
+
running: false,
|
|
2759
|
+
currentId: null,
|
|
2760
|
+
cases: {},
|
|
2761
|
+
skipPending: false,
|
|
2762
|
+
skipUnavailable: true,
|
|
2763
|
+
outcome: 'cancelled',
|
|
2764
|
+
}));
|
|
2745
2765
|
}, []);
|
|
2766
|
+
// Skip the executor's in-flight tool call WITHOUT ending the turn — the
|
|
2767
|
+
// model is told the command did not run and carries on. The card owns its own
|
|
2768
|
+
// pressed state, so this just forwards the host's answer: `false` means the
|
|
2769
|
+
// call had already finished (a race the person did not cause), which the card
|
|
2770
|
+
// answers by returning the button to rest rather than reporting anything.
|
|
2771
|
+
const handleSkipToolCall = useCallback(async (toolCallId) => {
|
|
2772
|
+
if (canEdit === false || !skipToolCall)
|
|
2773
|
+
return false;
|
|
2774
|
+
try {
|
|
2775
|
+
return await skipToolCall(toolCallId);
|
|
2776
|
+
}
|
|
2777
|
+
catch (error) {
|
|
2778
|
+
logger.warn('Failed to skip the running tool call', { error });
|
|
2779
|
+
return false;
|
|
2780
|
+
}
|
|
2781
|
+
}, [canEdit, skipToolCall]);
|
|
2782
|
+
// Skip the command the run is ON, leaving the run itself alive. The state
|
|
2783
|
+
// only records that the request went out — the run's own `result` for that
|
|
2784
|
+
// file is what moves the row, so a skip can never paint itself as a pass. A
|
|
2785
|
+
// host answering "there was nothing to skip" is a race the person did not
|
|
2786
|
+
// cause: the control goes away, no error line.
|
|
2787
|
+
const skipCurrentTest = useCallback(() => {
|
|
2788
|
+
if (canEdit === false || canRunTests === false)
|
|
2789
|
+
return;
|
|
2790
|
+
const skip = testsRunHandleRef.current?.skipCurrent;
|
|
2791
|
+
if (!skip) {
|
|
2792
|
+
setTestsRun((prev) => markSkipUnavailable(prev));
|
|
2793
|
+
return;
|
|
2794
|
+
}
|
|
2795
|
+
setTestsRun((prev) => requestSkip(prev));
|
|
2796
|
+
const unavailable = () => {
|
|
2797
|
+
if (testsMountedRef.current)
|
|
2798
|
+
setTestsRun((prev) => markSkipUnavailable(prev));
|
|
2799
|
+
};
|
|
2800
|
+
try {
|
|
2801
|
+
const outcome = skip.call(testsRunHandleRef.current);
|
|
2802
|
+
if (outcome) {
|
|
2803
|
+
void outcome.then((accepted) => {
|
|
2804
|
+
if (accepted === false)
|
|
2805
|
+
unavailable();
|
|
2806
|
+
}, unavailable);
|
|
2807
|
+
}
|
|
2808
|
+
}
|
|
2809
|
+
catch (error) {
|
|
2810
|
+
logger.warn('Failed to skip the running test', { error });
|
|
2811
|
+
unavailable();
|
|
2812
|
+
}
|
|
2813
|
+
}, [canEdit, canRunTests]);
|
|
2746
2814
|
/** Open the tests browser, re-listing so a spec just written shows up. */
|
|
2747
2815
|
const openTestsBrowser = useCallback((query = '', runAll = false) => {
|
|
2748
2816
|
openPanelOverlay('tests', query);
|
|
@@ -3169,6 +3237,35 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
|
|
|
3169
3237
|
const id = setInterval(() => dispatchAutoCommit({ type: 'tick' }), 1000);
|
|
3170
3238
|
return () => clearInterval(id);
|
|
3171
3239
|
}, [autoCommitArmed, autoCommitHeld]);
|
|
3240
|
+
// The tests bar hides itself on a project with no tests, so it has to LEARN
|
|
3241
|
+
// whether any exist without the person opening the browser first — otherwise
|
|
3242
|
+
// "shown by default" would mean "shown after you ask for it once", which is
|
|
3243
|
+
// not a default at all.
|
|
3244
|
+
//
|
|
3245
|
+
// Discovery runs when the environment comes up, and again when a turn ends
|
|
3246
|
+
// while we still know of none: that is the turn that wrote the project's
|
|
3247
|
+
// first spec. A project that already has tests never pays for the second
|
|
3248
|
+
// probe, because the effect returns the moment the list is non-empty.
|
|
3249
|
+
const turnInFlight = isLoading || isRemoteStreaming;
|
|
3250
|
+
useEffect(() => {
|
|
3251
|
+
if (!testsBarVisible || !listTests)
|
|
3252
|
+
return;
|
|
3253
|
+
if (testsAvailable !== true)
|
|
3254
|
+
return;
|
|
3255
|
+
if (turnInFlight || testsRun.running)
|
|
3256
|
+
return;
|
|
3257
|
+
if (testsList.length > 0)
|
|
3258
|
+
return;
|
|
3259
|
+
void refreshTests();
|
|
3260
|
+
}, [
|
|
3261
|
+
testsBarVisible,
|
|
3262
|
+
listTests,
|
|
3263
|
+
testsAvailable,
|
|
3264
|
+
turnInFlight,
|
|
3265
|
+
testsRun.running,
|
|
3266
|
+
testsList.length,
|
|
3267
|
+
refreshTests,
|
|
3268
|
+
]);
|
|
3172
3269
|
// Wrap onFileRevert so undo/redo also refreshes git status
|
|
3173
3270
|
const handleFileRevert = useCallback(async (path, content) => {
|
|
3174
3271
|
await onFileRevert?.(path, content);
|
|
@@ -4474,6 +4571,22 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
|
|
|
4474
4571
|
setSoundsPicker({ selectedIdx: -1 });
|
|
4475
4572
|
return;
|
|
4476
4573
|
}
|
|
4574
|
+
// `/test on | off | toggle` sets whether the TESTS STRIP is shown — a
|
|
4575
|
+
// per-device display preference, the same shape as /timestamps. Bare
|
|
4576
|
+
// `/test` is left alone: it opens the tests browser, which is a different
|
|
4577
|
+
// thing and is what the command menu offers.
|
|
4578
|
+
const testsBarMatch = /^\/test(?:s)?\s+(.+)$/i.exec(trimmed);
|
|
4579
|
+
if (testsBarMatch) {
|
|
4580
|
+
const next = parseTestsBarArg(testsBarMatch[1] ?? '', getTestsBarVisible());
|
|
4581
|
+
if (next !== null) {
|
|
4582
|
+
setInputValue('');
|
|
4583
|
+
setTestsBarVisible(next);
|
|
4584
|
+
addSystemCard(next
|
|
4585
|
+
? t('ide.chat.testsBarShown', undefined, { defaultValue: 'Tests bar shown.' })
|
|
4586
|
+
: t('ide.chat.testsBarHidden', undefined, { defaultValue: 'Tests bar hidden.' }), { clientOnly: true });
|
|
4587
|
+
return;
|
|
4588
|
+
}
|
|
4589
|
+
}
|
|
4477
4590
|
// Handle /timestamps [on | off] locally — a per-device display preference.
|
|
4478
4591
|
const timestampsCommand = parseTimestampsCommand(trimmed);
|
|
4479
4592
|
if (timestampsCommand) {
|
|
@@ -5842,7 +5955,7 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
|
|
|
5842
5955
|
return (_jsx(ScriptsCard, { projectId: projectId, initialQuery: item.card.query ?? '', isLight: isLight, agentName: agentName }, item.card.id));
|
|
5843
5956
|
}
|
|
5844
5957
|
if (item.card.variant === 'tests') {
|
|
5845
|
-
return (_jsx(TestsCard, { tests: testsList, status: testsStatus, run: testsRun, initialQuery: item.card.query ?? '', canRun: (canRunTests ?? canEdit !== false) && canEdit !== false, onRun: startTestsRun, onCancel: cancelTestsRun, onFix: fixTests, fixDisabledReason: canEdit === false
|
|
5958
|
+
return (_jsx(TestsCard, { tests: testsList, status: testsStatus, run: testsRun, initialQuery: item.card.query ?? '', canRun: (canRunTests ?? canEdit !== false) && canEdit !== false, onRun: startTestsRun, onCancel: cancelTestsRun, onSkipCurrent: skipCurrentTest, onFix: fixTests, fixDisabledReason: canEdit === false
|
|
5846
5959
|
? t('ide.tests.viewerCannotRun', undefined, {
|
|
5847
5960
|
defaultValue: 'Only editors can run this project’s tests.',
|
|
5848
5961
|
})
|
|
@@ -5943,7 +6056,11 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
|
|
|
5943
6056
|
// MessageItem builds the identity from the message's own
|
|
5944
6057
|
// author (teammates included), so the host shows their
|
|
5945
6058
|
// view-only profile and the viewer's editable own.
|
|
5946
|
-
onProfileClick: onProfileClick, currentUserId: currentUserId, showTimestamp: shownTimestampIds.has(msg.id), discovery: discovery, buildUpgradeCta: buildUpgradeCta, agentName: agentName, canEdit: canEdit
|
|
6059
|
+
onProfileClick: onProfileClick, currentUserId: currentUserId, showTimestamp: shownTimestampIds.has(msg.id), discovery: discovery, buildUpgradeCta: buildUpgradeCta, agentName: agentName, canEdit: canEdit, onSkipToolCall: skipToolCall ? handleSkipToolCall : undefined, skipToolCallReason: canEdit === false
|
|
6060
|
+
? t('ide.chat.skipToolCallViewer', undefined, {
|
|
6061
|
+
defaultValue: 'Only editors can skip this.',
|
|
6062
|
+
})
|
|
6063
|
+
: null }, msg.id));
|
|
5947
6064
|
})()) }, item.kind === 'message' ? item.msg.id : item.card.id))), error &&
|
|
5948
6065
|
!isStaleAnonymousLimit &&
|
|
5949
6066
|
(errorMeta?.limitType ? (_jsx(ResourceLimitBanner, { message: error, action: buildUpgradeCta?.({
|
|
@@ -7088,7 +7205,7 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
|
|
|
7088
7205
|
minHeight: 36,
|
|
7089
7206
|
}
|
|
7090
7207
|
: {}),
|
|
7091
|
-
}, children: '✕' })] }), _jsxs("div", { style: { overflowY: 'auto', flex: 1 }, children: [panelOverlay === 'settings' && (_jsx(SettingsCard, { settings: computeSettingsList(), onRunCommand: (commandId) => void executeCommand(commandId), onPrefillInput: (input) => setInputAndCursorEnd(`${input} `), isLight: isLight, agentName: agentName, embedded: true })), panelOverlay === 'skills' && (_jsx(SkillsCard, { projectId: projectId, initialQuery: panelOverlayQuery, onLoad: loadSkill, onCreate: createSkill, loadedSkillPaths: loadedSkillPaths, defaultSkillPaths: defaultSkillPaths, onToggleDefault: toggleDefaultSkill, onResetDefault: resetDefaultSkills, defaultsExplicit: defaultSkillsExplicitRef.current, isLight: isLight, embedded: true })), panelOverlay === 'scripts' && (_jsx(ScriptsCard, { projectId: projectId, initialQuery: panelOverlayQuery, isLight: isLight, agentName: agentName, embedded: true })), panelOverlay === 'tests' && (_jsx(TestsCard, { tests: testsList, status: testsStatus, run: testsRun, initialQuery: panelOverlayQuery, canRun: (canRunTests ?? canEdit !== false) && canEdit !== false, onRun: startTestsRun, onCancel: cancelTestsRun, onFix: fixTests, fixDisabledReason: canEdit === false
|
|
7208
|
+
}, children: '✕' })] }), _jsxs("div", { style: { overflowY: 'auto', flex: 1 }, children: [panelOverlay === 'settings' && (_jsx(SettingsCard, { settings: computeSettingsList(), onRunCommand: (commandId) => void executeCommand(commandId), onPrefillInput: (input) => setInputAndCursorEnd(`${input} `), isLight: isLight, agentName: agentName, embedded: true })), panelOverlay === 'skills' && (_jsx(SkillsCard, { projectId: projectId, initialQuery: panelOverlayQuery, onLoad: loadSkill, onCreate: createSkill, loadedSkillPaths: loadedSkillPaths, defaultSkillPaths: defaultSkillPaths, onToggleDefault: toggleDefaultSkill, onResetDefault: resetDefaultSkills, defaultsExplicit: defaultSkillsExplicitRef.current, isLight: isLight, embedded: true })), panelOverlay === 'scripts' && (_jsx(ScriptsCard, { projectId: projectId, initialQuery: panelOverlayQuery, isLight: isLight, agentName: agentName, embedded: true })), panelOverlay === 'tests' && (_jsx(TestsCard, { tests: testsList, status: testsStatus, run: testsRun, initialQuery: panelOverlayQuery, canRun: (canRunTests ?? canEdit !== false) && canEdit !== false, onRun: startTestsRun, onCancel: cancelTestsRun, onSkipCurrent: skipCurrentTest, onFix: fixTests, fixDisabledReason: canEdit === false
|
|
7092
7209
|
? t('ide.tests.viewerCannotRun', undefined, {
|
|
7093
7210
|
defaultValue: 'Only editors can run this project’s tests.',
|
|
7094
7211
|
})
|
|
@@ -7289,7 +7406,12 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
|
|
|
7289
7406
|
}, onMouseLeave: (e) => {
|
|
7290
7407
|
e.currentTarget.style.opacity = '0.7';
|
|
7291
7408
|
e.currentTarget.style.background = 'none';
|
|
7292
|
-
}, children: _jsx("svg", { width: "13", height: "13", viewBox: "0 0 12 12", style: { display: 'block' }, children: _jsx("path", { d: "M 2.5,6.5 L 6,3 L 9.5,6.5 M 6,3.5 L 6,10", fill: "none", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round", strokeLinejoin: "round" }) }) }))] }, qm.id))) })] })),
|
|
7409
|
+
}, children: _jsx("svg", { width: "13", height: "13", viewBox: "0 0 12 12", style: { display: 'block' }, children: _jsx("path", { d: "M 2.5,6.5 L 6,3 L 9.5,6.5 M 6,3.5 L 6,10", fill: "none", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round", strokeLinejoin: "round" }) }) }))] }, qm.id))) })] })), testsBarVisible &&
|
|
7410
|
+
shouldShowTestsBar(testsRun, testsList) &&
|
|
7411
|
+
!commandMenu &&
|
|
7412
|
+
!modelPicker &&
|
|
7413
|
+
!effortPicker &&
|
|
7414
|
+
!panelOverlay && (_jsx(TestStatusBar, { run: testsRun, tests: testsList, expanded: testsBarExpanded, onToggle: () => setTestsBarExpanded((v) => !v), onOpen: () => openTestsBrowser(''), onStop: testsRun.running ? cancelTestsRun : undefined })), canEdit !== false &&
|
|
7293
7415
|
pendingFiles != null &&
|
|
7294
7416
|
pendingFiles.length > 0 &&
|
|
7295
7417
|
!commandMenu &&
|
|
@@ -7843,7 +7965,7 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
|
|
|
7843
7965
|
* @param props - Component props (see {@link MessageItemProps}).
|
|
7844
7966
|
* @returns The rendered chat panel element.
|
|
7845
7967
|
*/
|
|
7846
|
-
export function ChatPanel({ projectId, endpoint, initialMessage, onInitialMessageSent, activeFile, openTabs, onFileOpen, onFileDoubleClick, onFileDiff, onFileRevert, onFileChange, onFileDeleted, onCommit, onActivityClick, onRenderError, onProfileClick, currentUserId, onReadyToBuild, awaitingSandboxBoot, onClientAction, onTurnComplete, onLoadingChange, onNavigatePreview, onRegisterPushHandler, onRegisterHistoryReconcile, autoSubmitSignal, initialInputValue, hideConversationMenu, renderConversationHeader = true, conversationId: controlledConversationId, chatKey: controlledChatKey, onConversationId: controlledOnConversationId, openShareSignal: controlledShareSignal, openReportSignal: controlledReportSignal, openSettingsSignal: controlledSettingsSignal, onManageCustomModels, gitStatusTick, pendingMessage, pendingMessageKey, pendingMessageSuppressUser, pendingMessageUserInitiated, userEditedFile, userEditedFileKey, isPro, isAnonymous, canEdit = true, canShare, buildUpgradeCta, buildHelpUpgradeSection, userAvatar, agentName, productName, version, extraCommands, feedbackUrl, listTests, runTests, canRunTests, testsAvailable, className, }) {
|
|
7968
|
+
export function ChatPanel({ projectId, endpoint, initialMessage, onInitialMessageSent, activeFile, openTabs, onFileOpen, onFileDoubleClick, onFileDiff, onFileRevert, onFileChange, onFileDeleted, onCommit, onActivityClick, onRenderError, onProfileClick, currentUserId, onReadyToBuild, awaitingSandboxBoot, onClientAction, onTurnComplete, onLoadingChange, onNavigatePreview, onRegisterPushHandler, onRegisterHistoryReconcile, autoSubmitSignal, initialInputValue, hideConversationMenu, renderConversationHeader = true, conversationId: controlledConversationId, chatKey: controlledChatKey, onConversationId: controlledOnConversationId, openShareSignal: controlledShareSignal, openReportSignal: controlledReportSignal, openSettingsSignal: controlledSettingsSignal, onManageCustomModels, gitStatusTick, pendingMessage, pendingMessageKey, pendingMessageSuppressUser, pendingMessageUserInitiated, userEditedFile, userEditedFileKey, isPro, isAnonymous, canEdit = true, canShare, buildUpgradeCta, buildHelpUpgradeSection, userAvatar, agentName, productName, version, extraCommands, feedbackUrl, listTests, runTests, canRunTests, testsAvailable, skipToolCall, className, }) {
|
|
7847
7969
|
const cm = getClassMap();
|
|
7848
7970
|
// Share management may be gated ABOVE canEdit by the host (see
|
|
7849
7971
|
// ChatPanelProps.canShare) — gates the built-in header share button here and
|
|
@@ -8056,7 +8178,7 @@ export function ChatPanel({ projectId, endpoint, initialMessage, onInitialMessag
|
|
|
8056
8178
|
textOverflow: 'ellipsis',
|
|
8057
8179
|
whiteSpace: 'nowrap',
|
|
8058
8180
|
width: '100%',
|
|
8059
|
-
}, children: conv.preview ?? 'New conversation' }), _jsx("span", { className: cm.cn(cm.textMuted, cm.textSize('xs')), style: { opacity: 0.55 }, children: relativeTime(conv.updatedAt) })] }, conv.id)))] }))] })), _jsx(ChatInner, { projectId: projectId, endpoint: chatEndpoint, initialMessage: initialMessage, onInitialMessageSent: onInitialMessageSent, isPro: isPro, isAnonymous: isAnonymous, canEdit: canEdit, canShare: shareAllowed, buildUpgradeCta: buildUpgradeCta, buildHelpUpgradeSection: buildHelpUpgradeSection, activeFile: activeFile, openTabs: openTabs, onFileOpen: onFileOpen, onFileDoubleClick: onFileDoubleClick, onFileDiff: onFileDiff, onFileRevert: onFileRevert, onFileChange: onFileChange, onFileDeleted: onFileDeleted, onCommit: onCommit, onConversationId: reportConversationId, onActivityClick: onActivityClick, onRenderError: onRenderError, onProfileClick: onProfileClick, currentUserId: currentUserId, onReadyToBuild: onReadyToBuild, awaitingSandboxBoot: awaitingSandboxBoot, onClientAction: onClientAction, onTurnComplete: onTurnComplete, onLoadingChange: onLoadingChange, onNavigatePreview: onNavigatePreview, onRegisterPushHandler: onRegisterPushHandler, onRegisterHistoryReconcile: onRegisterHistoryReconcile, autoSubmitSignal: autoSubmitSignal, openSettingsSignal: effectiveSettingsSignal, onManageCustomModels: onManageCustomModels, openReportSignal: effectiveReportSignal, openShareSignal: effectiveShareSignal, initialInputValue: initialInputValue, pendingMessage: pendingMessage, pendingMessageKey: pendingMessageKey, pendingMessageSuppressUser: pendingMessageSuppressUser, pendingMessageUserInitiated: pendingMessageUserInitiated, userEditedFile: userEditedFile, userEditedFileKey: userEditedFileKey, gitStatusTick: gitStatusTick, discovery: hideConversationMenu, userAvatar: userAvatar, agentName: agentName, productName: productName, version: version, extraCommands: extraCommands, feedbackUrl: feedbackUrl, listTests: listTests, runTests: runTests, canRunTests: canRunTests, testsAvailable: testsAvailable }, chatKey)] }));
|
|
8181
|
+
}, children: conv.preview ?? 'New conversation' }), _jsx("span", { className: cm.cn(cm.textMuted, cm.textSize('xs')), style: { opacity: 0.55 }, children: relativeTime(conv.updatedAt) })] }, conv.id)))] }))] })), _jsx(ChatInner, { projectId: projectId, endpoint: chatEndpoint, initialMessage: initialMessage, onInitialMessageSent: onInitialMessageSent, isPro: isPro, isAnonymous: isAnonymous, canEdit: canEdit, canShare: shareAllowed, buildUpgradeCta: buildUpgradeCta, buildHelpUpgradeSection: buildHelpUpgradeSection, activeFile: activeFile, openTabs: openTabs, onFileOpen: onFileOpen, onFileDoubleClick: onFileDoubleClick, onFileDiff: onFileDiff, onFileRevert: onFileRevert, onFileChange: onFileChange, onFileDeleted: onFileDeleted, onCommit: onCommit, onConversationId: reportConversationId, onActivityClick: onActivityClick, onRenderError: onRenderError, onProfileClick: onProfileClick, currentUserId: currentUserId, onReadyToBuild: onReadyToBuild, awaitingSandboxBoot: awaitingSandboxBoot, onClientAction: onClientAction, onTurnComplete: onTurnComplete, onLoadingChange: onLoadingChange, onNavigatePreview: onNavigatePreview, onRegisterPushHandler: onRegisterPushHandler, onRegisterHistoryReconcile: onRegisterHistoryReconcile, autoSubmitSignal: autoSubmitSignal, openSettingsSignal: effectiveSettingsSignal, onManageCustomModels: onManageCustomModels, openReportSignal: effectiveReportSignal, openShareSignal: effectiveShareSignal, initialInputValue: initialInputValue, pendingMessage: pendingMessage, pendingMessageKey: pendingMessageKey, pendingMessageSuppressUser: pendingMessageSuppressUser, pendingMessageUserInitiated: pendingMessageUserInitiated, userEditedFile: userEditedFile, userEditedFileKey: userEditedFileKey, gitStatusTick: gitStatusTick, discovery: hideConversationMenu, userAvatar: userAvatar, agentName: agentName, productName: productName, version: version, extraCommands: extraCommands, feedbackUrl: feedbackUrl, listTests: listTests, runTests: runTests, canRunTests: canRunTests, testsAvailable: testsAvailable, skipToolCall: skipToolCall }, chatKey)] }));
|
|
8060
8182
|
}
|
|
8061
8183
|
ChatPanel.displayName = 'ChatPanel';
|
|
8062
8184
|
//# sourceMappingURL=ChatPanel.js.map
|