@qwen-code/web-shell 0.24.4 → 0.24.5-nightly.20260924.ffea2d024e

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.
Files changed (69) hide show
  1. package/README.md +152 -1
  2. package/dist/code-highlighter.js +4 -0
  3. package/dist/codeHighlighter-pfciSYNN.js +89 -0
  4. package/dist/daemon-react-sdk.js +1 -1
  5. package/dist/index.js +47299 -43736
  6. package/dist/sw.js +1 -1
  7. package/dist/{toolNames-Cnaa5VCB.js → toolNames-DIL221YO.js} +6421 -5852
  8. package/dist/transcript.js +11346 -10971
  9. package/dist/types/App.d.ts +15 -3
  10. package/dist/types/App.typecheck.d.ts +6 -0
  11. package/dist/types/adapters/toolClassification.d.ts +1 -0
  12. package/dist/types/adapters/transcriptToMessages.d.ts +3 -2
  13. package/dist/types/code-highlighter.d.ts +6 -0
  14. package/dist/types/components/BranchPickerPopover.d.ts +3 -1
  15. package/dist/types/components/ChatEditor.d.ts +2 -0
  16. package/dist/types/components/ChatPane.d.ts +5 -3
  17. package/dist/types/components/ConversationSearch.d.ts +18 -0
  18. package/dist/types/components/GlobalTurnNavigation.d.ts +3 -1
  19. package/dist/types/components/MessageList.d.ts +10 -2
  20. package/dist/types/components/MessageTimestamp.d.ts +4 -1
  21. package/dist/types/components/SplitView.d.ts +3 -1
  22. package/dist/types/components/WorkspaceSessionProvider.d.ts +2 -0
  23. package/dist/types/components/artifacts/ArtifactPanel.d.ts +18 -1
  24. package/dist/types/components/artifacts/SideTaskPanel.d.ts +5 -1
  25. package/dist/types/components/artifacts/TrajectoryOverview.d.ts +71 -0
  26. package/dist/types/components/artifacts/TurnCallPromptSelect.d.ts +9 -0
  27. package/dist/types/components/artifacts/TurnCallsPanel.d.ts +38 -0
  28. package/dist/types/components/artifacts/TurnOutputs.d.ts +6 -1
  29. package/dist/types/components/artifacts/loadTurnCalls.d.ts +4 -0
  30. package/dist/types/components/channels/channel-editor-state.d.ts +9 -3
  31. package/dist/types/components/conversation-search-i18n.d.ts +6 -0
  32. package/dist/types/components/dialogs/GitDialog.d.ts +6 -2
  33. package/dist/types/components/dialogs/GitWorktreesDialog.d.ts +11 -0
  34. package/dist/types/components/messages/AuthMessage.d.ts +2 -1
  35. package/dist/types/components/messages/ModelManagementSection.d.ts +3 -2
  36. package/dist/types/components/messages/PlanExecutionView.d.ts +14 -66
  37. package/dist/types/components/messages/SettingsMessage.d.ts +2 -2
  38. package/dist/types/components/messages/ToolFilePreviewButton.d.ts +2 -1
  39. package/dist/types/components/messages/ToolGroup.d.ts +3 -0
  40. package/dist/types/components/messages/codeHighlighter.d.ts +7 -0
  41. package/dist/types/components/messages/taskExecutionIndex.d.ts +80 -0
  42. package/dist/types/components/panels/EnvironmentPanel.d.ts +2 -1
  43. package/dist/types/components/sidebar/WorkspaceSection.d.ts +8 -1
  44. package/dist/types/components/workflow/SessionWorkflowCockpit.d.ts +8 -1
  45. package/dist/types/components/workflow/SessionWorkflowInspector.d.ts +8 -1
  46. package/dist/types/components/workflow/session-workflow-model.d.ts +9 -1
  47. package/dist/types/customization.d.ts +9 -1
  48. package/dist/types/daemon/session/transcript-page-table.d.ts +1 -1
  49. package/dist/types/daemon/session/turn-navigation-store.d.ts +32 -0
  50. package/dist/types/hooks/useMessageNavigation.d.ts +12 -0
  51. package/dist/types/hooks/useQueuedPrompts.d.ts +4 -1
  52. package/dist/types/hooks/useTranscriptViewport.d.ts +4 -1
  53. package/dist/types/index.d.ts +13 -1
  54. package/dist/types/live/live-presence.d.ts +14 -0
  55. package/dist/types/live/screen-feed-sampler.d.ts +12 -0
  56. package/dist/types/live/useLiveBrowserHost.d.ts +7 -0
  57. package/dist/types/live/useLiveVoice.d.ts +2 -0
  58. package/dist/types/modelManagement.d.ts +16 -0
  59. package/dist/types/navigation.d.ts +37 -0
  60. package/dist/types/trajectory/buildTimeline.d.ts +67 -0
  61. package/dist/types/trajectory/timelineRange.d.ts +27 -0
  62. package/dist/types/trajectory/transcriptPageLoader.d.ts +4 -2
  63. package/dist/types/trajectory/types.d.ts +3 -3
  64. package/dist/types/trajectory/useTrajectoryWindow.d.ts +55 -17
  65. package/dist/types/turnCallsContext.d.ts +12 -0
  66. package/dist/types/utils/navigationUrl.d.ts +21 -0
  67. package/dist/types/utils/popoverRoom.d.ts +22 -0
  68. package/dist/types/utils/sessionPath.d.ts +1 -0
  69. package/package.json +5 -1
