@volter/supercode-frontend-vscode 0.1.42 → 0.1.44

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 (2) hide show
  1. package/dist/extension.js +62 -39
  2. package/package.json +1 -1
package/dist/extension.js CHANGED
@@ -410,6 +410,8 @@ export async function activate(context) {
410
410
  const resourceBindings = new Map(context.workspaceState.get('supercode.sessionBindings', []));
411
411
  const boundId = (resource) => resolveSessionBinding(resource, controls?.state.sessions ?? [], resourceBindings);
412
412
  let applying = Promise.resolve();
413
+ // the reason the last send from a new chat made no conversation, said by that draft's request handler
414
+ let refusedSend;
413
415
  let pendingDraft;
414
416
  let focusedResource;
415
417
  let focusGeneration = 0;
@@ -606,8 +608,12 @@ export async function activate(context) {
606
608
  const applied = pending.then(() => undefined, () => undefined);
607
609
  applying = applied;
608
610
  const revealed = pending.then(async (target) => {
611
+ // A blank chat the workbench restored keeps the focus, except from a conversation whose turn runs or waits for an
612
+ // answer: after a reload mid-turn, that is the chat a person needs (its Stop button, its pending approval).
613
+ const live = target?.kind === 'managed' && Boolean(frontends.get(target.id)?.session.pendingRequests.size
614
+ || frontends.get(target.id)?.session.descriptor?.turn_state === 'busy');
609
615
  if (!target || !controls || applying !== applied || target.generation !== focusGeneration
610
- || focusedResource?.path.startsWith('/untitled-'))
616
+ || (focusedResource?.path.startsWith('/untitled-') && !live))
611
617
  return;
612
618
  if (target.kind === 'managed') {
613
619
  if ((controls.state.setup && !controls.state.setup.ready) || controls.state.activeSession !== target.id
@@ -744,13 +750,7 @@ export async function activate(context) {
744
750
  const openNewChat = async () => {
745
751
  if (!controls || !granted.has('chatSessionsProvider'))
746
752
  throw new Error('This host does not expose native conversation creation.');
747
- // Its callers (the new-chat pickers) swallow the cancellation, so the warning is the one message shown. An error
748
- // would reach the person as a bare "Canceled" or not at all through the contributed-command boundary.
749
- const refusal = busyRefusal(managed(), 'starting a new chat');
750
- if (refusal) {
751
- void vscode.window.showWarningMessage(refusal);
752
- throw new vscode.CancellationError();
753
- }
753
+ // A turn running elsewhere does not stop a draft: its first send is refused there, in the chat (`create`).
754
754
  // Code-OSS materializes this untitled session on first send, awaiting our
755
755
  // newChatSessionItemHandler before accepting/clearing the draft. Never boot
756
756
  // beside the old widget and reveal another resource after it accepts input.
@@ -816,7 +816,6 @@ export async function activate(context) {
816
816
  try {
817
817
  // Open before the picker: a send can beat its result across the extension-
818
818
  // host boundary. Materialization awaits this exact draft's choice too.
819
- // Inside the try: a busy refusal is a cancellation already explained.
820
819
  const opened = draft = await openNewChat();
821
820
  picking = (async () => {
822
821
  const choice = await pick();
@@ -845,6 +844,42 @@ export async function activate(context) {
845
844
  // Publish capability-honest input groups only after the handoff descriptor is available.
846
845
  if (controls?.state.connection)
847
846
  await connectManaged().catch(error => log.warn(`Could not attach before registering chat input: ${String(error)}`));
847
+ const createConversation = async (inputState) => {
848
+ if (!controls)
849
+ throw new Error('The host does not expose conversation creation.');
850
+ const busy = busyRefusal(managed(), 'starting a new chat');
851
+ if (busy)
852
+ throw new Error(busy);
853
+ const draft = activeDraft();
854
+ await draft?.choosing;
855
+ if (draft && activeDraft() !== draft)
856
+ throw new vscode.CancellationError();
857
+ await controls.refresh();
858
+ controlsChanged.fire();
859
+ const choice = draft?.choice;
860
+ const loginHarness = choice?.kind === 'signIn' ? choice.harness : undefined;
861
+ if (loginHarness && !controls.state.harnesses.some(h => h.id === loginHarness && h.autoStart)) {
862
+ throw new Error(`Finish signing in with ${harnessDisplayName(loginHarness)} before sending.`);
863
+ }
864
+ if (choice?.kind !== 'agent' && controls.state.setup && !controls.state.setup.ready) {
865
+ throw new Error('Sign in before sending; use Check again after signing in.');
866
+ }
867
+ const selection = choice?.kind === 'agent' ? choice.selection
868
+ : { harness: loginHarness ?? controls.state.selection.harness, model: '', effort: '' };
869
+ const pending = applying.then(() => applySelection(selection));
870
+ applying = pending.then(() => undefined, () => undefined);
871
+ const connection = await pending;
872
+ // The picker shows the host's default until someone changes it; only a change is the person's choice.
873
+ const selected = inputState.groups.find(group => group.id === 'permissions')?.selected?.id;
874
+ const picked = selected === 'ask' || selected === 'autoApprove' ? selected : permission ?? newChatDefault();
875
+ choosePermission(connection.id, picked, permission !== undefined ? null : newChatDefault());
876
+ permission = undefined;
877
+ if (pendingDraft === draft) {
878
+ pendingDraft = undefined;
879
+ controlsChanged.fire();
880
+ }
881
+ return connection;
882
+ };
848
883
  const providerControls = {
849
884
  changed: controlsChanged.event,
850
885
  currentOptions,
@@ -883,38 +918,19 @@ export async function activate(context) {
883
918
  else
884
919
  permission = turnPermission(value);
885
920
  },
921
+ // A send that makes no conversation (another turn runs, or the host or a sign-in refuses it) answers no item: the
922
+ // host then runs the request on the draft itself, and its handler says why in the chat. A rejection here reaches
923
+ // nobody (the host's acceptInput drops it), so every refusal goes that way (#1282 review).
886
924
  create: async (inputState) => {
887
- if (!controls)
888
- throw new Error('The host does not expose conversation creation.');
889
- const draft = activeDraft();
890
- await draft?.choosing;
891
- if (draft && activeDraft() !== draft)
892
- throw new vscode.CancellationError();
893
- await controls.refresh();
894
- controlsChanged.fire();
895
- const choice = draft?.choice;
896
- const loginHarness = choice?.kind === 'signIn' ? choice.harness : undefined;
897
- if (loginHarness && !controls.state.harnesses.some(h => h.id === loginHarness && h.autoStart)) {
898
- throw new Error(`Finish signing in with ${harnessDisplayName(loginHarness)} before sending. Your draft is kept.`);
899
- }
900
- if (choice?.kind !== 'agent' && controls.state.setup && !controls.state.setup.ready) {
901
- throw new Error('Sign in before sending. Your draft is kept; use Check again after signing in.');
925
+ try {
926
+ return await createConversation(inputState);
902
927
  }
903
- const selection = choice?.kind === 'agent' ? choice.selection
904
- : { harness: loginHarness ?? controls.state.selection.harness, model: '', effort: '' };
905
- const pending = applying.then(() => applySelection(selection));
906
- applying = pending.then(() => undefined, () => undefined);
907
- const connection = await pending;
908
- // The picker shows the host's default until someone changes it; only a change is the person's choice.
909
- const selected = inputState.groups.find(group => group.id === 'permissions')?.selected?.id;
910
- const picked = selected === 'ask' || selected === 'autoApprove' ? selected : permission ?? newChatDefault();
911
- choosePermission(connection.id, picked, permission !== undefined ? null : newChatDefault());
912
- permission = undefined;
913
- if (pendingDraft === draft) {
914
- pendingDraft = undefined;
915
- controlsChanged.fire();
928
+ catch (error) {
929
+ if (error instanceof vscode.CancellationError)
930
+ throw error;
931
+ refusedSend = String(error?.message ?? error);
932
+ return undefined;
916
933
  }
917
- return connection;
918
934
  },
919
935
  resolve: (resource) => connectionFor(resource, false),
920
936
  attached: (connection) => attachedIds.has(connection.id),
@@ -1161,6 +1177,12 @@ export async function activate(context) {
1161
1177
  const handler = async (request, chatContext, stream, token) => {
1162
1178
  await applying;
1163
1179
  const requestedResource = chatContext.chatSessionContext?.chatSessionItem?.resource;
1180
+ if (refusedSend && requestedResource?.path.startsWith('/untitled-') && !boundId(requestedResource)) {
1181
+ const refusal = refusedSend;
1182
+ refusedSend = undefined;
1183
+ // thrown as is: the workbench writes a handler's error into the chat
1184
+ throw new Error(`${refusal} Nothing was sent; send it again in a new chat.`);
1185
+ }
1164
1186
  if (controls?.state.setup && !controls.state.setup.ready) {
1165
1187
  stream.markdown('Sign in before sending a message. Use **New Chat: Choose Agent** to get started.');
1166
1188
  return {};
@@ -1713,7 +1735,8 @@ function registerSessions(context, frontends, participant, granted, handler, his
1713
1735
  controller.newChatSessionItemHandler = async ({ inputState }, token) => {
1714
1736
  if (token.isCancellationRequested)
1715
1737
  throw new vscode.CancellationError();
1716
- return connectedItem(await controls.create(inputState));
1738
+ const connection = await controls.create(inputState);
1739
+ return connection ? connectedItem(connection) : undefined;
1717
1740
  };
1718
1741
  context.subscriptions.push(controls.changed(() => {
1719
1742
  refreshItems();
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.42",
4
+ "version": "0.1.44",
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",