@volter/supercode-frontend-vscode 0.1.34 → 0.1.36
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 +30 -2
- package/dist/chat-setup.d.ts +11 -1
- package/dist/chat-setup.js +8 -3
- package/dist/extension.js +103 -26
- package/dist/host-controls.d.ts +4 -1
- package/dist/host-controls.js +1 -1
- package/dist/index.d.ts +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -24,6 +24,25 @@ Gallery detection reads the host's `product.json` through `vscode.workspace.fs`
|
|
|
24
24
|
at `vscode.env.appRoot`; hosts without an inspectable gallery configuration hide
|
|
25
25
|
the choice. Neither the extension nor its credentials are bundled or copied.
|
|
26
26
|
|
|
27
|
+
The welcome's primary action uses `supercode.frontend.beginChatGPTSignIn`:
|
|
28
|
+
it starts one retained install/sidebar operation and returns a copied receipt
|
|
29
|
+
with its id, timestamps and current phase. This is a launch receipt, not proof
|
|
30
|
+
that installation, sidebar presentation or authentication succeeded. A second
|
|
31
|
+
begin while that operation is running returns the same id and starts no extra
|
|
32
|
+
installation. `supercode.frontend.chatGPTSignInStatus` reads its current phase
|
|
33
|
+
locally without waiting for host readiness or installation; pass the operation
|
|
34
|
+
id to receive only that operation (a mismatched id returns null).
|
|
35
|
+
Phases name the selected work before its awaited command: `checking-gallery`,
|
|
36
|
+
`installing-extension`, `opening-sidebar`, then `completed` or `failed`.
|
|
37
|
+
Completed means the official command sequence fulfilled, not signed in. Failures
|
|
38
|
+
remain in operation status and the existing native error notification/output.
|
|
39
|
+
Only the current or most recent operation is retained, for this extension-window
|
|
40
|
+
lifetime; reload does not restore or automatically retry it. Runtime status
|
|
41
|
+
inspection also includes this snapshot as `chatGPTSignIn`.
|
|
42
|
+
The existing `supercode.frontend.signInWithChatGPT` still awaits the same work
|
|
43
|
+
with its existing error-notification/fulfillment behavior, and the agent picker
|
|
44
|
+
continues to use it. Ordinary relay budgets and draft guards are unchanged.
|
|
45
|
+
|
|
27
46
|
The optional host-controls state can include `setup: { ready, actions, reason,
|
|
28
47
|
cwd }`. Each action supplies `kind` (`login` or `install`), `harness`, `name` and
|
|
29
48
|
the exact `command` revalidated before execution. On a signed-out first open,
|
|
@@ -123,8 +142,17 @@ the same cached conversation. Managed resources then notify
|
|
|
123
142
|
owns no processes.
|
|
124
143
|
|
|
125
144
|
The permission group offers **Ask for approval** and, on an answerable interactive attachment,
|
|
126
|
-
**Auto approve**. Policies are scoped by conversation and
|
|
127
|
-
|
|
145
|
+
**Auto approve**. Policies are scoped by conversation and read throughout the turn: switching to
|
|
146
|
+
**Auto approve** while a turn runs answers the approvals already waiting and every later one.
|
|
147
|
+
A lifecycle host may declare `defaultPermission: "autoApprove"` for conversations no one has
|
|
148
|
+
picked a mode for (Model Editor does); it applies to Claude Code and Codex where the runtime answers approvals
|
|
149
|
+
through Chat, every other harness keeps its own prompts, and a person's explicit pick always
|
|
150
|
+
wins. Only a pick that differs from the default (or replaces an earlier pick) is saved, so the
|
|
151
|
+
default is never stored as a choice (a pick equal to the default follows the default if it later
|
|
152
|
+
changes), and an Auto approve is never stored for a conversation that cannot answer. Conversations opened before 0.1.36 saved their picker's
|
|
153
|
+
**Ask** when opened and keep it. Auto approve approves the requests the harness would ask you about, including requests to run
|
|
154
|
+
outside its sandbox (Codex's approval requests are its sandbox escalations); the harness's deny
|
|
155
|
+
rules still apply. Each request it answers is noted in the turn ("auto-approved: …"). Unsupported modes are refused. Unanswerable
|
|
128
156
|
harnesses show **Harness permissions**. Previously answered requests cannot affect another
|
|
129
157
|
connection. Native command-button fallback limitations are documented below.
|
|
130
158
|
|
package/dist/chat-setup.d.ts
CHANGED
|
@@ -2,12 +2,22 @@
|
|
|
2
2
|
import * as vscode from 'vscode';
|
|
3
3
|
import type { ChatSetupState } from './host-controls.js';
|
|
4
4
|
export declare const CHATGPT_SIGN_IN = "supercode.frontend.signInWithChatGPT";
|
|
5
|
+
export declare const CHATGPT_SIGN_IN_BEGIN = "supercode.frontend.beginChatGPTSignIn";
|
|
6
|
+
export declare const CHATGPT_SIGN_IN_STATUS = "supercode.frontend.chatGPTSignInStatus";
|
|
7
|
+
export type ChatGPTSignInWorkPhase = 'checking-gallery' | 'installing-extension' | 'opening-sidebar';
|
|
8
|
+
export interface ChatGPTSignInOperation {
|
|
9
|
+
readonly id: string;
|
|
10
|
+
readonly phase: ChatGPTSignInWorkPhase | 'completed' | 'failed';
|
|
11
|
+
readonly startedAt: number;
|
|
12
|
+
readonly updatedAt: number;
|
|
13
|
+
readonly finishedAt?: number;
|
|
14
|
+
}
|
|
5
15
|
/** The install command also exists in gallery-less Code-OSS. Fail closed when
|
|
6
16
|
* the host's product configuration cannot be inspected through the VS Code API. */
|
|
7
17
|
export declare function chatGPTAvailable(): Promise<boolean>;
|
|
8
18
|
/** Only called by an explicit click. The gallery and extension own installation
|
|
9
19
|
* and authentication; there is no terminal or provider credential handling here. */
|
|
10
|
-
export declare function signInWithChatGPT(): Promise<void>;
|
|
20
|
+
export declare function signInWithChatGPT(report?: (phase: ChatGPTSignInWorkPhase) => void): Promise<void>;
|
|
11
21
|
/** Empty-chat welcome content, rendered by Code-OSS's ChatViewWelcomePart.
|
|
12
22
|
* Only the official extension gets the primary button; native local sign-in
|
|
13
23
|
* actions remain ordinary links. Commands and host diagnostic paths stay out
|
package/dist/chat-setup.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/** Native Chat presentation; the host supplies inventory and terminal actions. */
|
|
2
2
|
import * as vscode from 'vscode';
|
|
3
3
|
export const CHATGPT_SIGN_IN = 'supercode.frontend.signInWithChatGPT';
|
|
4
|
+
export const CHATGPT_SIGN_IN_BEGIN = 'supercode.frontend.beginChatGPTSignIn';
|
|
5
|
+
export const CHATGPT_SIGN_IN_STATUS = 'supercode.frontend.chatGPTSignInStatus';
|
|
4
6
|
const CODEX_EXTENSION = 'openai.chatgpt';
|
|
5
7
|
const INSTALL_EXTENSION = 'workbench.extensions.installExtension';
|
|
6
8
|
/** The install command also exists in gallery-less Code-OSS. Fail closed when
|
|
@@ -20,16 +22,19 @@ export async function chatGPTAvailable() {
|
|
|
20
22
|
}
|
|
21
23
|
/** Only called by an explicit click. The gallery and extension own installation
|
|
22
24
|
* and authentication; there is no terminal or provider credential handling here. */
|
|
23
|
-
export async function signInWithChatGPT() {
|
|
25
|
+
export async function signInWithChatGPT(report) {
|
|
26
|
+
report?.('checking-gallery');
|
|
24
27
|
if (!await chatGPTAvailable())
|
|
25
28
|
throw new Error('This host does not provide an extension gallery.');
|
|
26
29
|
if (!vscode.extensions.getExtension(CODEX_EXTENSION)) {
|
|
27
30
|
// enable makes the workbench await the running extension registry, not
|
|
28
31
|
// just the installed inventory, before we dispatch the contributed command.
|
|
32
|
+
report?.('installing-extension');
|
|
29
33
|
await vscode.commands.executeCommand(INSTALL_EXTENSION, CODEX_EXTENSION, { enable: true });
|
|
30
34
|
}
|
|
31
35
|
// openai.chatgpt contributes this command, not a public sign-in command.
|
|
32
36
|
// Revealing its sidebar presents its own Sign in with ChatGPT when signed out.
|
|
37
|
+
report?.('opening-sidebar');
|
|
33
38
|
await vscode.commands.executeCommand('chatgpt.openSidebar');
|
|
34
39
|
}
|
|
35
40
|
/** Empty-chat welcome content, rendered by Code-OSS's ChatViewWelcomePart.
|
|
@@ -38,9 +43,9 @@ export async function signInWithChatGPT() {
|
|
|
38
43
|
* of the welcome, and the host still revalidates every action on click. */
|
|
39
44
|
export function setupWelcome(setup, chatGPT = false) {
|
|
40
45
|
const welcome = new vscode.MarkdownString();
|
|
41
|
-
welcome.isTrusted = { enabledCommands: [
|
|
46
|
+
welcome.isTrusted = { enabledCommands: [CHATGPT_SIGN_IN_BEGIN, 'supercode.frontend.setup', 'supercode.frontend.refreshSetup'] };
|
|
42
47
|
if (chatGPT) {
|
|
43
|
-
welcome.appendMarkdown(`[Sign in with ChatGPT](command:${
|
|
48
|
+
welcome.appendMarkdown(`[Sign in with ChatGPT](command:${CHATGPT_SIGN_IN_BEGIN})\n\n`);
|
|
44
49
|
welcome.appendMarkdown('Use the official Codex extension.');
|
|
45
50
|
welcome.appendMarkdown('\n\n');
|
|
46
51
|
}
|
package/dist/extension.js
CHANGED
|
@@ -2,7 +2,7 @@ import { resolveSessionBinding } from './bindings.js';
|
|
|
2
2
|
import { withTextContext } from './context.js';
|
|
3
3
|
import { randomUUID } from 'node:crypto';
|
|
4
4
|
import { ChatHostControls, runtimeIdentity, harnessDisplayName, turnPermission } from './host-controls.js';
|
|
5
|
-
import { CHATGPT_SIGN_IN, chatGPTAvailable, setupWelcome, signInWithChatGPT } from './chat-setup.js';
|
|
5
|
+
import { CHATGPT_SIGN_IN, CHATGPT_SIGN_IN_BEGIN, CHATGPT_SIGN_IN_STATUS, chatGPTAvailable, setupWelcome, signInWithChatGPT } from './chat-setup.js';
|
|
6
6
|
import * as vscode from 'vscode';
|
|
7
7
|
import { createFrontendClient } from './client.js';
|
|
8
8
|
import { readCredentialFile } from './credential.js';
|
|
@@ -324,20 +324,77 @@ export async function activate(context) {
|
|
|
324
324
|
const controls = await ChatHostControls.fromEnvironment();
|
|
325
325
|
const offerChatGPT = await chatGPTAvailable();
|
|
326
326
|
let signingInWithChatGPT;
|
|
327
|
-
|
|
328
|
-
|
|
327
|
+
let chatGPTSignInOperation;
|
|
328
|
+
const signInSnapshot = () => chatGPTSignInOperation ? { ...chatGPTSignInOperation } : null;
|
|
329
|
+
const startChatGPTSignIn = () => {
|
|
330
|
+
if (signingInWithChatGPT)
|
|
331
|
+
return signingInWithChatGPT;
|
|
332
|
+
const startedAt = Date.now();
|
|
333
|
+
const operation = { id: randomUUID(), startedAt };
|
|
334
|
+
const update = (phase) => {
|
|
335
|
+
const updatedAt = Date.now();
|
|
336
|
+
chatGPTSignInOperation = { ...operation, phase, updatedAt,
|
|
337
|
+
...(phase === 'completed' || phase === 'failed' ? { finishedAt: updatedAt } : {}) };
|
|
338
|
+
};
|
|
339
|
+
signingInWithChatGPT = signInWithChatGPT(phase => update(phase)).then(() => {
|
|
340
|
+
// Fulfilled install/sidebar commands do not establish authentication.
|
|
341
|
+
update('completed');
|
|
342
|
+
}).catch(error => {
|
|
343
|
+
update('failed');
|
|
329
344
|
log.error(`Could not open ChatGPT sign-in: ${String(error)}`);
|
|
330
345
|
void vscode.window.showErrorMessage(`Could not open ChatGPT sign-in: ${error instanceof Error ? error.message : String(error)}`);
|
|
331
346
|
}).finally(() => { signingInWithChatGPT = undefined; });
|
|
332
347
|
return signingInWithChatGPT;
|
|
333
|
-
}
|
|
348
|
+
};
|
|
349
|
+
context.subscriptions.push(
|
|
350
|
+
// Preserve the completion-awaiting command used by the agent picker.
|
|
351
|
+
vscode.commands.registerCommand(CHATGPT_SIGN_IN, startChatGPTSignIn),
|
|
352
|
+
// A click starts one retained task. Its receipt is not install/login success.
|
|
353
|
+
vscode.commands.registerCommand(CHATGPT_SIGN_IN_BEGIN, () => {
|
|
354
|
+
void startChatGPTSignIn();
|
|
355
|
+
return signInSnapshot();
|
|
356
|
+
}), vscode.commands.registerCommand(CHATGPT_SIGN_IN_STATUS, (operationId) => operationId === undefined || operationId === chatGPTSignInOperation?.id ? signInSnapshot() : null));
|
|
334
357
|
const controlsChanged = new vscode.EventEmitter();
|
|
335
358
|
context.subscriptions.push(controlsChanged);
|
|
336
|
-
|
|
359
|
+
// A person's explicit picker choice: per conversation once it is bound, and for the new chat before then.
|
|
360
|
+
let permission;
|
|
337
361
|
const permissions = new Map(context.workspaceState.get('supercode.sessionPermissions', []));
|
|
338
362
|
const savePermission = (id, value) => {
|
|
339
363
|
permissions.set(id, value);
|
|
340
364
|
void Promise.resolve(context.workspaceState.update('supercode.sessionPermissions', [...permissions])).catch(error => log.error(`Could not persist conversation permissions: ${String(error)}`));
|
|
365
|
+
for (const sweep of runningTurns.get(id) ?? [])
|
|
366
|
+
sweep();
|
|
367
|
+
};
|
|
368
|
+
// The approval sweeps of each conversation's running turns, so a picker change reaches a turn already running.
|
|
369
|
+
const runningTurns = new Map();
|
|
370
|
+
// The host's default for a conversation no one has chosen for (Model Editor declares Auto approve).
|
|
371
|
+
const hostDefault = () => controls?.state.defaultPermission === 'autoApprove' ? 'autoApprove' : 'ask';
|
|
372
|
+
const canAnswer = (connection) => Boolean(connection.session.descriptor?.actions.respond && connection.session.permissions.has('approve'));
|
|
373
|
+
// The host's default for one conversation: Auto approve only for a conversation the host manages and only
|
|
374
|
+
// where this Chat can answer the runtime's approvals, read from its live connection, or, while it is not
|
|
375
|
+
// connected, from the harness the host records for it (hosted Claude Code and Codex answer through Chat).
|
|
376
|
+
// A runtime attached by address and every other harness keep their own prompts.
|
|
377
|
+
const defaultFor = (id) => {
|
|
378
|
+
if (hostDefault() !== 'autoApprove' || attachedIds.has(id))
|
|
379
|
+
return 'ask';
|
|
380
|
+
const connection = frontends.get(id);
|
|
381
|
+
const harness = controls?.state.sessions.find(session => session.id === id)?.selection.harness ?? '';
|
|
382
|
+
// Only the harnesses whose approvals this default was decided for; a runtime that answers through another
|
|
383
|
+
// protocol (an ACP agent) keeps asking until a host names it.
|
|
384
|
+
return ['claude-code', 'codex'].includes(harness) && (!connection || canAnswer(connection)) ? 'autoApprove' : 'ask';
|
|
385
|
+
};
|
|
386
|
+
// What governs a conversation's approvals: the person's choice, else the host's default.
|
|
387
|
+
const approvalFor = (id) => permissions.get(id) ?? defaultFor(id);
|
|
388
|
+
// A picker value becomes the person's choice only when it is one: it differs from the default the picker showed
|
|
389
|
+
// (`shown`; null when the person already picked it), or replaces an earlier choice. Echoes of the displayed default
|
|
390
|
+
// (the picker re-applied when a conversation opens) are not saved, and neither is an Auto approve the conversation
|
|
391
|
+
// cannot answer: the picker offers it only where it can, so there it is a default shown before the harness was known.
|
|
392
|
+
const choosePermission = (id, value, shown = defaultFor(id)) => {
|
|
393
|
+
const connection = frontends.get(id);
|
|
394
|
+
if (value === 'autoApprove' && connection && !canAnswer(connection))
|
|
395
|
+
return;
|
|
396
|
+
if (permissions.has(id) || value !== shown)
|
|
397
|
+
savePermission(id, value);
|
|
341
398
|
};
|
|
342
399
|
const resourceBindings = new Map(context.workspaceState.get('supercode.sessionBindings', []));
|
|
343
400
|
const boundId = (resource) => resolveSessionBinding(resource, controls?.state.sessions ?? [], resourceBindings);
|
|
@@ -429,7 +486,7 @@ export async function activate(context) {
|
|
|
429
486
|
}
|
|
430
487
|
const currentOptions = (resource) => {
|
|
431
488
|
const id = resource ? boundId(resource) : controls?.state.activeSession;
|
|
432
|
-
return { permissions: id ?
|
|
489
|
+
return { permissions: id ? approvalFor(id) : permission ?? hostDefault() };
|
|
433
490
|
};
|
|
434
491
|
const savedConnections = new Map();
|
|
435
492
|
const saveManagedHistory = async (connection) => {
|
|
@@ -726,8 +783,8 @@ export async function activate(context) {
|
|
|
726
783
|
const active = resource ? (id ? frontends.get(id) : undefined) : managed();
|
|
727
784
|
const canApprove = active?.session.descriptor?.actions.respond && active.session.permissions.has('approve');
|
|
728
785
|
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.' },
|
|
729
|
-
...((canApprove || (!active && resource && currentOptions(resource).permissions === 'autoApprove')) ? [{ id: 'autoApprove', name: 'Auto approve', description: '
|
|
730
|
-
const groups = [{ id: 'permissions', name: 'Permissions', kind: 'permissions', items: permissionItems, selected: permissionItems.find(i => i.id ===
|
|
786
|
+
...((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.' }] : [])];
|
|
787
|
+
const groups = [{ id: 'permissions', name: 'Permissions', kind: 'permissions', items: permissionItems, selected: permissionItems.find(i => i.id === currentOptions(resource).permissions) }];
|
|
731
788
|
const selected = controls?.state.sessions.find(session => session.id === id);
|
|
732
789
|
if (selected && ['claude-code', 'codex'].includes(selected.selection.harness)) {
|
|
733
790
|
// Native session-option commands remain reachable for nondelegating providers,
|
|
@@ -745,7 +802,7 @@ export async function activate(context) {
|
|
|
745
802
|
if (controls && !id)
|
|
746
803
|
throw new Error('This conversation has no session binding.');
|
|
747
804
|
if (id)
|
|
748
|
-
|
|
805
|
+
choosePermission(id, turnPermission(value));
|
|
749
806
|
else
|
|
750
807
|
permission = turnPermission(value);
|
|
751
808
|
},
|
|
@@ -771,7 +828,10 @@ export async function activate(context) {
|
|
|
771
828
|
const pending = applying.then(() => applySelection(selection));
|
|
772
829
|
applying = pending.then(() => undefined, () => undefined);
|
|
773
830
|
const connection = await pending;
|
|
774
|
-
|
|
831
|
+
// The picker shows the host's default until someone changes it; only a change is the person's choice.
|
|
832
|
+
const picked = turnPermission(inputState.groups.find(group => group.id === 'permissions')?.selected?.id);
|
|
833
|
+
choosePermission(connection.id, picked, permission !== undefined ? null : hostDefault());
|
|
834
|
+
permission = undefined;
|
|
775
835
|
if (pendingDraft === draft) {
|
|
776
836
|
pendingDraft = undefined;
|
|
777
837
|
controlsChanged.fire();
|
|
@@ -802,7 +862,7 @@ export async function activate(context) {
|
|
|
802
862
|
if (supplied?.permissions) {
|
|
803
863
|
const id = controls?.state.activeSession;
|
|
804
864
|
if (id)
|
|
805
|
-
|
|
865
|
+
choosePermission(id, turnPermission(supplied.permissions));
|
|
806
866
|
else
|
|
807
867
|
permission = turnPermission(supplied.permissions);
|
|
808
868
|
controlsChanged.fire();
|
|
@@ -886,7 +946,7 @@ export async function activate(context) {
|
|
|
886
946
|
}));
|
|
887
947
|
context.subscriptions.push({ dispose: () => frontends.dispose() });
|
|
888
948
|
const runTurnInto = async (connection, prompt, stream, token, approval) => {
|
|
889
|
-
if (approval === 'autoApprove' && (
|
|
949
|
+
if (approval() === 'autoApprove' && !canAnswer(connection)) {
|
|
890
950
|
throw new Error('This harness does not support automatic approval through Chat. Select Harness permissions.');
|
|
891
951
|
}
|
|
892
952
|
const answered = new Set();
|
|
@@ -902,25 +962,40 @@ export async function activate(context) {
|
|
|
902
962
|
// this view reports.
|
|
903
963
|
});
|
|
904
964
|
});
|
|
965
|
+
// Read at every event and on every picker change, so switching to Auto approve mid-turn
|
|
966
|
+
// answers the approvals already waiting and the ones after them.
|
|
967
|
+
const sweep = () => {
|
|
968
|
+
if (approval() !== 'autoApprove' || token.isCancellationRequested || !canAnswer(connection))
|
|
969
|
+
return;
|
|
970
|
+
for (const pending of connection.session.pendingRequests.values()) {
|
|
971
|
+
if (pending.kind !== 'approval' || answered.has(pending.id))
|
|
972
|
+
continue;
|
|
973
|
+
const decisions = acceptedDecisions(pending);
|
|
974
|
+
if (decisions && !decisions.includes('allow'))
|
|
975
|
+
continue;
|
|
976
|
+
answered.add(pending.id);
|
|
977
|
+
// Its card is already in the stream (the event that raised it was written first), so say it was answered.
|
|
978
|
+
const payload = pending.payload && typeof pending.payload === 'object' && !Array.isArray(pending.payload) ? pending.payload : {};
|
|
979
|
+
const named = [payload.title, payload.tool, payload.tool_name].find((value) => typeof value === 'string');
|
|
980
|
+
void connection.session.respond({ kind: 'approval', request_id: pending.id, decision: 'allow' }).then(() => {
|
|
981
|
+
stream.markdown(`\n_auto-approved: ${opaqueText(named ?? `request #${pending.id}`, 200)}_\n`);
|
|
982
|
+
}, error => {
|
|
983
|
+
stream.markdown(`\nApproval failed: ${String(error.message || error)}. Use the approval buttons to answer.\n`);
|
|
984
|
+
});
|
|
985
|
+
}
|
|
986
|
+
};
|
|
987
|
+
const sweeps = runningTurns.get(connection.id) ?? new Set();
|
|
988
|
+
runningTurns.set(connection.id, sweeps.add(sweep));
|
|
905
989
|
try {
|
|
906
990
|
await connection.session.runTurn(prompt, (event) => {
|
|
907
991
|
writeProjected(stream, projectEvent(event, projection), granted, state);
|
|
908
|
-
|
|
909
|
-
for (const pending of connection.session.pendingRequests.values()) {
|
|
910
|
-
if (pending.kind !== 'approval' || answered.has(pending.id))
|
|
911
|
-
continue;
|
|
912
|
-
const decisions = acceptedDecisions(pending);
|
|
913
|
-
if (decisions && !decisions.includes('allow'))
|
|
914
|
-
continue;
|
|
915
|
-
answered.add(pending.id);
|
|
916
|
-
void connection.session.respond({ kind: 'approval', request_id: pending.id, decision: 'allow' }).catch(error => {
|
|
917
|
-
stream.markdown(`\nApproval failed: ${String(error.message || error)}. Use the approval buttons to answer.\n`);
|
|
918
|
-
});
|
|
919
|
-
}
|
|
920
|
-
}
|
|
992
|
+
sweep();
|
|
921
993
|
});
|
|
922
994
|
}
|
|
923
995
|
finally {
|
|
996
|
+
sweeps.delete(sweep);
|
|
997
|
+
if (!sweeps.size && runningTurns.get(connection.id) === sweeps)
|
|
998
|
+
runningTurns.delete(connection.id);
|
|
924
999
|
cancellation.dispose();
|
|
925
1000
|
if (controls && !attachedIds.has(connection.id)) {
|
|
926
1001
|
if (connection.session.descriptor?.session_id)
|
|
@@ -970,7 +1045,8 @@ export async function activate(context) {
|
|
|
970
1045
|
stream.markdown('_nothing to submit_');
|
|
971
1046
|
return {};
|
|
972
1047
|
}
|
|
973
|
-
const
|
|
1048
|
+
const native = controls ? undefined : turnPermission(request.permissionLevel);
|
|
1049
|
+
const approval = () => native ?? approvalFor(connection.id);
|
|
974
1050
|
const attached = [];
|
|
975
1051
|
for (const reference of request.references) {
|
|
976
1052
|
const value = reference.value;
|
|
@@ -1160,6 +1236,7 @@ export async function activate(context) {
|
|
|
1160
1236
|
await controls.refresh();
|
|
1161
1237
|
if (inspect === true)
|
|
1162
1238
|
return {
|
|
1239
|
+
chatGPTSignIn: signInSnapshot(),
|
|
1163
1240
|
connections: frontends.all.map(c => ({ ...frontends.info(c), permissions: [...c.session.permissions],
|
|
1164
1241
|
pendingRequests: [...c.session.pendingRequests.values()] })),
|
|
1165
1242
|
selection: controls?.state.selection, activeSession: controls?.state.activeSession,
|
package/dist/host-controls.d.ts
CHANGED
|
@@ -49,6 +49,9 @@ export interface HostState {
|
|
|
49
49
|
actualModel?: string | null;
|
|
50
50
|
configurable: boolean;
|
|
51
51
|
setup?: ChatSetupState;
|
|
52
|
+
/** The approval mode of a conversation no one has picked one for. `autoApprove` takes effect only
|
|
53
|
+
* where the runtime can answer approvals through Chat; absent, every conversation asks. */
|
|
54
|
+
defaultPermission?: 'ask' | 'autoApprove';
|
|
52
55
|
}
|
|
53
56
|
export interface HostSelectionResult extends HostState {
|
|
54
57
|
connection: Record<string, string>;
|
|
@@ -75,7 +78,7 @@ export declare class ChatHostControls {
|
|
|
75
78
|
private update;
|
|
76
79
|
private request;
|
|
77
80
|
}
|
|
78
|
-
/**
|
|
81
|
+
/** A picked approval mode, never inferred from connection privileges (those only keep a host default at ask). */
|
|
79
82
|
export declare function turnPermission(value: string | undefined): 'ask' | 'autoApprove';
|
|
80
83
|
export declare function harnessDisplayName(harness: string | null | undefined): string;
|
|
81
84
|
export declare function runtimeIdentity(harness: string | null | undefined, model: string | null | undefined): {
|
package/dist/host-controls.js
CHANGED
|
@@ -53,7 +53,7 @@ export class ChatHostControls {
|
|
|
53
53
|
return value;
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
|
-
/**
|
|
56
|
+
/** A picked approval mode, never inferred from connection privileges (those only keep a host default at ask). */
|
|
57
57
|
export function turnPermission(value) {
|
|
58
58
|
if (!value || value === 'default' || value === 'ask')
|
|
59
59
|
return 'ask';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { createFrontendClient, type FrontendPermission, type VscodeFrontendConnection } from './client.js';
|
|
2
2
|
export { readCredentialFile } from './credential.js';
|
|
3
|
+
export type { ChatGPTSignInWorkPhase, ChatGPTSignInOperation } from './chat-setup.js';
|
|
3
4
|
export { grantedProposals, PROPOSAL_EFFECTS, REQUESTED_PROPOSALS, type ProposalName, } from './proposals.js';
|
|
4
5
|
export { EventSequenceGapError, LEASE_ERROR_NAMES, RequestNotPendingError, TURN_TERMINAL_KINDS, VscodeFrontendSession, type VscodeFrontendActions, type VscodeRuntimeClient, } from './session.js';
|
|
5
6
|
export { HISTORY_MARKER_PROMPT, VSCODE_CHAT_LIMITS, acceptedDecisions, diffPaths, fence, opaqueText, projectEvent, projectPendingRequests, projectHistory, projectReplayTurns, requestAnswers, requestNeedsTypedReply, requestSubject, requestSummary, resolutionSentence, resolveParts, toolSubject, typedAnswer, type ChatAnswer, type ChatPart, type ProjectedPart, type ProjectedTurn, type ProjectionContext, } from './view.js';
|
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.36",
|
|
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",
|