glad-web 1.0.12 → 1.0.14
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 +2 -1
- package/README.zh-CN.md +2 -1
- package/lib/ai-tools/registry.js +9 -0
- package/lib/commands/web.js +6 -5
- package/lib/session/pty-manager.js +1 -1
- package/lib/session/session-manager.js +38 -0
- package/lib/web/index.html +15 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -122,7 +122,7 @@ glad tools detect
|
|
|
122
122
|
|
|
123
123
|
## Supported Tools
|
|
124
124
|
|
|
125
|
-
Glad currently auto-detects the
|
|
125
|
+
Glad currently auto-detects the 21 terminal AI tools defined in the code registry. The names below are the registry `displayName` values used by Glad:
|
|
126
126
|
|
|
127
127
|
| Tool | Detected command |
|
|
128
128
|
| --- | --- |
|
|
@@ -132,6 +132,7 @@ Glad currently auto-detects the 20 terminal AI tools defined in the code registr
|
|
|
132
132
|
| Copilot | `copilot` |
|
|
133
133
|
| Cody | `cody chat` |
|
|
134
134
|
| Gemini | `gemini` |
|
|
135
|
+
| Antigravity | `agy` |
|
|
135
136
|
| Continue | `cn` |
|
|
136
137
|
| Cursor | `cursor-agent` |
|
|
137
138
|
| ChatGPT | `chatgpt` |
|
package/README.zh-CN.md
CHANGED
|
@@ -122,7 +122,7 @@ glad tools detect
|
|
|
122
122
|
|
|
123
123
|
## 支持的工具
|
|
124
124
|
|
|
125
|
-
Glad 当前会自动检测代码注册表中定义的
|
|
125
|
+
Glad 当前会自动检测代码注册表中定义的 21 个终端 AI 工具。下面的名称严格使用 Glad 注册表里的 `displayName`:
|
|
126
126
|
|
|
127
127
|
| 工具 | 检测命令 |
|
|
128
128
|
| --- | --- |
|
|
@@ -132,6 +132,7 @@ Glad 当前会自动检测代码注册表中定义的 20 个终端 AI 工具。
|
|
|
132
132
|
| Copilot | `copilot` |
|
|
133
133
|
| Cody | `cody chat` |
|
|
134
134
|
| Gemini | `gemini` |
|
|
135
|
+
| Antigravity | `agy` |
|
|
135
136
|
| Continue | `cn` |
|
|
136
137
|
| Cursor | `cursor-agent` |
|
|
137
138
|
| ChatGPT | `chatgpt` |
|
package/lib/ai-tools/registry.js
CHANGED
|
@@ -68,6 +68,15 @@ const AI_TOOLS = {
|
|
|
68
68
|
website: 'https://developers.google.com/gemini-code-assist',
|
|
69
69
|
checkInstalled: async () => await commandExists('gemini')
|
|
70
70
|
},
|
|
71
|
+
'antigravity': {
|
|
72
|
+
key: 'antigravity',
|
|
73
|
+
command: 'agy',
|
|
74
|
+
args: [],
|
|
75
|
+
displayName: 'Antigravity',
|
|
76
|
+
description: 'Google Antigravity CLI for local agentic coding workflows',
|
|
77
|
+
website: 'https://antigravity.google/docs/cli-overview',
|
|
78
|
+
checkInstalled: async () => await commandExists('agy')
|
|
79
|
+
},
|
|
71
80
|
'continue': {
|
|
72
81
|
key: 'continue',
|
|
73
82
|
command: 'cn',
|
package/lib/commands/web.js
CHANGED
|
@@ -349,11 +349,12 @@ async function webCommand(options) {
|
|
|
349
349
|
}
|
|
350
350
|
sessionManager.logWsConnected(sessionId, req);
|
|
351
351
|
|
|
352
|
-
// Send catchup buffer
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
352
|
+
// Send catchup output. TUI tools may skip the raw circular buffer, so fall
|
|
353
|
+
// back to the rendered/text history snapshot instead of reconnecting blank.
|
|
354
|
+
const catchup = sessionManager.getCatchupOutput(sessionId);
|
|
355
|
+
if (catchup && catchup.data) {
|
|
356
|
+
sessionManager.logWsCatchupOutput(sessionId, catchup);
|
|
357
|
+
ws.send(JSON.stringify({ type: 'output', data: catchup.data }));
|
|
357
358
|
}
|
|
358
359
|
|
|
359
360
|
ws.on('message', (message) => {
|
|
@@ -23,7 +23,7 @@ class PTYManager {
|
|
|
23
23
|
this.onExitCallback = null;
|
|
24
24
|
this.localResizeListener = null;
|
|
25
25
|
|
|
26
|
-
this.tuiTools = ['opencode', 'kilo'];
|
|
26
|
+
this.tuiTools = ['antigravity', 'opencode', 'kilo'];
|
|
27
27
|
this.isTUIMode = this.tuiTools.includes(tool.key);
|
|
28
28
|
|
|
29
29
|
this.recentOutputs = [];
|
|
@@ -192,6 +192,33 @@ class SessionManager extends EventEmitter {
|
|
|
192
192
|
};
|
|
193
193
|
}
|
|
194
194
|
|
|
195
|
+
getCatchupOutput(id) {
|
|
196
|
+
const session = this.get(id);
|
|
197
|
+
if (!session) return null;
|
|
198
|
+
|
|
199
|
+
const bufferHistory = session.buffer.getAfter(0);
|
|
200
|
+
if (bufferHistory.length > 0) {
|
|
201
|
+
return {
|
|
202
|
+
source: 'buffer',
|
|
203
|
+
items: bufferHistory.length,
|
|
204
|
+
data: bufferHistory.map(message => message.data).join('')
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const historySource = session.renderedHistory || session.textHistory;
|
|
209
|
+
if (!historySource || typeof historySource.toJSON !== 'function') {
|
|
210
|
+
return { source: 'none', items: 0, data: '' };
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const snapshot = historySource.toJSON();
|
|
214
|
+
const text = String(snapshot.text || '');
|
|
215
|
+
return {
|
|
216
|
+
source: session.renderedHistory ? 'rendered-history' : 'text-history',
|
|
217
|
+
items: snapshot.lines || 0,
|
|
218
|
+
data: text ? text + (text.endsWith('\n') ? '' : '\r\n') : ''
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
|
|
195
222
|
getDiagnostics(id) {
|
|
196
223
|
const session = this.get(id);
|
|
197
224
|
return session ? this.getSessionDiagnostics(session) : null;
|
|
@@ -234,6 +261,17 @@ class SessionManager extends EventEmitter {
|
|
|
234
261
|
}, { compact: true });
|
|
235
262
|
}
|
|
236
263
|
|
|
264
|
+
logWsCatchupOutput(id, catchup) {
|
|
265
|
+
const session = this.get(id);
|
|
266
|
+
if (!session) return;
|
|
267
|
+
this.logSessionDiagnostics('ws-catchup', session, {
|
|
268
|
+
catchupSource: catchup.source,
|
|
269
|
+
catchupItems: catchup.items,
|
|
270
|
+
catchupBytes: Buffer.byteLength(String(catchup.data || ''), 'utf8'),
|
|
271
|
+
catchupPreview: previewText(catchup.data)
|
|
272
|
+
}, { compact: true });
|
|
273
|
+
}
|
|
274
|
+
|
|
237
275
|
logWsResize(id, cols, rows) {
|
|
238
276
|
const session = this.get(id);
|
|
239
277
|
if (!session) return;
|
package/lib/web/index.html
CHANGED
|
@@ -179,7 +179,7 @@
|
|
|
179
179
|
<div class="key-btn" data-key="ctrl-y" data-role="tool-action-shortcut" title="Send Ctrl+Y">Ctrl+Y</div>
|
|
180
180
|
<button class="command-key" data-command="/model" title="Send /model">/model</button>
|
|
181
181
|
<button class="command-key" data-command="/resume" title="Send /resume">/resume</button>
|
|
182
|
-
<button class="command-key" data-command="/stat" title="Send /stat">/stat</button>
|
|
182
|
+
<button class="command-key" data-command="/stat" data-role="usage-shortcut" title="Send /stat">/stat</button>
|
|
183
183
|
</div>
|
|
184
184
|
</div>
|
|
185
185
|
</div>
|
|
@@ -832,12 +832,21 @@
|
|
|
832
832
|
|
|
833
833
|
function updateToolShortcuts(toolKey) {
|
|
834
834
|
const actionBtn = document.querySelector('[data-role="tool-action-shortcut"]');
|
|
835
|
+
const usageBtn = document.querySelector('[data-role="usage-shortcut"]');
|
|
836
|
+
|
|
837
|
+
if (usageBtn) {
|
|
838
|
+
const command = toolKey === 'antigravity' ? '/usage' : '/stat';
|
|
839
|
+
usageBtn.dataset.command = command;
|
|
840
|
+
usageBtn.textContent = command;
|
|
841
|
+
usageBtn.title = `Send ${command}`;
|
|
842
|
+
}
|
|
843
|
+
|
|
835
844
|
if (!actionBtn) return;
|
|
836
845
|
|
|
837
846
|
if (toolKey === 'codex') {
|
|
838
|
-
actionBtn.dataset.key = 'codex-
|
|
839
|
-
actionBtn.textContent = '/
|
|
840
|
-
actionBtn.title = 'Send /
|
|
847
|
+
actionBtn.dataset.key = 'codex-perm';
|
|
848
|
+
actionBtn.textContent = '/perm';
|
|
849
|
+
actionBtn.title = 'Send /perm';
|
|
841
850
|
return;
|
|
842
851
|
}
|
|
843
852
|
|
|
@@ -1139,8 +1148,8 @@
|
|
|
1139
1148
|
const keyBtn = e.target.closest('.key-btn'); if (!keyBtn) return;
|
|
1140
1149
|
const key = keyBtn.dataset.key;
|
|
1141
1150
|
if (key === 'ctrl') { modifiers[key] = !modifiers[key]; keyBtn.classList.toggle('active', modifiers[key]); return; }
|
|
1142
|
-
if (key === 'codex-
|
|
1143
|
-
sendWS('/
|
|
1151
|
+
if (key === 'codex-perm') {
|
|
1152
|
+
sendWS('/perm');
|
|
1144
1153
|
setTimeout(() => { sendWS('\r'); }, 1000);
|
|
1145
1154
|
return;
|
|
1146
1155
|
}
|