claude-simple 0.2.9 → 0.2.11

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/public/shell.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  expandedFolders, collapsedFolders, filesPath, viewingFile, filteredSessions, projectGroups,
8
8
  currentProject, currentTab, filesRoot, gitRoot,
9
9
  currentModel, currentEffort, currentPermission, currentAgent, setAgent, setCurrentModel,
10
- sidebarView, agentFilter, timeRange, activityHits, activityLoading,
10
+ sidebarView, agentFilter, agentFilters, timeRange, activityHits, activityLoading,
11
11
  chatDensity, setChatDensity,
12
12
  favoritesOnly, showHiddenOnly, hubMode, hubMachineReady, selectedMachineId, setSelectedMachine,
13
13
  machinesList, AGENT_LABELS, getDefaultModel, sessionMetaMap, ctx,
@@ -20,7 +20,7 @@ import {
20
20
  connectWS, clearMessages, appendMsg, appendSystemMsg, sendMessage, stopProcessing,
21
21
  applyChatDensity,
22
22
  } from './chat.js';
23
- import { syncHash } from './router.js';
23
+ import { syncHash, currentSessionShareUrl } from './router.js';
24
24
  import { initSettings, openSettings } from './settings.js';
25
25
  import { openMetaAgent, toggleMetaAgent } from './agent-panel.js';
26
26
  import {
@@ -322,20 +322,31 @@ export function initShell(opts = {}) {
322
322
  });
323
323
  document.addEventListener('router:home', goHome);
324
324
 
