@volter/supercode-frontend-vscode 0.1.29 → 0.1.30
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/extension.js +124 -46
- package/dist/host-controls.d.ts +4 -0
- package/dist/host-controls.js +16 -8
- package/package.json +1 -1
package/dist/extension.js
CHANGED
|
@@ -323,6 +323,7 @@ export async function activate(context) {
|
|
|
323
323
|
let applying = Promise.resolve();
|
|
324
324
|
let pendingDraft;
|
|
325
325
|
let focusedResource;
|
|
326
|
+
let focusGeneration = 0;
|
|
326
327
|
const activeDraft = () => pendingDraft?.resource && pendingDraft.resource.toString() === focusedResource?.toString() ? pendingDraft : undefined;
|
|
327
328
|
const draftSelection = () => {
|
|
328
329
|
const choice = activeDraft()?.choice;
|
|
@@ -333,8 +334,10 @@ export async function activate(context) {
|
|
|
333
334
|
focusedResource = resource;
|
|
334
335
|
if (pendingDraft?.resource && pendingDraft.resource.toString() !== resource?.toString())
|
|
335
336
|
pendingDraft = undefined;
|
|
336
|
-
if (changed)
|
|
337
|
+
if (changed) {
|
|
338
|
+
focusGeneration++;
|
|
337
339
|
controlsChanged.fire();
|
|
340
|
+
}
|
|
338
341
|
};
|
|
339
342
|
const frontends = new SupercodeFrontends();
|
|
340
343
|
// Runtimes attached by address ("Set Runtime Token", "Attach to Runtime")
|
|
@@ -406,11 +409,20 @@ export async function activate(context) {
|
|
|
406
409
|
const id = resource ? boundId(resource) : controls?.state.activeSession;
|
|
407
410
|
return { permissions: id ? permissions.get(id) ?? 'ask' : permission };
|
|
408
411
|
};
|
|
409
|
-
const
|
|
410
|
-
|
|
411
|
-
|
|
412
|
+
const savedConnections = new Map();
|
|
413
|
+
const saveManagedHistory = async (connection) => {
|
|
414
|
+
const state = await controls.open(connection.id);
|
|
415
|
+
if (state.activeSession !== connection.id)
|
|
416
|
+
throw new Error('The conversation changed before its history could be saved.');
|
|
417
|
+
connection.persistedHistory = state.history;
|
|
418
|
+
connection.historyTruncated = state.historyTruncated;
|
|
419
|
+
savedConnections.set(connection.id, connection);
|
|
420
|
+
};
|
|
421
|
+
const connectManaged = async (state = controls.state) => {
|
|
422
|
+
const env = state.connection;
|
|
423
|
+
if (!env || !state.activeSession)
|
|
412
424
|
throw new Error('The requested conversation has no runtime connection.');
|
|
413
|
-
const id =
|
|
425
|
+
const id = state.activeSession;
|
|
414
426
|
const existing = frontends.get(id);
|
|
415
427
|
if (existing && existing.baseUrl === env.SUPERCODE_FRONTEND_URL && existing.session.connection !== 'closed') {
|
|
416
428
|
if (existing.session.connection !== 'connected')
|
|
@@ -421,7 +433,7 @@ export async function activate(context) {
|
|
|
421
433
|
await frontends.disconnect(connection.id);
|
|
422
434
|
const connection = await frontends.connect({ connectionId: id, baseUrl: env.SUPERCODE_FRONTEND_URL,
|
|
423
435
|
token: await readCredentialFile(env.SUPERCODE_FRONTEND_CREDENTIAL_FILE), clientId: env.SUPERCODE_FRONTEND_CLIENT_ID,
|
|
424
|
-
permissions: normalizePermissions(env.SUPERCODE_FRONTEND_PERMISSIONS, ['observe']), label: runtimeIdentity(
|
|
436
|
+
permissions: normalizePermissions(env.SUPERCODE_FRONTEND_PERMISSIONS, ['observe']), label: runtimeIdentity(state.selection.harness, state.selection.model || state.actualModel).name }, log);
|
|
425
437
|
if (!connection)
|
|
426
438
|
throw new Error('Could not connect to the requested conversation.');
|
|
427
439
|
return connection;
|
|
@@ -458,17 +470,20 @@ export async function activate(context) {
|
|
|
458
470
|
};
|
|
459
471
|
let refreshingSetup;
|
|
460
472
|
const refreshSetup = () => {
|
|
461
|
-
|
|
473
|
+
if (refreshingSetup)
|
|
474
|
+
return refreshingSetup;
|
|
475
|
+
const pending = applying.then(async () => {
|
|
462
476
|
if (!controls)
|
|
463
477
|
return;
|
|
464
478
|
// Discover and publish readiness even while a blank chat holds a draft.
|
|
465
479
|
// Only the automatic reveal is suppressed; discovery must never stall.
|
|
466
480
|
await controls.refresh();
|
|
481
|
+
const state = controls.state;
|
|
467
482
|
controlsChanged.fire();
|
|
468
483
|
const preserveDraft = focusedResource?.path.startsWith('/untitled-');
|
|
469
|
-
if (
|
|
484
|
+
if (state.setup?.ready) {
|
|
470
485
|
setupRevealed = false;
|
|
471
|
-
await connectManaged();
|
|
486
|
+
await connectManaged(state);
|
|
472
487
|
controlsChanged.fire();
|
|
473
488
|
if (!preserveDraft && !setupHandoffComplete())
|
|
474
489
|
await revealManaged();
|
|
@@ -479,7 +494,9 @@ export async function activate(context) {
|
|
|
479
494
|
if (!preserveDraft)
|
|
480
495
|
await revealSetup();
|
|
481
496
|
}
|
|
482
|
-
})
|
|
497
|
+
});
|
|
498
|
+
applying = pending.then(() => undefined, () => undefined);
|
|
499
|
+
refreshingSetup = pending.finally(() => { refreshingSetup = undefined; });
|
|
483
500
|
return refreshingSetup;
|
|
484
501
|
};
|
|
485
502
|
const setupTerminals = new Map();
|
|
@@ -512,8 +529,8 @@ export async function activate(context) {
|
|
|
512
529
|
setupTerminals.set(key, terminal);
|
|
513
530
|
terminal.show();
|
|
514
531
|
}));
|
|
515
|
-
const
|
|
516
|
-
|
|
532
|
+
const restoring = new Map();
|
|
533
|
+
const connectionFor = async (resource, activate = true) => {
|
|
517
534
|
if (!controls) {
|
|
518
535
|
const connection = frontends.get(resource.authority);
|
|
519
536
|
if (!connection)
|
|
@@ -521,7 +538,7 @@ export async function activate(context) {
|
|
|
521
538
|
return connection;
|
|
522
539
|
}
|
|
523
540
|
const attached = attachedIds.has(resource.authority) ? frontends.get(resource.authority) : undefined;
|
|
524
|
-
if (focusedAttached !== attached) {
|
|
541
|
+
if (activate && focusedAttached !== attached) {
|
|
525
542
|
focusedAttached = attached;
|
|
526
543
|
controlsChanged.fire();
|
|
527
544
|
}
|
|
@@ -530,26 +547,55 @@ export async function activate(context) {
|
|
|
530
547
|
const id = boundId(resource);
|
|
531
548
|
if (!id)
|
|
532
549
|
throw new Error('This chat has no backend session binding. Start a new chat; no message was sent.');
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
550
|
+
// Content refresh is not a focus change. Replaying a previously connected
|
|
551
|
+
// conversation must not retire the runtime the person just selected.
|
|
552
|
+
if (!activate) {
|
|
553
|
+
const saved = frontends.get(id) ?? savedConnections.get(id);
|
|
554
|
+
if (saved)
|
|
555
|
+
return saved;
|
|
556
|
+
}
|
|
557
|
+
const existing = restoring.get(id);
|
|
558
|
+
// Coalesce adjacent requests only. A later A after a queued B must still
|
|
559
|
+
// activate A last, rather than borrowing an earlier A's completion.
|
|
560
|
+
if (existing?.completion === applying)
|
|
561
|
+
return existing.pending;
|
|
562
|
+
const pending = applying.then(async () => {
|
|
563
|
+
const active = managed();
|
|
564
|
+
if (active && active.id !== id && (active.session.descriptor?.turn_state === 'busy' || active.session.pendingRequests.size))
|
|
565
|
+
throw new Error('Finish or cancel the active turn before opening another conversation.');
|
|
566
|
+
if (active && active.id !== id) {
|
|
567
|
+
// Capture the exact saved transcript while its runtime still belongs
|
|
568
|
+
// to the host. Subsequent background content reads need no activation.
|
|
569
|
+
await saveManagedHistory(active);
|
|
570
|
+
}
|
|
571
|
+
let state;
|
|
572
|
+
try {
|
|
573
|
+
state = await controls.open(id);
|
|
574
|
+
}
|
|
575
|
+
catch (error) {
|
|
576
|
+
log.error(`Could not restore conversation ${id}: ${String(error)}`);
|
|
577
|
+
throw error;
|
|
578
|
+
}
|
|
579
|
+
if (state.activeSession !== id)
|
|
580
|
+
throw new Error('The host did not restore the requested conversation.');
|
|
581
|
+
const connection = await connectManaged(state);
|
|
582
|
+
connection.persistedHistory = state.history;
|
|
583
|
+
connection.historyTruncated = state.historyTruncated;
|
|
584
|
+
savedConnections.set(id, connection);
|
|
585
|
+
if (active !== connection)
|
|
586
|
+
controlsChanged.fire();
|
|
587
|
+
return connection;
|
|
588
|
+
});
|
|
589
|
+
const completion = pending.then(() => undefined, () => undefined);
|
|
590
|
+
restoring.set(id, { pending, completion });
|
|
591
|
+
applying = completion;
|
|
536
592
|
try {
|
|
537
|
-
await
|
|
593
|
+
return await pending;
|
|
538
594
|
}
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
595
|
+
finally {
|
|
596
|
+
if (restoring.get(id)?.pending === pending)
|
|
597
|
+
restoring.delete(id);
|
|
542
598
|
}
|
|
543
|
-
const history = controls.state.history;
|
|
544
|
-
const historyTruncated = controls.state.historyTruncated;
|
|
545
|
-
const connection = await connectManaged();
|
|
546
|
-
connection.persistedHistory = history;
|
|
547
|
-
connection.historyTruncated = historyTruncated;
|
|
548
|
-
// Resolving an already-focused session must not republish its catalogue
|
|
549
|
-
// while the native widget is still opening that same resource.
|
|
550
|
-
if (active !== connection)
|
|
551
|
-
controlsChanged.fire();
|
|
552
|
-
return connection;
|
|
553
599
|
};
|
|
554
600
|
async function applySelection(selection) {
|
|
555
601
|
if (!controls)
|
|
@@ -557,9 +603,12 @@ export async function activate(context) {
|
|
|
557
603
|
const active = managed();
|
|
558
604
|
if (active?.session.descriptor?.turn_state === 'busy' || active?.session.pendingRequests.size)
|
|
559
605
|
throw new Error('Finish or cancel the current turn before starting a new chat.');
|
|
560
|
-
|
|
561
|
-
|
|
606
|
+
if (active)
|
|
607
|
+
await saveManagedHistory(active);
|
|
608
|
+
const state = await controls.select(selection);
|
|
609
|
+
const connection = await connectManaged(state);
|
|
562
610
|
controlsChanged.fire();
|
|
611
|
+
return connection;
|
|
563
612
|
}
|
|
564
613
|
const openNewChat = async () => {
|
|
565
614
|
if (!controls || !granted.has('chatSessionsProvider'))
|
|
@@ -578,6 +627,7 @@ export async function activate(context) {
|
|
|
578
627
|
const draft = { resource: vscode.Uri.from({ scheme: SESSION_SCHEME, path: `/untitled-${randomUUID()}` }) };
|
|
579
628
|
pendingDraft = draft;
|
|
580
629
|
focusedResource = draft.resource;
|
|
630
|
+
focusGeneration++;
|
|
581
631
|
focusedAttached = undefined;
|
|
582
632
|
controlsChanged.fire();
|
|
583
633
|
await vscode.commands.executeCommand(controls.state.openSessionCommand, draft.resource.toString());
|
|
@@ -672,9 +722,8 @@ export async function activate(context) {
|
|
|
672
722
|
const selection = choice?.kind === 'agent' ? choice.selection
|
|
673
723
|
: { harness: loginHarness ?? controls.state.selection.harness, model: '', effort: '' };
|
|
674
724
|
const pending = applying.then(() => applySelection(selection));
|
|
675
|
-
applying = pending.
|
|
676
|
-
await pending;
|
|
677
|
-
const connection = frontends.get(controls.state.activeSession);
|
|
725
|
+
applying = pending.then(() => undefined, () => undefined);
|
|
726
|
+
const connection = await pending;
|
|
678
727
|
savePermission(connection.id, turnPermission(inputState.groups.find(group => group.id === 'permissions')?.selected?.id));
|
|
679
728
|
if (pendingDraft === draft) {
|
|
680
729
|
pendingDraft = undefined;
|
|
@@ -682,8 +731,7 @@ export async function activate(context) {
|
|
|
682
731
|
}
|
|
683
732
|
return connection;
|
|
684
733
|
},
|
|
685
|
-
resolve: connectionFor,
|
|
686
|
-
focus: focusSession,
|
|
734
|
+
resolve: (resource) => connectionFor(resource, false),
|
|
687
735
|
attached: (connection) => attachedIds.has(connection.id),
|
|
688
736
|
catalogue: () => controls?.state.sessions ?? [],
|
|
689
737
|
bindings: boundId,
|
|
@@ -695,7 +743,12 @@ export async function activate(context) {
|
|
|
695
743
|
focusSession(resource ? vscode.Uri.parse(resource) : undefined);
|
|
696
744
|
}));
|
|
697
745
|
context.subscriptions.push(vscode.commands.registerCommand('supercode.frontend.openSession', async (id) => {
|
|
698
|
-
|
|
746
|
+
const resource = vscode.Uri.from({ scheme: SESSION_SCHEME, authority: id, path: '/conversation' });
|
|
747
|
+
focusSession(resource);
|
|
748
|
+
const generation = focusGeneration;
|
|
749
|
+
await connectionFor(resource);
|
|
750
|
+
if (generation !== focusGeneration)
|
|
751
|
+
return;
|
|
699
752
|
await revealManaged();
|
|
700
753
|
}));
|
|
701
754
|
context.subscriptions.push(vscode.commands.registerCommand('supercode.frontend.configure', async (supplied) => {
|
|
@@ -945,7 +998,28 @@ export async function activate(context) {
|
|
|
945
998
|
p.iconPath = icon();
|
|
946
999
|
};
|
|
947
1000
|
context.subscriptions.push({ dispose: () => sessionParticipant.dispose() }, controlsChanged.event(updateIdentity), frontends.onDidChange(updateIdentity));
|
|
948
|
-
|
|
1001
|
+
// Replayed turns outlive the active composer participant. Keep their
|
|
1002
|
+
// author tied to the saved harness, including passive background loads.
|
|
1003
|
+
const historyParticipants = new Map();
|
|
1004
|
+
const historyParticipant = (connection) => {
|
|
1005
|
+
if (!granted.has('chatParticipantPrivate'))
|
|
1006
|
+
return sessionParticipant.id;
|
|
1007
|
+
const harness = connection.session.descriptor?.source_harness
|
|
1008
|
+
?? controls?.state.sessions.find(entry => entry.id === connection.id)?.selection.harness;
|
|
1009
|
+
if (!harness)
|
|
1010
|
+
return sessionParticipant.id;
|
|
1011
|
+
let author = historyParticipants.get(harness);
|
|
1012
|
+
if (!author) {
|
|
1013
|
+
const name = harnessDisplayName(harness);
|
|
1014
|
+
author = vscode.chat.createDynamicChatParticipant(`${SESSION_SCHEME}.history.${encodeURIComponent(harness)}`, { name: name.replace(/[^a-zA-Z0-9]/g, ''), fullName: name, publisherName: 'Volter' }, handler);
|
|
1015
|
+
const provider = runtimeIdentity(harness, '').provider;
|
|
1016
|
+
author.iconPath = provider ? vscode.Uri.joinPath(context.extensionUri, 'media', `${provider}.svg`) : new vscode.ThemeIcon('hubot');
|
|
1017
|
+
historyParticipants.set(harness, author);
|
|
1018
|
+
context.subscriptions.push(author);
|
|
1019
|
+
}
|
|
1020
|
+
return author.id;
|
|
1021
|
+
};
|
|
1022
|
+
registerSessions(context, frontends, sessionParticipant, granted, handler, historyParticipant, controls ? providerControls : undefined);
|
|
949
1023
|
}
|
|
950
1024
|
catch (error) {
|
|
951
1025
|
log.warn(`Volter Harness chat sessions were not registered: ${String(error?.message ?? error)}`);
|
|
@@ -1315,7 +1389,7 @@ function applyTiming(item, connection) {
|
|
|
1315
1389
|
lastRequestEnded: connection.session.lastTurnEndedMs ?? undefined,
|
|
1316
1390
|
};
|
|
1317
1391
|
}
|
|
1318
|
-
function registerSessions(context, frontends, participant, granted, handler, controls) {
|
|
1392
|
+
function registerSessions(context, frontends, participant, granted, handler, historyParticipant, controls) {
|
|
1319
1393
|
const turns = vscode;
|
|
1320
1394
|
const items = () => {
|
|
1321
1395
|
return (controls?.catalogue() ?? []).filter(entry => !frontends.get(entry.id)).map(entry => {
|
|
@@ -1369,12 +1443,15 @@ function registerSessions(context, frontends, participant, granted, handler, con
|
|
|
1369
1443
|
}));
|
|
1370
1444
|
}
|
|
1371
1445
|
context.subscriptions.push(vscode.chat.registerChatSessionContentProvider(SESSION_SCHEME, {
|
|
1372
|
-
provideChatSessionContent: async (resource,
|
|
1373
|
-
|
|
1446
|
+
provideChatSessionContent: async (resource, token, { inputState }) => {
|
|
1447
|
+
if (token.isCancellationRequested)
|
|
1448
|
+
throw new vscode.CancellationError();
|
|
1374
1449
|
const boundHandler = (request, chatContext, stream, token) => handler(request, { ...chatContext, chatSessionContext: { chatSessionItem: { resource, label: 'Conversation' } } }, stream, token);
|
|
1375
1450
|
// Only a native untitled resource can create a conversation. Existing
|
|
1376
1451
|
// resources must resolve their exact saved binding; there is no fallback.
|
|
1377
1452
|
const connection = controls ? (resource.path.startsWith('/untitled-') && !controls.bindings(resource) ? undefined : await controls.resolve(resource)) : frontends.get(resource.authority);
|
|
1453
|
+
if (token.isCancellationRequested)
|
|
1454
|
+
throw new vscode.CancellationError();
|
|
1378
1455
|
if (!connection) {
|
|
1379
1456
|
return { history: [], requestHandler: boundHandler };
|
|
1380
1457
|
}
|
|
@@ -1387,13 +1464,14 @@ function registerSessions(context, frontends, participant, granted, handler, con
|
|
|
1387
1464
|
// `state.history`), so the copy taken when this window attached is
|
|
1388
1465
|
// stale as soon as a turn runs. The generated client reuses the
|
|
1389
1466
|
// already-open event stream, so this is a snapshot, not a reconnect.
|
|
1390
|
-
const attached = await connection.session.attach().then(() => true).catch(() => {
|
|
1467
|
+
const attached = frontends.get(connection.id) === connection && await connection.session.attach().then(() => true).catch(() => {
|
|
1391
1468
|
// An unreachable runtime replays what this window last saw.
|
|
1392
1469
|
return false;
|
|
1393
1470
|
});
|
|
1394
1471
|
// The attach snapshot IS the session's history: the runtime's own
|
|
1395
1472
|
// canonical transcript, replayed as turns.
|
|
1396
1473
|
const history = [];
|
|
1474
|
+
const authorId = historyParticipant(connection);
|
|
1397
1475
|
// A hosted harness runtime has no canonical ChatMessage history —
|
|
1398
1476
|
// `HostedHarnessRuntime::attach` returns an empty one and puts the
|
|
1399
1477
|
// conversation in `replay`. Read whichever the runtime actually
|
|
@@ -1419,13 +1497,13 @@ function registerSessions(context, frontends, participant, granted, handler, con
|
|
|
1419
1497
|
canRespond: connection.session.descriptor?.actions.respond !== false,
|
|
1420
1498
|
});
|
|
1421
1499
|
if (connection.historyTruncated)
|
|
1422
|
-
history.push(new turns.ChatRequestTurn('[Earlier conversation history]', undefined, [],
|
|
1500
|
+
history.push(new turns.ChatRequestTurn('[Earlier conversation history]', undefined, [], authorId, []), new turns.ChatResponseTurn([new vscode.ChatResponseMarkdownPart('_Showing the latest 120 saved messages. Earlier context remains in the harness session._')], {}, authorId));
|
|
1423
1501
|
for (const turn of projected) {
|
|
1424
1502
|
if (turn.role === 'user') {
|
|
1425
|
-
history.push(new turns.ChatRequestTurn(turn.prompt ?? '', undefined, [],
|
|
1503
|
+
history.push(new turns.ChatRequestTurn(turn.prompt ?? '', undefined, [], authorId, []));
|
|
1426
1504
|
continue;
|
|
1427
1505
|
}
|
|
1428
|
-
history.push(new turns.ChatResponseTurn(historyParts(oneRowPerToolCall(turn.parts ?? [])), {},
|
|
1506
|
+
history.push(new turns.ChatResponseTurn(historyParts(oneRowPerToolCall(turn.parts ?? [])), {}, authorId));
|
|
1429
1507
|
}
|
|
1430
1508
|
const busy = connection.session.descriptor?.turn_state === 'busy';
|
|
1431
1509
|
return {
|
package/dist/host-controls.d.ts
CHANGED
|
@@ -55,6 +55,7 @@ export declare class ChatHostControls {
|
|
|
55
55
|
readonly baseUrl: string;
|
|
56
56
|
private readonly credential;
|
|
57
57
|
state: HostState;
|
|
58
|
+
private updating;
|
|
58
59
|
private constructor();
|
|
59
60
|
static fromEnvironment(env?: NodeJS.ProcessEnv): Promise<ChatHostControls | undefined>;
|
|
60
61
|
refresh(): Promise<void>;
|
|
@@ -67,6 +68,9 @@ export declare class ChatHostControls {
|
|
|
67
68
|
arguments: string[];
|
|
68
69
|
env?: Record<string, string>;
|
|
69
70
|
}>;
|
|
71
|
+
/** Publish complete host replies in request order; a late refresh must not
|
|
72
|
+
* overwrite the connection returned by a newer lifecycle operation. */
|
|
73
|
+
private update;
|
|
70
74
|
private request;
|
|
71
75
|
}
|
|
72
76
|
/** Approval policy is captured for one turn, never inferred from connection privileges. */
|
package/dist/host-controls.js
CHANGED
|
@@ -3,6 +3,7 @@ export class ChatHostControls {
|
|
|
3
3
|
baseUrl;
|
|
4
4
|
credential;
|
|
5
5
|
state;
|
|
6
|
+
updating = Promise.resolve();
|
|
6
7
|
constructor(baseUrl, credential, state) {
|
|
7
8
|
this.baseUrl = baseUrl;
|
|
8
9
|
this.credential = credential;
|
|
@@ -19,21 +20,28 @@ export class ChatHostControls {
|
|
|
19
20
|
host.state = await host.request('/state');
|
|
20
21
|
return host;
|
|
21
22
|
}
|
|
22
|
-
async refresh() {
|
|
23
|
+
async refresh() { await this.update('/state'); }
|
|
23
24
|
async select(selection) {
|
|
24
|
-
|
|
25
|
-
this.state = result;
|
|
26
|
-
return result;
|
|
25
|
+
return this.update('/select', selection);
|
|
27
26
|
}
|
|
28
|
-
async remember(id, nativeId) {
|
|
27
|
+
async remember(id, nativeId) { await this.update('/remember', { id, nativeId }); }
|
|
29
28
|
async open(id) {
|
|
30
|
-
|
|
31
|
-
this.state = result;
|
|
32
|
-
return result;
|
|
29
|
+
return this.update('/open', { id });
|
|
33
30
|
}
|
|
34
31
|
async setup(kind, harness) {
|
|
35
32
|
return this.request('/setup', { kind, harness });
|
|
36
33
|
}
|
|
34
|
+
/** Publish complete host replies in request order; a late refresh must not
|
|
35
|
+
* overwrite the connection returned by a newer lifecycle operation. */
|
|
36
|
+
update(path, selection) {
|
|
37
|
+
const pending = this.updating.then(async () => {
|
|
38
|
+
const result = await this.request(path, selection);
|
|
39
|
+
this.state = result;
|
|
40
|
+
return result;
|
|
41
|
+
});
|
|
42
|
+
this.updating = pending.then(() => undefined, () => undefined);
|
|
43
|
+
return pending;
|
|
44
|
+
}
|
|
37
45
|
async request(path, selection) {
|
|
38
46
|
const response = await fetch(this.baseUrl + path, {
|
|
39
47
|
method: selection ? 'POST' : 'GET', headers: { Authorization: `Bearer ${this.credential}`, 'Content-Type': 'application/json' },
|
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.
|
|
4
|
+
"version": "0.1.30",
|
|
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",
|