diff --git a/.gitignore b/.gitignore index 471efbebaf00..92bb52c665c2 100644 --- a/.gitignore +++ b/.gitignore @@ -90,3 +90,4 @@ go/keybase_openbsd .claude .*-mcp CLAUDE.md +.tsOuts diff --git a/go/chat/flipmanager.go b/go/chat/flipmanager.go index 8528086e68ee..1b4112b0951e 100644 --- a/go/chat/flipmanager.go +++ b/go/chat/flipmanager.go @@ -610,7 +610,7 @@ func (m *FlipManager) formatError(ctx context.Context, rawErr error) chat1.UICoi } func (m *FlipManager) handleSummaryUpdate(ctx context.Context, gameID chat1.FlipGameID, - update *flip.GameSummary, convID chat1.ConversationID, force bool, + update *flip.GameSummary, statusConvID chat1.ConversationID, resultConvID chat1.ConversationID, force bool, ) (status chat1.UICoinFlipStatus) { defer m.queueDirtyGameID(ctx, gameID, force) if update.Err != nil { @@ -622,6 +622,7 @@ func (m *FlipManager) handleSummaryUpdate(ctx context.Context, gameID chat1.Flip formatted := m.formatError(ctx, update.Err) status = chat1.UICoinFlipStatus{ GameID: gameID.FlipGameIDStr(), + ConvID: statusConvID.ConvIDStr(), Phase: chat1.UICoinFlipPhase_ERROR, ProgressText: fmt.Sprintf("Something went wrong: %s", update.Err), Participants: parts, @@ -632,9 +633,10 @@ func (m *FlipManager) handleSummaryUpdate(ctx context.Context, gameID chat1.Flip } status = chat1.UICoinFlipStatus{ GameID: gameID.FlipGameIDStr(), + ConvID: statusConvID.ConvIDStr(), Phase: chat1.UICoinFlipPhase_COMPLETE, } - m.addResult(ctx, &status, update.Result, convID) + m.addResult(ctx, &status, update.Result, resultConvID) for _, p := range update.Players { m.addParticipant(ctx, &status, flip.CommitmentUpdate{ User: p.Device, @@ -669,6 +671,14 @@ func (m *FlipManager) handleUpdate(ctx context.Context, update flip.GameStateUpd GameID: gameID.FlipGameIDStr(), } } + if len(status.ConvID) == 0 { + hmi, hmiErr := m.getHostMessageInfo(ctx, update.Metadata.ConversationID) + if hmiErr != nil { + m.Debug(ctx, "handleUpdate: failed to get host message info: %s", hmiErr) + } else { + status.ConvID = hmi.ConvID.ConvIDStr() + } + } switch { case update.Err != nil: @@ -1371,10 +1381,10 @@ func (m *FlipManager) loadGame(ctx context.Context, job loadGameJob) (err error) } } m.Debug(ctx, "loadGame: game had no action after pausing, sending error") - job.resCh <- m.handleSummaryUpdate(ctx, job.gameID, summary, flipConvID, true) + job.resCh <- m.handleSummaryUpdate(ctx, job.gameID, summary, hmi.ConvID, flipConvID, true) }(globals.BackgroundChatCtx(ctx, m.G()), summary) } else { - job.resCh <- m.handleSummaryUpdate(ctx, job.gameID, summary, flipConvID, true) + job.resCh <- m.handleSummaryUpdate(ctx, job.gameID, summary, hmi.ConvID, flipConvID, true) } return nil } @@ -1406,7 +1416,9 @@ func (m *FlipManager) LoadFlip(ctx context.Context, uid gregor1.UID, hostConvID default: m.queueDirtyGameID(ctx, gameID, true) res = make(chan chat1.UICoinFlipStatus, 1) - res <- stored.(chat1.UICoinFlipStatus) + status := stored.(chat1.UICoinFlipStatus) + status.ConvID = hostConvID.ConvIDStr() + res <- status err = make(chan error, 1) return res, err } diff --git a/go/chat/flipmanager_test.go b/go/chat/flipmanager_test.go index f061c396558d..a8d6b6cd0116 100644 --- a/go/chat/flipmanager_test.go +++ b/go/chat/flipmanager_test.go @@ -437,6 +437,7 @@ func TestFlipManagerLoadFlip(t *testing.T) { case updates := <-ui0.CoinFlipUpdates: require.Equal(t, 1, len(updates)) require.Equal(t, chat1.UICoinFlipPhase_COMPLETE, updates[0].Phase) + require.Equal(t, conv.Id.ConvIDStr(), updates[0].ConvID) require.Equal(t, res, updates[0].ResultText) case <-time.After(timeout): require.Fail(t, "no updates") diff --git a/go/protocol/chat1/chat_ui.go b/go/protocol/chat1/chat_ui.go index 70a744cf430c..c42d991ae124 100644 --- a/go/protocol/chat1/chat_ui.go +++ b/go/protocol/chat1/chat_ui.go @@ -2739,6 +2739,7 @@ func (o UICoinFlipParticipant) DeepCopy() UICoinFlipParticipant { type UICoinFlipStatus struct { GameID FlipGameIDStr `codec:"gameID" json:"gameID"` + ConvID ConvIDStr `codec:"convID" json:"convID"` Phase UICoinFlipPhase `codec:"phase" json:"phase"` ProgressText string `codec:"progressText" json:"progressText"` ResultText string `codec:"resultText" json:"resultText"` @@ -2752,6 +2753,7 @@ type UICoinFlipStatus struct { func (o UICoinFlipStatus) DeepCopy() UICoinFlipStatus { return UICoinFlipStatus{ GameID: o.GameID.DeepCopy(), + ConvID: o.ConvID.DeepCopy(), Phase: o.Phase.DeepCopy(), ProgressText: o.ProgressText, ResultText: o.ResultText, diff --git a/protocol/avdl/chat1/chat_ui.avdl b/protocol/avdl/chat1/chat_ui.avdl index f0e4cb64d733..054096969769 100644 --- a/protocol/avdl/chat1/chat_ui.avdl +++ b/protocol/avdl/chat1/chat_ui.avdl @@ -535,6 +535,7 @@ protocol chatUi { } record UICoinFlipStatus { FlipGameIDStr gameID; + ConvIDStr convID; UICoinFlipPhase phase; string progressText; string resultText; diff --git a/protocol/json/chat1/chat_ui.json b/protocol/json/chat1/chat_ui.json index fed9b38044ac..8d481c46ee3c 100644 --- a/protocol/json/chat1/chat_ui.json +++ b/protocol/json/chat1/chat_ui.json @@ -1929,6 +1929,10 @@ "type": "FlipGameIDStr", "name": "gameID" }, + { + "type": "ConvIDStr", + "name": "convID" + }, { "type": "UICoinFlipPhase", "name": "phase" diff --git a/shared/constants/types/rpc-chat-gen.tsx b/shared/constants/types/rpc-chat-gen.tsx index fb897f2c67d5..2b883c642956 100644 --- a/shared/constants/types/rpc-chat-gen.tsx +++ b/shared/constants/types/rpc-chat-gen.tsx @@ -1554,7 +1554,7 @@ export type UICoinFlipErrorParticipant = {readonly user: String; readonly device export type UICoinFlipHand = {readonly target: String; readonly hand?: ReadonlyArray | null} export type UICoinFlipParticipant = {readonly uid: String; readonly deviceID: String; readonly username: String; readonly deviceName: String; readonly commitment: String; readonly reveal?: String | null} export type UICoinFlipResult = {typ: UICoinFlipResultTyp.number; number: String} | {typ: UICoinFlipResultTyp.shuffle; shuffle: ReadonlyArray} | {typ: UICoinFlipResultTyp.deck; deck: ReadonlyArray} | {typ: UICoinFlipResultTyp.hands; hands: ReadonlyArray} | {typ: UICoinFlipResultTyp.coin; coin: Bool} -export type UICoinFlipStatus = {readonly gameID: FlipGameIDStr; readonly phase: UICoinFlipPhase; readonly progressText: String; readonly resultText: String; readonly commitmentVisualization: String; readonly revealVisualization: String; readonly participants?: ReadonlyArray | null; readonly errorInfo?: UICoinFlipError | null; readonly resultInfo?: UICoinFlipResult | null} +export type UICoinFlipStatus = {readonly gameID: FlipGameIDStr; readonly convID: ConvIDStr; readonly phase: UICoinFlipPhase; readonly progressText: String; readonly resultText: String; readonly commitmentVisualization: String; readonly revealVisualization: String; readonly participants?: ReadonlyArray | null; readonly errorInfo?: UICoinFlipError | null; readonly resultInfo?: UICoinFlipResult | null} export type UICommandMarkdown = {readonly body: String; readonly title?: String | null} export type UIInboxBigTeamChannelRow = {readonly convID: ConvIDStr; readonly teamname: String; readonly channelname: String; readonly draft?: String | null; readonly isMuted: Boolean} export type UIInboxBigTeamLabelRow = {readonly name: String; readonly id: TLFIDStr}