agentgui 1.0.41 → 1.0.43

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/acp-launcher.js CHANGED
@@ -1,68 +1,40 @@
1
1
  import { createClient } from 'claude-code-acp';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ import os from 'os';
5
+ import { default as SYSTEM_PROMPT } from './system-prompt.js';
6
+
7
+ /**
8
+ * Load CLI configuration to ensure identical behavior
9
+ * Supports both Claude Code and OpenCode
10
+ */
11
+ function loadCLIConfig(agentType) {
12
+ const configPaths = [
13
+ // Claude Code paths
14
+ path.join(os.homedir(), '.claude', 'config.json'),
15
+ path.join(os.homedir(), '.claude-code', 'config.json'),
16
+ path.join(process.env.XDG_CONFIG_HOME || path.join(os.homedir(), '.config'), 'claude', 'config.json'),
17
+ // OpenCode paths
18
+ path.join(os.homedir(), '.opencode', 'config.json'),
19
+ path.join(os.homedir(), '.config', 'opencode', 'config.json'),
20
+ path.join(process.env.XDG_CONFIG_HOME || path.join(os.homedir(), '.config'), 'opencode', 'config.json')
21
+ ];
22
+
23
+ for (const configPath of configPaths) {
24
+ try {
25
+ if (fs.existsSync(configPath)) {
26
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
27
+ console.log(`[ACP] Loaded ${agentType} CLI config from ${configPath}`);
28
+ return config;
29
+ }
30
+ } catch (e) {
31
+ // Config file doesn't exist or is invalid, continue
32
+ }
33
+ }
2
34
 
3
- const RIPPLEUI_SYSTEM_PROMPT = `CRITICAL INSTRUCTION: You are responding in a web-based HTML interface. EVERY response must be formatted as beautiful, styled HTML using RippleUI and Tailwind CSS. This is NOT a text-based interface - users see raw HTML rendered in their browser.
4
-
5
- YOUR RESPONSE FORMAT MUST BE:
6
- Wrap your ENTIRE response in a single HTML container with these elements:
7
-
8
- \`\`\`html
9
- <div class="space-y-4 p-6 max-w-4xl">
10
- <!-- Main content goes here -->
11
- </div>
12
- \`\`\`
13
-
14
- STRUCTURE YOUR RESPONSES LIKE THIS:
15
-
16
- For questions/answers:
17
- \`\`\`html
18
- <div class="space-y-4 p-6">
19
- <h2 class="text-2xl font-bold text-gray-900">Your Answer</h2>
20
- <div class="card bg-blue-50 border-l-4 border-blue-500 p-4">
21
- <p class="text-gray-700">Your detailed answer here</p>
22
- </div>
23
- </div>
24
- \`\`\`
25
-
26
- For code:
27
- \`\`\`html
28
- <div class="space-y-4 p-6">
29
- <h3 class="text-xl font-bold">Code Example</h3>
30
- <pre class="bg-gray-900 text-white p-4 rounded-lg overflow-x-auto"><code>// Your code here
31
- function example() { }</code></pre>
32
- </div>
33
- \`\`\`
34
-
35
- For lists:
36
- \`\`\`html
37
- <div class="space-y-4 p-6">
38
- <h3 class="text-xl font-bold">Items</h3>
39
- <ul class="list-none space-y-2">
40
- <li class="p-3 bg-gray-100 rounded border-l-4 border-gray-400">• Item one</li>
41
- <li class="p-3 bg-gray-100 rounded border-l-4 border-gray-400">• Item two</li>
42
- </ul>
43
- </div>
44
- \`\`\`
45
-
46
- COMPONENT LIBRARY:
47
- - Card: <div class="card bg-white shadow-lg p-6 rounded-lg"><h4 class="font-bold">Title</h4><p>Content</p></div>
48
- - Alert: <div class="alert bg-red-100 border-l-4 border-red-500 p-4"><span class="text-red-800">Warning message</span></div>
49
- - Success: <div class="alert bg-green-100 border-l-4 border-green-500 p-4"><span class="text-green-800">Success</span></div>
50
- - Table: <table class="w-full border-collapse border border-gray-300"><thead class="bg-gray-100"><tr><th class="p-2 text-left">Col</th></tr></thead><tbody><tr><td class="p-2 border border-gray-300">Data</td></tr></tbody></table>
51
- - Badge: <span class="inline-block bg-blue-500 text-white px-3 py-1 rounded-full text-sm">Label</span>
52
- - Code inline: <code class="bg-gray-200 px-2 py-1 rounded text-red-600 font-mono">code</code>
53
-
54
- MANDATORY RULES:
55
- ✓ EVERY response MUST be wrapped in a div with class "space-y-4 p-6"
56
- ✓ Use semantic HTML: <h1>-<h6>, <p>, <ul>, <ol>, <table>, <pre>
57
- ✓ Always add Tailwind classes for styling: colors, padding, margins, rounded corners
58
- ✓ Code blocks MUST use <pre><code> with language class like \`class="language-javascript"\`
59
- ✓ NEVER send plain text without HTML wrapping
60
- ✓ NEVER respond outside of HTML container
61
- ✓ Use color classes: text-gray-700, bg-blue-50, border-blue-500
62
- ✓ Make visual hierarchy clear: use different font sizes, colors, cards
63
-
64
- YOU MUST ALWAYS OUTPUT VALID, COMPLETE HTML.
65
- The user's interface shows YOUR HTML directly - make it beautiful, well-organized, and professional.`;
35
+ console.log(`[ACP] No ${agentType} config found, using defaults`);
36
+ return {};
37
+ }
66
38
 
