claude-simple 0.2.32 → 0.2.34
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/client.js +3 -1
- package/dist/{app.0.2.32.min.js → app.0.2.34.min.js} +98 -98
- package/dist/index.html +2 -2
- package/package.json +1 -1
- package/public/chat.js +12 -2
- package/public/index.html +2 -2
- package/public/sw.js +3 -3
- package/src/agents/sessions.js +26 -2
- package/src/app.js +14 -6
- package/src/runtime/external-session-sync.js +2 -0
- package/src/runtime/http-transfer.js +7 -1
- /package/dist/{style.0.2.32.min.css → style.0.2.34.min.css} +0 -0
package/dist/index.html
CHANGED
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
|
|
6
6
|
<title>Claude Code</title>
|
|
7
|
-
<link rel="stylesheet" href="/style.0.2.
|
|
7
|
+
<link rel="stylesheet" href="/style.0.2.34.min.css">
|
|
8
8
|
<link rel="stylesheet" href="/highlight.min.css">
|
|
9
9
|
<script src="/marked.min.js"></script>
|
|
10
10
|
<script src="/highlight.min.js"></script>
|
|
11
11
|
</head>
|
|
12
12
|
<body class="h-dvh overflow-hidden flex flex-col bg-base-100 text-base-content">
|
|
13
13
|
<div id="root" class="flex flex-col flex-1 overflow-hidden"></div>
|
|
14
|
-
<script type="module" src="/app.0.2.
|
|
14
|
+
<script type="module" src="/app.0.2.34.min.js"></script>
|
|
15
15
|
</body>
|
|
16
16
|
</html>
|
package/package.json
CHANGED
package/public/chat.js
CHANGED
|
@@ -305,8 +305,9 @@ export function applyComposerAccess() {
|
|
|
305
305
|
banner.classList.remove('hidden');
|
|
306
306
|
banner.textContent = composerBlockReason();
|
|
307
307
|
} else {
|
|
308
|
-
|
|
309
|
-
banner.
|
|
308
|
+
const notice = ctx.nativeRunNotice?.sessionId === ctx.sessionId ? ctx.nativeRunNotice.message : '';
|
|
309
|
+
banner.classList.toggle('hidden', !notice);
|
|
310
|
+
banner.textContent = notice;
|
|
310
311
|
}
|
|
311
312
|
}
|
|
312
313
|
}
|
|
@@ -393,6 +394,15 @@ export function connectWS(opts = {}) {
|
|
|
393
394
|
return;
|
|
394
395
|
}
|
|
395
396
|
if (msg.type === 'run-status') {
|
|
397
|
+
if (msg._hubReplay) return;
|
|
398
|
+
if (msg.sessionId && msg.sessionId !== ctx.sessionId) return;
|
|
399
|
+
if (typeof msg.running !== 'boolean') {
|
|
400
|
+
ctx.nativeRunNotice = { sessionId: ctx.sessionId, message: msg.message || '终端会话未确认结束' };
|
|
401
|
+
applyComposerAccess();
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
ctx.nativeRunNotice = null;
|
|
405
|
+
applyComposerAccess();
|
|
396
406
|
// Only adopt "running" from server; never re-lock after we already finished a turn
|
|
397
407
|
// unless the server still has a busy run (reconnect mid-stream).
|
|
398
408
|
if (msg.running) {
|
package/public/index.html
CHANGED
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
<script src="/vendor/mermaid.min.js"></script>
|
|
86
86
|
<link rel="stylesheet" href="/vendor/katex.min.css">
|
|
87
87
|
<script src="/vendor/katex.min.js"></script>
|
|
88
|
-
<link rel="stylesheet" href="style.css?v=ui-
|
|
88
|
+
<link rel="stylesheet" href="style.css?v=ui-28">
|
|
89
89
|
</head>
|
|
90
90
|
<body class="h-dvh overflow-hidden flex flex-col bg-base-100 text-base-content">
|
|
91
91
|
<div id="root" class="flex flex-col flex-1 overflow-hidden"></div>
|
|
@@ -101,6 +101,6 @@
|
|
|
101
101
|
}
|
|
102
102
|
}, 10000);
|
|
103
103
|
</script>
|
|
104
|
-
<script type="module" src="app.js?v=ui-
|
|
104
|
+
<script type="module" src="app.js?v=ui-28"></script>
|
|
105
105
|
</body>
|
|
106
106
|
</html>
|
package/public/sw.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
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-v37';
|
|
5
5
|
const PRECACHE = [
|
|
6
6
|
'/',
|
|
7
7
|
'/index.html',
|
|
8
8
|
'/manifest.webmanifest',
|
|
9
|
-
'/style.css?v=ui-
|
|
9
|
+
'/style.css?v=ui-28',
|
|
10
10
|
'/style.css',
|
|
11
11
|
'/ui.min.css',
|
|
12
12
|
'/vendor/mini-react.min.js',
|
|
@@ -16,7 +16,7 @@ const PRECACHE = [
|
|
|
16
16
|
'/vendor/mermaid.min.js',
|
|
17
17
|
'/vendor/katex.min.js',
|
|
18
18
|
'/vendor/katex.min.css',
|
|
19
|
-
'/app.js?v=ui-
|
|
19
|
+
'/app.js?v=ui-28',
|
|
20
20
|
'/icons/icon-192.png',
|
|
21
21
|
'/icons/icon-512.png',
|
|
22
22
|
'/icons/icon-maskable-512.png',
|
package/src/agents/sessions.js
CHANGED
|
@@ -424,6 +424,18 @@ export async function parseCodexMessages(filePath) {
|
|
|
424
424
|
return entry.messages;
|
|
425
425
|
}
|
|
426
426
|
|
|
427
|
+
export async function readCodexRuntime(filePath, now = Date.now()) {
|
|
428
|
+
await parseCodexMessages(filePath);
|
|
429
|
+
const entry = codexTranscripts.get(filePath);
|
|
430
|
+
const runtime = entry?.runtime;
|
|
431
|
+
const pending = runtime?.state === 'pending';
|
|
432
|
+
const state = pending ? (now - entry.mtimeMs < 120_000 ? 'running' : 'unconfirmed') : runtime?.state || 'unknown';
|
|
433
|
+
return { ...runtime, state, running: state === 'running' ? true : ['completed','aborted'].includes(state) ? false : null,
|
|
434
|
+
updatedAt: entry?.mtimeMs || null, source: 'native-jsonl',
|
|
435
|
+
message: state === 'unconfirmed' || state === 'unknown' ? '终端会话未确认结束,请以原始记录核对' : state === 'running' ? '终端会话正在运行' : '终端会话已结束',
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
|
|
427
439
|
async function updateCodexTranscript(filePath, entry, stat) {
|
|
428
440
|
const messages = entry.messages;
|
|
429
441
|
// Codex writes the same assistant turn twice:
|
|
@@ -467,10 +479,19 @@ async function updateCodexTranscript(filePath, entry, stat) {
|
|
|
467
479
|
// their multi-megabyte payloads when building the visible transcript.
|
|
468
480
|
const head = line.slice(0, 400);
|
|
469
481
|
if (!/"type"\s*:\s*"(?:response_item|event_msg)"/.test(head) ||
|
|
470
|
-
!/"type"\s*:\s*"(?:message|agent_message|function_call|command_execution|custom_tool_call)"/.test(head)) continue;
|
|
482
|
+
!/"type"\s*:\s*"(?:message|agent_message|function_call|command_execution|custom_tool_call|task_started|task_complete|turn_aborted)"/.test(head)) continue;
|
|
471
483
|
let d;
|
|
472
484
|
try { d = JSON.parse(line); } catch { continue; }
|
|
473
485
|
|
|
486
|
+
if (d.type === 'event_msg' && d.payload) {
|
|
487
|
+
const p = d.payload;
|
|
488
|
+
if (p.type === 'task_started') entry.runtime = { state: 'pending', turnId: p.turn_id || null, startedAt: d.timestamp };
|
|
489
|
+
if ((p.type === 'task_complete' || p.type === 'turn_aborted') &&
|
|
490
|
+
(!entry.runtime?.turnId || !p.turn_id || entry.runtime.turnId === p.turn_id)) {
|
|
491
|
+
entry.runtime = { ...entry.runtime, state: p.type === 'task_complete' ? 'completed' : 'aborted', endedAt: d.timestamp };
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
474
495
|
if (d.type === 'response_item' && d.payload) {
|
|
475
496
|
const p = d.payload;
|
|
476
497
|
if (p.type === 'message' && p.role === 'user') {
|
|
@@ -1739,7 +1760,10 @@ export async function loadSessionMessages(sessionId, agent, { claudeConfigDirs,
|
|
|
1739
1760
|
if (a === 'codex') {
|
|
1740
1761
|
const file = await findCodexSessionFile(sessionId, codexHome);
|
|
1741
1762
|
if (!file) return null;
|
|
1742
|
-
|
|
1763
|
+
const messages = await parseCodexMessages(file);
|
|
1764
|
+
const runtime = await readCodexRuntime(file);
|
|
1765
|
+
const entry = codexTranscripts.get(file);
|
|
1766
|
+
return { messages, context: null, agent: 'codex', runtime, revision: `${entry?.ino}:${entry?.size}:${entry?.mtimeMs}` };
|
|
1743
1767
|
}
|
|
1744
1768
|
if (a === 'grok') {
|
|
1745
1769
|
const dir = await findGrokSessionDir(sessionId, grokHome);
|
package/src/app.js
CHANGED
|
@@ -1452,6 +1452,7 @@ export function createApp() {
|
|
|
1452
1452
|
oldestIndex: page.oldestIndex,
|
|
1453
1453
|
tail: page.tail,
|
|
1454
1454
|
compact,
|
|
1455
|
+
runtime: bundle.runtime || null,
|
|
1455
1456
|
};
|
|
1456
1457
|
res.setHeader('X-Session-Agent', payload.agent);
|
|
1457
1458
|
// A session can be appended while a turn is streaming. Returning a
|
|
@@ -1603,7 +1604,9 @@ export function createApp() {
|
|
|
1603
1604
|
tail: req.query.tail === '1', maxChars: req.query.maxChars });
|
|
1604
1605
|
if (!result) return res.status(404).json({ error: 'Session JSONL not found' });
|
|
1605
1606
|
res.setHeader('Cache-Control', 'no-store');
|
|
1606
|
-
|
|
1607
|
+
const bundle = isSessionBusy(sessionId) ? null : await readSessionBundle(sessionId, agent);
|
|
1608
|
+
const runtime = bundle?.runtime || { running: isSessionBusy(sessionId), source: 'ui' };
|
|
1609
|
+
res.json({ ...result, sessionId, ...runtime });
|
|
1607
1610
|
} catch (e) { res.status(500).json({ error: e.message }); }
|
|
1608
1611
|
});
|
|
1609
1612
|
|
|
@@ -2048,11 +2051,16 @@ export function createApp() {
|
|
|
2048
2051
|
if (cmd.cmd === 'session.subscribe') {
|
|
2049
2052
|
client.sessionId = cmd.sessionId || client.sessionId || null;
|
|
2050
2053
|
client.agent = cmd.agent || client.agent || null;
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
running:
|
|
2055
|
-
}
|
|
2054
|
+
const sid = client.sessionId;
|
|
2055
|
+
const agent = client.agent;
|
|
2056
|
+
if (isSessionBusy(sid)) {
|
|
2057
|
+
wireSend({ type: 'run-status', sessionId: sid, agent, running: true, source: 'ui' });
|
|
2058
|
+
} else {
|
|
2059
|
+
const bundle = await readSessionBundle(sid, agent).catch(() => null);
|
|
2060
|
+
if (client.sessionId !== sid || client.agent !== agent) return;
|
|
2061
|
+
wireSend({ type: 'run-status', sessionId: sid, agent,
|
|
2062
|
+
...(bundle?.runtime || { running: false, source: 'ui' }) });
|
|
2063
|
+
}
|
|
2056
2064
|
// UI-managed active runs already stream their events directly. For
|
|
2057
2065
|
// everything else, tail the native persisted transcript so an agent
|
|
2058
2066
|
// launched in an ordinary terminal appears live in this UI.
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
function transcriptFingerprint(bundle) {
|
|
13
|
+
if (bundle?.revision) return `${bundle.revision}:${JSON.stringify(bundle.runtime || null)}`;
|
|
13
14
|
const messages = Array.isArray(bundle?.messages) ? bundle.messages : [];
|
|
14
15
|
// Message parsing already normalizes the native formats. JSON preserves a
|
|
15
16
|
// change to an in-progress/rewritten final message as well as append-only
|
|
@@ -49,6 +50,7 @@ export function createExternalSessionMirror({ readSession, emit, intervalMs = 75
|
|
|
49
50
|
const changed = fingerprint !== entry.fingerprint;
|
|
50
51
|
entry.fingerprint = fingerprint;
|
|
51
52
|
if (changed || announce) {
|
|
53
|
+
if (bundle.runtime) emit(entry.sessionId, { type: 'run-status', sessionId: entry.sessionId, agent: bundle.agent || entry.agent, ...bundle.runtime });
|
|
52
54
|
emit(entry.sessionId, {
|
|
53
55
|
type: 'external-session-updated',
|
|
54
56
|
sessionId: entry.sessionId,
|
|
@@ -47,7 +47,13 @@ export function createHTTPTransfer({ gatewayURL, token, machineId, budget = new
|
|
|
47
47
|
});
|
|
48
48
|
try {
|
|
49
49
|
const res = await fetch(url, { ...options, signal: controller.signal });
|
|
50
|
-
|
|
50
|
+
const headers = sanitizeHeaders(Object.fromEntries(res.headers.entries()));
|
|
51
|
+
// Identity bodies retain their exact length (ordinary proxy replies recompute it).
|
|
52
|
+
if (!res.headers.get('content-encoding') || res.headers.get('content-encoding') === 'identity') {
|
|
53
|
+
const length = res.headers.get('content-length');
|
|
54
|
+
if (length !== null) headers['content-length'] = length;
|
|
55
|
+
}
|
|
56
|
+
await send({ type: 'http-res-start', status: res.status, headers });
|
|
51
57
|
for await (const value of res.body || []) {
|
|
52
58
|
// Each frame is small; sends wait for socket backpressure and share a rate cap.
|
|
53
59
|
for (let offset = 0; offset < value.byteLength; offset += 24 * 1024) {
|
|
File without changes
|