@mobius-os/mobius 0.2.2 → 0.2.3
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/package.json +1 -1
- package/src/components/Chat.tsx +5 -1
- package/src/hooks/useChat.ts +28 -0
package/package.json
CHANGED
package/src/components/Chat.tsx
CHANGED
|
@@ -78,7 +78,11 @@ export function ChatScreen({ client, ready, webUserId, resumeSessionId, onClear,
|
|
|
78
78
|
() => fitTranscript(chat.entries, transcriptRows, terminal.columns),
|
|
79
79
|
[chat.entries, transcriptRows, terminal.columns],
|
|
80
80
|
)
|
|
81
|
-
|
|
81
|
+
// Welcome card is for fresh / short sessions only. Once the conversation is
|
|
82
|
+
// long enough that fitTranscript hides older entries, switch to the compact
|
|
83
|
+
// header + full transcript — otherwise the 12-row welcome card crowds out the
|
|
84
|
+
// recent messages and the chat area reads as blank after "已隐藏较早的…".
|
|
85
|
+
const showWelcome = fitted.hiddenCount === 0 && fitted.estimatedRows + WELCOME_ROWS <= transcriptRows
|
|
82
86
|
|
|
83
87
|
return (
|
|
84
88
|
<Box
|
package/src/hooks/useChat.ts
CHANGED
|
@@ -15,6 +15,7 @@ import { MobiusClient, ApiError } from '../api.js'
|
|
|
15
15
|
import { SseConnection } from '../sse.js'
|
|
16
16
|
import { updateIssuePreference } from '../config.js'
|
|
17
17
|
import { tuiAimuxIdentifier, probeAimuxBridgeConnection } from '../aimux.js'
|
|
18
|
+
import { viewsForEntry } from '../lib/entry-view.js'
|
|
18
19
|
import type { AnyEntry } from '../types.js'
|
|
19
20
|
import type { ReadyState } from '../components/PrepScreen.js'
|
|
20
21
|
|
|
@@ -38,6 +39,33 @@ export interface ChatController {
|
|
|
38
39
|
let ID = 0
|
|
39
40
|
function nextId(): number { ID += 1; return ID }
|
|
40
41
|
|
|
42
|
+
/**
|
|
43
|
+
* Does this entry represent the user's just-submitted message? Used to retire the
|
|
44
|
+
* optimistic `pendingUser` placeholder once the real entry is observed — including
|
|
45
|
+
* via a reconnect's history replay (the live `jsonl_entry` path already clears it).
|
|
46
|
+
*
|
|
47
|
+
* Mobius may prepend injected context (project/issue framing) to a user turn, so we
|
|
48
|
+
* match the typed text as a suffix of the entry's normalized text rather than
|
|
49
|
+
* requiring exact equality; a verbatim entry still matches because it ends with the
|
|
50
|
+
* typed text.
|
|
51
|
+
*/
|
|
52
|
+
function entryMatchesPendingUser(entry: AnyEntry, pendingText: string): boolean {
|
|
53
|
+
if (!pendingText) return false
|
|
54
|
+
const want = pendingText.replace(/\s+/g, ' ').trim()
|
|
55
|
+
if (!want) return false
|
|
56
|
+
for (const view of viewsForEntry(entry)) {
|
|
57
|
+
if (view.kind !== 'user') continue
|
|
58
|
+
const got = view.text.replace(/\s+/g, ' ').trim()
|
|
59
|
+
if (got === want || got.endsWith(want)) return true
|
|
60
|
+
}
|
|
61
|
+
return false
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Stable identity for de-duplication. Every Mobius jsonl entry carries a uuid. */
|
|
65
|
+
function entryKey(entry: AnyEntry): string | null {
|
|
66
|
+
return typeof entry?.uuid === 'string' ? entry.uuid : null
|
|
67
|
+
}
|
|
68
|
+
|
|
41
69
|
// Retry transient gateway/transport errors so a brief 502/503/504 (a reverse-
|
|
42
70
|
// proxy blip, a backend worker recycling after a deploy, a transient upstream
|
|
43
71
|
// failure) doesn't immediately fail a message dispatch. 4xx errors are not
|