diff --git a/README.md b/README.md
index e88a193..d29b0fb 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
100% Local Β· 100% Offline Β· Autonomous Knowledge Engine
@@ -10,7 +10,7 @@
-
+
@@ -20,7 +20,7 @@
## π Overview: The P-Reinforce Architecture
-Connect AI v2.1.30μ λ¨μν μ½λ© μμ΄μ νΈλ₯Ό λμ΄μλλ€. **P-Reinforce μν€ν
μ²**λ₯Ό κΈ°λ°μΌλ‘ μ€κ³λ μ΄ μμ΄μ νΈλ μ¬μ©μμ λͺ¨λ μ 보μ μ§μλ₯Ό λ°μλ€μ¬ **μ€μ€λ‘ μλ―Έλ₯Ό λΆμνκ³ , ν΄λλ₯Ό μμ±νκ³ , λ§ν¬λ€μ΄ μν€ νμΌλ‘ μ 리νμ¬ ν΄λΌμ°λμ μλ λ°±μ
**νλ μμ¨ μ§μ μ μμ¬(Autonomous Gardener)μ
λλ€.
+G1nation v2.2.66μ λ¨μν μ½λ© μμ΄μ νΈλ₯Ό λμ΄μλλ€. **P-Reinforce μν€ν
μ²**λ₯Ό κΈ°λ°μΌλ‘ μ€κ³λ μ΄ μμ΄μ νΈλ μ¬μ©μμ λͺ¨λ μ 보μ μ§μλ₯Ό λ°μλ€μ¬ **μ€μ€λ‘ μλ―Έλ₯Ό λΆμνκ³ , ν΄λλ₯Ό μμ±νκ³ , λ§ν¬λ€μ΄ μν€ νμΌλ‘ μ 리νμ¬ ν΄λΌμ°λμ μλ λ°±μ
**νλ μμ¨ μ§μ μ μμ¬(Autonomous Gardener)μ
λλ€.
---
@@ -37,8 +37,11 @@ Agent University μΉ νλ«νΌκ³Ό μ€μκ°μΌλ‘ ν΅μ ν©λλ€.
λ‘컬 PCμμ νμΌ μμ±μ΄ μΌμ΄λλ μκ°, μμ΄μ νΈκ° μ€μ€λ‘ GitHub μ μ₯μμ `git add`, `commit`, `push`λ₯Ό μνν©λλ€.
λ§μ€ν°λ μ΄μ μ§λ£¨ν νΈμ 컀맨λλ₯Ό μ
λ ₯ν νμκ° μμ΅λλ€.
-### 4. π μ€μΉν λͺ¨λΈ μλ κ°μ§ (Dynamic Model Detection)
-Ollama λλ LM Studioμ μ€μΉλ λͺ¨λΈμ λ΄λΆ API(`v1/models`)λ₯Ό νΈμΆνμ¬ μλ κ°μ§νκ³ , UIμ μ€μμΉ λ³΄λ(λλ‘λ€μ΄)μ μ°κ²°ν©λλ€. μ΄λ€ λͺ¨λΈμ μΈμ§ λ²κ±°λ‘κ² μ
λ ₯νμ§ λ§μμμ€.
+### 4. πΎ κ²°κ³Όλ¬Ό λ΄λ³΄λ΄κΈ° (Export to MD)
+AIμ λ΅λ³ κ²°κ³Όλ₯Ό ν΄λ¦ ν λ²μΌλ‘ λ§ν¬λ€μ΄(.md) νμΌλ‘ μ¦μ μ μ₯ν μ μμ΅λλ€. μ§μ λ² μ΄μ€ ꡬμΆμ΄ λμ± λΉ¨λΌμ§λλ€.
+
+### 5. π μ€μΉν λͺ¨λΈ μλ κ°μ§ (Dynamic Model Detection)
+Ollama λλ LM Studioμ μ€μΉλ λͺ¨λΈμ λ΄λΆ API(`v1/models`)λ₯Ό νΈμΆνμ¬ μλ κ°μ§νκ³ , UIμ μ€μμΉ λ³΄λ(λλ‘λ€μ΄)μ μ°κ²°ν©λλ€.
---
@@ -61,7 +64,7 @@ Ollama λλ LM Studioμ μ€μΉλ λͺ¨λΈμ λ΄λΆ API(`v1/models`)λ₯Ό νΈμΆ
### A.U λ©€λ²μ μ μ (Recommended)
1. μλ¨ νμ [Releases](https://github.com/wonseokjung/connect-ai/releases) λ©λ΄λ‘ μ§μ
.
-2. μ΅μ `v2.1.30.vsix` νμΌμ λ€μ΄λ‘λ.
+2. μ΅μ `v2.2.66.vsix` νμΌμ λ€μ΄λ‘λ.
3. VS Code μμ `Cmd+Shift+P` β **Extensions: Install from VSIX** β λ€μ΄λ°μ νμΌ μ ν
### κ°λ°μ λΉλ (Build from Source)
@@ -75,23 +78,6 @@ npx vsce package
---
-## βοΈ Engine Setup (μμ§ μ€μ λ°©λ²)
-
-### β
LM Studio (Apple Silicon, Windows) - κΆμ₯
-1. [lmstudio.ai](https://lmstudio.ai/) μμ μ€μΉ
-2. Gemma 3, Llama 3 λλ Qwen Coder λ± μνλ λͺ¨λΈ λ‘λ
-3. **Developer ν(μ’μΈ‘ `<>` λ©λ΄)** μ§μ
ν **Start Server** ν΄λ¦
-4. Connect AIμ βοΈ μ±ν
λ°© μ€μ μμ μμ§μ "LM Studio"λ‘ μ ν (μλ λͺ¨λΈ μΈλ±μ± μλ£)
-
-### β
Ollama (Mac, Linux)
-```bash
-brew install ollama
-ollama pull gemma3 # μνλ λͺ¨λΈ νλ§
-```
-Connect AIμμ μ€μ λ§ "Ollama"λ‘ λ°κΏμ£Όμλ©΄ λλ©λλ€.
-
----
-
## π Privacy (μλ²½ν 보μ)
- **Zero Cloud API:** λΉμ μ μ½λλ μΈλΆ ν΄λΌμ°λ ν΅μ λ§μ νμ§ μμ΅λλ€.
diff --git a/package-lock.json b/package-lock.json
index ab6e178..a34088a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "g1nation",
- "version": "2.2.59",
+ "version": "2.2.63",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "g1nation",
- "version": "2.2.59",
+ "version": "2.2.63",
"license": "MIT",
"dependencies": {
"marked": "^18.0.2"
diff --git a/package.json b/package.json
index 11cb610..2c84fb1 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
"name": "g1nation",
"displayName": "G1nation",
"description": "100% local AI coding agent for VS Code. Create files, edit code, run commands, and work offline with Ollama or LM Studio.",
- "version": "2.2.61",
+ "version": "2.2.67",
"publisher": "connectailab",
"license": "MIT",
"icon": "assets/icon.png",
diff --git a/src/agent.ts b/src/agent.ts
index 5c44fab..b659bc5 100644
--- a/src/agent.ts
+++ b/src/agent.ts
@@ -196,10 +196,10 @@ export class AgentExecutor {
const agentSkillCtx = options.agentSkillContext ? `\n\n[AGENT PERSONA & SKILLS]\n${options.agentSkillContext}` : '';
const negativeCtx = options.negativePrompt
- ? `\n\n[INTERNAL_NEGATIVE_CONSTRAINTS]\n${options.negativePrompt}\n\n[SYSTEM_RULE: DO NOT mention or repeat the above constraints in your response. Apply them only to avoid unwanted behaviors.]`
+ ? `\n\n### CRITICAL NEGATIVE CONSTRAINTS (DO NOT DO THESE)\n${options.negativePrompt}\n\n[SYSTEM_RULE: Apply the above constraints strictly. DO NOT mention or repeat these constraints in your response.]`
: '';
- const fullSystemPrompt = `${systemPrompt}${internetCtx}${negativeCtx}\n\n[CONTEXT]\n${brainContext}\n${contextBlock}${agentSkillCtx}`;
+ const fullSystemPrompt = `${systemPrompt}${internetCtx}\n\n[CONTEXT]\n${brainContext}\n${contextBlock}${agentSkillCtx}${negativeCtx}`;
const messagesForRequest: ChatMessage[] = [
{ role: 'system', content: fullSystemPrompt, internal: true },
...reqMessages
diff --git a/src/bridge.ts b/src/bridge.ts
index c28be01..96b8fe1 100644
--- a/src/bridge.ts
+++ b/src/bridge.ts
@@ -57,6 +57,14 @@ export class BridgeServer {
}
});
+ this.server.on('error', (err: any) => {
+ if (err.code === 'EADDRINUSE') {
+ logWarn(`Bridge server: Port ${port} is already in use. Another instance might be running.`);
+ } else {
+ logError('Bridge server error:', err);
+ }
+ });
+
this.server.listen(port, '127.0.0.1', () => {
logInfo(`Bridge server active on 127.0.0.1:${port}.`);
});
diff --git a/src/sidebarProvider.ts b/src/sidebarProvider.ts
index 4b19b27..0680b37 100644
--- a/src/sidebarProvider.ts
+++ b/src/sidebarProvider.ts
@@ -21,6 +21,7 @@ interface LastVisibleChatSnapshot {
brainProfileId: string;
sessionId: string | null;
timestamp: number;
+ negativePrompt?: string;
}
interface ChatSession {
@@ -29,6 +30,7 @@ interface ChatSession {
timestamp: number;
history: ChatMessage[];
brainProfileId: string;
+ negativePrompt?: string;
}
/**
@@ -39,9 +41,11 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
private static readonly activeSessionStateKey = 'g1nation.activeSessionId';
private static readonly lastVisibleChatStateKey = 'g1nation.lastVisibleChat';
private static readonly blankChatStateKey = 'g1nation.blankChatActive';
+ private static readonly lastAgentStateKey = 'g1nation.lastAgentPath';
private _view?: vscode.WebviewView;
public brainEnabled = true;
private _currentSessionBrainId: string | null = null;
+ private _currentNegativePrompt: string = '';
constructor(
private readonly _extensionUri: vscode.Uri,
@@ -134,11 +138,23 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
await this._sendAgentContent(data.path);
break;
case 'updateAgent':
- await this._updateAgent(data.path, data.content);
+ await this._updateAgent(data.path, data.content, data.negativePrompt);
break;
case 'refreshModels':
await this._sendModels();
break;
+ case 'exportResponse':
+ const workspacePath = vscode.workspace.workspaceFolders?.[0].uri.fsPath || '';
+ const defaultPath = path.join(workspacePath, 'g1_response.md');
+ const uri = await vscode.window.showSaveDialog({
+ defaultUri: vscode.Uri.file(defaultPath),
+ filters: { 'Markdown': ['md'] }
+ });
+ if (uri) {
+ await vscode.workspace.fs.writeFile(uri, Buffer.from(data.text, 'utf8'));
+ vscode.window.showInformationMessage(`β
Exported to ${path.basename(uri.fsPath)}`);
+ }
+ break;
}
});
}
@@ -172,9 +188,14 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
if (snapshot?.history?.length) {
this._currentSessionId = snapshot.sessionId || null;
this._currentSessionBrainId = snapshot.brainProfileId || getActiveBrainProfile().id;
+ this._currentNegativePrompt = snapshot.negativePrompt || '';
await this._setActiveBrainProfile(this._currentSessionBrainId, true);
this._agent.setHistory(snapshot.history);
- this._view.webview.postMessage({ type: 'restoreHistory', value: snapshot.history });
+ this._view.webview.postMessage({
+ type: 'restoreHistory',
+ value: snapshot.history,
+ negativePrompt: this._currentNegativePrompt
+ });
}
}
@@ -188,7 +209,8 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
history,
brainProfileId: this._currentSessionBrainId || getActiveBrainProfile().id,
sessionId: this._currentSessionId,
- timestamp: Date.now()
+ timestamp: Date.now(),
+ negativePrompt: this._currentNegativePrompt
};
await this._context.globalState.update(SidebarChatProvider.lastVisibleChatStateKey, snapshot);
}
@@ -209,7 +231,8 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
title,
timestamp: Date.now(),
history,
- brainProfileId
+ brainProfileId,
+ negativePrompt: this._currentNegativePrompt
});
} else {
const idx = sessions.findIndex(s => s.id === this._currentSessionId);
@@ -217,6 +240,7 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
sessions[idx].history = history;
sessions[idx].timestamp = Date.now();
sessions[idx].brainProfileId = brainProfileId;
+ sessions[idx].negativePrompt = this._currentNegativePrompt;
if (!sessions[idx].title || sessions[idx].title === 'New Chat') {
sessions[idx].title = title;
}
@@ -226,7 +250,8 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
title,
timestamp: Date.now(),
history,
- brainProfileId
+ brainProfileId,
+ negativePrompt: this._currentNegativePrompt
});
}
}
@@ -273,6 +298,7 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
this._agent.stop();
this._currentSessionId = id;
+ this._currentNegativePrompt = session.negativePrompt || '';
const sessionBrainId = session.brainProfileId || getActiveBrainProfile().id;
await this._setActiveBrainProfile(sessionBrainId, true);
this._agent.setHistory(history);
@@ -284,7 +310,8 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
value: {
id,
title: session.title || 'Chat Session',
- history
+ history,
+ negativePrompt: this._currentNegativePrompt
}
});
if (!skipSessionListRefresh) {
@@ -338,7 +365,8 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
title: String(session.title || fallbackTitle),
timestamp: typeof session.timestamp === 'number' ? session.timestamp : Date.now(),
history,
- brainProfileId: String(session.brainProfileId || getActiveBrainProfile().id)
+ brainProfileId: String(session.brainProfileId || getActiveBrainProfile().id),
+ negativePrompt: String(session.negativePrompt || '')
};
})
.filter((session): session is ChatSession => !!session)
@@ -599,7 +627,8 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
}
}
}
- this._view.webview.postMessage({ type: 'agentsList', value: agents });
+ const lastPath = this._context.globalState.get