@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mobius-os/mobius",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "type": "module",
5
5
  "description": "Mobius terminal client. Reuses Mobius frontend TypeScript types and jsonl entry shapes.",
6
6
  "bin": {
@@ -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
- const showWelcome = fitted.estimatedRows + WELCOME_ROWS <= transcriptRows
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
@@ -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