325
- document.addEventListener('router:session', async ({ detail: { id, tab } }) => {
325
+ document.addEventListener('router:session', async ({ detail: { id, tab, machineId, agent } }) => {
326
326
  const s = sessionsData.peek().find(x => x.sessionId === id);
327
327
  const last = getLastSessionContext();
328
328
  await resumeSession(
329
329
  id,
330
330
  s?.cwd || (last?.sessionId === id ? last.cwd : null) || null,
331
331
  s?.configDir || (last?.sessionId === id ? last.configDir : null) || null,
332
- s?.agent || (last?.sessionId === id ? last.agent : null) || null,
333
- s?.machineId || (last?.sessionId === id ? last.machineId : null) || null,
332
+ agent || s?.agent || (last?.sessionId === id ? last.agent : null) || null,
333
+ machineId || s?.machineId || (last?.sessionId === id ? last.machineId : null) || null,
334
334
  { tab: tab || 'chat' },
335
335
  );
336
336
  });
337
337
 
338
338
  delegate.on('click', '#btn-home', goHome);
339
+ delegate.on('click', '#btn-share-session', async (_, el) => {
340
+ const url = currentSessionShareUrl();
341
+ if (!url) return;
342
+ try {
343
+ await navigator.clipboard.writeText(url);
344
+ el.textContent = '已复制';
345
+ setTimeout(() => { el.textContent = '分享'; }, 1400);
346
+ } catch {
347
+ window.prompt('复制会话链接:', url);
348
+ }
349
+ });
339
350
  delegate.on('click', '#auth-btn', submitAuth);
340
351
  delegate.on('submit', '#auth-form', e => { e.preventDefault(); submitAuth(); });
341
352
  delegate.on('keydown', '#auth-username, #auth-password', e => { if (e.key === 'Enter') submitAuth(); });
@@ -353,6 +364,41 @@ export function initShell(opts = {}) {
353
364
  sessionSearch.value = el.value;
354
365
  scheduleActivitySearch(el.value);
355
366
  });
367
+ delegate.on('click', '#sidebar-filter-toggle', () => {
368
+ const menu = $('sidebar-filter-menu');
369
+ if (!menu) return;
370
+ const open = menu.classList.toggle('hidden');
371
+ $('sidebar-filter-toggle')?.setAttribute('aria-expanded', String(!open));
372
+ });
373
+ delegate.on('change', '[data-agent-option]', (_, el) => {
374
+ const next = new Set(agentFilters.peek());
375
+ if (el.checked) next.add(el.dataset.agentOption);
376
+ else next.delete(el.dataset.agentOption);
377
+ const values = [...next];
378
+ agentFilters.value = values;
379
+ localStorage.setItem('agentFilters', JSON.stringify(values));
380
+ agentFilter.value = values.length === 1 ? values[0] : 'all';
381
+ });
382
+ delegate.on('change', '#filter-favorites', (_, el) => {
383
+ favoritesOnly.value = el.checked;
384
+ localStorage.setItem('favoritesOnly', el.checked ? '1' : '0');
385
+ });
386
+ delegate.on('change', '#filter-hidden', (_, el) => {
387
+ showHiddenOnly.value = el.checked;
388
+ localStorage.setItem('showHiddenOnly', el.checked ? '1' : '0');
389
+ });
390
+ delegate.on('click', '#filter-clear', () => {
391
+ agentFilters.value = [];
392
+ agentFilter.value = 'all';
393
+ favoritesOnly.value = false;
394
+ showHiddenOnly.value = false;
395
+ localStorage.setItem('agentFilters', '[]');
396
+ localStorage.setItem('favoritesOnly', '0');
397
+ localStorage.setItem('showHiddenOnly', '0');
398
+ document.querySelectorAll('[data-agent-option]').forEach(el => { el.checked = false; });
399
+ if ($('filter-favorites')) $('filter-favorites').checked = false;
400
+ if ($('filter-hidden')) $('filter-hidden').checked = false;
401
+ });
356
402
  delegate.on('click', '#session-filter-badge', () => { sessionFilter.value = null; });
357
403
  delegate.on('click', '[data-ws-tab]', (_, el) => { sessionFilter.value = el.dataset.wsTab || null; });
358
404
  delegate.on('click', '#sidebar-refresh', () => {
@@ -368,12 +414,6 @@ export function initShell(opts = {}) {
368
414
  localStorage.setItem('agentFilter', el.dataset.agentFilter);
369
415
  if (sessionSearch.peek().trim()) scheduleActivitySearch(sessionSearch.peek());
370
416
  });
371
- delegate.on('change', '#time-range', (_, el) => {
372
- timeRange.value = el.value;
373
- localStorage.setItem('timeRange', el.value);
374
- loadAllSessions({ waitFresh: true });
375
- if (sessionSearch.peek().trim()) scheduleActivitySearch(sessionSearch.peek());
376
- });
377
417
  delegate.on('dblclick', '[data-project-cwd]', (_, el) => {
378
418
  const cwd = el.dataset.projectCwd;
379
419
  if (!cwd) return;
@@ -783,8 +823,9 @@ export function initShell(opts = {}) {
783
823
  applyChatDensity();
784
824
  const dens = $('sel-density');
785
825
  if (dens) dens.value = chatDensity.peek() || 'normal';
786
- const tr = $('time-range');
787
- if (tr) tr.value = timeRange.peek() || '14';
826
+ document.querySelectorAll('[data-agent-option]').forEach(el => { el.checked = agentFilters.peek().includes(el.dataset.agentOption); });
827
+ if ($('filter-favorites')) $('filter-favorites').checked = favoritesOnly.peek();
828
+ if ($('filter-hidden')) $('filter-hidden').checked = showHiddenOnly.peek();
788
829
  document.querySelectorAll('[data-agent-filter]').forEach(btn => {
789
830
  btn.classList.toggle('active', btn.dataset.agentFilter === agentFilter.peek());
790
831
  });
package/public/state.js CHANGED
@@ -55,7 +55,7 @@ export function setCurrentModel(model, agent = currentAgent.peek(), sessionId =
55
55
  currentModel.value = value;
56
56
  }
57
57
 
58
- export const currentAgent = signal(initialAgent); // 'claude'|'codex'|'grok'
58
+ export const currentAgent = signal(initialAgent); // 'claude'|'codex'|'grok'|'gemini'|'cursor'
59
59
  export const currentModel = signal('claude-sonnet-4-5');
60
60
  export const currentEffort = signal('');
61
61
  // All local agents are trusted by default; users can still choose another mode
@@ -67,7 +67,13 @@ export const agentsMeta = signal(null); // from /api/agents (dynamic model l
67
67
 
68
68
  // Sidebar project-management filters
69
69
  export const sidebarView = signal(localStorage.getItem('sidebarView') || 'projects'); // 'projects' | 'timeline'
70
- export const agentFilter = signal(localStorage.getItem('agentFilter') || 'all'); // all|claude|codex|grok
70
+ export const agentFilter = signal(localStorage.getItem('agentFilter') || 'all'); // all|claude|codex|grok|gemini|cursor
71
+ export const agentFilters = signal((() => {
72
+ try {
73
+ const saved = JSON.parse(localStorage.getItem('agentFilters') || '[]');
74
+ return Array.isArray(saved) ? saved.filter(Boolean) : [];
75
+ } catch { return []; }
76
+ })()); // multi-select sidebar filter; empty means all agents
71
77
  export const timeRange = signal(localStorage.getItem('timeRange') || '14'); // '0'|'1'|'7'|'14'|'30'
72
78
  export const activityHits = signal(null); // null | { q, results, loading, error }
73
79
  export const activityLoading = signal(false);
@@ -147,6 +153,8 @@ export const AGENT_LABELS = {
147
153
  claude: 'Claude',
148
154
  codex: 'Codex',
149
155
  grok: 'Grok',
156
+ gemini: 'Gemini',
157
+ cursor: 'Cursor',
150
158
  };
151
159
 
152
160
  /** Static fallbacks when /api/agents has not loaded yet. */
@@ -171,12 +179,32 @@ export const AGENT_MODELS = {
171
179
  { value: 'grok-3', label: 'grok-3' },
172
180
  { value: 'grok-3-mini', label: 'grok-3-mini' },
173
181
  ],
182
+ gemini: [
183
+ { value: 'gemini-3.7-flash-high', label: 'Gemini 3.7 Flash (High)' },
184
+ { value: 'gemini-3.7-flash-medium', label: 'Gemini 3.7 Flash (Medium)' },
185
+ { value: 'gemini-3.7-flash-low', label: 'Gemini 3.7 Flash (Low)' },
186
+ { value: 'gemini-3.6-flash-high', label: 'Gemini 3.6 Flash (High)' },
187
+ { value: 'gemini-3.6-flash-medium', label: 'Gemini 3.6 Flash (Medium)' },
188
+ { value: 'gemini-3.6-flash-low', label: 'Gemini 3.6 Flash (Low)' },
189
+ { value: 'gemini-3.5-flash-high', label: 'Gemini 3.5 Flash (High)' },
190
+ { value: 'gemini-3.5-flash-medium', label: 'Gemini 3.5 Flash (Medium)' },
191
+ { value: 'gemini-3.5-flash-low', label: 'Gemini 3.5 Flash (Low)' },
192
+ { value: 'gemini-3.1-pro-high', label: 'Gemini 3.1 Pro (High)' },
193
+ { value: 'gemini-3.1-pro-low', label: 'Gemini 3.1 Pro (Low)' },
194
+ ],
195
+ cursor: [
196
+ { value: 'auto', label: 'Auto' },
197
+ { value: 'gpt-5.3-codex', label: 'GPT-5.3 Codex' },
198
+ { value: 'composer-2.5', label: 'Composer 2.5' },
199
+ ],
174
200
  };
175
201
 
176
202
  export const AGENT_DEFAULT_MODEL = {
177
203
  claude: 'claude-sonnet-4-5',
178
204
  codex: 'gpt-5.4',
179
205
  grok: 'grok-4.5',
206
+ gemini: 'gemini-3.7-flash-high',
207
+ cursor: 'auto',
180
208
  };
181
209
 
182
210
  function normalizeModelEntry(m) {
@@ -294,6 +322,7 @@ export function getDefaultEffort(agent, modelId) {
294
322
  const m = models.find(x => x.value === modelId);
295
323
  if (m?.defaultEffort) return String(m.defaultEffort);
296
324
  if (a === 'grok') return 'low';
325
+ if (a === 'gemini') return String(modelId || '').match(/-(low|medium|high)$/i)?.[1]?.toLowerCase() || '';
297
326
  return '';
298
327
  }
299
328
 
@@ -314,7 +343,7 @@ export function setAgent(agent) {
314
343
  }
315
344
  const defEffort = getDefaultEffort(a, currentModel.peek());
316
345
  if (defEffort) currentEffort.value = defEffort;
317
- else if (a !== 'grok') currentEffort.value = '';
346
+ else if (a !== 'grok' && a !== 'gemini') currentEffort.value = '';
318
347
  }
319
348
 
320
349
  function matchesAgentFilter(s, filter) {
@@ -359,7 +388,7 @@ export const filteredSessions = computed(() => {
359
388
  const search = sessionSearch.value.toLowerCase().trim();
360
389
  const sort = sessionSort.value;
361
390
  const aFilter = agentFilter.value;
362
- const days = timeRange.value;
391
+ const aFilters = agentFilters.value;
363
392
  const favOnly = favoritesOnly.value;
364
393
  const hiddenOnly = showHiddenOnly.value;
365
394
  const metaMap = sessionMetaMap.value;
@@ -375,7 +404,9 @@ export const filteredSessions = computed(() => {
375
404
  if (hubMode.value && mid) {
376
405
  list = list.filter(s => s && (!s.machineId || s.machineId === mid));
377
406
  }
378
- list = list.filter(s => s && matchesAgentFilter(s, aFilter) && matchesTimeRange(s, days));
407
+ list = list.filter(s => s && (aFilters.length
408
+ ? aFilters.includes(s.agent || 'claude')
409
+ : matchesAgentFilter(s, aFilter)));
379
410
  // Hidden sessions: excluded by default; "Hidden" filter shows only them
380
411
  if (hiddenOnly) {
381
412
  list = list.filter(s => s && metaMap?.[metaKey(s.agent, s.sessionId, s.machineId)]?.hidden);
package/public/style.css CHANGED
@@ -1141,6 +1141,18 @@ html.pwa-standalone .ma-panel {
1141
1141
  #recent-menu.recent-menu-open {
1142
1142
  display: block; /* beat .hidden if both race */
1143
1143
  }
1144
+ .topbar-icon-btn {
1145
+ gap: .35rem;
1146
+ min-width: 2rem;
1147
+ padding-inline: .45rem;
1148
+ }
1149
+ .topbar-icon {
1150
+ width: 1rem;
1151
+ height: 1rem;
1152
+ display: block;
1153
+ flex: 0 0 auto;
1154
+ }
1155
+ .topbar-icon-label { display: inline; }
1144
1156
  @media (max-width: 640px) {
1145
1157
  #recent-menu {
1146
1158
  min-width: 0;
@@ -1161,6 +1173,7 @@ html.pwa-standalone .ma-panel {
1161
1173
  #btn-pwa-install {
1162
1174
  display: none !important;
1163
1175
  }
1176
+ .topbar-icon-label { display: none; }
1164
1177
  #topbar-project {
1165
1178
  font-size: 11px;
1166
1179
  max-width: 30vw;
package/public/sw.js CHANGED
@@ -1,13 +1,18 @@
1
1
  /* Agent UI service worker — cache shell assets only.
2
2
  * Never intercepts WebSocket or mutates API semantics beyond offline fallback.
3
3
  * Bump CACHE when shipping UI that must invalidate old shells. */
4
- const CACHE = 'agent-ui-shell-v15';
4
+ const CACHE = 'agent-ui-shell-v16';
5
5
  const PRECACHE = [
6
6
  '/',
7
7
  '/index.html',
8
8
  '/manifest.webmanifest',
9
9
  '/style.css?v=ui-11',
10
10
  '/style.css',
11
+ '/ui.min.css',
12
+ '/vendor/mini-react.min.js',
13
+ '/vendor/marked.min.js',
14
+ '/vendor/highlight.min.js',
15
+ '/vendor/highlight-dark.min.css',
11
16
  '/app.js',
12
17
  '/icons/icon-192.png',
13
18
  '/icons/icon-512.png',
@@ -60,7 +65,6 @@ self.addEventListener('fetch', (event) => {
60
65
  // Let the browser handle API + anything that might upgrade to WebSocket.
61
66
  if (isApiOrRealtime(url)) return;
62
67
 
63
- // Cross-origin (CDN daisyui/tailwind/marked): network only — do not cache opaque forever.
64
68
  if (url.origin !== self.location.origin) return;
65
69
 
66
70
  // Navigations: network-first so deploys show up; offline → cached shell.