release: v2.33.2 - Final polish and build

This commit is contained in:
g1nation
2026-05-01 18:13:49 +09:00
parent 250c998293
commit e91b0d9fb0
2 changed files with 183 additions and 21 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "g1nation",
"displayName": "G1nation",
"description": "High-performance autonomous local AI coding agent for VS Code. Features vectorized inference, asynchronous task management, and 100% offline processing.",
"version": "2.33.1",
"version": "2.33.2",
"publisher": "connectailab",
"license": "MIT",
"icon": "assets/icon.png",
+182 -20
View File
@@ -141,6 +141,12 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
case 'addBrain':
await this._addBrainProfile();
break;
case 'editBrain':
await this._editBrainProfile(data.id);
break;
case 'deleteBrain':
await this._deleteBrainProfile(data.id);
break;
case 'setBrainProfile':
await this._setActiveBrainProfile(data.id);
break;
@@ -150,6 +156,9 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
case 'updateAgent':
await this._updateAgent(data.path, data.content, data.negativePrompt);
break;
case 'deleteAgent':
await this._deleteAgent(data.path);
break;
case 'refreshModels':
await this._sendModels();
break;
@@ -449,6 +458,23 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
});
}
private _postBrainProfiles(profiles: any[], activeBrainId: string) {
if (!this._view) return;
this._view.webview.postMessage({
type: 'brainProfiles',
value: {
activeBrainId,
profiles: profiles.map((p: any) => ({
id: p.id || '',
name: p.name || '',
path: p.localBrainPath || '',
description: p.description || '',
repo: p.secondBrainRepo || ''
}))
}
});
}
private async _setActiveBrainProfile(profileId: string, silent: boolean = false) {
const profiles = getBrainProfiles();
const nextProfile = profiles.find((profile) => profile.id === profileId) || profiles[0];
@@ -555,28 +581,90 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
await cfg.update('activeBrainId', id, vscode.ConfigurationTarget.Global);
this._currentSessionBrainId = id;
// Directly post the freshly-built profile list to the webview.
// cfg.update() is async and VSCode's config cache may not reflect the new value
// immediately, so we avoid re-reading via getBrainProfiles() here.
if (this._view) {
this._view.webview.postMessage({
type: 'brainProfiles',
value: {
activeBrainId: id,
profiles: nextProfiles.map((p: any) => ({
id: p.id || '',
name: p.name || '',
path: p.localBrainPath || '',
description: p.description || '',
repo: p.secondBrainRepo || ''
}))
}
});
}
// immediately, so we post the freshly-built profile list directly.
this._postBrainProfiles(nextProfiles, id);
await this._sendBrainStatus();
this.injectSystemMessage(`**[Brain Added]** ${name.trim()}\n\`${folder}\``);
}
private async _editBrainProfile(profileId?: string) {
const currentProfiles = getBrainProfiles();
const target = currentProfiles.find((profile) => profile.id === profileId) || getActiveBrainProfile();
if (!target) return;
const name = await vscode.window.showInputBox({
prompt: 'Edit brain profile name',
value: target.name,
validateInput: (value) => value.trim() ? null : 'Brain name is required.'
});
if (!name) return;
const folder = await vscode.window.showInputBox({
prompt: 'Edit local brain folder path',
value: target.localBrainPath,
validateInput: (value) => value.trim() ? null : 'Brain folder path is required.'
});
if (!folder) return;
const description = await vscode.window.showInputBox({
prompt: 'Edit optional description shown in the G1nation sidebar',
value: target.description || ''
});
const repo = await vscode.window.showInputBox({
prompt: 'Edit optional Second Brain Git repository URL',
value: target.secondBrainRepo || ''
});
const nextProfiles = currentProfiles.map((profile) => profile.id === target.id
? {
...profile,
name: name.trim(),
localBrainPath: folder.trim(),
secondBrainRepo: (repo || '').trim(),
description: (description || '').trim()
}
: profile
);
const cfg = vscode.workspace.getConfiguration('g1nation');
await cfg.update('brainProfiles', nextProfiles, vscode.ConfigurationTarget.Global);
await cfg.update('activeBrainId', target.id, vscode.ConfigurationTarget.Global);
this._currentSessionBrainId = target.id;
this._postBrainProfiles(nextProfiles, target.id);
await this._sendBrainStatus();
this.injectSystemMessage(`**[Brain Updated]** ${name.trim()}\n\`${folder.trim()}\``);
}
private async _deleteBrainProfile(profileId?: string) {
const currentProfiles = getBrainProfiles();
const target = currentProfiles.find((profile) => profile.id === profileId) || getActiveBrainProfile();
if (!target) return;
if (currentProfiles.length <= 1) {
vscode.window.showWarningMessage('At least one brain profile is required.');
return;
}
const confirm = await vscode.window.showWarningMessage(
`Delete brain profile "${target.name}"? The folder itself will not be deleted.`,
{ modal: true },
'Delete Profile'
);
if (confirm !== 'Delete Profile') return;
const nextProfiles = currentProfiles.filter((profile) => profile.id !== target.id);
const nextActive = nextProfiles[0];
const cfg = vscode.workspace.getConfiguration('g1nation');
await cfg.update('brainProfiles', nextProfiles, vscode.ConfigurationTarget.Global);
await cfg.update('activeBrainId', nextActive.id, vscode.ConfigurationTarget.Global);
this._currentSessionBrainId = nextActive.id;
this._postBrainProfiles(nextProfiles, nextActive.id);
await this._sendBrainStatus();
this.injectSystemMessage(`**[Brain Deleted]** ${target.name}`);
}
// --- BridgeInterface Methods ---
public injectSystemMessage(msg: string): void {
@@ -741,6 +829,40 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
}
}
private async _deleteAgent(agentPath: string) {
if (!agentPath || agentPath === 'none') return;
try {
const agentsDir = path.resolve(this._getAgentsDir());
const targetPath = path.resolve(agentPath);
if (!targetPath.startsWith(`${agentsDir}${path.sep}`) || path.extname(targetPath) !== '.md') {
vscode.window.showErrorMessage('Selected agent skill path is not valid.');
return;
}
if (!fs.existsSync(targetPath)) {
await this._context.globalState.update(SidebarChatProvider.lastAgentStateKey, 'none');
await this._sendAgentsList();
return;
}
const confirm = await vscode.window.showWarningMessage(
`Delete agent skill "${path.basename(targetPath, '.md')}"?`,
{ modal: true },
'Delete Skill'
);
if (confirm !== 'Delete Skill') return;
fs.unlinkSync(targetPath);
await this._context.globalState.update(SidebarChatProvider.lastAgentStateKey, 'none');
await this._sendAgentsList();
this._view?.webview.postMessage({ type: 'agentDeleted' });
vscode.window.showInformationMessage('Agent skill deleted successfully.');
} catch (err: any) {
vscode.window.showErrorMessage(`Failed to delete agent: ${err.message}`);
}
}
private async _handlePrompt(data: any) {
if (!this._view) return;
@@ -942,6 +1064,7 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
.header-actions,
.tool-strip,
.tool-group,
.select-stack,
.select-line,
.status-pill {
@@ -951,6 +1074,13 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
.header-actions { gap: 6px; flex-shrink: 0; }
.tool-strip { gap: 6px; flex-wrap: wrap; }
.tool-group {
gap: 4px;
padding: 3px;
border: 1px solid var(--border);
border-radius: 8px;
background: rgba(255, 255, 255, 0.02);
}
.select-stack { flex-direction: column; gap: 6px; min-width: 0; }
.select-line { gap: 6px; width: 100%; min-width: 0; }
@@ -1465,11 +1595,19 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
</div>
</div>
<div class="tool-strip">
<button class="icon-btn" id="editAgentBtn" data-tooltip="Edit Agent Skill">✎</button>
<button class="icon-btn" id="addAgentBtn" data-tooltip="Create Agent">+</button>
<div class="tool-group" aria-label="Brain actions">
<button class="icon-btn" id="addBrainBtn" data-tooltip="Add Brain">+</button>
<button class="icon-btn" id="editBrainBtn" data-tooltip="Edit Brain">✎</button>
<button class="icon-btn" id="deleteBrainBtn" data-tooltip="Delete Brain"></button>
<button class="icon-btn" id="brainBtn" data-tooltip="Sync Knowledge">↻</button>
</div>
<div class="tool-group" aria-label="Agent actions">
<button class="icon-btn" id="addAgentBtn" data-tooltip="Create Agent">+</button>
<button class="icon-btn" id="editAgentBtn" data-tooltip="Edit Agent Skill">✎</button>
<button class="icon-btn" id="deleteAgentBtn" data-tooltip="Delete Agent Skill"></button>
</div>
<button class="icon-btn" id="multiAgentBtn" data-tooltip="Multi-Agent Mode">⧉</button>
<button class="icon-btn" id="internetBtn" data-tooltip="Internet Access">↗</button>
<button class="icon-btn" id="brainBtn" data-tooltip="Sync Knowledge">↻</button>
<button class="icon-btn" id="historyBtn" data-tooltip="View History">◷</button>
</div>
</div>
@@ -1653,6 +1791,10 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
const agentSel = document.getElementById('agentSel');
const editAgentBtn = document.getElementById('editAgentBtn');
const addAgentBtn = document.getElementById('addAgentBtn');
const deleteAgentBtn = document.getElementById('deleteAgentBtn');
const addBrainBtn = document.getElementById('addBrainBtn');
const editBrainBtn = document.getElementById('editBrainBtn');
const deleteBrainBtn = document.getElementById('deleteBrainBtn');
const agentConfigPanel = document.getElementById('agentConfigPanel');
const agentPrompt = document.getElementById('agentPrompt');
const negativePrompt = document.getElementById('negativePrompt');
@@ -1865,6 +2007,13 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
agentPrompt.value = msg.value;
negativePrompt.value = msg.negativePrompt || '';
break;
case 'agentDeleted':
agentConfigPanel.style.display = 'none';
editMode = false;
editAgentBtn.classList.remove('active');
agentPrompt.value = '';
negativePrompt.value = '';
break;
case 'error':
thinkingBar.classList.remove('active'); sendBtn.disabled = false;
addMsg(msg.value, 'error');
@@ -2018,6 +2167,15 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
const syncBrain = () => { Sound.play(550, 'sine', 0.1); vscode.postMessage({ type: 'syncBrain' }); };
document.getElementById('brainBtn').onclick = syncBrain;
addBrainBtn.onclick = () => vscode.postMessage({ type: 'addBrain' });
editBrainBtn.onclick = () => {
if (!brainSel.value || brainSel.value === 'new') return;
vscode.postMessage({ type: 'editBrain', id: brainSel.value });
};
deleteBrainBtn.onclick = () => {
if (!brainSel.value || brainSel.value === 'new') return;
vscode.postMessage({ type: 'deleteBrain', id: brainSel.value });
};
document.getElementById('inputSyncBtn').onclick = syncBrain;
document.getElementById('historyBtn').onclick = () => vscode.postMessage({ type: 'getSessions' });
document.getElementById('historyBtn').addEventListener('click', () => historyOverlay.classList.add('visible'));
@@ -2092,6 +2250,10 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
};
addAgentBtn.onclick = () => vscode.postMessage({ type: 'createAgent' });
deleteAgentBtn.onclick = () => {
if (agentSel.value === 'none') return;
vscode.postMessage({ type: 'deleteAgent', path: agentSel.value });
};
vscode.postMessage({ type: 'getModels' });
vscode.postMessage({ type: 'getAgents' });