Skip to content

Commit 6dbdbf6

Browse files
author
SqlRush
committed
Accept string permission requests
1 parent ee24459 commit 6dbdbf6

4 files changed

Lines changed: 122 additions & 17 deletions

File tree

docs/cc-100-roadmap.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434

3535
M7 补充:scripted task runtime payload 和 task expectation 现在接受 `taskID``jobId``runId``label``displayName``phase``taskState``message``currentStep``percent`/`percentage`/`pct` 等相邻字段,并支持数字 task ID 与数字字符串 progress。
3636

37-
M7 补充:scripted permission payload、dialog expectation、event、cancel-permission 和 dialog-result expectation 现在接受 `permissionID``requestID``toolUseID``operationID``operation``commandName``resourcePath``body``reasonText``allowedActions``buttons` 等相邻字段,并支持数字 request ID。
37+
M7 补充:scripted permission payload、dialog expectation、event、cancel-permission 和 dialog-result expectation 现在接受 `ID`/`ToolName`/`Actions``permissionID``requestID``toolUseID``operationID``operation``commandName``resourcePath``body``reasonText``allowedActions``buttons` 等相邻字段,并支持数字 request ID。
3838

3939
M6 补充:microcompact disk cache loader 和 prune 现在接受 digest 缺失但文件名已 keyed 的 cache entry,会用 `<digest>.json` 文件名作为 digest fallback,同时保留显式 digest mismatch 的 invalid-cache guard。
4040

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ test/parity/ # golden tests against TS/official behavior
281281
- 本轮补充:task runtime 在状态行、任务面板排序/渲染、批量取消和 scripted task expectation 前会把 `active`/`in_progress``success`/`done``error``canceled` 等 task state 别名归一为 canonical 状态。
282282
- 本轮补充:scripted task runtime payload 和 task expectation 现在接受 `taskID``jobId``runId``label``displayName``phase``taskState``message``currentStep``percent`/`percentage`/`pct` 等相邻字段,并支持数字 task ID 与数字字符串 progress。
283283
- 本轮补充:permission runtime 会把 `Reject`/`deny`/`decline`/`disallow`/`no` 等 permission action 归一为 denied 结果,把 `Cancel`/`abort` 归一为 cancelled 结果,并让 scripted dialog-result status 断言接受 `rejected`/`approved` 等状态别名。
284-
- 本轮补充:scripted permission payload、dialog expectation、event、cancel-permission 和 dialog-result expectation 现在接受 `permissionID``requestID``toolUseID``operationID``operation``commandName``resourcePath``body``reasonText``allowedActions``buttons` 等相邻字段,并支持数字 request ID。
284+
- 本轮补充:scripted permission payload、dialog expectation、event、cancel-permission 和 dialog-result expectation 现在接受 `ID`/`ToolName`/`Actions``permissionID``requestID``toolUseID``operationID``operation``commandName``resourcePath``body``reasonText``allowedActions``buttons` 等相邻字段,并支持数字 request ID。
285285
- 本轮补充:scripted runtime 的 permission/task payload 现在会递归解包 `value`/`payload`/`data`/`resource`/`attributes`/`properties`/`attrs`/`edge`/`node` 等 JSON:API/GraphQL wrapper;resource/node 顶层 ID 会回填到内层 permission/task,并避免仅因 wrapper 顶层 ID 生成半空 runtime 对象。
286286
- 本轮补充:scripted runtime mutation 的 `removeTask`/`cancelPermission`/`cancelTasks` 现在也会从 wrapped `value`/`payload`/`data`/`resource`/`edge.node` 中递归读取 task/permission ID 和 cancellation detail,兼容 resource/action fixture 直接驱动 runtime mutation。
287287
- 本轮补充:scripted runtime mutation 的直接 alias 字段现在也接受 object payload,例如 `removeTask: {resource:{id}}``cancelPermission: {edge:{node:{id}}}``cancelTasks: {resource:{attributes:{reasonText}}}` 不再因 string/bool 强类型字段提前解析失败。

internal/tui/script_aliases.go

