@volter/supercode-frontend-vscode 0.1.41 → 0.1.42

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/README.md CHANGED
@@ -155,7 +155,8 @@ The permission group offers **Ask for approval** and, on an answerable interacti
155
155
  A lifecycle host may start the conversations it creates in **Auto approve**: it records
156
156
  `defaultPermission: "autoApprove"` on each such conversation and declares `newChatPermission` for the new
157
157
  chat's picker (Model Editor does). A conversation without its own recorded default asks, so one that existed
158
- before a host began doing this keeps its behaviour. It applies to Claude Code and Codex where the runtime answers approvals
158
+ before a host began doing this keeps its behaviour. A new blank chat does not inherit the previous conversation's permission choice.
159
+ It applies to Claude Code and Codex where the runtime answers approvals
159
160
  through Chat, every other harness keeps its own prompts, and a person's explicit pick always
160
161
  wins. Only a pick that differs from the default (or replaces an earlier pick) is saved, so the
161
162
  default is never stored as a choice (a pick equal to the default follows the default if it later
@@ -403,7 +404,13 @@ the extension manifest beside those bytes with no build step of its own.
403
404
  Conversation creation uses `ChatSessionItemController.newChatSessionItemHandler`.
404
405
  Permissions use `getChatSessionInputState` and its change/disposal events, with
405
406
  per-conversation preferences persisted in workspace state. New untitled chats
406
- start with Ask; old untitled bindings are read only for backwards compatibility.
407
+ start with the host's new-chat default and offer modes for the selected draft's harness,
408
+ independently of the previous runtime. The paired native host exposes actual
409
+ `initialSessionOptions` separately from its type-wide previous input state, so an
410
+ explicit draft choice survives materialization. Draft input groups refresh after
411
+ agent selection without overwriting the person's choice. Stock hosts without
412
+ that optional context retain their previous-state contract; old untitled bindings
413
+ are read only for backwards compatibility.
407
414
  Restored response cancellation interrupts the runtime and waits for acknowledgement.
408
415
  Session-list updates consistently prioritize pending input over busy status.
409
416
 
package/dist/extension.js CHANGED
@@ -506,7 +506,7 @@ export async function activate(context) {
506
506
  }));
507
507
  }
508
508
  const currentOptions = (resource) => {
509
- const id = resource ? boundId(resource) : controls?.state.activeSession;
509
+ const id = resource ? boundId(resource) : activeDraft() ? undefined : controls?.state.activeSession;
510
510
  return { permissions: id ? approvalFor(id) : permission ?? newChatDefault() };
511
511
  };
512
512
  const savedConnections = new Map();
