Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
70d6965
feat(web-shell): add artifact right panel
Jul 9, 2026
a53087b
Merge remote-tracking branch 'upstream/main' into feat/web-shell-righ…
Jul 9, 2026
b0f7108
fix(web-shell): address artifact panel review feedback
Jul 9, 2026
1907e91
Merge branch 'main' into feat/web-shell-right-panel
ytahdn Jul 9, 2026
942e70a
fix(web-shell): handle artifact panel review edge cases
Jul 9, 2026
73817fa
fix(web-shell): tighten scheduled task parsing
Jul 9, 2026
57aadab
fix(web-shell): address artifact panel review followups
Jul 9, 2026
985d04e
fix(web-shell): guard large file diff stats
Jul 9, 2026
617a87b
fix(web-shell): address review panel suggestions
Jul 9, 2026
8420cc0
test(webui): stabilize heartbeat prompt cleanup test
Jul 9, 2026
406884d
fix(web-shell): address artifact review refresh issues
Jul 9, 2026
0cfd4ee
test(web-shell): stabilize ChatPane artifact hook mock
Jul 9, 2026
bb58ddd
fix(web-shell): clear stale session artifacts while loading
Jul 9, 2026
11f1f5d
fix(web-shell): preserve artifact tabs during refresh
Jul 9, 2026
847cf36
fix(web-shell): address artifact review followups
Jul 9, 2026
8113ab7
fix(web-shell): respect workspace cwd for artifact outputs
Jul 10, 2026
166d578
fix(web-shell): scope artifact panel actions to pane
Jul 10, 2026
ec470bb
fix(web-shell): resolve split pane merge conflict
Jul 10, 2026
18c5273
Merge upstream/main into feat/web-shell-right-panel
Jul 10, 2026
05158d7
fix(web-shell): clear stale artifact panel state
Jul 10, 2026
e4b7bcd
Merge upstream/main into feat/web-shell-right-panel
Jul 10, 2026
f7a8101
fix(web-shell): preserve leading turn outputs
Jul 10, 2026
39c4a6c
fix(web-shell): tighten turn output selectors
Jul 10, 2026
3ccfa30
fix(web-shell): harden artifact preview sanitizer
Jul 10, 2026
12c46cc
fix(web-shell): address artifact panel review regressions
Jul 10, 2026
1914eee
fix(web-shell): reconcile split pane artifact snapshots
Jul 10, 2026
5dbf8a3
fix(web-shell): clear pane artifacts on session switch
Jul 10, 2026
b670b9d
Merge remote-tracking branch 'upstream/main' into feat/web-shell-righ…
Jul 10, 2026
e92bb16
fix(web-shell): clear stale right panel snapshots
Jul 10, 2026
0d4f3bf
chore(web-shell): resolve merge conflicts with main in i18n.tsx
qwen-code-dev-bot Jul 10, 2026
a374618
Merge remote-tracking branch 'upstream/main' into feat/web-shell-righ…
Jul 10, 2026
385b66e
Merge remote-tracking branch 'origin/feat/web-shell-right-panel' into…
Jul 10, 2026
45932ee
fix(web-shell): repair scheduled task hint string
Jul 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .qwen/skills/triage/references/pr-workflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,7 @@ gh pr review "$PR_NUMBER" --repo "$REPO" --request-changes --body "Needs some re
```

Genuinely unsure, or `GUARD` blocked approval — **don't approve or reject**, but **never defer silently**. Post an explicit defer comment that:

1. States you are escalating to the maintainer.
2. Names the specific reason(s) for uncertainty — what you cannot resolve from the diff, tests, and PR description.
3. @mentions the maintainer (use `$QWEN_MAINTAINER_HANDLE` if set, or the most recent human reviewer).
Expand Down
14 changes: 14 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 28 additions & 0 deletions packages/sdk-typescript/src/daemon/ui/normalizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type {
DaemonAuthProviderId,
DaemonErrorKind,
DaemonEvent,
DaemonSessionArtifactChange,
} from '../types.js';
import { DAEMON_ERROR_KINDS } from '../types.js';
import type {
Expand Down Expand Up @@ -299,6 +300,9 @@ export function normalizeDaemonEvent(
case 'extensions_changed':
return normalizeExtensionsChanged(event, base);

case 'artifact_changed':
return normalizeArtifactChanged(event, base);

// ── Auth device-flow events (RFC 8628) ─────────────────
case 'auth_device_flow_started':
return normalizeAuthDeviceFlowStarted(event, base);
Expand Down Expand Up @@ -1126,6 +1130,30 @@ function normalizeSessionMetadataUpdated(
];
}

function normalizeArtifactChanged(
event: DaemonEvent,
base: NormalizedEventBase,
): DaemonUiEvent[] {
const sessionId = getString(event.data, 'sessionId');
const change = isRecord(event.data) ? event.data['change'] : undefined;
if (!sessionId || !isRecord(change)) {
return fallbackDebug(event, base, 'malformed artifact_changed payload');
}
const action = getString(change, 'action');
const artifactId = getString(change, 'artifactId');
if (!action || !artifactId) {
return fallbackDebug(event, base, 'missing action or artifactId');
}
return [
{
...base,
type: 'session.artifact.changed',
sessionId,
change: change as unknown as DaemonSessionArtifactChange,
Comment thread
ytahdn marked this conversation as resolved.
},
];
}

function normalizeApprovalModeChanged(
event: DaemonEvent,
base: NormalizedEventBase,
Expand Down
6 changes: 6 additions & 0 deletions packages/sdk-typescript/src/daemon/ui/terminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@ export function daemonUiEventToTerminalText(event: DaemonUiEvent): string {
`metadata: ${event.displayName ?? '(no display name)'}`,
'36',
);
case 'session.artifact.changed':
return terminalLine(
'artifact',
`${event.change.action} ${event.change.artifact?.title ?? event.change.artifactId}`,
'36',
);
case 'session.approval_mode.changed':
return terminalLine(
'approval-mode',
Expand Down
1 change: 1 addition & 0 deletions packages/sdk-typescript/src/daemon/ui/transcript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ function applyDaemonTranscriptEvent(
next.approvalMode = event.next;
break;
case 'session.metadata.changed':
case 'session.artifact.changed':
case 'session.available_commands':
// Intentional no-op against `blocks[]`.
break;
Expand Down
9 changes: 9 additions & 0 deletions packages/sdk-typescript/src/daemon/ui/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type {
DaemonAuthProviderId,
DaemonEvent,
DaemonErrorKind,
DaemonSessionArtifactChange,
PermissionResponse,
} from '../types.js';

Expand All @@ -34,6 +35,7 @@ export type DaemonUiEventType =
| 'debug'
// Session-meta events
| 'session.metadata.changed'
| 'session.artifact.changed'
| 'session.approval_mode.changed'
| 'session.available_commands'
| 'session.state_resync_required'
Expand Down Expand Up @@ -281,6 +283,12 @@ export interface DaemonUiSessionMetadataChangedEvent extends DaemonUiEventBase {
displayName?: string;
}

export interface DaemonUiSessionArtifactChangedEvent extends DaemonUiEventBase {
type: 'session.artifact.changed';
sessionId: string;
change: DaemonSessionArtifactChange;
}

export interface DaemonUiSessionApprovalModeChangedEvent
extends DaemonUiEventBase {
type: 'session.approval_mode.changed';
Expand Down Expand Up @@ -556,6 +564,7 @@ export type DaemonUiEvent =
| DaemonUiErrorEvent
// Session-meta events
| DaemonUiSessionMetadataChangedEvent
| DaemonUiSessionArtifactChangedEvent
| DaemonUiSessionApprovalModeChangedEvent
| DaemonUiSessionAvailableCommandsEvent
| DaemonUiStateResyncRequiredEvent
Expand Down
65 changes: 65 additions & 0 deletions packages/sdk-typescript/test/unit/daemonUi.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6651,6 +6651,71 @@ describe('parallel subAgent text interleaving — normalizer', () => {
});
});

describe('daemon UI normalizer — artifact events', () => {
it('normalizes artifact_changed as a structured session event', () => {
const events = normalizeDaemonEvent({
type: 'artifact_changed',
data: {
sessionId: 'session-1',
change: {
action: 'updated',
artifactId: 'artifact-1',
artifact: {
id: 'artifact-1',
title: 'Report',
kind: 'html',
storage: 'workspace',
source: 'tool',
status: 'available',
},
},
},
} as never);

expect(events).toEqual([
expect.objectContaining({
type: 'session.artifact.changed',
sessionId: 'session-1',
change: expect.objectContaining({
action: 'updated',
artifactId: 'artifact-1',
}),
}),
]);
});

it('falls back to debug for malformed artifact_changed payloads', () => {
const events = normalizeDaemonEvent({
type: 'artifact_changed',
data: { sessionId: 'session-1' },
} as never);

expect(events).toEqual([
expect.objectContaining({
type: 'debug',
text: 'artifact_changed: malformed artifact_changed payload',
}),
]);
});

it('falls back to debug when artifact_changed change misses required fields', () => {
const events = normalizeDaemonEvent({
type: 'artifact_changed',
data: {
sessionId: 'session-1',
change: {},
},
} as never);

expect(events).toEqual([
expect.objectContaining({
type: 'debug',
text: 'artifact_changed: missing action or artifactId',
}),
]);
});
});

describe('parallel subAgent text interleaving fix', () => {
it('T1: separates text chunks by parentToolCallId into independent blocks', () => {
let state = createDaemonTranscriptState({ now: 1 });
Expand Down
23 changes: 23 additions & 0 deletions packages/web-shell/client/App.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,23 @@
overflow: hidden;
}

.artifactResizeHandle {
flex: 0 0 8px;
width: 8px;
margin-left: -4px;
cursor: col-resize;
position: relative;
z-index: 2;
touch-action: none;
}

.artifactResizeHandle::after {
content: '';
position: absolute;
inset: 0 3px;
background: transparent;
}

/* Positioning context so the scheduled-tasks page (position:absolute) covers
exactly the chat pane. Only applied while the page is shown, so normal chat
layout is untouched. */
Expand Down Expand Up @@ -176,6 +193,12 @@
height: 20px;
}

@media (max-width: 900px) {
.artifactResizeHandle {
display: none;
}
}

@media (max-width: 760px) {
.mobileDrawer {
display: block;
Expand Down
Loading
Loading