claude-simple 0.2.7 → 0.2.9
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 +0 -0
- package/dist/app.0.2.9.min.js +1080 -0
- package/dist/index.html +2 -2
- package/dist/{style.0.2.7.min.css → style.0.2.9.min.css} +1 -1
- package/gateway.js +0 -0
- package/package.json +1 -1
- package/public/addon-fit.min.js +0 -0
- package/public/agent-panel.js +0 -0
- package/public/api.js +2 -0
- package/public/app.js +0 -0
- package/public/base.css +0 -0
- package/public/cache.js +0 -0
- package/public/chat.js +42 -8
- package/public/files.js +0 -0
- package/public/git.js +0 -0
- package/public/icons/icon-180.png +0 -0
- package/public/icons/icon-192.png +0 -0
- package/public/icons/icon-512.png +0 -0
- package/public/icons/icon-maskable-512.png +0 -0
- package/public/index.html +0 -0
- package/public/lib.js +0 -0
- package/public/manifest.webmanifest +0 -0
- package/public/mobile.js +0 -0
- package/public/notifications.js +215 -0
- package/public/offline.html +0 -0
- package/public/pwa.js +0 -0
- package/public/router.js +0 -0
- package/public/settings.js +0 -0
- package/public/shell/boot.js +0 -0
- package/public/shell/dashboard.js +46 -26
- package/public/shell/hub.js +0 -0
- package/public/shell/layout.js +2 -3
- package/public/shell/notes.js +0 -0
- package/public/shell/session-context.js +0 -0
- package/public/shell/session-list.js +22 -18
- package/public/shell/session-nav.js +18 -1
- package/public/shell/templates.js +18 -0
- package/public/shell/util.js +0 -0
- package/public/shell.js +24 -6
- package/public/state.js +64 -7
- package/public/style.css +0 -0
- package/public/sw.js +1 -1
- package/public/terminal.js +0 -0
- package/public/wake-lock.js +0 -0
- package/public/xterm.min.css +0 -0
- package/public/xterm.min.js +0 -0
- package/src/agents/claude.js +0 -0
- package/src/agents/codex.js +0 -0
- package/src/agents/grok.js +415 -271
- package/src/agents/meta-agent.js +0 -0
- package/src/agents/models.js +2 -1
- package/src/agents/sessions.js +0 -0
- package/src/agents/stream-batch.js +0 -0
- package/src/app.js +12 -2
- package/src/auto-update.js +0 -0
- package/src/runtime/approvals.js +0 -0
- package/src/runtime/outbox.js +0 -0
- package/src/runtime/protocol.js +0 -0
- package/dist/app.0.2.7.min.js +0 -1039
|
@@ -69,6 +69,13 @@ export const AppShell = (opts = {}) => {
|
|
|
69
69
|
<span class="text-[10px] opacity-50">▾</span>
|
|
70
70
|
</button>
|
|
71
71
|
</div>
|
|
72
|
+
<div id="notifications-wrap" class="relative flex-shrink-0">
|
|
73
|
+
<button type="button" id="btn-notifications" class="btn btn-ghost btn-xs border border-base-300 gap-1 min-h-8 px-2"
|
|
74
|
+
title="通知" aria-haspopup="dialog" aria-expanded="false">
|
|
75
|
+
<span>🔔</span>
|
|
76
|
+
<span id="notifications-badge" class="hidden inline-flex min-w-5 h-5 px-1 items-center justify-center rounded-full bg-error text-error-content text-[10px] font-bold">0</span>
|
|
77
|
+
</button>
|
|
78
|
+
</div>
|
|
72
79
|
<span id="topbar-project" class="text-sm text-base-content/50 flex-1 truncate min-w-0">Select a session</span>
|
|
73
80
|
<span id="conn-dot" class="w-2 h-2 rounded-full bg-base-content/30 flex-shrink-0" title="连接状态"></span>
|
|
74
81
|
<div class="flex gap-2 topbar-actions">
|
|
@@ -93,6 +100,17 @@ export const AppShell = (opts = {}) => {
|
|
|
93
100
|
<div id="recent-menu-list" class="flex flex-col gap-0.5"></div>
|
|
94
101
|
<p id="recent-menu-empty" class="text-xs text-base-content/40 px-1 py-2 hidden">暂无最近会话</p>
|
|
95
102
|
</div>
|
|
103
|
+
<div id="notifications-backdrop" class="hidden fixed inset-0 z-[55] bg-black/40" aria-hidden="true"></div>
|
|
104
|
+
<div id="notifications-menu" class="hidden fixed z-[60] w-[min(26rem,calc(100vw-1rem))] max-h-[min(30rem,75vh)] overflow-y-auto
|
|
105
|
+
rounded-lg border border-base-300 bg-base-100 shadow-xl p-2"
|
|
106
|
+
role="dialog" aria-label="通知中心">
|
|
107
|
+
<div class="flex items-center justify-between px-1 pb-1.5 mb-1 border-b border-base-300 sticky top-0 bg-base-100 z-[1]">
|
|
108
|
+
<span class="text-[10px] uppercase tracking-wide text-base-content/45 font-semibold">通知</span>
|
|
109
|
+
<button type="button" id="btn-notifications-read-all" class="btn btn-ghost btn-xs px-1 text-[10px]">全部已读</button>
|
|
110
|
+
</div>
|
|
111
|
+
<div id="notifications-menu-list" class="flex flex-col gap-1"></div>
|
|
112
|
+
<p id="notifications-menu-empty" class="text-xs text-base-content/40 px-1 py-2 hidden">暂无通知</p>
|
|
113
|
+
</div>
|
|
96
114
|
<!-- Hub: only when no remembered machine (or last one offline) -->
|
|
97
115
|
<div id="machine-picker" class="hidden fixed inset-0 z-[60] bg-base-100 flex items-center justify-center p-4">
|
|
98
116
|
<div class="w-full max-w-md">
|
package/public/shell/util.js
CHANGED
|
File without changes
|
package/public/shell.js
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
sessionsData, workspacesData, sessionFilter, sessionSearch,
|
|
7
7
|
expandedFolders, collapsedFolders, filesPath, viewingFile, filteredSessions, projectGroups,
|
|
8
8
|
currentProject, currentTab, filesRoot, gitRoot,
|
|
9
|
-
currentModel, currentEffort, currentPermission, currentAgent, setAgent,
|
|
9
|
+
currentModel, currentEffort, currentPermission, currentAgent, setAgent, setCurrentModel,
|
|
10
10
|
sidebarView, agentFilter, timeRange, activityHits, activityLoading,
|
|
11
11
|
chatDensity, setChatDensity,
|
|
12
12
|
favoritesOnly, showHiddenOnly, hubMode, hubMachineReady, selectedMachineId, setSelectedMachine,
|
|
@@ -23,6 +23,9 @@ import {
|
|
|
23
23
|
import { syncHash } from './router.js';
|
|
24
24
|
import { initSettings, openSettings } from './settings.js';
|
|
25
25
|
import { openMetaAgent, toggleMetaAgent } from './agent-panel.js';
|
|
26
|
+
import {
|
|
27
|
+
initNotifications, refreshNotifications, toggleNotificationsMenu, closeNotificationsMenu,
|
|
28
|
+
} from './notifications.js';
|
|
26
29
|
|
|
27
30
|
import { AuthScreen, AppShell } from './shell/templates.js';
|
|
28
31
|
import {
|
|
@@ -306,6 +309,7 @@ export function initShell(opts = {}) {
|
|
|
306
309
|
|
|
307
310
|
initSidebarResize();
|
|
308
311
|
initSidebarToggle();
|
|
312
|
+
initNotifications({ openSession: resumeSession });
|
|
309
313
|
|
|
310
314
|
let sessionsChangedTimer = null;
|
|
311
315
|
document.addEventListener('sessions-changed', () => {
|
|
@@ -519,8 +523,7 @@ export function initShell(opts = {}) {
|
|
|
519
523
|
if (prev !== next) {
|
|
520
524
|
ctx.sessionId = null;
|
|
521
525
|
setAgent(next);
|
|
522
|
-
|
|
523
|
-
localStorage.setItem('model', currentModel.peek());
|
|
526
|
+
setCurrentModel(getDefaultModel(next) || currentModel.peek());
|
|
524
527
|
$('sel-permission').value = currentPermission.peek();
|
|
525
528
|
refreshModelSelect();
|
|
526
529
|
appendSystemMsg(`Agent → ${AGENT_LABELS[next] || next} · model ${currentModel.peek()} · new session`);
|
|
@@ -554,8 +557,7 @@ export function initShell(opts = {}) {
|
|
|
554
557
|
}
|
|
555
558
|
});
|
|
556
559
|
delegate.on('change', '#sel-model', (_, el) => {
|
|
557
|
-
|
|
558
|
-
localStorage.setItem('model', el.value);
|
|
560
|
+
setCurrentModel(el.value);
|
|
559
561
|
refreshEffortSelect();
|
|
560
562
|
});
|
|
561
563
|
delegate.on('click', '#btn-model-add', () => promptCustomModel({ editCurrent: false }));
|
|
@@ -590,6 +592,7 @@ export function initShell(opts = {}) {
|
|
|
590
592
|
return;
|
|
591
593
|
}
|
|
592
594
|
await enterMachine(id, { forceReload: true });
|
|
595
|
+
refreshNotifications();
|
|
593
596
|
});
|
|
594
597
|
const refreshMachinesUi = async () => {
|
|
595
598
|
const st = $('machine-picker-status');
|
|
@@ -611,6 +614,7 @@ export function initShell(opts = {}) {
|
|
|
611
614
|
delegate.on('click', '#btn-machine-menu', async e => {
|
|
612
615
|
e.stopPropagation();
|
|
613
616
|
closeRecentMenu();
|
|
617
|
+
closeNotificationsMenu();
|
|
614
618
|
const menu = $('machine-menu');
|
|
615
619
|
if (!menu) return;
|
|
616
620
|
if (menu.classList.contains('hidden')) {
|
|
@@ -625,7 +629,8 @@ export function initShell(opts = {}) {
|
|
|
625
629
|
e.preventDefault();
|
|
626
630
|
e.stopPropagation();
|
|
627
631
|
closeMachineMenu();
|
|
628
|
-
|
|
632
|
+
closeNotificationsMenu();
|
|
633
|
+
toggleRecentMenu();
|
|
629
634
|
const open = !$('recent-menu')?.classList.contains('hidden');
|
|
630
635
|
const btn = $('btn-recent-sessions');
|
|
631
636
|
if (btn) btn.setAttribute('aria-expanded', open ? 'true' : 'false');
|
|
@@ -649,6 +654,13 @@ export function initShell(opts = {}) {
|
|
|
649
654
|
btn?.setAttribute('aria-expanded', 'false');
|
|
650
655
|
}
|
|
651
656
|
});
|
|
657
|
+
delegate.on('click', '#btn-notifications', e => {
|
|
658
|
+
e.preventDefault();
|
|
659
|
+
e.stopPropagation();
|
|
660
|
+
closeMachineMenu();
|
|
661
|
+
closeRecentMenu();
|
|
662
|
+
toggleNotificationsMenu();
|
|
663
|
+
});
|
|
652
664
|
// Keep panel glued under topbar on rotate / URL bar show-hide
|
|
653
665
|
window.addEventListener('resize', () => {
|
|
654
666
|
if ($('recent-menu') && !$('recent-menu').classList.contains('hidden')) {
|
|
@@ -761,6 +773,12 @@ export function initShell(opts = {}) {
|
|
|
761
773
|
});
|
|
762
774
|
|
|
763
775
|
refreshModelSelect();
|
|
776
|
+
effect(() => {
|
|
777
|
+
void hubMode.value;
|
|
778
|
+
void selectedMachineId.value;
|
|
779
|
+
if (!ctx.token) return;
|
|
780
|
+
refreshNotifications();
|
|
781
|
+
});
|
|
764
782
|
$('sel-permission').value = currentPermission.peek();
|
|
765
783
|
applyChatDensity();
|
|
766
784
|
const dens = $('sel-density');
|
package/public/state.js
CHANGED
|
@@ -15,8 +15,48 @@ export const currentTab = signal('chat');
|
|
|
15
15
|
export const isProcessing = signal(false);
|
|
16
16
|
/** Chat socket: idle | connecting | open | reconnecting | offline */
|
|
17
17
|
export const wsStatus = signal('idle');
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
const MODEL_BY_SESSION_KEY = 'modelBySession';
|
|
19
|
+
const initialAgent = localStorage.getItem('agent') || 'claude';
|
|
20
|
+
|
|
21
|
+
function readModelBySession() {
|
|
22
|
+
try {
|
|
23
|
+
const value = JSON.parse(localStorage.getItem(MODEL_BY_SESSION_KEY) || '{}');
|
|
24
|
+
return value && typeof value === 'object' ? value : {};
|
|
25
|
+
} catch {
|
|
26
|
+
return {};
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function modelSessionKey(agent, sessionId = ctx.sessionId, machineId = ctx.machineId) {
|
|
31
|
+
if (!sessionId) return '';
|
|
32
|
+
const a = (agent || 'claude').toLowerCase();
|
|
33
|
+
return `${machineId || ''}:${a}:${sessionId}`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Restore the model explicitly selected for the active session. */
|
|
37
|
+
export function getSavedModel(agent, sessionId = ctx.sessionId, machineId = ctx.machineId) {
|
|
38
|
+
const key = modelSessionKey(agent, sessionId, machineId);
|
|
39
|
+
if (!key) return null;
|
|
40
|
+
const saved = readModelBySession()[key];
|
|
41
|
+
if (typeof saved === 'string' && saved.trim()) return saved;
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Update the picker and persist its value only when a session exists. */
|
|
46
|
+
export function setCurrentModel(model, agent = currentAgent.peek(), sessionId = ctx.sessionId, machineId = ctx.machineId) {
|
|
47
|
+
const value = String(model || '').trim();
|
|
48
|
+
if (!value) return;
|
|
49
|
+
const key = modelSessionKey(agent, sessionId, machineId);
|
|
50
|
+
if (key) {
|
|
51
|
+
const saved = readModelBySession();
|
|
52
|
+
saved[key] = value;
|
|
53
|
+
localStorage.setItem(MODEL_BY_SESSION_KEY, JSON.stringify(saved));
|
|
54
|
+
}
|
|
55
|
+
currentModel.value = value;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export const currentAgent = signal(initialAgent); // 'claude'|'codex'|'grok'
|
|
59
|
+
export const currentModel = signal('claude-sonnet-4-5');
|
|
20
60
|
export const currentEffort = signal('');
|
|
21
61
|
// All local agents are trusted by default; users can still choose another mode
|
|
22
62
|
// from the expanded composer options before starting a turn.
|
|
@@ -245,6 +285,18 @@ export function getEffortsForModel(agent, modelId) {
|
|
|
245
285
|
return ['low', 'medium', 'high', 'xhigh', 'max'];
|
|
246
286
|
}
|
|
247
287
|
|
|
288
|
+
/** Default reasoning effort for agent/model (Grok → low). */
|
|
289
|
+
export function getDefaultEffort(agent, modelId) {
|
|
290
|
+
const a = (agent || 'claude').toLowerCase();
|
|
291
|
+
const meta = agentsMeta.peek()?.defaults?.[a];
|
|
292
|
+
if (meta?.effortDefault) return String(meta.effortDefault);
|
|
293
|
+
const models = getModelsForAgent(a);
|
|
294
|
+
const m = models.find(x => x.value === modelId);
|
|
295
|
+
if (m?.defaultEffort) return String(m.defaultEffort);
|
|
296
|
+
if (a === 'grok') return 'low';
|
|
297
|
+
return '';
|
|
298
|
+
}
|
|
299
|
+
|
|
248
300
|
export function setAgent(agent) {
|
|
249
301
|
const a = (agent || 'claude').toLowerCase();
|
|
250
302
|
currentAgent.value = a;
|
|
@@ -252,12 +304,17 @@ export function setAgent(agent) {
|
|
|
252
304
|
currentPermission.value = 'bypassPermissions';
|
|
253
305
|
const permissionSelect = typeof document === 'undefined' ? null : document.getElementById('sel-permission');
|
|
254
306
|
if (permissionSelect) permissionSelect.value = currentPermission.peek();
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
307
|
+
// Model selection belongs to a concrete session, not to the whole agent.
|
|
308
|
+
// New sessions start from the agent default until they receive a session id.
|
|
309
|
+
const saved = getSavedModel(a);
|
|
310
|
+
if (saved) {
|
|
311
|
+
currentModel.value = saved;
|
|
312
|
+
} else {
|
|
313
|
+
setCurrentModel(getDefaultModel(a), a);
|
|
260
314
|
}
|
|
315
|
+
const defEffort = getDefaultEffort(a, currentModel.peek());
|
|
316
|
+
if (defEffort) currentEffort.value = defEffort;
|
|
317
|
+
else if (a !== 'grok') currentEffort.value = '';
|
|
261
318
|
}
|
|
262
319
|
|
|
263
320
|
function matchesAgentFilter(s, filter) {
|
package/public/style.css
CHANGED
|
File without changes
|
package/public/sw.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
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-
|
|
4
|
+
const CACHE = 'agent-ui-shell-v15';
|
|
5
5
|
const PRECACHE = [
|
|
6
6
|
'/',
|
|
7
7
|
'/index.html',
|
package/public/terminal.js
CHANGED
|
File without changes
|
package/public/wake-lock.js
CHANGED
|
File without changes
|
package/public/xterm.min.css
CHANGED
|
File without changes
|
package/public/xterm.min.js
CHANGED
|
File without changes
|
package/src/agents/claude.js
CHANGED
|
File without changes
|
package/src/agents/codex.js
CHANGED
|
File without changes
|