@volter/supercode-frontend-vscode 0.1.62 → 0.1.64

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.
@@ -52,7 +52,6 @@ export interface ChatSetupState {
52
52
  }
53
53
  export interface HostState {
54
54
  history?: ChatMessage[];
55
- historyTruncated?: boolean;
56
55
  activeSession: string | null;
57
56
  openSessionCommand?: string;
58
57
  /** Automatic ready-session reveal checks the observed native focus through its queued commit. */
package/dist/proposals.js CHANGED
@@ -27,8 +27,8 @@ export const PROPOSAL_EFFECTS = Object.freeze({
27
27
  without: 'the ordinary `@supercode` participant answers; a mention is required',
28
28
  },
29
29
  chatParticipantPrivate: {
30
- grants: 'the dynamic-participant and participant-detection APIs a bundling host can use to route without a mention',
31
- without: 'nothing is lost in this package: it registers no dynamic participant and no detection provider',
30
+ grants: 'the dynamic-participant identity, and an interrupted turn ending with a warning-level, expected error',
31
+ without: 'a static participant identity; an interrupted turn ends with an ordinary error',
32
32
  },
33
33
  chatParticipantAdditions: {
34
34
  grants: 'tool-invocation, confirmation, warning and codeblock-uri response parts',
package/dist/session.d.ts CHANGED
@@ -16,9 +16,6 @@ export interface VscodeRuntimeClient {
16
16
  steer(prompt: string): Promise<{
17
17
  queued: boolean;
18
18
  }>;
19
- stopTask(taskId: string): Promise<{
20
- stopped: boolean;
21
- }>;
22
19
  interrupt(): Promise<{
23
20
  interrupted: boolean;
24
21
  }>;
@@ -66,12 +63,6 @@ export declare const TURN_TERMINAL_KINDS: readonly ["turn_succeeded", "turn_fail
66
63
  * the view reports.
67
64
  */
68
65
  export declare const LEASE_ERROR_NAMES: readonly string[];
69
- /** One of the harness's own background tasks (a Monitor, a background shell), as it last listed them. */
70
- export interface BackgroundTask {
71
- id: string;
72
- kind: string;
73
- description: string;
74
- }
75
66
  /**
76
67
  * One attachment to one already-running Volter Harness SDK runtime: cursor-safe
77
68
  * event projection, permission narrowing, and the semantic actions the runtime
@@ -87,7 +78,6 @@ export declare class VscodeFrontendSession {
87
78
  history: ChatMessage[];
88
79
  historyCursor: number;
89
80
  historyEvents: FrontendEvent[];
90
- historyEventsDropped: number;
91
81
  cursor: number;
92
82
  /**
93
83
  * Every event this attachment has seen, in order — NOT just the last
@@ -99,15 +89,8 @@ export declare class VscodeFrontendSession {
99
89
  replay: FrontendEvent[];
100
90
  pendingRequests: Map<number, FrontendRequest>;
101
91
  /**
102
- * The harness's own background tasks as it last listed them (`background_tasks`). Each event one reports starts a
103
- * turn of its own, so while any runs the session can be busy with turns no one here submitted.
104
- */
105
- backgroundTasks: BackgroundTask[];
106
- /**
107
- * Requests this attachment has seen resolved. `request_resolved` deletes the
108
- * pending entry while it is being projected, so without this the resolution
109
- * could only say "request #1" — it would have lost the very thing it needs to
110
- * name. Bounded, because a long session resolves a lot of them.
92
+ * Requests this attachment has seen resolved, so a resolution can still name what it answered once the pending
93
+ * entry is gone. Bounded, because a long session resolves a lot of them.
111
94
  */
112
95
  resolvedRequests: Map<number, FrontendRequest>;
113
96
  connection: 'disconnected' | 'connected' | 'closed';
@@ -158,8 +141,6 @@ export declare class VscodeFrontendSession {
158
141
  submit(prompt: string, throwIfCancelled?: () => void): Promise<void>;
159
142
  steer(prompt: string): Promise<void>;
160
143
  interrupt(): Promise<void>;
161
- /** Stop one of the harness's own background tasks, by the id it listed it with. */
162
- stopTask(taskId: string): Promise<boolean>;
163
144
  respond(response: FrontendResponse): Promise<void>;
164
145
  detach(): Promise<void>;
165
146
  close(): Promise<void>;
package/dist/session.js CHANGED
@@ -48,7 +48,6 @@ export class VscodeFrontendSession {
48
48
  history = [];
49
49
  historyCursor = 0;
50
50
  historyEvents = [];
51
- historyEventsDropped = 0;
52
51
  cursor = 0;
53
52
  /**
54
53
  * Every event this attachment has seen, in order — NOT just the last
@@ -60,15 +59,8 @@ export class VscodeFrontendSession {
60
59
  replay = [];
61
60
  pendingRequests = new Map();
62
61
  /**
63
- * The harness's own background tasks as it last listed them (`background_tasks`). Each event one reports starts a
64
- * turn of its own, so while any runs the session can be busy with turns no one here submitted.
65
- */
66
- backgroundTasks = [];
67
- /**
68
- * Requests this attachment has seen resolved. `request_resolved` deletes the
69
- * pending entry while it is being projected, so without this the resolution
70
- * could only say "request #1" — it would have lost the very thing it needs to
71
- * name. Bounded, because a long session resolves a lot of them.
62
+ * Requests this attachment has seen resolved, so a resolution can still name what it answered once the pending
63
+ * entry is gone. Bounded, because a long session resolves a lot of them.
72
64
  */
73
65
  resolvedRequests = new Map();
74
66
  connection = 'disconnected';
@@ -130,23 +122,12 @@ export class VscodeFrontendSession {
130
122
  descriptor: structuredClone(snapshot.descriptor),
131
123
  pendingRequests: new Map((authoritative ? snapshot.pending_requests : [...this.pendingRequests.values()])
132
124
  .map(request => [request.id, structuredClone(request)])),
133
- backgroundTasks: structuredClone(this.backgroundTasks),
134
125
  cursor: authoritative ? recovery.captureCursor : Math.max(this.cursor, snapshot.history_cursor),
135
126
  };
136
127
  // Validate and project the whole attachment before any observable field
137
128
  // moves or a live listener is registered.
138
129
  if (authoritative) {
139
130
  // Snapshot state is authoritative at capture, before any later events.
140
- // Background listings have no separate snapshot field; retain their
141
- // latest original event without replaying historical request state.
142
- for (const event of recovery.replay) {
143
- const payload = (event.payload ?? {});
144
- if (event.kind === 'background_tasks' && Array.isArray(payload.tasks)) {
145
- staged.backgroundTasks = payload.tasks
146
- .filter(task => task && typeof task.id === 'string')
147
- .map(task => ({ id: task.id, kind: String(task.kind ?? 'task'), description: String(task.description ?? '') }));
148
- }
149
- }
150
131
  for (const event of recovery.later)
151
132
  this.projectEvent(staged, event);
152
133
  }
@@ -197,10 +178,8 @@ export class VscodeFrontendSession {
197
178
  this.history = structuredClone(snapshot.history);
198
179
  this.historyCursor = snapshot.history_cursor;
199
180
  this.historyEvents = structuredClone(snapshot.history_events ?? []);
200
- this.historyEventsDropped = snapshot.history_events_dropped ?? 0;
201
181
  this.appendTranscript(structuredClone(recovery.replay));
202
182
  this.pendingRequests = staged.pendingRequests;
203
- this.backgroundTasks = staged.backgroundTasks;
204
183
  const previousCursor = this.cursor;
205
184
  this.cursor = staged.cursor;
206
185
  this.connection = 'connected';
@@ -392,18 +371,12 @@ export class VscodeFrontendSession {
392
371
  if (request && typeof request.id === 'number')
393
372
  state.pendingRequests.set(request.id, structuredClone(request));
394
373
  }
395
- if (event.kind === 'background_tasks' && Array.isArray(payload.tasks)) {
396
- state.backgroundTasks = payload.tasks
397
- .filter(task => task && typeof task.id === 'string')
398
- .map(task => ({ id: task.id, kind: String(task.kind ?? 'task'), description: String(task.description ?? '') }));
399
- }
400
374
  if (event.kind === 'request_resolved' && typeof payload.request_id === 'number') {
401
375
  const resolved = state.pendingRequests.get(payload.request_id);
402
376
  if (resolved) {
403
377
  this.resolvedRequests.set(payload.request_id, resolved);
404
- while (this.resolvedRequests.size > 50) {
378
+ while (this.resolvedRequests.size > 50)
405
379
  this.resolvedRequests.delete(this.resolvedRequests.keys().next().value);
406
- }
407
380
  }
408
381
  state.pendingRequests.delete(payload.request_id);
409
382
  }
@@ -480,11 +453,6 @@ export class VscodeFrontendSession {
480
453
  this.require('interrupt');
481
454
  await this.withControl(() => this.client.interrupt());
482
455
  }
483
- /** Stop one of the harness's own background tasks, by the id it listed it with. */
484
- async stopTask(taskId) {
485
- const result = await this.withControl(() => this.client.stopTask(taskId));
486
- return result?.stopped === true;
487
- }
488
456
  async respond(response) {
489
457
  this.require('respond');
490
458
  if (!this.pendingRequests.has(response.request_id))
package/dist/view.d.ts CHANGED
@@ -50,6 +50,13 @@ export type ChatPart = {
50
50
  uri: string;
51
51
  value: string;
52
52
  language: string;
53
+ }
54
+ /** A harness hook that blocked or warned: which event it ran on, and what it said. */
55
+ | {
56
+ part: 'hook';
57
+ hookType: HookType;
58
+ blocked: boolean;
59
+ reason: string;
53
60
  } | {
54
61
  part: 'tool';
55
62
  toolName: string;
@@ -62,13 +69,62 @@ export type ChatPart = {
62
69
  resultText?: string;
63
70
  /** A shell call's command line: the row is then VS Code's own terminal block, command and output. */
64
71
  commandLine?: string;
72
+ /** The plan as this call left it (`planItems`, `PlanTracker`): the row is then VS Code's own todo list. */
73
+ plan?: PlanItem[];
74
+ /** A subagent call's own fields (`subagentCall`): the row is then VS Code's own subagent row. */
75
+ subagent?: SubagentCall;
76
+ /** The subagent call this call was made inside (Claude Code's `parent_tool_use_id`): VS Code groups it there. */
77
+ parentToolCallId?: string;
78
+ /** The call started its subagent in the background: its result is a launch notice, not the subagent's answer. */
79
+ background?: boolean;
65
80
  } | {
66
81
  part: 'answers';
82
+ connectionId: string;
83
+ requestId: number;
67
84
  approval: boolean;
68
85
  title: string;
69
86
  message: string;
87
+ /** None: a request this window cannot answer, drawn read-only. */
70
88
  answers: ChatAnswer[];
89
+ }
90
+ /** How a request drawn in this stream was answered, said only when the answer did not come through that card in
91
+ * this window (`writePart`), so a card answered elsewhere is not left looking open. Markdown-safe. */
92
+ | {
93
+ part: 'resolution';
94
+ connectionId: string;
95
+ requestId: number;
96
+ value: string;
97
+ }
98
+ /** A record that is not conversation (an event kind this version does not know, a malformed request): written to
99
+ * the output channel, never to the transcript. */
100
+ | {
101
+ part: 'unshown';
102
+ value: string;
103
+ }
104
+ /** A harness's questions (`requestQuestions`): VS Code's question carousel on a turn this window runs, its
105
+ * `answers` part anywhere else. */
106
+ | {
107
+ part: 'questions';
108
+ connectionId: string;
109
+ requestId: number;
110
+ questions: QuestionField[];
111
+ fallback: Extract<ChatPart, {
112
+ part: 'answers';
113
+ }>;
71
114
  };
115
+ /** One question of an elicitation that asks questions (`requestQuestions`), as VS Code's carousel asks it. */
116
+ export interface QuestionField {
117
+ /** The elicitation's property, which the answer's `content` is keyed by. */
118
+ key: string;
119
+ title: string;
120
+ message?: string;
121
+ /** Each option's label (also its answer) and what it means. None: a free-text question. */
122
+ options: {
123
+ label: string;
124
+ description?: string;
125
+ }[];
126
+ multiSelect: boolean;
127
+ }
72
128
  /**
73
129
  * One rendered part plus the API proposal it needs and what this view renders
74
130
  * instead when the host did not grant it. README.md's proposal table is this
@@ -105,7 +161,54 @@ export declare function toolTitles(toolName: string, argumentsText: string): {
105
161
  invocation: string;
106
162
  pastTense: string;
107
163
  };
108
- /** The command line of a shell tool call, read from its own arguments; undefined for any other tool. */
164
+ /** A hook's row as words, as VS Code titles its own (`chatHookContentPart.ts`): "Blocked by …" or "Warning from …". */
165
+ export declare function hookSentence(hookEvent: string, blocked: boolean, reason: string): string;
166
+ /** The hook events VS Code's own Chat names (`ChatHookType`), which are Claude Code's. */
167
+ export declare const HOOK_TYPES: readonly ["SessionStart", "SessionEnd", "UserPromptSubmit", "PreToolUse", "PostToolUse", "PreCompact", "SubagentStart", "SubagentStop", "Stop", "ErrorOccurred"];
168
+ export type HookType = (typeof HOOK_TYPES)[number];
169
+ /** One item of an agent's plan, as VS Code's own todo list holds it. */
170
+ export interface PlanItem {
171
+ title: string;
172
+ status: 'not-started' | 'in-progress' | 'completed';
173
+ }
174
+ /** A plan call's items (Claude Code's TodoWrite `todos` of `content`; the `update_plan` tool's `plan` of `step`, as
175
+ * supercode's own and Codex's take it), each its text and status, read from its own arguments; undefined for any
176
+ * other tool, or arguments holding none. Both carry the whole list, so they need no state. */
177
+ export declare function planItems(toolName: string, argumentsText: string): PlanItem[] | undefined;
178
+ /**
179
+ * The task list Claude Code keeps with its task tools, which it offers in place of TodoWrite (TaskCreate, TaskUpdate,
180
+ * TaskList; Claude Code 2.1.312 enables them by default and TodoWrite only when its tasks are turned off). Each call
181
+ * changes ONE task, while VS Code's own todo list shows the WHOLE list, so this keeps the list for one conversation as
182
+ * the calls go by and gives each call's row the list as that call left it.
183
+ *
184
+ * Read from the calls' own arguments, and from Claude Code's own result text where only the result has it (measured
185
+ * on 2.1.312, its `mapToolResultToToolResultBlockParam`): TaskCreate's `Task #<id> created successfully: <subject>`,
186
+ * TaskUpdate's `Updated task #<id> <fields>`, and TaskList's lines `#<id> [<status>] <subject>…`. A result in other
187
+ * words changes nothing here; the row is then an ordinary one.
188
+ */
189
+ export declare class PlanTracker {
190
+ #private;
191
+ /** A call that started: the list as it leaves it, or undefined when it is not a task call (or changes nothing). */
192
+ started(toolName: string, argumentsText: string, toolCallId: string): PlanItem[] | undefined;
193
+ /** A call that completed: the list as it now stands (a failed call's change undone; TaskList's result is the
194
+ * list), so a finished row never shows an older list than the calls before it left. */
195
+ completed(toolCallId: string, output: string, isError: boolean): PlanItem[] | undefined;
196
+ private items;
197
+ }
198
+ /** What a subagent call says of its subagent, as VS Code's own subagent row shows it. */
199
+ export interface SubagentCall {
200
+ description?: string;
201
+ agentName?: string;
202
+ prompt?: string;
203
+ }
204
+ /** A subagent call's description, kind and prompt (Claude Code's Task and Agent tools: `description`,
205
+ * `subagent_type`, `prompt`), read from its own arguments; undefined for any other tool. */
206
+ export declare function subagentCall(toolName: string, argumentsText: string): SubagentCall | undefined;
207
+ /**
208
+ * The command line of a shell tool call, read from its own arguments; undefined for any other tool. Claude Code's
209
+ * BashOutput and KillBash are terminal rows too, as Code-OSS's own Claude host draws them (`claudeToolDisplay.ts`
210
+ * `TOOL_ROWS`): their command line is their `command`, else their input (`getClaudeToolInputString`).
211
+ */
109
212
  export declare function shellCommand(toolName: string, argumentsText: string): string | undefined;
110
213
  /** The information this view shows for a request payload. */
111
214
  export declare function requestSummary(request: FrontendRequest): string;
@@ -118,6 +221,14 @@ export declare function requestAnswers(request: FrontendRequest, connectionId: s
118
221
  export declare function typedAnswer(request: FrontendRequest, reply: string): FrontendResponse;
119
222
  /** The decisions a runtime said its harness accepts, when it said so. */
120
223
  export declare function acceptedDecisions(request: FrontendRequest): string[] | undefined;
224
+ /**
225
+ * An elicitation that asks questions, the shape supercode's `ask_user` asks with and a hosted Claude Code's
226
+ * AskUserQuestion is raised as (`question-tool.mjs` `questionElicitation`): every property of its
227
+ * `requested_schema` is one question, with a `title`, the question alone (`x-question`) and its `x-options`
228
+ * (`[{label, description}]`, with `x-multi-select`; none for free text). Any other form (an MCP server's schema with
229
+ * its own `enum`, `format` or `required`) is undefined here and keeps the `Answer…` door, which honours them.
230
+ */
231
+ export declare function requestQuestions(request: FrontendRequest): QuestionField[] | undefined;
121
232
  /** True when this request asks for content a button click cannot carry. */
122
233
  export declare function requestNeedsTypedReply(request: FrontendRequest): boolean;
123
234
  /**
@@ -128,6 +239,15 @@ export declare function requestNeedsTypedReply(request: FrontendRequest): boolea
128
239
  export declare function resolutionSentence(response: FrontendResponse | undefined, request: FrontendRequest | undefined, requestId: number): string;
129
240
  /** `write_file on hello.txt`, read from the request's own payload. */
130
241
  export declare function requestSubject(request: FrontendRequest): string | undefined;
242
+ /**
243
+ * How a turn that did not succeed ends the response its request handler runs, as VS Code's own agent host ends one
244
+ * (`agentHostSessionHandler.ts` `_getTurnErrorDetails`): a failed turn is the response's error, an interrupted one its
245
+ * warning-level, expected error. Undefined for any other event.
246
+ */
247
+ export declare function turnOutcome(event: FrontendEvent): {
248
+ message: string;
249
+ interrupted: boolean;
250
+ } | undefined;
131
251
  export interface ProjectionContext {
132
252
  /** Identifies which attached runtime a confirmation click must answer. */
133
253
  connectionId: string;
@@ -135,8 +255,14 @@ export interface ProjectionContext {
135
255
  echoOwnPrompts?: boolean;
136
256
  /** Show input arriving in an observed turn, without inventing a native request turn. */
137
257
  liveUserMessages?: boolean;
138
- /** The request a `request_resolved` answers, so its sentence can name it. */
258
+ /** The request a `request_resolved` answers, so its line can name it. */
139
259
  pendingRequest?: (requestId: number) => FrontendRequest | undefined;
260
+ /** The calls whose background task's notification this stream has drawn (`firstNotice`), so a task finishing is one
261
+ * line: Claude Code reports it both as `system/task_notification` (a `status`) and as the user-role record that
262
+ * wakes the agent (a `user_message` notice). */
263
+ notices?: Set<string>;
264
+ /** Where a record that is not conversation goes when there is no writer to log it (history). */
265
+ unshown?: (value: string) => void;
140
266
  /**
141
267
  * Whether the runtime's own descriptor advertises `respond`. A HOSTED
142
268
  * harness runtime sets `actions.respond: false` — the portable contract
@@ -147,6 +273,8 @@ export interface ProjectionContext {
147
273
  * buttons are absent rather than dead.
148
274
  */
149
275
  canRespond?: boolean;
276
+ /** The conversation's task list as its task tools change it; without one, those calls are ordinary rows. */
277
+ plan?: PlanTracker;
150
278
  }
151
279
  /** Pending requests belong to the live runtime, even when saved transcript
152
280
  * history predates them. Rehydrate their controls before waiting for new events. */
@@ -160,10 +288,11 @@ export declare function projectEvent(event: FrontendEvent, context: ProjectionCo
160
288
  /** Replace every part whose proposal the host did not grant with its fallback. */
161
289
  export declare function resolveParts(parts: readonly ProjectedPart[], granted: ReadonlySet<string>): ChatPart[];
162
290
  /**
163
- * The prompt of the marker turn that carries runtime history with no user turn
164
- * of its own. It names itself; nothing here is presented as a person's words.
291
+ * The prompt of the marker turn that carries runtime history with no user turn of its own: VS Code's own words for a
292
+ * turn whose request is not in the transcript (`claudeReplayMapper.ts` `missingPromptPlaceholder`), so nothing is
293
+ * presented as a person's words.
165
294
  */
166
- export declare const HISTORY_MARKER_PROMPT = "\u27E8supercode runtime history\u27E9";
295
+ export declare const HISTORY_MARKER_PROMPT = "Message content could not be retrieved";
167
296
  export type TurnRole = 'user' | 'assistant';
168
297
  export interface ProjectedTurn {
169
298
  role: TurnRole;
@@ -179,4 +308,4 @@ export declare function projectReplayTurns(events: readonly FrontendEvent[], gra
179
308
  */
180
309
  export declare function projectHistory(history: readonly (ChatMessage & {
181
310
  metadata?: Record<string, string>;
182
- })[], granted: ReadonlySet<string>, pendingToolNames?: ReadonlySet<string>): ProjectedTurn[];
311
+ })[], granted: ReadonlySet<string>, pendingToolNames?: ReadonlySet<string>, plan?: PlanTracker): ProjectedTurn[];