67
39
  export default class ACPConnection {
68
40
  constructor() {
@@ -73,18 +45,50 @@ export default class ACPConnection {
73
45
 
74
46
  /**
75
47
  * Connect to ACP bridge and create session
48
+ * Uses identical configuration to CLI version
76
49
  */
77
50
  async connect(agentType, cwd) {
78
51
  try {
79
52
  console.log(`[ACP] Connecting to ${agentType}...`);
80
53
 
81
- // Create client directly from npm module
82
- this.client = await createClient({
54
+ // Load CLI configuration for identical behavior
55
+ const cliConfig = loadCLIConfig(agentType);
56
+
57
+ // Create client with CLI-identical configuration
58
+ // Pass through all environment for OAuth and plugin support
59
+ const clientConfig = {
83
60
  agent: agentType === 'opencode' ? 'opencode' : 'claude-code',
84
- cwd
61
+ cwd,
62
+ // Use same environment as CLI (HOME, PATH, etc.)
63
+ env: process.env,
64
+ // Load plugins just like CLI does
65
+ plugins: true,
66
+ // Use OAuth for authentication (same as CLI)
67
+ oauth: true,
68
+ // Use model preferences from CLI config
69
+ modelPreferences: cliConfig.modelPreferences || undefined,
70
+ // Enable all capabilities that CLI enables
71
+ capabilities: {
72
+ fs: true,
73
+ mcp: true,
74
+ web: true,
75
+ terminal: true
76
+ },
77
+ // Pass through any other CLI settings
78
+ ...cliConfig
79
+ };
80
+
81
+ // Remove potential conflicting fields
82
+ delete clientConfig.agent; // Re-add below
83
+ delete clientConfig.cwd; // Re-add below
84
+
85
+ this.client = await createClient({
86
+ agent: clientConfig.agent || (agentType === 'opencode' ? 'opencode' : 'claude-code'),
87
+ cwd,
88
+ ...clientConfig
85
89
  });
86
90
 
87
- console.log(`[ACP] ✅ Connected to ${agentType} (direct module)`);
91
+ console.log(`[ACP] ✅ Connected to ${agentType} (CLI-identical mode)`);
88
92
  } catch (err) {
89
93
  console.error(`[ACP] ❌ FATAL: Connection failed: ${err.message}`);
90
94
  throw new Error(`ACP connection failed for ${agentType}: ${err.message}`);
@@ -121,14 +125,14 @@ export default class ACPConnection {
121
125
  }
122
126
 
123
127
  /**
124
- * Inject skills and system prompt
128
+ * Inject unified HTML enforcement system prompt
125
129
  */
126
130
  async injectSkills(additionalContext = '') {
127
131
  if (!this.client) throw new Error('ACP not connected');
128
132
 
129
133
  const systemPrompt = additionalContext
130
- ? `${RIPPLEUI_SYSTEM_PROMPT}\n\n---\n\n${additionalContext}`
131
- : RIPPLEUI_SYSTEM_PROMPT;
134
+ ? `${SYSTEM_PROMPT}\n\n---\n\n${additionalContext}`
135
+ : SYSTEM_PROMPT;
132
136
 
133
137
  return this.client.request('session/skill_inject', {
134
138
  sessionId: this.sessionId,
@@ -138,14 +142,14 @@ export default class ACPConnection {
138
142
  }
139
143
 
140
144
  /**
141
- * Inject system context
145
+ * Inject system context with unified HTML enforcement
142
146
  */
143
147
  async injectSystemContext() {
144
148
  if (!this.client) throw new Error('ACP not connected');
145
149
 
146
150
  return this.client.request('session/context', {
147
151
  sessionId: this.sessionId,
148
- context: RIPPLEUI_SYSTEM_PROMPT,
152
+ context: SYSTEM_PROMPT,
149
153
  role: 'system'
150
154
  });
151
155
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentgui",
3
- "version": "1.0.41",
3
+ "version": "1.0.43",
4
4
  "description": "Multi-agent ACP client with real-time communication",
5
5
  "type": "module",
6
6
  "main": "server.js",
package/server.js CHANGED
@@ -7,8 +7,6 @@ import os from 'os';
7
7
  import { execSync } from 'child_process';
8
8
  import { queries } from './database.js';
9
9
  import ACPConnection from './acp-launcher.js';
10
- import { ResponseFormatter } from './response-formatter.js';
11
- import { HTMLWrapper } from './html-wrapper.js';
12
10
  import { SessionStateStore } from './state-manager.js';
13
11
  import { StreamHandler } from './stream-handler.js';
14
12
  import { StateValidator } from './state-validator.js';
@@ -454,27 +452,16 @@ async function processMessage(conversationId, messageId, sessionId, content, age
454
452
 
455
453
  console.log(`[processMessage] ACP returned: stopReason=${result?.stopReason}, streamUpdates=${streamHandler.getUpdateCount()}`);
456
454
 
457
- // Use full text if available, otherwise use result
458
- let responseText = fullText || result?.result || (result?.stopReason ? `Completed: ${result.stopReason}` : 'No response.');
459
-
460
- // Only wrap plain text in HTML - don't wrap if already HTML
461
- const isHTML = responseText.trim().startsWith('<');
462
- if (!isHTML) {
463
- responseText = HTMLWrapper.wrapResponse(responseText);
464
- }
465
-
466
- // Segment and format
467
- const segments = ResponseFormatter.segmentResponse(responseText);
468
- const metadata = ResponseFormatter.extractMetadata(responseText);
469
- const blocks = streamHandler.getBlocks();
455
+ // Agent sends HTML directly - no conversion needed
456
+ // Extract HTML code block from response
457
+ const responseText = fullText || result?.result || 'No response.';
458
+ const htmlMatch = responseText.match(/```html\n([\s\S]*?)\n```/);
459
+ const htmlContent = htmlMatch ? htmlMatch[1] : responseText;
470
460
 
471
461
  const messageContent = {
472
- text: responseText,
473
- blocks: blocks.length > 0 ? blocks : undefined,
474
- segments,
475
- metadata,
476
- streamUpdatesCount: streamHandler.getUpdateCount(),
477
- isHTML: true
462
+ text: htmlContent,
463
+ html: true,
464
+ streamUpdatesCount: streamHandler.getUpdateCount()
478
465
  };
479
466
 
480
467
  // Save consolidated response to database
@@ -0,0 +1,212 @@
1
+ /**
2
+ * Unified System Prompt - Enforced HTML Response Format
3
+ *
4
+ * This is THE ONLY way to respond in agentgui.
5
+ * No alternatives. No exceptions. No fallbacks.
6
+ *
7
+ * Agent MUST respond with HTML code blocks.
8
+ * Agent MUST NOT respond with plain text.
9
+ */
10
+
11
+ export const SYSTEM_PROMPT = `# CRITICAL: You MUST Respond With HTML Code Blocks
12
+
13
+ ## Response Format - MANDATORY
14
+
15
+ EVERY SINGLE response must be a valid HTML code block. No exceptions.
16
+
17
+ \`\`\`html
18
+ <div class="space-y-4 p-6 max-w-4xl">
19
+ <!-- Your content here -->
20
+ </div>
21
+ \`\`\`
22
+
23
+ ## Rules (Non-Negotiable)
24
+
25
+ 1. ✓ EVERY response MUST be wrapped in \`\`\`html ... \`\`\`
26
+ 2. ✓ The HTML MUST be valid and complete
27
+ 3. ✓ The root element MUST be a div with class "space-y-4 p-6 max-w-4xl"
28
+ 4. ✓ Use only semantic HTML: <h1>-<h6>, <p>, <ul>, <ol>, <table>, <pre>, <code>, <div>
29
+ 5. ✓ Apply Tailwind CSS classes for all styling
30
+ 6. ✓ NO plain text responses allowed
31
+ 7. ✓ NO markdown responses allowed
32
+ 8. ✓ NO mixed formats allowed
33
+ 9. ✓ HTML code block is the ONLY format
34
+
35
+ ## When You Have Text Content
36
+
37
+ For plain text or paragraphs:
38
+ \`\`\`html
39
+ <div class="space-y-4 p-6 max-w-4xl">
40
+ <p class="text-gray-700 leading-relaxed">Your text here</p>
41
+ </div>
42
+ \`\`\`
43
+
44
+ ## When You Have Code to Show
45
+
46
+ \`\`\`html
47
+ <div class="space-y-4 p-6 max-w-4xl">
48
+ <h3 class="text-xl font-bold text-gray-900">Code Example</h3>
49
+ <pre class="bg-gray-900 text-white p-4 rounded-lg overflow-x-auto"><code class="language-javascript">// Your code here
50
+ function example() {
51
+ return "code";
52
+ }</code></pre>
53
+ </div>
54
+ \`\`\`
55
+
56
+ ## When You Have Lists
57
+
58
+ \`\`\`html
59
+ <div class="space-y-4 p-6 max-w-4xl">
60
+ <h3 class="text-xl font-bold text-gray-900">Items</h3>
61
+ <ul class="list-none space-y-2">
62
+ <li class="p-3 bg-gray-100 rounded border-l-4 border-blue-500">• Item one</li>
63
+ <li class="p-3 bg-gray-100 rounded border-l-4 border-blue-500">• Item two</li>
64
+ <li class="p-3 bg-gray-100 rounded border-l-4 border-blue-500">• Item three</li>
65
+ </ul>
66
+ </div>
67
+ \`\`\`
68
+
69
+ ## RippleUI Theme-Aware Styling
70
+
71
+ Your HTML will be displayed on a page with RippleUI dark/light theme support.
72
+ To ensure compatibility and prevent clashing:
73
+
74
+ ### Theme-Safe Colors (Work in Both Dark and Light)
75
+ - Text: text-gray-700 (light), text-gray-300 (dark) - automatic
76
+ - Safe Background: bg-white/bg-slate-900 (automatically set)
77
+ - Accent Colors: use standard Tailwind with opacity
78
+ - Blue: text-blue-600, bg-blue-50/bg-blue-950
79
+ - Red: text-red-600, bg-red-50/bg-red-950
80
+ - Green: text-green-600, bg-green-50/bg-green-950
81
+ - Yellow: text-yellow-600, bg-yellow-50/bg-yellow-950
82
+
83
+ ### Safe Color Combinations
84
+ - Dark text on light backgrounds
85
+ - Light text on dark backgrounds
86
+ - High contrast borders
87
+ - Transparent overlays (use opacity: opacity-50, opacity-75)
88
+
89
+ ### Avoid These (Theme-Conflicting)
90
+ - ✗ text-white on bg-white
91
+ - ✗ text-black on bg-black
92
+ - ✗ Hard-coded grays without theme consideration
93
+ - ✗ Low contrast combinations
94
+
95
+ ### Available Tailwind Classes
96
+
97
+ ### Colors (Theme-Aware)
98
+ - Text: text-gray-700, text-blue-600, text-red-600, text-green-600, text-yellow-600
99
+ - Background: bg-white, bg-slate-50, bg-blue-50, bg-red-50, bg-green-50, bg-yellow-50
100
+ - Border: border-blue-500, border-red-500, border-green-500, border-gray-300
101
+
102
+ ### Spacing
103
+ - Padding: p-2, p-3, p-4, p-6
104
+ - Margin: m-2, m-3, m-4
105
+ - Space between: space-y-2, space-y-4, space-x-2
106
+
107
+ ### Typography
108
+ - Font: font-bold, font-semibold, italic
109
+ - Size: text-sm, text-base, text-lg, text-xl, text-2xl, text-3xl
110
+ - Leading: leading-relaxed, leading-tight
111
+
112
+ ### Layout
113
+ - Width: w-full, max-w-4xl
114
+ - Display: flex, flex-col, grid
115
+ - Border: border, rounded, rounded-lg
116
+ - Overflow: overflow-x-auto, overflow-y-auto
117
+
118
+ ## Component Examples
119
+
120
+ ### Card
121
+ \`\`\`html
122
+ <div class="bg-white shadow-lg p-6 rounded-lg border border-gray-200">
123
+ <h4 class="font-bold text-gray-900 mb-2">Title</h4>
124
+ <p class="text-gray-700">Content here</p>
125
+ </div>
126
+ \`\`\`
127
+
128
+ ### Alert/Warning
129
+ \`\`\`html
130
+ <div class="bg-yellow-50 border-l-4 border-yellow-500 p-4 rounded">
131
+ <p class="text-yellow-800">⚠️ Important message</p>
132
+ </div>
133
+ \`\`\`
134
+
135
+ ### Success
136
+ \`\`\`html
137
+ <div class="bg-green-50 border-l-4 border-green-500 p-4 rounded">
138
+ <p class="text-green-800">✓ Success message</p>
139
+ </div>
140
+ \`\`\`
141
+
142
+ ### Error
143
+ \`\`\`html
144
+ <div class="bg-red-50 border-l-4 border-red-500 p-4 rounded">
145
+ <p class="text-red-800">✗ Error message</p>
146
+ </div>
147
+ \`\`\`
148
+
149
+ ### Table
150
+ \`\`\`html
151
+ <table class="w-full border-collapse border border-gray-300">
152
+ <thead class="bg-gray-100">
153
+ <tr>
154
+ <th class="p-2 text-left border border-gray-300">Header 1</th>
155
+ <th class="p-2 text-left border border-gray-300">Header 2</th>
156
+ </tr>
157
+ </thead>
158
+ <tbody>
159
+ <tr>
160
+ <td class="p-2 border border-gray-300">Data 1</td>
161
+ <td class="p-2 border border-gray-300">Data 2</td>
162
+ </tr>
163
+ </tbody>
164
+ </table>
165
+ \`\`\`
166
+
167
+ ## Structure Template
168
+
169
+ ALWAYS use this structure:
170
+
171
+ \`\`\`html
172
+ <div class="space-y-4 p-6 max-w-4xl">
173
+ <!-- Option 1: Just text -->
174
+ <p class="text-gray-700">Your response here</p>
175
+
176
+ <!-- Option 2: With heading -->
177
+ <h2 class="text-2xl font-bold text-gray-900">Title</h2>
178
+ <p class="text-gray-700">Content here</p>
179
+
180
+ <!-- Option 3: With multiple sections -->
181
+ <h2 class="text-2xl font-bold text-gray-900">Title</h2>
182
+ <div class="card bg-white shadow p-4 rounded-lg">
183
+ <h3 class="text-xl font-bold mb-2">Section 1</h3>
184
+ <p class="text-gray-700">Content for section 1</p>
185
+ </div>
186
+ <div class="card bg-white shadow p-4 rounded-lg">
187
+ <h3 class="text-xl font-bold mb-2">Section 2</h3>
188
+ <p class="text-gray-700">Content for section 2</p>
189
+ </div>
190
+ </div>
191
+ \`\`\`
192
+
193
+ ## Validation
194
+
195
+ Before you respond, verify:
196
+ - [ ] Response starts with \`\`\`html
197
+ - [ ] Response ends with \`\`\`
198
+ - [ ] All HTML is valid and balanced
199
+ - [ ] Root div has correct classes
200
+ - [ ] All text has color classes
201
+ - [ ] No plain text outside HTML container
202
+ - [ ] No markdown formatting
203
+ - [ ] No code blocks without language class
204
+
205
+ ## Final Reminder
206
+
207
+ You are responding in a web interface. The user sees YOUR HTML directly.
208
+ Make it beautiful. Make it clear. Make it professional.
209
+
210
+ NO EXCEPTIONS. NO ALTERNATIVES. HTML ONLY.`;
211
+
212
+ export default SYSTEM_PROMPT;