@qwen-code/web-shell 0.24.1-preview.1 → 0.24.3-nightly.20260921.2800e9bb4f

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 (79) hide show
  1. package/LICENSE +203 -0
  2. package/README.md +51 -4
  3. package/dist/daemon-react-sdk.js +1 -1
  4. package/dist/index.js +54062 -49941
  5. package/dist/sw.js +1 -1
  6. package/dist/{toolNames-DgCpmhML.js → toolNames-DQad2xSu.js} +6114 -5488
  7. package/dist/transcript.js +10297 -9531
  8. package/dist/types/App.d.ts +13 -2
  9. package/dist/types/adapters/messageTypes.d.ts +12 -1
  10. package/dist/types/adapters/reported-artifacts.d.ts +2 -0
  11. package/dist/types/adapters/transcriptToMessages.d.ts +16 -0
  12. package/dist/types/assistant-turn-settlement.d.ts +12 -0
  13. package/dist/types/components/BranchPickerPopover.d.ts +3 -1
  14. package/dist/types/components/ChatContextHeader.d.ts +10 -1
  15. package/dist/types/components/ChatEditor.d.ts +10 -0
  16. package/dist/types/components/GoalStatusStrip.d.ts +12 -0
  17. package/dist/types/components/MessageItem.d.ts +7 -1
  18. package/dist/types/components/SplitView.d.ts +3 -1
  19. package/dist/types/components/StandaloneAuth.d.ts +3 -1
  20. package/dist/types/components/artifacts/ArtifactPanel.d.ts +22 -1
  21. package/dist/types/components/artifacts/TrajectoryPanel.d.ts +14 -0
  22. package/dist/types/components/artifacts/TurnOutputs.d.ts +7 -0
  23. package/dist/types/components/artifacts/artifactUtils.d.ts +1 -1
  24. package/dist/types/components/composer/AddMenu.d.ts +24 -2
  25. package/dist/types/components/dialogs/AddWorkspaceDialog.d.ts +11 -1
  26. package/dist/types/components/dialogs/DaemonStatusDialog.d.ts +4 -0
  27. package/dist/types/components/dialogs/WorkspaceAddStatusDialog.d.ts +11 -0
  28. package/dist/types/components/messages/AssistantMessage.d.ts +5 -1
  29. package/dist/types/components/messages/SettingsMessage.d.ts +4 -1
  30. package/dist/types/components/messages/tools/ShellToolOutput.d.ts +4 -0
  31. package/dist/types/components/messages/tools/shellLiveOutput.d.ts +13 -0
  32. package/dist/types/components/panels/EnvironmentPanel.d.ts +2 -1
  33. package/dist/types/components/sidebar/WorkspaceSection.d.ts +2 -1
  34. package/dist/types/components/ui/alert-dialog.d.ts +1 -1
  35. package/dist/types/components/ui/field.d.ts +1 -1
  36. package/dist/types/components/ui/toggle-group.d.ts +1 -1
  37. package/dist/types/components/workspaces/CapacityRecoveryDialog.d.ts +11 -0
  38. package/dist/types/config/daemon.d.ts +3 -1
  39. package/dist/types/config/remote-connections.d.ts +18 -0
  40. package/dist/types/config/remote-workspace-add.d.ts +17 -0
  41. package/dist/types/customization.d.ts +59 -1
  42. package/dist/types/daemon/session/DaemonSessionProvider.d.ts +3 -2
  43. package/dist/types/daemon/session/actions.d.ts +1 -1
  44. package/dist/types/daemon/session/httpErrors.d.ts +1 -0
  45. package/dist/types/daemon/session/types.d.ts +30 -1
  46. package/dist/types/daemon/workspace/hooks/useDaemonMemory.d.ts +3 -1
  47. package/dist/types/daemon/workspace/types.d.ts +8 -1
  48. package/dist/types/hooks/useAssistantFeedback.d.ts +16 -0
  49. package/dist/types/hooks/useCapacityRecovery.d.ts +8 -0
  50. package/dist/types/hooks/useComposerCore.d.ts +6 -1
  51. package/dist/types/hooks/useContextCompressionReconcile.d.ts +38 -0
  52. package/dist/types/hooks/useQueuedPrompts.d.ts +2 -1
  53. package/dist/types/hooks/useReportedArtifactRegistration.d.ts +20 -0
  54. package/dist/types/hooks/useSessionArtifacts.d.ts +2 -1
  55. package/dist/types/index.d.ts +1 -1
  56. package/dist/types/live/LiveLevelMeter.d.ts +31 -0
  57. package/dist/types/live/LiveVoiceButton.d.ts +7 -1
  58. package/dist/types/live/LiveVoiceMenuItem.d.ts +9 -0
  59. package/dist/types/live/live-model-options.d.ts +24 -0
  60. package/dist/types/live/messages.d.ts +16 -0
  61. package/dist/types/live/messages.transcript-stub.d.ts +12 -0
  62. package/dist/types/live/pcm-player.d.ts +34 -0
  63. package/dist/types/live/screen-share.d.ts +25 -0
  64. package/dist/types/live/useLiveBrowserHost.d.ts +92 -0
  65. package/dist/types/live/useLiveVoice.d.ts +6 -0
  66. package/dist/types/session-catalog/session-catalog-store.d.ts +9 -0
  67. package/dist/types/settings.d.ts +6 -4
  68. package/dist/types/trajectory/buildTrajectory.d.ts +15 -0
  69. package/dist/types/trajectory/projectTrajectoryWindow.d.ts +23 -0
  70. package/dist/types/trajectory/transcriptPageLoader.d.ts +31 -0
  71. package/dist/types/trajectory/types.d.ts +130 -0
  72. package/dist/types/trajectory/useTrajectoryWindow.d.ts +75 -0
  73. package/dist/types/utils/assistantFeedback.d.ts +71 -0
  74. package/dist/types/utils/commitGraph.d.ts +39 -0
  75. package/dist/types/utils/contextCompression.d.ts +38 -0
  76. package/dist/types/utils/sessionPreparation.d.ts +3 -1
  77. package/dist/types/voice/capture-utils.d.ts +22 -0
  78. package/dist/types/voice/useVoiceCapture.d.ts +2 -1
  79. package/package.json +25 -20
