Skip to content

Commit 345efd1

Browse files
author
SqlRush
committed
Accept string dialog payloads
1 parent 6dbdbf6 commit 345efd1

4 files changed

Lines changed: 104 additions & 27 deletions

File tree

docs/cc-100-roadmap.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -642,7 +642,7 @@ M7 补充:prompt history `LogEntry` 读取现在接受 `sessionID`/`session`/`
642642

643643
本轮补充:interaction script 的 direct single message 字段现在也复用 raw message parser;`message`/`Message` 可递归解包 `resource.attributes``edge.node.attrs`,并在数组形态下回退为多条 message 追加,避免单条消息 wrapper 被基础解码成空消息。
644644

645-
本轮补充:interaction script 的 direct dialog 字段现在改为 raw payload 解析;`dialog`/`Dialog` 可递归解包 `resource.attributes``edge.node.attrs` 和单元素数组,`showDialog` action payload 也复用同一解析路径,避免 wrapper-only dialog 被解码成空弹窗
645+
本轮补充:interaction script 的 direct dialog 字段现在改为 raw payload 解析;`dialog`/`Dialog` 可递归解包 `resource.attributes``edge.node.attrs` 和单元素数组,`showDialog` action payload 也复用同一解析路径,dialog payload 的 `ID`/`Focused` 可接受数字和数字字符串,避免 wrapper-only 或 Go 默认字段名 dialog 被解码失败/空弹窗
646646

647647
本轮补充:interaction script 的 direct image 字段现在改为 raw payload 解析;`image`/`Image` 可复用 pasteImage action 的 wrapper 解析,递归解包 `resource.attributes``edge.node.attrs` 和单元素数组,保留 filename/media/content/source-path 后再生成 prompt pasted-image。
648648

docs/claude-code-go-rewrite-plan.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ test/parity/ # golden tests against TS/official behavior
330330
- 本轮补充:interaction script 的 direct mouse 字段现在改为 raw payload 解析;`mouse`/`mouse_event`/`mouseEvent` singular 字段可接受单元素数组并递归解包 `resource.attributes``edge.node.attrs` 等 wrapper,避免录制脚本把鼠标事件包成 API payload 时提前失败。
331331
- 本轮补充:interaction script 的 direct message list 字段现在改为 raw payload 解析;`messages`/`appendMessages`/`transcriptMessages` 可递归解包 `resource.attributes``data[]``edge.node.attrs` 等 API/GraphQL wrapper,并保留 image paste id 等 message metadata。
332332
- 本轮补充:interaction script 的 direct single message 字段现在也复用 raw message parser;`message`/`Message` 可递归解包 `resource.attributes``edge.node.attrs`,并在数组形态下回退为多条 message 追加,避免单条消息 wrapper 被基础解码成空消息。
333-
- 本轮补充:interaction script 的 direct dialog 字段现在改为 raw payload 解析;`dialog`/`Dialog` 可递归解包 `resource.attributes``edge.node.attrs` 和单元素数组,`showDialog` action payload 也复用同一解析路径,避免 wrapper-only dialog 被解码成空弹窗
333+
- 本轮补充:interaction script 的 direct dialog 字段现在改为 raw payload 解析;`dialog`/`Dialog` 可递归解包 `resource.attributes``edge.node.attrs` 和单元素数组,`showDialog` action payload 也复用同一解析路径,dialog payload 的 `ID`/`Focused` 可接受数字和数字字符串,避免 wrapper-only 或 Go 默认字段名 dialog 被解码失败/空弹窗
334334
- 本轮补充:interaction script 的 direct image 字段现在改为 raw payload 解析;`image`/`Image` 可复用 pasteImage action 的 wrapper 解析,递归解包 `resource.attributes``edge.node.attrs` 和单元素数组,保留 filename/media/content/source-path 后再生成 prompt pasted-image。
335335
- 本轮补充:interaction script 的 direct keybinding mutation 字段现在改为 raw-only 解析;`keybindings`/`key_bindings`/`keyBindings`/`keybindingSpecs`/`Keybindings` 不再先走 `[]BindingSpec` 基础解码,统一复用 keybinding loader 的 object-map、resource wrapper 和 edge/node collection parser。
336336
- 本轮补充:interaction script 的 UpperCamel step 字段现在也进入 raw/wrapper 解析路径;`UpsertTask`、`CancelAllTasks`、`OpenTasksDialog`、`ExpectEvent(s)`、`ExpectDialog`、`ExpectDialogResult(s)`、`ExpectPrompt`、`ExpectVim`、`ExpectScreen`、`ExpectViewport`、`ExpectReverseSearch`、`ExpectTasks` 等 Go 默认字段名可直接接受 JSON:API/GraphQL-style wrapper,task status/expectation 的 ID/title/state/detail/progress、tasks expectation 的 Count/StateCounts、event expectation 的 Type/Value/DialogID、dialog expectation 的 Active/ActionCount/FocusedIndex、dialog-result expectation 的 ID/Found/Stale、prompt expectation 的 Cursor/PastedContentCount/NextPastedID/Empty、pasted-content expectation 的 ID/MediaType/Filename/ContentContains、vim expectation 的 Enabled/Mode/Register/RegisterLinewise、screen expectation 的 Width/Height、viewport expectation 的 Offset/VisibleLineCount 和 reverse-search expectation 的 Cursor/ResultCount/NoResults 改为 raw-first 解码并继续接受数字字符串/非严格 bool。

internal/tui/script_aliases.go

Lines changed: 91 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4108,15 +4108,92 @@ func (expect *DialogExpectation) UnmarshalJSON(data []byte) error {
41084108

41094109
func (dialog *Dialog) UnmarshalJSON(data []byte) error {
41104110
data = normalizeStringFieldsToArray(data,
4111-
"actions",
41124111
"Actions",
4112+
"actions",
4113+
"Options",
41134114
"options",
4115+
"Choices",
41144116
"choices",
4117+
"Buttons",
41154118
"buttons",
41164119
)
41174120
type alias Dialog
41184121
var raw alias
4119-
if err := json.Unmarshal(data, &raw); err != nil {
4122+
if err := json.Unmarshal(stripJSONAliasFields(data,
4123+
"ID",
4124+
"id",
4125+
"DialogID",
4126+
"dialog_id",
4127+
"dialogId",
4128+
"dialogID",
4129+
"PermissionID",
4130+
"permission_id",
4131+
"permissionId",
4132+
"permissionID",
4133+
"RequestID",
4134+
"request_id",
4135+
"requestId",
4136+
"requestID",
4137+
"ToolUseID",
4138+
"tool_use_id",
4139+
"toolUseId",
4140+
"toolUseID",
4141+
"OperationID",
4142+
"operation_id",
4143+
"operationId",
4144+
"operationID",
4145+
"Kind",
4146+
"kind",
4147+
"DialogKind",
4148+
"dialog_kind",
4149+
"dialogKind",
4150+
"DialogType",
4151+
"dialog_type",
4152+
"dialogType",
4153+
"Title",
4154+
"title",
4155+
"Heading",
4156+
"heading",
4157+
"Header",
4158+
"header",
4159+
"Label",
4160+
"label",
4161+
"Name",
4162+
"name",
4163+
"Body",
4164+
"body",
4165+
"Content",
4166+
"content",
4167+
"Text",
4168+
"text",
4169+
"Message",
4170+
"message",
4171+
"Description",
4172+
"description",
4173+
"Actions",
4174+
"actions",
4175+
"Options",
4176+
"options",
4177+
"Choices",
4178+
"choices",
4179+
"Buttons",
4180+
"buttons",
4181+
"Focused",
4182+
"focused",
4183+
"FocusedIndex",
4184+
"focused_index",
4185+
"focusedIndex",
4186+
"FocusIndex",
4187+
"focus_index",
4188+
"focusIndex",
4189+
"SelectedIndex",
4190+
"selected_index",
4191+
"selectedIndex",
4192+
"Focus",
4193+
"focus",
4194+
"Selected",
4195+
"selected",
4196+
), &raw); err != nil {
41204197
return err
41214198
}
41224199
*dialog = Dialog(raw)
@@ -4125,26 +4202,26 @@ func (dialog *Dialog) UnmarshalJSON(data []byte) error {
41254202
if err := json.Unmarshal(data, &fields); err != nil {
41264203
return err
41274204
}
4205+
if dialog.ID == "" {
4206+
dialog.ID = scalarStringJSONField(fields, "ID", "id", "DialogID", "dialog_id", "dialogId", "dialogID", "PermissionID", "permission_id", "permissionId", "permissionID", "RequestID", "request_id", "requestId", "requestID", "ToolUseID", "tool_use_id", "toolUseId", "toolUseID", "OperationID", "operation_id", "operationId", "operationID")
4207+
}
4208+
if dialog.Kind == "" {
4209+
if dialogKind := stringJSONField(fields, "Kind", "kind", "DialogKind", "dialog_kind", "dialogKind", "DialogType", "dialog_type", "dialogType"); dialogKind != "" {
4210+
dialog.Kind = DialogKind(dialogKind)
4211+
}
4212+
}
41284213
if dialog.Title == "" {
4129-
dialog.Title = stringJSONField(fields, "heading", "header", "label", "name")
4214+
dialog.Title = stringJSONField(fields, "Title", "title", "Heading", "heading", "Header", "header", "Label", "label", "Name", "name")
41304215
}
41314216
if dialog.Body == "" {
4132-
dialog.Body = stringJSONField(fields, "content", "text", "message", "description")
4217+
dialog.Body = stringJSONField(fields, "Body", "body", "Content", "content", "Text", "text", "Message", "message", "Description", "description")
41334218
}
41344219
if len(dialog.Actions) == 0 {
4135-
dialog.Actions = stringListJSONField(fields, "options", "choices", "buttons")
4220+
dialog.Actions = stringListJSONField(fields, "Actions", "actions", "Options", "options", "Choices", "choices", "Buttons", "buttons")
41364221
}
4137-
if focused := intPtrJSONField(fields, "focused_index", "focusedIndex", "selected_index", "selectedIndex", "focus", "selected"); focused != nil {
4222+
if focused := intPtrJSONField(fields, "Focused", "focused", "FocusedIndex", "focused_index", "focusedIndex", "FocusIndex", "focus_index", "focusIndex", "SelectedIndex", "selected_index", "selectedIndex", "Focus", "focus", "Selected", "selected"); focused != nil {
41384223
dialog.Focused = *focused
41394224
}
4140-
if dialog.ID == "" {
4141-
dialog.ID = scalarStringJSONField(fields, "dialog_id", "dialogId", "dialogID", "permission_id", "permissionId", "permissionID", "request_id", "requestId", "requestID", "tool_use_id", "toolUseId", "toolUseID", "operation_id", "operationId", "operationID")
4142-
}
4143-
if dialog.Kind == "" {
4144-
if dialogKind := stringJSONField(fields, "dialog_kind", "dialogKind"); dialogKind != "" {
4145-
dialog.Kind = DialogKind(dialogKind)
4146-
}
4147-
}
41484225
return nil
41494226
}
41504227

internal/tui/tui_test.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7000,28 +7000,28 @@ func TestRunInteractionScriptAcceptsWrappedDialogStepFields(t *testing.T) {
70007000
"resource": {
70017001
"type": "dialog",
70027002
"attributes": {
7003-
"dialogId": "wrapped_direct",
7004-
"dialogKind": "permission",
7005-
"heading": "Wrapped Direct",
7006-
"content": "Choose direct.",
7007-
"options": ["Proceed", "Cancel"],
7008-
"focusedIndex": 0
7003+
"ID": 123,
7004+
"Kind": "permission",
7005+
"Title": "Wrapped Direct",
7006+
"Body": "Choose direct.",
7007+
"Actions": "Proceed",
7008+
"Focused": "0"
70097009
}
70107010
}
70117011
},
70127012
"expectDialog": {
70137013
"visible": true,
7014-
"dialogId": "wrapped_direct",
7014+
"dialogId": "123",
70157015
"dialogKind": "permission",
70167016
"heading": "Wrapped Direct",
70177017
"content": "Choose direct.",
7018-
"actions": ["Proceed", "Cancel"],
7018+
"actions": "Proceed",
70197019
"focusedIndex": 0
70207020
}
70217021
},
70227022
{
70237023
"key": "enter",
7024-
"expectEvent": {"type": "dialog_action", "value": "Proceed", "dialogId": "wrapped_direct", "dialogKind": "permission"}
7024+
"expectEvent": {"type": "dialog_action", "value": "Proceed", "dialogId": "123", "dialogKind": "permission"}
70257025
},
70267026
{
70277027
"dialog": [
@@ -7050,7 +7050,7 @@ func TestRunInteractionScriptAcceptsWrappedDialogStepFields(t *testing.T) {
70507050
t.Fatal(err)
70517051
}
70527052
if len(steps) != 4 ||
7053-
steps[0].Dialog == nil || steps[0].Dialog.ID != "wrapped_direct" || steps[0].Dialog.Title != "Wrapped Direct" || len(steps[0].Dialog.Actions) != 2 ||
7053+
steps[0].Dialog == nil || steps[0].Dialog.ID != "123" || steps[0].Dialog.Title != "Wrapped Direct" || len(steps[0].Dialog.Actions) != 1 ||
70547054
steps[2].Dialog == nil || steps[2].Dialog.ID != "wrapped_array" || steps[2].Dialog.Title != "Wrapped Array" || len(steps[2].Dialog.Actions) != 1 {
70557055
t.Fatalf("steps = %#v", steps)
70567056
}
@@ -7060,7 +7060,7 @@ func TestRunInteractionScriptAcceptsWrappedDialogStepFields(t *testing.T) {
70607060
t.Fatal(err)
70617061
}
70627062
if len(result.Events) != 2 ||
7063-
result.Events[0].DialogID != "wrapped_direct" || result.Events[0].Value != "Proceed" ||
7063+
result.Events[0].DialogID != "123" || result.Events[0].Value != "Proceed" ||
70647064
result.Events[1].DialogID != "wrapped_array" || result.Events[1].Value != "Approve" {
70657065
t.Fatalf("events = %#v", result.Events)
70667066
}

0 commit comments

Comments
 (0)