@@ -0,0 +1,37 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Qwen Team
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { type ReactNode } from 'react';
7
+ import type { DaemonProductSessionContext } from '@qwen-code/web-shell/daemon-react-sdk';
8
+ import type { WebShellProps } from './App';
9
+ import { type WebShellPage, type WebShellRoute } from './utils/navigationUrl';
10
+ export type { WebShellPage } from './utils/navigationUrl';
11
+ export interface WebShellUrlNavigationOptions {
12
+ /** URL pathname containing the shell, e.g. /agentic-code. Defaults to root. */
13
+ basePath?: string;
14
+ }
15
+ export interface NavigationSessionProps {
16
+ sessionId?: string;
17
+ workspaceId?: string;
18
+ workspaceCwd?: string;
19
+ sessionContext?: DaemonProductSessionContext;
20
+ }
21
+ interface NavigationController {
22
+ route: WebShellRoute;
23
+ revision: number;
24
+ openPage: (page: WebShellPage) => void;
25
+ returnToChat: () => void;
26
+ reconcilePage: (page: WebShellPage | undefined) => void;
27
+ beginSessionNavigation: (sessionId?: string, workspaceId?: string, sessionContext?: DaemonProductSessionContext) => void;
28
+ cancelSessionNavigation: () => void;
29
+ finishNewChat: (context?: DaemonProductSessionContext) => void;
30
+ }
31
+ export declare const useWebShellNavigation: () => NavigationController | undefined;
32
+ export declare function WebShellNavigationBoundary({ options, externalTarget, onSessionIdChange, children, }: {
33
+ options?: WebShellUrlNavigationOptions;
34
+ externalTarget: NavigationSessionProps;
35
+ onSessionIdChange?: WebShellProps['onSessionIdChange'];
36
+ children: (target: NavigationSessionProps, onChange: NonNullable<WebShellProps['onSessionIdChange']>) => ReactNode;
37
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,67 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Qwen Team
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import type { Trajectory, TrajectoryRow } from './types';
7
+ /** 0 main-session requests · 1 tool calls · 2 subagent requests. */
8
+ export type TimelineLane = 0 | 1 | 2;
9
+ export interface TimelineSpan {
10
+ /** The table row this span draws; selecting a span selects this row. */
11
+ rowKey: string;
12
+ row: TrajectoryRow;
13
+ lane: TimelineLane;
14
+ /** Offset into the compressed domain, ms. */
15
+ start: number;
16
+ end: number;
17
+ /** Requests with a recorded TTFT only: where the first token landed. */
18
+ ttftEnd?: number;
19
+ error: boolean;
20
+ }
21
+ /**
22
+ * How the axis treats time in which nothing ran. `active` cuts it out, so the
23
+ * strip answers where the running time went; `clock` keeps it, so the strip
24
+ * answers when things ran and how long the run waited between them.
25
+ */
26
+ export type TimelineMode = 'active' | 'clock';
27
+ export interface TimelineTurnMark {
28
+ turnIndex: number;
29
+ at: number;
30
+ }
31
+ export interface TimelineModel {
32
+ /** Ascending by start, then lane, then row key. */
33
+ spans: TimelineSpan[];
34
+ turnMarks: TimelineTurnMark[];
35
+ mode: TimelineMode;
36
+ /**
37
+ * Length of the domain. In `active` mode idle gaps are cut out, so this is
38
+ * the time during which at least one request or tool was running. In
39
+ * `clock` mode it runs from the first drawn span's start to the last one's
40
+ * end — which is the loaded window's span, not the session's age.
41
+ */
42
+ total: number;
43
+ /**
44
+ * Time during which at least one drawn span was running. Equal to `total` in
45
+ * `active` mode.
46
+ */
47
+ activeMs: number;
48
+ /** Epoch ms of domain 0: the earliest recorded start among drawn spans. */
49
+ originMs: number;
50
+ /**
51
+ * Rows with a recorded duration but no recorded start — tool calls from a
52
+ * session written before tools recorded one. Not drawn, never estimated.
53
+ */
54
+ droppedRows: number;
55
+ }
56
+ /**
57
+ * Project the rows that recorded both a start and a duration onto one time
58
+ * axis — with the idle stretches between them cut out (`active`, the default)
59
+ * or left in (`clock`).
60
+ *
61
+ * Only measured values are drawn. A row without a start is left off rather
62
+ * than placed next to its neighbours: a bar in the wrong place reads as a fact.
63
+ * Returns `undefined` when nothing in the window can be drawn.
64
+ */
65
+ export declare function buildTimeline(trajectory: Trajectory, options?: {
66
+ mode?: TimelineMode;
67
+ }): TimelineModel | undefined;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Qwen Team
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import type { TimelineModel } from './buildTimeline';
7
+ /**
8
+ * A stretch of the overview's domain, in the same compressed milliseconds as
9
+ * the spans. Always ordered: `start <= end`.
10
+ */
11
+ export interface TimelineRange {
12
+ start: number;
13
+ end: number;
14
+ }
15
+ /**
16
+ * Rows whose span was running at any point in the range, ends included.
17
+ *
18
+ * With idle time cut out of the domain, spans cover it end to end, so any
19
+ * range finds at least one row. In `clock` mode the gaps stay on the axis, and
20
+ * a range that falls inside one finds nothing — an ordinary answer the panel
21
+ * says in words rather than an edge case.
22
+ *
23
+ * Closed on both sides so a zero-length span sitting on an edge — a tool that
24
+ * reported 0 ms, or a range made by a drag that stopped exactly on a bar's
25
+ * end — still counts as inside rather than vanishing from both sides.
26
+ */
27
+ export declare function rowKeysInRange(model: TimelineModel, range: TimelineRange): Set<string>;
@@ -12,6 +12,7 @@ export interface TrajectoryTranscriptClient {
12
12
  getSessionTranscriptPage(sessionId: string, opts: {
13
13
  direction?: 'backward';
14
14
  limit?: number;
15
+ cursor?: string;
15
16
  }): Promise<TrajectoryPageResult>;
16
17
  }
17
18
  /**
@@ -20,8 +21,9 @@ export interface TrajectoryTranscriptClient {
20
21
  * Identity matters: the loader is the window hook's effect dependency, so a
21
22
  * fresh function on every render would refetch the newest page on every render.
22
23
  *
23
- * Reads ask for the newest page, which is the one the reader wants — the newest
24
- * turn is the one they just watched run. It deliberately goes through the raw
24
+ * Reads walk backward from the newest page, which is the one the reader wants —
25
+ * the newest turn is the one they just watched run — following the cursor each
26
+ * page hands back. It deliberately goes through the raw
25
27
  * client rather than
26
28
  * `DaemonSessionClient.getTranscriptPage`, which hydrates attachments and would
27
29
  * fetch image bytes this table never shows, and it never asks for the
@@ -42,9 +42,9 @@ export type TrajectoryEntry = {
42
42
  export interface TrajectoryTiming {
43
43
  durationMs: number;
44
44
  /**
45
- * Requests only. Tool calls are logged in one loop after their whole batch
46
- * settles, so the recorded timestamp is the batch's end for every tool in it
47
- * and no honest per-tool start can be derived.
45
+ * Epoch ms. Requests have one whenever their end was recorded; tool calls
46
+ * only when the session recorded the call's start, which older sessions did
47
+ * not.
48
48
  */
49
49
  startedAt?: number;
50
50
  /** Requests only: dispatch to first user-visible content. */
@@ -11,6 +11,18 @@ import type { Trajectory } from './types';
11
11
  * shorter than this — `truncated` is what says so, never the count.
12
12
  */
13
13
  export declare const TRAJECTORY_PAGE_SIZE = 250;
14
+ /**
15
+ * Pages read, newest first, before the window is drawn. The window is
16
+ * re-projected whole on every change and each page is a full replay of its
17
+ * records, so this is what bounds the retained bytes and the per-change work —
18
+ * and holding four pages where the table held one raises both by four, to 1000
19
+ * records nominally. The true worst case is nearer 3000: a backward page can
20
+ * exceed the limit it was asked for, because the daemon extends it to keep
21
+ * turns and tool pairs whole, up to `3 * limit` records and its own 4 MB
22
+ * ceiling. Four is where that ceiling stays defensible while still reaching a
23
+ * useful way back.
24
+ */
25
+ export declare const TRAJECTORY_MAX_PAGES = 4;
14
26
  /**
15
27
  * The fields of a transcript page this view reads. Narrower than the daemon's
16
28
  * own page type on purpose: the client's page satisfies it structurally, and a
@@ -19,11 +31,14 @@ export declare const TRAJECTORY_PAGE_SIZE = 250;
19
31
  export interface TrajectoryPageResult {
20
32
  events: readonly DaemonEvent[];
21
33
  hasMore: boolean;
34
+ /** Where the next older page starts; absent when there is none to ask for. */
35
+ nextCursor?: string;
22
36
  partial?: true;
23
37
  replayError?: string;
24
38
  }
25
39
  /**
26
- * Fetches the newest page of the session's transcript.
40
+ * Fetches one page of the session's transcript: the newest without a cursor,
41
+ * the one older than a previous page with that page's `nextCursor`.
27
42
  *
28
43
  * Supplied by the host rather than called here so the panel never reaches for
29
44
  * a daemon client of its own. There is no cancellation: the daemon client
@@ -32,11 +47,12 @@ export interface TrajectoryPageResult {
32
47
  */
33
48
  export type TrajectoryPageLoader = (opts: {
34
49
  limit: number;
50
+ cursor?: string;
35
51
  }) => Promise<TrajectoryPageResult>;
36
52
  /**
37
- * Why the last read failed. `partial` is not a message — the daemon reports it
38
- * as a flag — so it is carried as a kind for the view to name, rather than as
39
- * a word that would end up quoted at the reader.
53
+ * Why a read failed. `partial` is not a message — the daemon reports it as a
54
+ * flag — so it is carried as a kind for the view to name, rather than as a
55
+ * word that would end up quoted at the reader.
40
56
  */
41
57
  export type TrajectoryWindowFailure = {
42
58
  kind: 'partial';
@@ -47,29 +63,51 @@ export type TrajectoryWindowFailure = {
47
63
  export interface TrajectoryWindow {
48
64
  trajectory: Trajectory | undefined;
49
65
  status: 'idle' | 'loading' | 'ready' | 'error';
66
+ /**
67
+ * The newest page could not be read. The window already on screen, if any,
68
+ * is kept.
69
+ */
50
70
  error?: TrajectoryWindowFailure;
51
71
  /**
52
- * The session has history older than what this page carries. Nothing here
53
- * can reach it yet, so the view says so rather than offering an action.
72
+ * Pages read so far by the load under way, or held by the window once it
73
+ * is ready. What the placeholder counts while the walk back is running.
74
+ */
75
+ loadedPages: number;
76
+ /**
77
+ * The session has history older than the window: the walk stopped at the
78
+ * page cap, at a page the daemon gave no cursor for, or at an older page it
79
+ * could not read.
54
80
  */
55
81
  truncated: boolean;
56
- /** Re-read the newest page. Also how a failed read is retried. */
82
+ /**
83
+ * An older page could not be read, so the window stops just after it. The
84
+ * newer pages are drawn; `refresh` is the retry.
85
+ */
86
+ olderFailure?: TrajectoryWindowFailure;
87
+ /** Read the window again from the newest page. Also every retry. */
57
88
  refresh: () => void;
58
89
  }
59
90
  /**
60
- * Hold the newest page of one session's transcript and fold it into a
61
- * trajectory.
91
+ * Hold a window of one session's transcript and fold it into a trajectory.
92
+ *
93
+ * The pages are this view's own: paged replay is the only path that emits
94
+ * timing frames, and the chat store is fed by the live stream and by bulk
95
+ * replay, neither of which carries them. Reading here also keeps the window
96
+ * contiguous by construction, which is what lets the projection pair a frame
97
+ * with what it measured.
62
98
  *
63
- * The page is this view's own: paged replay is the only path that emits timing
64
- * frames, and the chat store is fed by the live stream and by bulk replay,
65
- * neither of which carries them. Reading here also keeps the window contiguous
66
- * by construction, which is what lets the projection pair a frame with what it
67
- * measured.
99
+ * A load walks back from the newest page by cursor, up to the page cap, and
100
+ * the window lands once, whole, when the walk ends. Nothing is ever put in
101
+ * front of rows already drawn: a list that grew upwards under the reader would
102
+ * have to move its scroll offset, its keys, its selection and its focus in
103
+ * step, and no part of that is observable outside a real browser.
68
104
  *
69
- * `refresh` replaces the page rather than splicing into it: page boundaries
70
- * are chosen per request, so a fresh page and the held one overlap by an
71
- * unknown amount and cannot be joined without dropping or repeating records.
105
+ * `refresh` rebuilds the window from the newest page rather than splicing into
106
+ * it: page boundaries are chosen per request, so a fresh page and the held
107
+ * ones overlap by an unknown amount and cannot be joined without dropping or
108
+ * repeating records.
72
109
  */
73
110
  export declare function useTrajectoryWindow(loadPage: TrajectoryPageLoader | undefined, options?: {
74
111
  pageSize?: number;
112
+ maxPages?: number;
75
113
  }): TrajectoryWindow;
@@ -0,0 +1,12 @@
1
+ import { type ReactNode } from 'react';
2
+ /**
3
+ * Opens the right-panel list of tool calls belonging to one turn. `turnId` is
4
+ * the id of the turn's leading user message.
5
+ */
6
+ export type OpenTurnCalls = (turnId: string, recordId?: string, promptId?: string, promptLabel?: string) => void;
7
+ export declare function isTurnCallsPrompt(source: unknown, text: string): boolean;
8
+ export declare function TurnCallsProvider({ onOpen, children, }: {
9
+ onOpen: OpenTurnCalls | undefined;
10
+ children: ReactNode;
11
+ }): import("react/jsx-runtime").JSX.Element;
12
+ export declare function useOpenTurnCalls(): OpenTurnCalls | undefined;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Qwen Team
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ export declare const WEB_SHELL_PAGES: readonly ["plugins", "channels", "scheduled-tasks", "goals", "settings"];
7
+ export type WebShellPage = (typeof WEB_SHELL_PAGES)[number];
8
+ export interface SessionUrlTarget {
9
+ sessionId?: string;
10
+ workspaceId?: string;
11
+ context?: 'standalone' | 'live';
12
+ }
13
+ export type WebShellRoute = {
14
+ page: WebShellPage;
15
+ } | ({
16
+ page: 'chat';
17
+ } & SessionUrlTarget);
18
+ export declare function normalizeNavigationBasePath(basePath?: string): string;
19
+ export declare function isWebShellPage(value: string): value is WebShellPage;
20
+ export declare function readNavigationUrl(url: URL, basePath?: string): WebShellRoute | undefined;
21
+ export declare function buildNavigationUrl(current: URL, route: WebShellRoute, basePath?: string): URL;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * The top clearance a host declares for upward-opening popovers through
3
+ * `--web-shell-popover-safe-top`, or `undefined` when it declares none. A
4
+ * declared `0px` stays 0 instead of falling back to a default.
5
+ */
6
+ export declare function readPopoverSafeTop(element: Element): number | undefined;
7
+ export declare const POPOVER_MIN_HEIGHT = 96;
8
+ /**
9
+ * The highest viewport y at which a popover positioned inside `anchor` is still
10
+ * painted: below the top edge of every ancestor that clips its overflow, and
11
+ * below the host's declared safe top.
12
+ *
13
+ * With no declared safe top the bound starts at 0, because an in-flow popover
14
+ * is already bounded by the clipping ancestors this walk measures. A popover
15
+ * portaled out of that chain has no clipping ancestor to measure and needs a
16
+ * numeric allowance instead — see AtMentionPanel's
17
+ * `readPopoverSafeTop(anchor) ?? 48`. Keep the two defaults distinct: folding
18
+ * the 48 in here would steal room from in-flow popovers, and folding the 0
19
+ * into AtMentionPanel would let it rise under a host header that declares
20
+ * nothing.
21
+ */
22
+ export declare function popoverTopEdge(anchor: Element): number;
@@ -3,6 +3,7 @@
3
3
  * Copyright 2026 Qwen Team
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
+ export declare function inferStandaloneBasePath(pathname: string): string;
6
7
  /**
7
8
  * Build the pathname for a standalone session URL while preserving any base
8
9
  * path the app is deployed under (e.g. `/app/session/<id>` stays under
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qwen-code/web-shell",
3
- "version": "0.24.4",
3
+ "version": "0.24.5-nightly.20260924.ffea2d024e",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/QwenLM/qwen-code.git",
@@ -22,6 +22,10 @@
22
22
  "./transcript": {
23
23
  "types": "./dist/types/transcript.d.ts",
24
24
  "import": "./dist/transcript.js"
25
+ },
26
+ "./code-highlighter": {
27
+ "types": "./dist/types/code-highlighter.d.ts",
28
+ "import": "./dist/code-highlighter.js"
25
29
  }
26
30
  },
27
31
  "files": [