Files
weichen b5a782bb38 feat(chat): dialogue triggers for comments/reopen/pending-supplements with mistouch guards
Wire intent→coordinator DocResolver confirm cards→action_executor kinds for comment, reopen, pending-supplements query, and real submit-review execution.
2026-09-25 20:14:10 +00:00

116 lines
4.4 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package supplementimpact
import (
"context"
"fmt"
"time"
)
// HTTPBatchView is the JSON shape expected by server supplement-impact handlers.
type HTTPBatchView struct {
BatchID string `json:"batch_id"`
ProjectID int64 `json:"project_id"`
SessionID string `json:"session_id,omitempty"`
InitiatorUserID int64 `json:"initiator_user_id"`
SourceKind string `json:"source_kind,omitempty"`
SourceSummary string `json:"source_summary,omitempty"`
CoverageStatus string `json:"coverage_status,omitempty"`
Status string `json:"status"`
DecisionNonce string `json:"decision_nonce"`
DecisionDigest string `json:"decision_digest,omitempty"`
Revision int64 `json:"revision"`
ExpiresAt time.Time `json:"expires_at"`
Items []HTTPItemView `json:"items,omitempty"`
}
type HTTPItemView struct {
DocID string `json:"doc_id"`
Title string `json:"title,omitempty"`
ItemKey string `json:"item_key,omitempty"`
ImpactType string `json:"impact_type,omitempty"`
Depth int `json:"depth,omitempty"`
Reason string `json:"reason,omitempty"`
AuthorClaimedSnapshot bool `json:"author_claimed_snapshot"`
BusySnapshot bool `json:"busy_snapshot"`
LockedSnapshot bool `json:"locked_snapshot"`
ChangeSummary string `json:"change_summary,omitempty"`
Selected bool `json:"selected"`
Outcome string `json:"outcome,omitempty"`
ProposalID string `json:"proposal_id,omitempty"`
}
// HTTPDecision is the CAS decision envelope from HTTP.
type HTTPDecision struct {
Kind string
SelectedDocIDs []string
DecisionNonce string
DecisionDigest string
ExpectedRevision int64
}
// HTTPPort adapts *Service to the server SupplementImpactService port.
type HTTPPort struct{ Svc *Service }
func (p HTTPPort) GetBatch(ctx context.Context, batchID string) (*HTTPBatchView, error) {
if p.Svc == nil || p.Svc.Store == nil {
return nil, fmt.Errorf("supplementimpact: not configured")
}
b, err := p.Svc.Store.GetBatch(ctx, batchID)
if err != nil {
return nil, err
}
return toHTTPView(b), nil
}
func (p HTTPPort) Decide(ctx context.Context, batchID string, actorUserID int64, in HTTPDecision) (*HTTPBatchView, error) {
if p.Svc == nil {
return nil, fmt.Errorf("supplementimpact: not configured")
}
b, err := p.Svc.Decide(ctx, DecisionCommand{
BatchID: batchID, ActorUserID: actorUserID, Kind: in.Kind,
SelectedDocIDs: in.SelectedDocIDs, DecisionNonce: in.DecisionNonce,
DecisionDigest: in.DecisionDigest, ExpectedRevision: in.ExpectedRevision,
})
if err != nil {
return nil, err
}
return toHTTPView(b), nil
}
func toHTTPView(b *Batch) *HTTPBatchView {
if b == nil {
return nil
}
v := &HTTPBatchView{
BatchID: b.BatchID, ProjectID: b.ProjectID, SessionID: b.SessionID,
InitiatorUserID: b.InitiatorUserID, SourceKind: b.SourceKind, SourceSummary: b.SourceSummary,
CoverageStatus: b.CoverageStatus, Status: b.Status, DecisionNonce: b.DecisionNonce,
DecisionDigest: b.DecisionDigest, Revision: b.Revision, ExpiresAt: b.ExpiresAt,
}
for _, it := range b.Items {
v.Items = append(v.Items, HTTPItemView{
DocID: it.DocID, Title: it.Title, ItemKey: it.ItemKey, ImpactType: it.ImpactType,
Depth: it.Depth, Reason: it.Reason, AuthorClaimedSnapshot: it.AuthorClaimedSnapshot,
BusySnapshot: it.BusySnapshot, LockedSnapshot: it.LockedSnapshot, ChangeSummary: it.ChangeSummary,
Selected: it.Selected, Outcome: it.Outcome, ProposalID: it.ProposalID,
})
}
return v
}
// BuildConfirmCardJSON returns a lightweight map for coordinator InteractiveCardPayload.ProposedContent.
func BuildConfirmCardMeta(b *Batch) (title, summary string) {
if b == nil {
return "补充影响确认", ""
}
n := len(b.Items)
switch b.CoverageStatus {
case "index_pending", "partial", "failed":
return "补充影响分析未完成", fmt.Sprintf("覆盖状态:%s(不得视为无影响)。批次 %s", b.CoverageStatus, b.BatchID)
}
if n == 0 {
return "补充已记录", fmt.Sprintf("暂无文档受影响。批次 %s", b.BatchID)
}
return fmt.Sprintf("本次补充可能影响 %d 份文档", n), fmt.Sprintf("请勾选要更新的文档。批次 %s;nonce=%s;rev=%d", b.BatchID, b.DecisionNonce, b.Revision)
}