Lines changed: 111 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4217,7 +4217,112 @@ func (request *PermissionRequest) UnmarshalJSON(data []byte) error {
42174217
data = normalizeStringFieldsToArray(data, "Actions", "actions")
42184218
type alias PermissionRequest
42194219
var raw alias
4220-
if err := json.Unmarshal(data, &raw); err != nil {
4220+
if err := json.Unmarshal(stripJSONAliasFields(data,
4221+
"ID",
4222+
"id",
4223+
"RequestID",
4224+
"request_id",
4225+
"requestId",
4226+
"requestID",
4227+
"PermissionID",
4228+
"permission_id",
4229+
"permissionId",
4230+
"permissionID",
4231+
"ToolUseID",
4232+
"tool_use_id",
4233+
"toolUseId",
4234+
"toolUseID",
4235+
"OperationID",
4236+
"operation_id",
4237+
"operationId",
4238+
"operationID",
4239+
"ToolName",
4240+
"tool_name",
4241+
"toolName",
4242+
"Tool",
4243+
"tool",
4244+
"Name",
4245+
"name",
4246+
"Operation",
4247+
"operation",
4248+
"Command",
4249+
"command",
4250+
"CommandName",
4251+
"command_name",
4252+
"commandName",
4253+
"ToolTitle",
4254+
"tool_title",
4255+
"toolTitle",
4256+
"Path",
4257+
"path",
4258+
"FilePath",
4259+
"file_path",
4260+
"filePath",
4261+
"TargetPath",
4262+
"target_path",
4263+
"targetPath",
4264+
"ResourcePath",
4265+
"resource_path",
4266+
"resourcePath",
4267+
"WorkingDirectory",
4268+
"working_directory",
4269+
"workingDirectory",
4270+
"Cwd",
4271+
"cwd",
4272+
"Target",
4273+
"target",
4274+
"Resource",
4275+
"resource",
4276+
"URI",
4277+
"uri",
4278+
"URL",
4279+
"url",
4280+
"File",
4281+
"file",
4282+
"Filename",
4283+
"filename",
4284+
"Description",
4285+
"description",
4286+
"Prompt",
4287+
"prompt",
4288+
"Message",
4289+
"message",
4290+
"Reason",
4291+
"reason",
4292+
"ReasonText",
4293+
"reason_text",
4294+
"reasonText",
4295+
"Summary",
4296+
"summary",
4297+
"Details",
4298+
"details",
4299+
"Body",
4300+
"body",
4301+
"Text",
4302+
"text",
4303+
"Content",
4304+
"content",
4305+
"Actions",
4306+
"actions",
4307+
"Options",
4308+
"options",
4309+
"Choices",
4310+
"choices",
4311+
"AllowedActions",
4312+
"allowed_actions",
4313+
"allowedActions",
4314+
"AvailableActions",
4315+
"available_actions",
4316+
"availableActions",
4317+
"ActionChoices",
4318+
"action_choices",
4319+
"actionChoices",
4320+
"Buttons",
4321+
"buttons",
4322+
"ActionsList",
4323+
"actions_list",
4324+
"actionsList",
4325+
), &raw); err != nil {
42214326
return err
42224327
}
42234328
*request = PermissionRequest(raw)
@@ -4227,19 +4332,19 @@ func (request *PermissionRequest) UnmarshalJSON(data []byte) error {
42274332
return err
42284333
}
42294334
if request.ID == "" {
4230-
request.ID = scalarStringJSONField(fields, "request_id", "requestId", "requestID", "permission_id", "permissionId", "permissionID", "tool_use_id", "toolUseId", "toolUseID", "operation_id", "operationId", "operationID", "id")
4335+
request.ID = scalarStringJSONField(fields, "ID", "id", "RequestID", "request_id", "requestId", "requestID", "PermissionID", "permission_id", "permissionId", "permissionID", "ToolUseID", "tool_use_id", "toolUseId", "toolUseID", "OperationID", "operation_id", "operationId", "operationID")
42314336
}
42324337
if request.ToolName == "" {
4233-
request.ToolName = stringJSONField(fields, "tool_name", "toolName", "tool", "name", "operation", "command", "command_name", "commandName", "tool_title", "toolTitle")
4338+
request.ToolName = stringJSONField(fields, "ToolName", "tool_name", "toolName", "Tool", "tool", "Name", "name", "Operation", "operation", "Command", "command", "CommandName", "command_name", "commandName", "ToolTitle", "tool_title", "toolTitle")
42344339
}
42354340
if request.Path == "" {
4236-
request.Path = stringJSONField(fields, "file_path", "filePath", "target_path", "targetPath", "resource_path", "resourcePath", "working_directory", "workingDirectory", "cwd", "path", "target", "resource", "uri", "url", "file", "filename")
4341+
request.Path = stringJSONField(fields, "Path", "path", "FilePath", "file_path", "filePath", "TargetPath", "target_path", "targetPath", "ResourcePath", "resource_path", "resourcePath", "WorkingDirectory", "working_directory", "workingDirectory", "Cwd", "cwd", "Target", "target", "Resource", "resource", "URI", "uri", "URL", "url", "File", "file", "Filename", "filename")
42374342
}
42384343
if request.Description == "" {
4239-
request.Description = stringJSONField(fields, "prompt", "message", "reason", "reason_text", "reasonText", "summary", "description", "details", "body", "text", "content")
4344+
request.Description = stringJSONField(fields, "Description", "description", "Prompt", "prompt", "Message", "message", "Reason", "reason", "ReasonText", "reason_text", "reasonText", "Summary", "summary", "Details", "details", "Body", "body", "Text", "text", "Content", "content")
42404345
}
42414346
if len(request.Actions) == 0 {
4242-
request.Actions = stringListJSONField(fields, "options", "choices", "allowed_actions", "allowedActions", "available_actions", "availableActions", "action_choices", "actionChoices", "buttons", "actions_list", "actionsList")
4347+
request.Actions = stringListJSONField(fields, "Actions", "actions", "Options", "options", "Choices", "choices", "AllowedActions", "allowed_actions", "allowedActions", "AvailableActions", "available_actions", "availableActions", "ActionChoices", "action_choices", "actionChoices", "Buttons", "buttons", "ActionsList", "actions_list", "actionsList")
42434348
}
42444349
return nil
42454350
}

internal/tui/tui_test.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6684,19 +6684,19 @@ func TestRunDialogRuntimeScriptAcceptsPermissionRequestAliases(t *testing.T) {
66846684
steps, err := ParseInteractionScript([]byte(`[
66856685
{
66866686
"request_permission": {
6687-
"permissionId": "perm_alias",
6688-
"tool": "Write",
6689-
"filePath": "/tmp/a.txt",
6690-
"prompt": "Need write access.",
6691-
"actions": "Approve"
6687+
"ID": 9001,
6688+
"ToolName": "Write",
6689+
"Path": "/tmp/a.txt",
6690+
"Description": "Need write access.",
6691+
"Actions": "Approve"
66926692
},
6693-
"expectDialog": {"active": true, "id": "perm_alias", "kind": "permission"},
6693+
"expectDialog": {"active": true, "id": "9001", "kind": "permission"},
66946694
"expectSnapshotContains": ["Tool: Write", "Path: /tmp/a.txt", "Need write access.", "Approve"]
66956695
},
66966696
{
66976697
"key": "enter",
6698-
"expectEvent": {"type": "dialog_action", "value": "Approve", "dialogId": "perm_alias", "dialogKind": "permission"},
6699-
"expectDialogResult": {"id": "perm_alias", "kind": "permission", "action": "Approve", "status": "allowed", "found": true}
6698+
"expectEvent": {"type": "dialog_action", "value": "Approve", "dialogId": "9001", "dialogKind": "permission"},
6699+
"expectDialogResult": {"id": "9001", "kind": "permission", "action": "Approve", "status": "allowed", "found": true}
67006700
}
67016701
]`))
67026702
if err != nil {
@@ -6708,7 +6708,7 @@ func TestRunDialogRuntimeScriptAcceptsPermissionRequestAliases(t *testing.T) {
67086708
if err != nil {
67096709
t.Fatal(err)
67106710
}
6711-
if len(result.DialogResults) != 1 || result.DialogResults[0].ID != "perm_alias" || result.DialogResults[0].Status != DialogResultAllowed {
6711+
if len(result.DialogResults) != 1 || result.DialogResults[0].ID != "9001" || result.DialogResults[0].Status != DialogResultAllowed {
67126712
t.Fatalf("dialog results = %#v", result.DialogResults)
67136713
}
67146714
if len(runtime.Permissions) != 0 || runtime.Active != nil {

0 commit comments

Comments
 (0)