@@ -852,11 +852,16 @@ export async function activate(context) {
852
852
  if (controls?.state.setup && !controls.state.setup.ready)
853
853
  return [];
854
854
  const id = resource ? boundId(resource) : undefined;
855
- const active = resource ? (id ? frontends.get(id) : undefined) : managed();
856
- const canApprove = active?.session.descriptor?.actions.respond && active.session.permissions.has('approve');
855
+ const active = id ? frontends.get(id) : undefined;
856
+ // A new draft's harness, not the previous runtime, owns its offered modes.
857
+ const harness = resource ? controls?.state.sessions.find(session => session.id === id)?.selection.harness : draftSelection()?.harness;
858
+ const canApprove = resource ? (active ? canAnswer(active) : ['claude-code', 'codex'].includes(harness ?? ''))
859
+ : (harness ? ['claude-code', 'codex'].includes(harness) : newChatDefault() === 'autoApprove' || ['claude-code', 'codex'].includes(controls?.state.selection.harness ?? ''));
860
+ // An unbound input is a new chat, not the active conversation left behind it.
861
+ const selectedPermission = resource ? currentOptions(resource).permissions : permission ?? newChatDefault();
857
862
  const permissionItems = [{ id: 'ask', name: canApprove ? 'Ask for approval' : 'Harness permissions', description: canApprove ? 'Show each approval requested by the harness.' : 'Approval controls are unavailable for this harness.' },
858
863
  ...((canApprove || (!active && resource && currentOptions(resource).permissions === 'autoApprove')) ? [{ id: 'autoApprove', name: 'Auto approve', description: 'Approve the requests the harness would ask you about, including requests to run outside its sandbox. Its deny rules still apply.' }] : [])];
859
- const groups = [{ id: 'permissions', name: 'Permissions', kind: 'permissions', items: permissionItems, selected: permissionItems.find(i => i.id === currentOptions(resource).permissions) }];
864
+ const groups = [{ id: 'permissions', name: 'Permissions', kind: 'permissions', items: permissionItems, selected: permissionItems.find(i => i.id === selectedPermission) ?? permissionItems[0] }];
860
865
  const selected = controls?.state.sessions.find(session => session.id === id);
861
866
  if (selected && ['claude-code', 'codex'].includes(selected.selection.harness)) {
862
867
  // Native session-option commands remain reachable for nondelegating providers,
@@ -901,7 +906,8 @@ export async function activate(context) {
901
906
  applying = pending.then(() => undefined, () => undefined);
902
907
  const connection = await pending;
903
908
  // The picker shows the host's default until someone changes it; only a change is the person's choice.
904
- const picked = turnPermission(inputState.groups.find(group => group.id === 'permissions')?.selected?.id);
909
+ const selected = inputState.groups.find(group => group.id === 'permissions')?.selected?.id;
910
+ const picked = selected === 'ask' || selected === 'autoApprove' ? selected : permission ?? newChatDefault();
905
911
  choosePermission(connection.id, picked, permission !== undefined ? null : newChatDefault());
906
912
  permission = undefined;
907
913
  if (pendingDraft === draft) {
@@ -1676,19 +1682,30 @@ function registerSessions(context, frontends, participant, granted, handler, his
1676
1682
  context.subscriptions.push(controller, frontends.onDidChange(refreshItems));
1677
1683
  if (controls) {
1678
1684
  const states = new Set();
1679
- controller.getChatSessionInputState = (resource, { previousInputState }) => {
1680
- const previous = previousInputState?.groups.find(group => group.id === 'permissions')?.selected?.id;
1681
- // Saved conversation preferences survive extension-host reloads. Native input state
1682
- // owns live changes; a blank conversation always starts with its own Ask default.
1683
- const groups = controls.options(resource).map(group => ({ ...group,
1684
- selected: group.items.find(item => item.id === (resource ? group.selected?.id : previous ?? group.selected?.id)) ?? group.selected,
1685
- }));
1686
- const state = controller.createChatSessionInputState(groups);
1685
+ const draftPermissions = new WeakMap();
1686
+ const applyOptions = (groups, options) => groups.map(group => {
1687
+ const value = options.find(option => option.optionId === group.id)?.value;
1688
+ const selected = group.items.find(item => item.id === value);
1689
+ return selected ? { ...group, selected } : group;
1690
+ });
1691
+ controller.getChatSessionInputState = (resource, inputContext) => {
1692
+ const groups = controls.options(resource);
1693
+ // Native request options belong to this draft. previousInputState may instead
1694
+ // be the type-wide last chat, so the paired host exposes them separately.
1695
+ // Stock hosts without that context keep their existing previous-state contract.
1696
+ const initial = inputContext.initialSessionOptions ?? inputContext.previousInputState?.groups.flatMap(group => group.selected ? [{ optionId: group.id, value: group.selected.id }] : []) ?? [];
1697
+ const state = controller.createChatSessionInputState(resource ? groups : applyOptions(groups, initial));
1698
+ const initialPermission = initial.find(option => option.optionId === 'permissions')?.value;
1699
+ if (!resource && initialPermission)
1700
+ draftPermissions.set(state, initialPermission);
1687
1701
  states.add(state);
1688
1702
  const changed = state.onDidChange(() => {
1689
1703
  const target = state.sessionResource ?? resource;
1704
+ const value = state.groups.find(group => group.id === 'permissions')?.selected?.id;
1690
1705
  if (target)
1691
- controls.setPermission(target, state.groups.find(group => group.id === 'permissions')?.selected?.id);
1706
+ controls.setPermission(target, value);
1707
+ else if (value)
1708
+ draftPermissions.set(state, value);
1692
1709
  });
1693
1710
  const disposed = state.onDidDispose(() => { states.delete(state); changed.dispose(); disposed.dispose(); });
1694
1711
  return state;
@@ -1701,8 +1718,9 @@ function registerSessions(context, frontends, participant, granted, handler, his
1701
1718
  context.subscriptions.push(controls.changed(() => {
1702
1719
  refreshItems();
1703
1720
  for (const state of states) {
1704
- if (state.sessionResource)
1705
- state.groups = controls.options(state.sessionResource);
1721
+ const groups = controls.options(state.sessionResource);
1722
+ const value = draftPermissions.get(state);
1723
+ state.groups = state.sessionResource || !value ? groups : applyOptions(groups, [{ optionId: 'permissions', value }]);
1706
1724
  }
1707
1725
  }));
1708
1726
  }
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.41",
4
+ "version": "0.1.42",
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",