@@ -0,0 +1,92 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Qwen
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { type RefObject } from 'react';
7
+ import type { DaemonLiveStatus } from '@qwen-code/sdk';
8
+ /**
9
+ * Makes this page the Live Voice audio endpoint: it holds the daemon's single
10
+ * Host lease over WS `/live/web`, streams the microphone up and plays the
11
+ * model's speech. The call itself is still driven through `/live/*` (start,
12
+ * stop, mute); this hook only moves audio and mirrors the pushed status.
13
+ */
14
+ export declare const LIVE_WEB_HOST_PATH = "/live/web";
15
+ /**
16
+ * What the capture callback last saw. `at` is the `performance.now()` of that
17
+ * frame: a meter that only kept the level would go on showing the last value
18
+ * after the callback stops firing (a suspended AudioContext, a device change),
19
+ * which is exactly when it is being looked at.
20
+ */
21
+ export interface LiveInputLevel {
22
+ /** RMS of the frame, 0..1. Zero while input is muted. */
23
+ level: number;
24
+ at: number;
25
+ /**
26
+ * The call is running but frames are not being sent: the socket is backed
27
+ * up. The microphone is fine and the daemon is still not hearing it. Held
28
+ * for a moment after the last dropped frame, so it does not flicker.
29
+ */
30
+ dropping: boolean;
31
+ }
32
+ /**
33
+ * `worklet`: microphone frames are produced, converted and measured on the
34
+ * audio rendering thread. `script-processor`: the deprecated main-thread
35
+ * node, kept as the fallback for wherever the worklet module cannot be
36
+ * loaded — a browser without AudioWorklet, or an embedding whose library build
37
+ * inlines the module as a `data:` URL the CSP refuses.
38
+ */
39
+ export type LiveCaptureMode = 'worklet' | 'script-processor';
40
+ export type LiveBrowserHostPhase = 'idle' | 'connecting' | 'connected' | 'error';
41
+ export type LiveBrowserHostCloseReason =
42
+ /** Another Host holds the lease (4009). `connect({ takeover })` may help. */
43
+ 'occupied'
44
+ /** A native Host took over (4010). */
45
+ | 'superseded-native'
46
+ /** Another Web Shell tab took over (4010). */
47
+ | 'superseded-tab'
48
+ /** Live Voice is off, or the workspace is not trusted (4003). */
49
+ | 'refused' | 'microphone' | 'lost';
50
+ export interface UseLiveBrowserHostOptions {
51
+ baseUrl: string;
52
+ token?: string;
53
+ /** Status pushed by the daemon; fresher than polling `/live/status`. */
54
+ onStatus?: (status: DaemonLiveStatus) => void;
55
+ }
56
+ export interface UseLiveBrowserHostResult {
57
+ phase: LiveBrowserHostPhase;
58
+ closeReason: LiveBrowserHostCloseReason | undefined;
59
+ errorMessage: string | undefined;
60
+ /** How the microphone is being captured; undefined until connected. */
61
+ captureMode: LiveCaptureMode | undefined;
62
+ /**
63
+ * Most recent microphone frame, for a meter. A ref rather than state:
64
+ * at 64 ms frames this changes ~16 times a second, and re-rendering the
65
+ * dialog that often would steal the main thread from the very
66
+ * ScriptProcessor callback that produces the audio.
67
+ */
68
+ inputLevel: RefObject<LiveInputLevel>;
69
+ /** Must run inside a user gesture: it asks for the microphone. */
70
+ connect: (options?: {
71
+ takeover?: boolean;
72
+ }) => void;
73
+ disconnect: () => void;
74
+ /** What the model can see, and when it last looked. */
75
+ screenShare: LiveScreenShareState;
76
+ /** Must run inside a user gesture: it asks which screen to share. */
77
+ startSharingScreen: () => Promise<void>;
78
+ stopSharingScreen: () => void;
79
+ }
80
+ export interface LiveScreenShareState {
81
+ /** False where `getDisplayMedia` is unavailable, so the share is never offered. */
82
+ supported: boolean;
83
+ sharing: boolean;
84
+ /** The track's own name for what is shared, e.g. a window title. */
85
+ label: string | undefined;
86
+ errorMessage: string | undefined;
87
+ /** `performance.now()` of the last frame the model was given, for the UI. */
88
+ lastLookAt: number | undefined;
89
+ /** The model asked while nothing was shared, so the UI can offer to start. */
90
+ requestedWhileIdle: boolean;
91
+ }
92
+ export declare function useLiveBrowserHost({ baseUrl, token, onStatus, }: UseLiveBrowserHostOptions): UseLiveBrowserHostResult;
@@ -4,8 +4,14 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
  import type { DaemonLiveMuteUpdate, DaemonLiveStatus } from '@qwen-code/sdk';
