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 CHANGED
@@ -122,7 +122,7 @@ glad tools detect
122
122
 
123
123
  ## Supported Tools
124
124
 
125
- Glad currently auto-detects the 20 terminal AI tools defined in the code registry. The names below are the registry `displayName` values used by Glad:
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 当前会自动检测代码注册表中定义的 20 个终端 AI 工具。下面的名称严格使用 Glad 注册表里的 `displayName`:
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` |
@@ -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',
@@ -349,11 +349,12 @@ async function webCommand(options) {
349
349
  }
350
350
  sessionManager.logWsConnected(sessionId, req);
351
351
 
352
- // Send catchup buffer
353
- const history = session.buffer.getAfter(0);
354
- if (history.length > 0) {
355
- sessionManager.logWsCatchup(sessionId, history);
356
- ws.send(JSON.stringify({ type: 'output', data: history.map(m => m.data).join('') }));
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;
@@ -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-app';
839
- actionBtn.textContent = '/app';
840
- actionBtn.title = 'Send /app';
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-app') {
1143
- sendWS('/app');
1151
+ if (key === 'codex-perm') {
1152
+ sendWS('/perm');
1144
1153
  setTimeout(() => { sendWS('\r'); }, 1000);
1145
1154
  return;
1146
1155
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "glad-web",
3
- "version": "1.0.12",
3
+ "version": "1.0.14",
4
4
  "description": "Glad transforms terminal-based AI coding tools into a polished, mobile-friendly local Web interface.",
5
5
  "main": "index.js",
6
6
  "bin": {