@volter/supercode-frontend-vscode 0.1.60 → 0.1.61
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
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { resolveSessionBinding } from './bindings.js';
|
|
2
2
|
import { withTextContext } from './context.js';
|
|
3
3
|
import { randomUUID } from 'node:crypto';
|
|
4
|
+
import { WorkbenchTools } from './workbench-tools.js';
|
|
4
5
|
import { ChatHostControls, runtimeIdentity, harnessDisplayName, turnPermission } from './host-controls.js';
|
|
5
6
|
import { SETUP_BEGIN, SETUP_CANCEL, SETUP_STATE, setupAgents, setupPresentation, setupWelcome } from './chat-setup.js';
|
|
6
7
|
import { ChatSetupFlow } from './setup-flow.js';
|
|
@@ -360,6 +361,16 @@ export async function activate(context) {
|
|
|
360
361
|
const controls = await ChatHostControls.fromEnvironment();
|
|
361
362
|
const controlsChanged = new vscode.EventEmitter();
|
|
362
363
|
context.subscriptions.push(controlsChanged);
|
|
364
|
+
// The workbench's tools for the host's runtimes, on the endpoint the host names (ADR 0255).
|
|
365
|
+
if (controls) {
|
|
366
|
+
const workbenchTools = new WorkbenchTools();
|
|
367
|
+
context.subscriptions.push(workbenchTools);
|
|
368
|
+
const serveTools = (state) => {
|
|
369
|
+
workbenchTools.serve(state.workbenchTools).catch(error => log.warn(`Workbench tools unavailable: ${String(error)}`));
|
|
370
|
+
};
|
|
371
|
+
context.subscriptions.push({ dispose: controls.onState(serveTools) });
|
|
372
|
+
serveTools(controls.state);
|
|
373
|
+
}
|
|
363
374
|
// A person's explicit picker choice: per conversation once it is bound, and for the new chat before then.
|
|
364
375
|
let permission;
|
|
365
376
|
const permissions = new Map(context.workspaceState.get('supercode.sessionPermissions', []));
|
package/dist/host-controls.d.ts
CHANGED
|
@@ -79,15 +79,26 @@ export interface HostState {
|
|
|
79
79
|
/** Project policy for the next start/resume; an existing runtime uses its recorded session policy. */
|
|
80
80
|
newChatRuntimePolicy?: 'default' | 'yolo' | null;
|
|
81
81
|
runtimePolicyError?: string | null;
|
|
82
|
+
/** The workbench tools this host's runtimes reach (ADR 0255): the tag they carry, and the socket and token the host
|
|
83
|
+
* named, where their relay (`supercode mcp workbench`) calls them. Absent, they reach none. */
|
|
84
|
+
workbenchTools?: WorkbenchToolsEndpoint;
|
|
85
|
+
}
|
|
86
|
+
export interface WorkbenchToolsEndpoint {
|
|
87
|
+
tag: string;
|
|
88
|
+
socket: string;
|
|
89
|
+
token: string;
|
|
82
90
|
}
|
|
83
91
|
export interface HostSelectionResult extends HostState {
|
|
84
92
|
connection: Record<string, string>;
|
|
85
93
|
}
|
|
86
94
|
export declare class ChatHostControls {
|
|
95
|
+
#private;
|
|
87
96
|
readonly baseUrl: string;
|
|
88
97
|
private readonly credential;
|
|
89
98
|
state: HostState;
|
|
90
99
|
private updating;
|
|
100
|
+
/** Call `listener` with each state the host replies with; returns the unsubscribe. */
|
|
101
|
+
onState(listener: (state: HostState) => void): () => void;
|
|
91
102
|
private constructor();
|
|
92
103
|
static fromEnvironment(env?: NodeJS.ProcessEnv): Promise<ChatHostControls | undefined>;
|
|
93
104
|
refresh(): Promise<void>;
|
package/dist/host-controls.js
CHANGED
|
@@ -4,6 +4,12 @@ export class ChatHostControls {
|
|
|
4
4
|
credential;
|
|
5
5
|
state;
|
|
6
6
|
updating = Promise.resolve();
|
|
7
|
+
#stateListeners = new Set();
|
|
8
|
+
/** Call `listener` with each state the host replies with; returns the unsubscribe. */
|
|
9
|
+
onState(listener) {
|
|
10
|
+
this.#stateListeners.add(listener);
|
|
11
|
+
return () => this.#stateListeners.delete(listener);
|
|
12
|
+
}
|
|
7
13
|
constructor(baseUrl, credential, state) {
|
|
8
14
|
this.baseUrl = baseUrl;
|
|
9
15
|
this.credential = credential;
|
|
@@ -37,6 +43,8 @@ export class ChatHostControls {
|
|
|
37
43
|
const pending = this.updating.then(async () => {
|
|
38
44
|
const result = await this.request(path, selection);
|
|
39
45
|
this.state = result;
|
|
46
|
+
for (const listener of this.#stateListeners)
|
|
47
|
+
listener(result);
|
|
40
48
|
return result;
|
|
41
49
|
});
|
|
42
50
|
this.updating = pending.then(() => undefined, () => undefined);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as vscode from 'vscode';
|
|
2
|
+
import type { WorkbenchToolsEndpoint } from './host-controls.js';
|
|
3
|
+
export declare class WorkbenchTools implements vscode.Disposable {
|
|
4
|
+
#private;
|
|
5
|
+
/** Serve on the endpoint the host names, or nothing when it names none. A changed endpoint replaces the server.
|
|
6
|
+
* Calls apply in order, so two quick state replies cannot race a close against a listen. */
|
|
7
|
+
serve(endpoint: WorkbenchToolsEndpoint | undefined): Promise<void>;
|
|
8
|
+
private apply;
|
|
9
|
+
private answer;
|
|
10
|
+
private handle;
|
|
11
|
+
private close;
|
|
12
|
+
dispose(): void;
|
|
13
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The workbench's tools, for the harness agents in its Chat (ADR 0255).
|
|
3
|
+
*
|
|
4
|
+
* The host names the tools and where they run (`HostState.workbenchTools`: a tag, a socket and a token), and lists
|
|
5
|
+
* them to its runtimes itself, through `supercode mcp workbench`. That relay calls them here: this serves, in the
|
|
6
|
+
* extension host where `vscode.lm` exists, one call of a tool `vscode.lm.tools` lists with the tag, through
|
|
7
|
+
* Code-OSS's own tool service. With no endpoint it serves nothing.
|
|
8
|
+
*
|
|
9
|
+
* The wire is one JSON line each way per connection: `{token, name, input}` → `{text, isError}`.
|
|
10
|
+
*/
|
|
11
|
+
import { rmSync } from 'node:fs';
|
|
12
|
+
import { createServer } from 'node:net';
|
|
13
|
+
import * as vscode from 'vscode';
|
|
14
|
+
export class WorkbenchTools {
|
|
15
|
+
#served;
|
|
16
|
+
#applying = Promise.resolve();
|
|
17
|
+
/** Serve on the endpoint the host names, or nothing when it names none. A changed endpoint replaces the server.
|
|
18
|
+
* Calls apply in order, so two quick state replies cannot race a close against a listen. */
|
|
19
|
+
serve(endpoint) {
|
|
20
|
+
const applying = this.#applying.then(() => this.apply(endpoint));
|
|
21
|
+
this.#applying = applying.catch(() => undefined);
|
|
22
|
+
return applying;
|
|
23
|
+
}
|
|
24
|
+
async apply(endpoint) {
|
|
25
|
+
const current = this.#served?.endpoint;
|
|
26
|
+
if (current?.tag === endpoint?.tag && current?.socket === endpoint?.socket && current?.token === endpoint?.token)
|
|
27
|
+
return;
|
|
28
|
+
this.close();
|
|
29
|
+
if (!endpoint)
|
|
30
|
+
return;
|
|
31
|
+
// A socket left by an earlier extension host of this window is this window's own.
|
|
32
|
+
if (process.platform !== 'win32')
|
|
33
|
+
rmSync(endpoint.socket, { force: true });
|
|
34
|
+
const server = createServer(socket => this.answer(socket, endpoint));
|
|
35
|
+
await new Promise((resolve, reject) => { server.once('error', reject); server.listen(endpoint.socket, resolve); });
|
|
36
|
+
this.#served = { endpoint, server };
|
|
37
|
+
}
|
|
38
|
+
answer(socket, endpoint) {
|
|
39
|
+
let buffer = '';
|
|
40
|
+
socket.setEncoding('utf8');
|
|
41
|
+
socket.on('data', chunk => {
|
|
42
|
+
buffer += chunk;
|
|
43
|
+
const end = buffer.indexOf('\n');
|
|
44
|
+
if (end < 0)
|
|
45
|
+
return;
|
|
46
|
+
const line = buffer.slice(0, end);
|
|
47
|
+
buffer = '';
|
|
48
|
+
void this.handle(line, endpoint).then(reply => socket.end(`${JSON.stringify(reply)}\n`));
|
|
49
|
+
});
|
|
50
|
+
socket.on('error', () => socket.destroy());
|
|
51
|
+
}
|
|
52
|
+
async handle(line, { tag, token }) {
|
|
53
|
+
let request;
|
|
54
|
+
try {
|
|
55
|
+
request = JSON.parse(line);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return { text: 'The call was not JSON.', isError: true };
|
|
59
|
+
}
|
|
60
|
+
if (request.token !== token)
|
|
61
|
+
return { text: 'The call was refused.', isError: true };
|
|
62
|
+
const name = request.name;
|
|
63
|
+
if (typeof name !== 'string' || !vscode.lm.tools.some(tool => tool.name === name && tool.tags.includes(tag))) {
|
|
64
|
+
return { text: `The workbench has no tool ${String(name)}.`, isError: true };
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
const input = request.input && typeof request.input === 'object' ? request.input : {};
|
|
68
|
+
const result = await vscode.lm.invokeTool(name, { input, toolInvocationToken: undefined });
|
|
69
|
+
return { text: result.content.map(part => part instanceof vscode.LanguageModelTextPart ? part.value : '').join(''), isError: false };
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
return { text: error instanceof Error ? error.message : String(error), isError: true };
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
close() {
|
|
76
|
+
const served = this.#served;
|
|
77
|
+
this.#served = undefined;
|
|
78
|
+
served?.server.close();
|
|
79
|
+
}
|
|
80
|
+
dispose() { this.close(); }
|
|
81
|
+
}
|
package/package.json
CHANGED
|
@@ -1,14 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volter/supercode-frontend-vscode",
|
|
3
|
-
"devEngines": {
|
|
4
|
-
"packageManager": {
|
|
5
|
-
"name": "pnpm",
|
|
6
|
-
"version": ">=12.15.0",
|
|
7
|
-
"onFail": "error"
|
|
8
|
-
}
|
|
9
|
-
},
|
|
10
3
|
"displayName": "Volter Harness",
|
|
11
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.61",
|
|
12
5
|
"type": "module",
|
|
13
6
|
"description": "VS Code chat-view frontend for an existing Volter Harness SDK runtime",
|
|
14
7
|
"repository": {
|
|
@@ -34,6 +27,11 @@
|
|
|
34
27
|
"NOTICE.md",
|
|
35
28
|
"media"
|
|
36
29
|
],
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "node -e \"require('node:fs').rmSync('dist', {recursive:true, force:true})\" && node scripts/sync-sdk.mjs && node scripts/fetch-icon.mjs && node scripts/sync-marks.mjs && tsc -p tsconfig.build.json",
|
|
32
|
+
"extension": "npm run build && node scripts/pack-extension.mjs",
|
|
33
|
+
"prepack": "npm run build"
|
|
34
|
+
},
|
|
37
35
|
"engines": {
|
|
38
36
|
"node": ">=20",
|
|
39
37
|
"vscode": "^1.138.0"
|
|
@@ -214,9 +212,5 @@
|
|
|
214
212
|
"version": "0.2.12",
|
|
215
213
|
"mode": "generated-artifact"
|
|
216
214
|
},
|
|
217
|
-
"license": "MIT OR Apache-2.0"
|
|
218
|
-
|
|
219
|
-
"build": "node -e \"require('node:fs').rmSync('dist', {recursive:true, force:true})\" && node scripts/sync-sdk.mjs && node scripts/fetch-icon.mjs && node scripts/sync-marks.mjs && tsc -p tsconfig.build.json",
|
|
220
|
-
"extension": "pnpm run build && node scripts/pack-extension.mjs"
|
|
221
|
-
}
|
|
222
|
-
}
|
|
215
|
+
"license": "MIT OR Apache-2.0"
|
|
216
|
+
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volter/supercode-frontend",
|
|
3
|
-
"devEngines": { "packageManager": { "name": "pnpm", "version": ">=12.15.0", "onFail": "error" } },
|
|
4
3
|
"version": "0.2.12",
|
|
5
4
|
"type": "module",
|
|
6
5
|
"description": "Generated language-neutral attachment client for Volter Harness SDK runtimes",
|