7
+ import { type UseLiveBrowserHostResult } from './useLiveBrowserHost';
7
8
  export interface UseLiveVoiceResult {
9
+ /** Either kind of Host is available on this daemon. */
8
10
  supported: boolean;
11
+ nativeSupported: boolean;
12
+ browserSupported: boolean;
13
+ /** This page as the audio endpoint; idle until the user connects it. */
14
+ browserHost: UseLiveBrowserHostResult;
9
15
  status: DaemonLiveStatus | undefined;
10
16
  loading: boolean;
11
17
  mutating: boolean;
@@ -54,6 +54,13 @@ export declare class SessionCatalogStore {
54
54
  private visibilityListening;
55
55
  constructor(client: DaemonClient);
56
56
  getSnapshot(query: SessionCatalogQuery): SessionCatalogSnapshot;
57
+ /**
58
+ * Reads a display name the catalog already holds for a session, scheduling
59
+ * nothing. A history session's name exists only here — neither the load
60
+ * response nor the metadata events carry it — so the header seeds the title
61
+ * from this cache instead of waiting for a round-trip.
62
+ */
63
+ peekSessionDisplayName(sessionId: string, workspaceCwd: string | undefined): string | undefined;
57
64
  getEmptySnapshot(): SessionCatalogSnapshot;
58
65
  retainWorkspaceLiveState(workspaceCwd: string): () => void;
59
66
  isWorkspaceLiveStateEnabled(workspaceCwd: string): boolean;
@@ -140,4 +147,6 @@ export declare function getSessionCatalogStore(client: DaemonClient): SessionCat
140
147
  export declare function loadSessionCatalogOnce(client: DaemonClient, query: SessionCatalogQuery, options?: {
141
148
  fresh?: boolean;
142
149
  }): Promise<DaemonSessionListPage>;
150
+ /** Sync read of a cached display name; see `SessionCatalogStore.peekSessionDisplayName`. */
151
+ export declare function peekSessionCatalogDisplayName(client: DaemonClient, sessionId: string | undefined, workspaceCwd: string | undefined): string | undefined;
143
152
  export {};
@@ -58,13 +58,15 @@ declare const SETTING_KEYS: {
58
58
  readonly 'setting:voice-model': "voiceModel";
59
59
  readonly 'setting:image-model': "imageModel";
60
60
  };
61
- declare const BUILTIN_IDS: readonly ["builtin:chat-width", "builtin:browser-notifications", "builtin:live-setup", "builtin:local-control", "builtin:model-management"];
61
+ declare const BUILTIN_IDS: readonly ["builtin:chat-width", "builtin:browser-notifications", "builtin:live-setup", "builtin:local-control", "builtin:connections", "builtin:model-management"];
62
62
  export type WebShellSettingItemId = keyof typeof SETTING_KEYS | (typeof BUILTIN_IDS)[number];
63
63
  export declare const WEB_SHELL_SETTING_ITEM_IDS: readonly WebShellSettingItemId[];
64
64
  export interface WebShellSettingsOptions {
65
- /** Hide native settings items. Presentation only; other commands/APIs remain available. */
65
+ /** Show only these eligible native items; an empty list hides all. Presentation only. */
66
+ includeItems?: readonly WebShellSettingItemId[];
67
+ /** Hide native items, taking precedence over includeItems. Other commands/APIs remain available. */
66
68
  excludeItems?: readonly WebShellSettingItemId[];
67
69
  }
68
- export declare function isItemExcluded(id: WebShellSettingItemId, options?: WebShellSettingsOptions): boolean;
69
- export declare function isSettingExcluded(key: string, options?: WebShellSettingsOptions): boolean;
70
+ export declare function isItemVisible(id: WebShellSettingItemId, options?: WebShellSettingsOptions): boolean;
71
+ export declare function isSettingVisible(key: string, options?: WebShellSettingsOptions): boolean;
70
72
  export {};
@@ -0,0 +1,15 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Qwen Team
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import type { Trajectory, TrajectoryEntry } from './types';
7
+ /**
8
+ * Fold a run of raw entries into turns and rows, pairing each timing frame with
9
+ * what it measured.
10
+ *
11
+ * Nothing here invents a duration. A row whose frame never arrived — an
12
+ * in-flight call, a session written before timing frames existed — carries no
13
+ * timing at all rather than a value derived from arrival times.
14
+ */
15
+ export declare function buildTrajectory(entries: readonly TrajectoryEntry[]): Trajectory;
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Qwen Team
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { type DaemonEvent } from '@qwen-code/sdk/daemon';
7
+ import type { TrajectoryEntry } from './types';
8
+ /**
9
+ * Project one contiguous run of raw daemon events into ordered trajectory
10
+ * entries: the blocks the SDK reducer materializes, with each timing frame
11
+ * placed where its telemetry record was written.
12
+ *
13
+ * A timing frame's position is the block count at the moment it arrived. The
14
+ * telemetry record for a model request is written after that round's tool
15
+ * results — which update blocks already in the list rather than appending — and
16
+ * before the next assistant record, which appends. So "after the current last
17
+ * block" lands the frame between the two, matching the record order on disk.
18
+ *
19
+ * A timing frame is never normalized at all. Every other reader turns it into
20
+ * nothing, and leaning on that would put a row in the table the day a
21
+ * normalizer started surfacing it.
22
+ */
23
+ export declare function projectTrajectoryWindow(events: readonly DaemonEvent[]): TrajectoryEntry[];
@@ -0,0 +1,31 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Qwen Team
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import type { TrajectoryPageLoader, TrajectoryPageResult } from './useTrajectoryWindow';
7
+ /**
8
+ * The one client method this view needs. Narrower than `DaemonClient` so the
9
+ * trajectory modules stay independent of the rest of its surface.
10
+ */
11
+ export interface TrajectoryTranscriptClient {
12
+ getSessionTranscriptPage(sessionId: string, opts: {
13
+ direction?: 'backward';
14
+ limit?: number;
15
+ }): Promise<TrajectoryPageResult>;
16
+ }
17
+ /**
18
+ * A page loader for one session, stable per (client, session).
19
+ *
20
+ * Identity matters: the loader is the window hook's effect dependency, so a
21
+ * fresh function on every render would refetch the newest page on every render.
22
+ *
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
25
+ * client rather than
26
+ * `DaemonSessionClient.getTranscriptPage`, which hydrates attachments and would
27
+ * fetch image bytes this table never shows, and it never asks for the
28
+ * `summary` projection, which rewrites the event stream the timing frames sit
29
+ * in.
30
+ */
31
+ export declare function createTrajectoryPageLoader(client: TrajectoryTranscriptClient, sessionId: string): TrajectoryPageLoader;
@@ -0,0 +1,130 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Qwen Team
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import type { DaemonTextTranscriptBlock, DaemonToolTranscriptBlock, DaemonTranscriptBlock, DaemonTranscriptTimingMeta, DaemonTurnUsage } from '@qwen-code/sdk/daemon';
7
+ /**
8
+ * One item of a trajectory window in wire order: either a materialized
9
+ * transcript block or a timing frame sitting where the telemetry record that
10
+ * produced it was written.
11
+ *
12
+ * Timing frames are kept out of the block stream on purpose. Paged replay emits
13
+ * one per telemetry record with no pairing of its own, precisely so a page
14
+ * boundary cannot separate a request from its timing; pairing happens here,
15
+ * over a window that is contiguous by construction.
16
+ */
17
+ export type TrajectoryEntry = {
18
+ kind: 'block';
19
+ block: DaemonTranscriptBlock;
20
+ } | {
21
+ kind: 'timing';
22
+ timing: DaemonTranscriptTimingMeta;
23
+ /** Persisted record uuid of the telemetry record, when stamped. */
24
+ recordId?: string;
25
+ }
26
+ /**
27
+ * One round's token counts, kept at the position the daemon reported them.
28
+ *
29
+ * The reducer folds these onto the round's assistant block, and a round that
30
+ * produced only a thought and tool calls has no assistant block of its own —
31
+ * its counts sum into the previous round's. Reading the frame where it
32
+ * arrived is what keeps each round's tokens on the round that spent them.
33
+ */
34
+ | {
35
+ kind: 'usage';
36
+ usage: DaemonTurnUsage;
37
+ };
38
+ /**
39
+ * Recorded span of one row. Only values the daemon actually measured appear
40
+ * here — a missing field means "not recorded", never "zero".
41
+ */
42
+ export interface TrajectoryTiming {
43
+ durationMs: number;
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.
48
+ */
49
+ startedAt?: number;
50
+ /** Requests only: dispatch to first user-visible content. */
51
+ ttftMs?: number;
52
+ }
53
+ /** What a subagent spent, rolled up onto the tool call that spawned it. */
54
+ export interface TrajectorySubagentSummary {
55
+ requests: number;
56
+ tools: number;
57
+ /** Summed request durations; 0 when none were recorded. */
58
+ requestMs: number;
59
+ }
60
+ interface TrajectoryRowBase {
61
+ /**
62
+ * Identity that survives re-projection and page prepends. Derived from
63
+ * persisted record / call identity, never from array position.
64
+ */
65
+ key: string;
66
+ turnIndex: number;
67
+ /** 0 for the main session, 1 for anything a subagent produced. */
68
+ depth: number;
69
+ /** Main-session request this row belongs to, when one was recorded. */
70
+ requestIndex?: number;
71
+ }
72
+ export interface TrajectoryUserRow extends TrajectoryRowBase {
73
+ kind: 'user';
74
+ block: DaemonTextTranscriptBlock;
75
+ }
76
+ export interface TrajectoryRequestRow extends TrajectoryRowBase {
77
+ kind: 'request';
78
+ /** `unknown` when the frame recorded no status. */
79
+ status: 'ok' | 'error' | 'unknown';
80
+ timing: TrajectoryTiming;
81
+ model?: string;
82
+ /** Folded from the round's assistant block; absent when none carried it. */
83
+ usage?: DaemonTurnUsage;
84
+ responseId?: string;
85
+ promptId?: string;
86
+ /** Set when a subagent issued the request. */
87
+ subagentId?: string;
88
+ /** Main-session tool call that spawned the subagent, when resolvable. */
89
+ parentToolCallId?: string;
90
+ }
91
+ export interface TrajectoryMessageRow extends TrajectoryRowBase {
92
+ kind: 'message';
93
+ block: DaemonTextTranscriptBlock;
94
+ thought: boolean;
95
+ }
96
+ export interface TrajectoryToolRow extends TrajectoryRowBase {
97
+ kind: 'tool';
98
+ block: DaemonToolTranscriptBlock;
99
+ /** Absent for an in-flight call, or a window with no timing frames. */
100
+ timing?: TrajectoryTiming;
101
+ toolStatus?: 'success' | 'error' | 'cancelled';
102
+ /** Present on a tool call that spawned a subagent. */
103
+ subagentSummary?: TrajectorySubagentSummary;
104
+ }
105
+ /** Shell output, permission prompts, status markers — carried, not paired. */
106
+ export interface TrajectoryOtherRow extends TrajectoryRowBase {
107
+ kind: 'other';
108
+ block: DaemonTranscriptBlock;
109
+ }
110
+ export type TrajectoryRow = TrajectoryUserRow | TrajectoryRequestRow | TrajectoryMessageRow | TrajectoryToolRow | TrajectoryOtherRow;
111
+ export interface TrajectoryTurn {
112
+ /** 1-based within the loaded window; not a session-wide turn number. */
113
+ index: number;
114
+ /** Absent when the window starts inside the turn. */
115
+ userRowKey?: string;
116
+ rowKeys: string[];
117
+ requestCount: number;
118
+ /** Top-level tool rows; subagent tools are in the parent's summary. */
119
+ toolCount: number;
120
+ /** Summed main-session request durations; 0 when none were recorded. */
121
+ requestMs: number;
122
+ /** The window cut this turn's head off. */
123
+ partial: boolean;
124
+ }
125
+ export interface Trajectory {
126
+ turns: TrajectoryTurn[];
127
+ rows: TrajectoryRow[];
128
+ rowIndexByKey: Map<string, number>;
129
+ }
130
+ export {};
@@ -0,0 +1,75 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Qwen Team
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import type { DaemonEvent } from '@qwen-code/sdk/daemon';
7
+ import type { Trajectory } from './types';
8
+ /**
9
+ * Records asked for per read. The daemon caps a page at 500 records and at
10
+ * 4 MB, whichever binds first, so a session whose tools wrote a lot comes back
11
+ * shorter than this — `truncated` is what says so, never the count.
12
+ */
13
+ export declare const TRAJECTORY_PAGE_SIZE = 250;
14
+ /**
15
+ * The fields of a transcript page this view reads. Narrower than the daemon's
16
+ * own page type on purpose: the client's page satisfies it structurally, and a
17
+ * test can hand back a page without standing up the rest of the envelope.
18
+ */
19
+ export interface TrajectoryPageResult {
20
+ events: readonly DaemonEvent[];
21
+ hasMore: boolean;
22
+ partial?: true;
23
+ replayError?: string;
24
+ }
25
+ /**
26
+ * Fetches the newest page of the session's transcript.
27
+ *
28
+ * Supplied by the host rather than called here so the panel never reaches for
29
+ * a daemon client of its own. There is no cancellation: the daemon client
30
+ * exposes no abort, so a superseded request is discarded on arrival by
31
+ * generation rather than stopped in flight.
32
+ */
33
+ export type TrajectoryPageLoader = (opts: {
34
+ limit: number;
35
+ }) => Promise<TrajectoryPageResult>;
36
+ /**
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.
40
+ */
41
+ export type TrajectoryWindowFailure = {
42
+ kind: 'partial';
43
+ } | {
44
+ kind: 'unreadable';
45
+ message: string;
46
+ };
47
+ export interface TrajectoryWindow {
48
+ trajectory: Trajectory | undefined;
49
+ status: 'idle' | 'loading' | 'ready' | 'error';
50
+ error?: TrajectoryWindowFailure;
51
+ /**
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.
54
+ */
55
+ truncated: boolean;
56
+ /** Re-read the newest page. Also how a failed read is retried. */
57
+ refresh: () => void;
58
+ }
59
+ /**
60
+ * Hold the newest page of one session's transcript and fold it into a
61
+ * trajectory.
62
+ *
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.
68
+ *
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.
72
+ */
73
+ export declare function useTrajectoryWindow(loadPage: TrajectoryPageLoader | undefined, options?: {
74
+ pageSize?: number;
75
+ }): TrajectoryWindow;
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Persisted satisfied / not-satisfied marks for assistant answers.
3
+ *
4
+ * The mark is Web Shell's own UI state: the host is notified through
5
+ * `customization.assistantFeedback.onRate`, but never feeds state back. Storage
6
+ * is therefore best-effort and local to this browser — a failure to read or
7
+ * write must never affect the click that just happened.
8
+ */
9
+ import type { WebShellAssistantFeedbackInfo, WebShellAssistantFeedbackOptions, WebShellAssistantFeedbackUserMessage } from '../customization';
10
+ import type { TranscriptRenderMode } from '../transcriptRenderMode';
11
+ /**
12
+ * Whether an assistant answer may carry satisfied / not-satisfied marks.
13
+ *
14
+ * Two conditions, both required: a session to store the mark under, and an
15
+ * interactive rendering — read-only and document transcripts stay untouched
16
+ * however much session context they carry.
17
+ */
18
+ export declare function shouldOfferAssistantFeedback({ renderMode, sessionId, options, }: {
19
+ renderMode: TranscriptRenderMode;
20
+ sessionId?: string;
21
+ options?: WebShellAssistantFeedbackOptions;
22
+ }): boolean;
23
+ /**
24
+ * Tells the host about a mark the user just made. The host is a listener, not
25
+ * an authority: it cannot veto the mark, and a throw here must not reach the
26
+ * click handler.
27
+ */
28
+ export declare function notifyAssistantFeedback(handler: ((info: WebShellAssistantFeedbackInfo) => void) | undefined, info: WebShellAssistantFeedbackInfo): void;
29
+ export type AssistantFeedbackRating = 'up' | 'down';
30
+ /** Session id -> turn prompt id -> mark. */
31
+ export type AssistantFeedbackStore = Record<string, Record<string, AssistantFeedbackRating>>;
32
+ export declare const ASSISTANT_FEEDBACK_STORAGE_KEY = "qwen-web-shell-assistant-feedback";
33
+ /** Sessions kept in storage; the rest age out oldest-first. */
34
+ export declare const MAX_ASSISTANT_FEEDBACK_SESSIONS = 10;
35
+ /** Characters of the turn's prompt forwarded to the host. */
36
+ export declare const FEEDBACK_USER_MESSAGE_MAX_CHARS = 100;
37
+ /**
38
+ * Summarises the turn's prompt for the host. Only the tail is kept: the end of
39
+ * a prompt is what distinguishes it from its neighbours in a list of marks.
40
+ */
41
+ export declare function describeFeedbackUserMessage(message: {
42
+ content: string;
43
+ images?: readonly unknown[];
44
+ files?: readonly unknown[];
45
+ timestamp?: number;
46
+ }): WebShellAssistantFeedbackUserMessage;
47
+ /**
48
+ * The prompt that started the turn whose head message is `turnId`. A shell
49
+ * turn's prompt is its command; anything else is reported as unknown rather
50
+ * than guessed.
51
+ */
52
+ export declare function feedbackUserMessageOf(messages: readonly {
53
+ id: string;
54
+ role: string;
55
+ content?: string;
56
+ command?: string;
57
+ images?: readonly unknown[];
58
+ files?: readonly unknown[];
59
+ timestamp?: number;
60
+ }[], turnId: string): WebShellAssistantFeedbackUserMessage;
61
+ /**
62
+ * Reads the persisted marks, dropping anything unrecognizable rather than
63
+ * guessing: a hand-edited or future payload must degrade to "nothing marked".
64
+ */
65
+ export declare function readAssistantFeedbackStore(): AssistantFeedbackStore;
66
+ export declare function writeAssistantFeedbackStore(store: AssistantFeedbackStore): void;
67
+ /**
68
+ * Returns a new store with `promptId` marked (or cleared when `rating` is
69
+ * null). Pure so React can run it inside a state updater.
70
+ */
71
+ export declare function setAssistantFeedbackRating(store: AssistantFeedbackStore, sessionId: string, promptId: string, rating: AssistantFeedbackRating | null): AssistantFeedbackStore;
@@ -0,0 +1,39 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Qwen Team
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ /** A line segment drawn across one row, addressed by lane index. */
7
+ export interface CommitGraphLine {
8
+ column: number;
9
+ color: number;
10
+ }
11
+ export interface CommitGraphRow {
12
+ /** Lane holding this commit's node. */
13
+ column: number;
14
+ /** Colour index of the node and of the lane it continues. */
15
+ color: number;
16
+ /** Lanes entering the node from the row above (own lane and merged children). */
17
+ incoming: CommitGraphLine[];
18
+ /** Lanes leaving the node toward the row below (one per parent). */
19
+ outgoing: CommitGraphLine[];
20
+ /** Lanes that cross this row without touching the node. */
21
+ through: CommitGraphLine[];
22
+ /** Lanes still open below this row; drawn straight through expanded rows. */
23
+ after: CommitGraphLine[];
24
+ /** Highest lane index touched on this row plus one. */
25
+ width: number;
26
+ }
27
+ /**
28
+ * Lay out commits (newest first, parents never before children) into lanes.
29
+ *
30
+ * Each lane waits for one commit. A commit takes the lowest lane waiting for
31
+ * it, or a fresh lane when none is; every other lane waiting for it merges in
32
+ * at its node, so a mainline never jogs sideways to meet a fork. Its first
33
+ * parent continues the lane; further parents each get the lane already
34
+ * waiting for them or a new one.
35
+ */
36
+ export declare function layoutCommitGraph(entries: ReadonlyArray<{
37
+ sha: string;
38
+ parents: string[];
39
+ }>): CommitGraphRow[];
@@ -0,0 +1,38 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Qwen Team
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ /**
7
+ * Structured companion to the English sentence `/compress` streams over ACP.
8
+ *
9
+ * The daemon ships on its own release cadence, so this is parsed defensively:
10
+ * an unreadable payload falls back to rendering the sentence as before rather
11
+ * than dropping the message.
12
+ */
13
+ export interface ContextCompressionResult {
14
+ originalTokenCount: number;
15
+ newTokenCount: number;
16
+ originalTokenCountIsEstimated: boolean;
17
+ newTokenCountIsEstimated: boolean;
18
+ /** Server-authored advisory. Free-form text, not a translation key. */
19
+ warning?: string;
20
+ }
21
+ export type ContextCompressionMeta = {
22
+ phase: 'notice';
23
+ instructionsLimit: number;
24
+ } | {
25
+ phase: 'progress';
26
+ } | {
27
+ phase: 'noop';
28
+ } | {
29
+ phase: 'done';
30
+ result: ContextCompressionResult;
31
+ };
32
+ export declare function parseContextCompressionMeta(value: unknown): ContextCompressionMeta | undefined;
33
+ /**
34
+ * Token count for a compression line, grouped for the UI language rather than
35
+ * the browser's locale. `~` marks a locally estimated count, the same
36
+ * convention the TUI banner uses (#9309).
37
+ */
38
+ export declare function formatCompressionTokens(count: number, isEstimated: boolean, language: string): string;
@@ -3,6 +3,7 @@ import type { ReasoningSelection } from '@qwen-code/sdk/daemon';
3
3
  type PromptSessionActions = {
4
4
  createSession: (options?: {
5
5
  workspaceCwd?: string;
6
+ getCurrentWorkspaceCwd?: () => string | undefined;
6
7
  sessionContext?: DaemonProductSessionContext;
7
8
  modelServiceId?: string;
8
9
  approvalMode?: DaemonApprovalMode;
@@ -40,7 +41,7 @@ type PromptSessionActions = {
40
41
  }) => Promise<void>;
41
42
  };
42
43
  export declare function isDaemonApprovalMode(mode: string): mode is DaemonApprovalMode;
43
- export declare function createAndAttachSessionForPrompt({ sessionActions, modelId, reasoningEffort, modeId, planMode, workspaceCwd, sessionContext, worktree, branch, sessionSourceType, onSessionCreated, onSessionAllocated, getCurrentSessionId, warn, }: {
44
+ export declare function createAndAttachSessionForPrompt({ sessionActions, modelId, reasoningEffort, modeId, planMode, workspaceCwd, sessionContext, worktree, branch, sessionSourceType, onSessionCreated, onSessionAllocated, getCurrentSessionId, getCurrentWorkspaceCwd, warn, }: {
44
45
  sessionActions: PromptSessionActions;
45
46
  modelId?: string;
46
47
  reasoningEffort?: ReasoningSelection;
@@ -62,6 +63,7 @@ export declare function createAndAttachSessionForPrompt({ sessionActions, modelI
62
63
  onSessionCreated?: (sessionId: string) => Promise<void> | void;
63
64
  onSessionAllocated?: (sessionId: string) => void;
64
65
  getCurrentSessionId: () => string | undefined;
66
+ getCurrentWorkspaceCwd?: () => string | undefined;
65
67
  warn?: (message?: unknown, ...optionalParams: unknown[]) => void;
66
68
  }): Promise<{
67
69
  worktree?: {
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Qwen
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ /**
7
+ * Transport-agnostic pieces of browser microphone capture, shared by voice
8
+ * dictation (`/voice/stream`) and the Live Voice browser Host (`/live/web`).
9
+ */
10
+ export declare function toVoiceWebSocketUrl(baseUrl: string, streamPath: string): string;
11
+ export declare const WS_AUTH_SUBPROTOCOL = "qwen-ws";
12
+ export declare function bearerSubprotocol(token: string): string;
13
+ export declare function describeMicError(err: unknown): string;
14
+ /** Float32 [-1,1] frame → Int16 PCM + RMS level. */
15
+ export declare function floatToPcm16(input: Float32Array): {
16
+ pcm: ArrayBuffer;
17
+ level: number;
18
+ };
19
+ /** `Sec-WebSocket-Protocol` values that carry the daemon bearer token. */
20
+ export declare function voiceWebSocketProtocols(token?: string): string[] | undefined;
21
+ /** Microphone constraints: mono, with the browser's echo and noise handling. */
22
+ export declare const MICROPHONE_CONSTRAINTS: MediaStreamConstraints;
@@ -3,6 +3,8 @@
3
3
  * Copyright 2025 Qwen
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
+ import { toVoiceWebSocketUrl } from './capture-utils';
7
+ export { toVoiceWebSocketUrl };
6
8
  /**
7
9
  * Captures 16 kHz mono PCM in the browser and streams it to the immutable
8
10
  * workspace owner selected when recording starts. Credentials remain in the
@@ -38,5 +40,4 @@ export interface UseVoiceCaptureReturn {
38
40
  stop: () => void;
39
41
  abort: () => void;
40
42
  }
41
- export declare function toVoiceWebSocketUrl(baseUrl: string, streamPath: string): string;
42
43
  export declare function useVoiceCapture({ baseUrl, token, target, onFinal, onError, onUnexpectedClose, }: UseVoiceCaptureOptions): UseVoiceCaptureReturn;