@volter/supercode-frontend-vscode 0.1.17 → 0.1.20

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/dist/session.js CHANGED
@@ -121,7 +121,9 @@ export class VscodeFrontendSession {
121
121
  // dead id. An approval can only be outstanding while a turn is running,
122
122
  // because `decide_approval` blocks the agent loop, so an idle runtime has
123
123
  // none no matter what its replay still carries.
124
- if (staged.descriptor?.turn_state !== 'busy')
124
+ // Hosted Codex also receives standalone MCP elicitations. Its host retains
125
+ // request/resolved pairs without the native broker's turn compaction.
126
+ if (staged.descriptor?.turn_state !== 'busy' && staged.descriptor?.source_harness !== 'codex')
125
127
  staged.pendingRequests.clear();
126
128
  this.descriptor = staged.descriptor;
127
129
  this.history = structuredClone(snapshot.history);
@@ -278,6 +280,11 @@ export class VscodeFrontendSession {
278
280
  }
279
281
  state.pendingRequests.delete(payload.request_id);
280
282
  }
283
+ if (event.kind === 'runtime_disconnected') {
284
+ state.pendingRequests.clear();
285
+ if (state.descriptor)
286
+ state.descriptor = { ...state.descriptor, connection_state: 'shutting_down', turn_state: 'idle', actions: { ...state.descriptor.actions, submit: false, steer: false, interrupt: false, respond: false } };
287
+ }
281
288
  if (state === this) {
282
289
  if (BUSY_KINDS.has(event.kind))
283
290
  this.lastTurnStartedMs = Date.now();
package/dist/view.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { typedRequestContent } from './request-schema.js';
1
2
  /**
2
3
  * The bounded projection this presentation package renders. Mirrors
3
4
  * `@volter/supercode-frontend-browser`'s rule: the view is size-bounded
@@ -111,8 +112,10 @@ export function requestSummary(request) {
111
112
  // naming a runtime uses and falls back to bounded JSON.
112
113
  for (const field of ['subject', 'message', 'tool', 'tool_name', 'summary', 'prompt', 'reason']) {
113
114
  const value = fields[field];
114
- if (typeof value === 'string')
115
- return clamp(stripControls(value), VSCODE_CHAT_LIMITS.partCharacters);
115
+ if (typeof value === 'string') {
116
+ const url = typeof fields.url === 'string' ? `\n\n${fields.url}` : '';
117
+ return clamp(stripControls(value + url), VSCODE_CHAT_LIMITS.partCharacters);
118
+ }
116
119
  }
117
120
  }
118
121
  return opaqueText(payload);
@@ -121,6 +124,18 @@ export function requestSummary(request) {
121
124
  export function requestAnswers(request, connectionId) {
122
125
  const base = { connectionId, requestId: request.id };
123
126
  if (request.kind === 'approval') {
127
+ const options = request.payload && typeof request.payload === 'object' && !Array.isArray(request.payload)
128
+ ? request.payload.options : undefined;
129
+ if (Array.isArray(options)) {
130
+ return options.flatMap(option => {
131
+ if (!option || typeof option !== 'object' || Array.isArray(option) || typeof option.id !== 'string' || typeof option.label !== 'string')
132
+ return [];
133
+ const response = ['allow', 'allow_for_session', 'deny'].includes(option.id)
134
+ ? { kind: 'approval', request_id: request.id, decision: option.id }
135
+ : { kind: 'other', request_id: request.id, action: 'accept', content: { option_id: option.id } };
136
+ return [{ ...base, label: option.label, response }];
137
+ });
138
+ }
124
139
  const all = [
125
140
  { ...base, label: 'Allow', response: { kind: 'approval', request_id: request.id, decision: 'allow' } },
126
141
  {
@@ -161,6 +176,9 @@ export function requestAnswers(request, connectionId) {
161
176
  export function typedAnswer(request, reply) {
162
177
  const normalized = reply.trim().toLowerCase();
163
178
  if (request.kind === 'approval') {
179
+ if (['cancel', 'allow_always', 'execpolicy'].includes(normalized) || /^network_\d+$/.test(normalized)) {
180
+ return { kind: 'other', request_id: request.id, action: 'accept', content: { option_id: normalized } };
181
+ }
164
182
  if (['allow for session', 'allow_for_session', 'session'].includes(normalized)) {
165
183
  return { kind: 'approval', request_id: request.id, decision: 'allow_for_session' };
166
184
  }
@@ -174,7 +192,7 @@ export function typedAnswer(request, reply) {
174
192
  return { kind, request_id: request.id, action: 'cancel' };
175
193
  if (['decline', 'no'].includes(normalized))
176
194
  return { kind, request_id: request.id, action: 'decline' };
177
- return { kind, request_id: request.id, action: 'accept', content: reply };
195
+ return { kind, request_id: request.id, action: 'accept', content: typedRequestContent(request, reply) };
178
196
  }
179
197
  /** The decisions a runtime said its harness accepts, when it said so. */
180
198
  export function acceptedDecisions(request) {
@@ -194,6 +212,8 @@ export function requestNeedsTypedReply(request) {
194
212
  const payload = request.payload;
195
213
  if (!payload || typeof payload !== 'object' || Array.isArray(payload))
196
214
  return false;
215
+ if (Array.isArray(payload.questions))
216
+ return true;
197
217
  const schema = payload.requested_schema;
198
218
  return schema !== undefined && schema !== null;
199
219
  }
@@ -211,6 +231,12 @@ export function resolutionSentence(response, request, requestId) {
211
231
  const verb = { allow: 'Allowed', allow_for_session: 'Allowed for session', deny: 'Denied' }[response.decision];
212
232
  return `${verb ?? 'Resolved'}${suffix}`;
213
233
  }
234
+ if (response.kind === 'other' && response.content && typeof response.content === 'object' && !Array.isArray(response.content) && typeof response.content.option_id === 'string') {
235
+ const options = request?.payload && typeof request.payload === 'object' && !Array.isArray(request.payload) ? request.payload.options : undefined;
236
+ const option = Array.isArray(options) ? options.find(value => value && typeof value === 'object' && !Array.isArray(value) && value.id === response.content.option_id) : undefined;
237
+ if (option && typeof option === 'object' && !Array.isArray(option) && typeof option.label === 'string')
238
+ return `Selected “${option.label}” for${suffix}`;
239
+ }
214
240
  const verb = { accept: 'Accepted', decline: 'Declined', cancel: 'Cancelled' }[response.action];
215
241
  const content = typeof response.content === 'string' && response.content.length > 0
216
242
  ? ` — ${clamp(stripControls(response.content), 160)}`
@@ -419,7 +445,7 @@ export function projectEvent(event, context) {
419
445
  // runtime is left blocked. A preferred path that silently swallows
420
446
  // the answer is worse than a plain one that works.
421
447
  // A command button runs inside the live turn and carries its own answer,
422
- // so all three approval decisions are offered. It cannot be withdrawn
448
+ // so the runtime's offered answers remain usable. It cannot be withdrawn
423
449
  // once pushed (`chatCommandContentPart` enables on `!isStale` and has no
424
450
  // used-state), so `supercode.frontend.respond` refuses a request that is
425
451
  // no longer pending and SAYS so instead of sending a stale answer.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@volter/supercode-frontend-vscode",
3
3
  "displayName": "Volter Harness",
4
- "version": "0.1.17",
4
+ "version": "0.1.20",
5
5
  "type": "module",
6
6
  "description": "VS Code chat-view frontend for an existing Volter Harness SDK runtime",
7
7
  "publisher": "volter-ai-dev",
@@ -23,7 +23,7 @@
23
23
  "media"
24
24
  ],
25
25
  "scripts": {
26
- "build": "node scripts/sync-sdk.mjs && node scripts/fetch-icon.mjs && tsc -p tsconfig.build.json",
26
+ "build": "node scripts/sync-sdk.mjs && node scripts/fetch-icon.mjs && tsc -p tsconfig.build.json && node scripts/build-request-schema.mjs",
27
27
  "extension": "npm run build && node scripts/pack-extension.mjs",
28
28
  "prepack": "npm run build"
29
29
  },
@@ -140,9 +140,14 @@
140
140
  },
141
141
  {
142
142
  "command": "supercode.frontend.configure",
143
- "title": "New Chat: Choose Harness, Model and Reasoning",
143
+ "title": "New Chat: Choose Agent",
144
144
  "category": "Chat",
145
145
  "icon": "$(add)"
146
+ },
147
+ {
148
+ "command": "supercode.frontend.configureModel",
149
+ "title": "Model and Reasoning: Open New Chat",
150
+ "category": "Chat"
146
151
  }
147
152
  ],
148
153
  "configuration": {
@@ -189,6 +194,9 @@
189
194
  "devDependencies": {
190
195
  "@types/node": "22.10.0",
191
196
  "@types/vscode": "1.138.0",
197
+ "ajv": "8.18.0",
198
+ "ajv-formats": "3.0.1",
199
+ "esbuild": "0.28.2",
192
200
  "typescript": "5.6.3"
193
201
  },
194
202
  "supercodeFrontendWelcome": {