@jingyi0605/codingns 1.0.0-beta.1 → 1.0.0-beta.2

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.
Files changed (105) hide show
  1. package/dist/public/assets/AdaptiveButlerPage-BHUAx_24.js +2 -0
  2. package/dist/public/assets/{App-CHsm-VrM.js → App-D5hc6KuU.js} +6 -6
  3. package/dist/public/assets/{BootstrapPage-Bp0KfySv.js → BootstrapPage-C2sMZMJa.js} +1 -1
  4. package/dist/public/assets/ConversationPage-CDpyEOUA.js +9 -0
  5. package/dist/public/assets/{DesktopDetachPreviewPage-DlDSb_tf.js → DesktopDetachPreviewPage-D9Abm5NU.js} +1 -1
  6. package/dist/public/assets/{DesktopModal-Csj5AdAN.js → DesktopModal-BCVZq_PQ.js} +1 -1
  7. package/dist/public/assets/{DesktopWindowPage-CacXiWjV.js → DesktopWindowPage-Cotl5fte.js} +1 -1
  8. package/dist/public/assets/{FileContextPanel-DzMUQvE5.js → FileContextPanel-DbPOq5w-.js} +1 -1
  9. package/dist/public/assets/{GitSidebar-C8IC18GH.js → GitSidebar-Cuxi2R93.js} +1 -1
  10. package/dist/public/assets/{MobileCreateSessionSheet-BtqR_hKc.js → MobileCreateSessionSheet-DYqarJqO.js} +1 -1
  11. package/dist/public/assets/{MobileSheet-Co-qPMBD.js → MobileSheet-DPYtp5Ze.js} +1 -1
  12. package/dist/public/assets/{PluginAccessOverview-D-KXkcyj.js → PluginAccessOverview-CiVzb_NI.js} +1 -1
  13. package/dist/public/assets/{PluginContainerPage-BKwCIs4r.js → PluginContainerPage-BfZ3E41c.js} +1 -1
  14. package/dist/public/assets/{PluginDetailPage-Djv_swcO.js → PluginDetailPage-DQQAg_ba.js} +1 -1
  15. package/dist/public/assets/{PluginsListPage-DAECNoN6.js → PluginsListPage-bF1NmA_r.js} +1 -1
  16. package/dist/public/assets/{PureConversationPage-DP1X7Hix.js → PureConversationPage-CWji-ARJ.js} +1 -1
  17. package/dist/public/assets/{RelayConnectEntryPage-xL_IPH8a.js → RelayConnectEntryPage-D4-3Fher.js} +1 -1
  18. package/dist/public/assets/{ServerSettingsModal-CyhMgk10.js → ServerSettingsModal-BUY1Y3g6.js} +1 -1
  19. package/dist/public/assets/{SessionIndexPage-CVEz50tc.js → SessionIndexPage-zVB9jnzP.js} +1 -1
  20. package/dist/public/assets/SettingsPage-DeqR2p7d.js +2 -0
  21. package/dist/public/assets/{TerminalManagerPanel-wVnoRA8u.js → TerminalManagerPanel-BjnC70ga.js} +1 -1
  22. package/dist/public/assets/{ToolFilesPage-BospXumK.js → ToolFilesPage-BZseQqvZ.js} +1 -1
  23. package/dist/public/assets/{ToolGitPage-B2zOeCAD.js → ToolGitPage-SrOO8Ftz.js} +1 -1
  24. package/dist/public/assets/{ToolProcessesPage-BDShao4b.js → ToolProcessesPage-Dbzlqjdy.js} +1 -1
  25. package/dist/public/assets/{ToolsHomePage-s4zH7D9M.js → ToolsHomePage-BBilUc0P.js} +1 -1
  26. package/dist/public/assets/{WorkbenchLandingPage-D51QCU_u.js → WorkbenchLandingPage-FdsBC8WN.js} +1 -1
  27. package/dist/public/assets/WorkbenchLayout-yGxGKcG1.js +1081 -0
  28. package/dist/public/assets/{WorkbenchModal-YsyEdJ_m.js → WorkbenchModal-Cm-ciXO9.js} +1 -1
  29. package/dist/public/assets/WorkbenchShellRoute-CijuAd9-.js +1 -0
  30. package/dist/public/assets/WorkbenchShellRoute-DpycFsbp.css +1 -0
  31. package/dist/public/assets/{WorkspaceDebugDetailPage-CMjNLqFq.js → WorkspaceDebugDetailPage-CZtpOiY0.js} +1 -1
  32. package/dist/public/assets/{WorkspaceDetailPage-CKxTbPKh.js → WorkspaceDetailPage-CbbgUz1H.js} +1 -1
  33. package/dist/public/assets/{WorkspaceHomePage-CEy4ShCu.js → WorkspaceHomePage-DMNJKAYe.js} +1 -1
  34. package/dist/public/assets/{client-runtime-manager-BFXU9DmS.js → client-runtime-manager-tsFkLtO_.js} +1 -1
  35. package/dist/public/assets/{host-alias-Zb2xyVrf.js → host-alias-df5bYDlE.js} +1 -1
  36. package/dist/public/assets/index-CILPuSCp.js +50 -0
  37. package/dist/public/assets/index-CSlwKnM4.css +1 -0
  38. package/dist/public/assets/{login-direct-candidate-resolver-DL8DS-Si.js → login-direct-candidate-resolver-pkfXrMJy.js} +1 -1
  39. package/dist/public/assets/peer-host-config-sync-nS_66OLg.js +1 -0
  40. package/dist/public/assets/{plugin-permission-copy-DrLk22m5.js → plugin-permission-copy-LDy-lW7h.js} +1 -1
  41. package/dist/public/assets/{plugins-api-COF4oh24.js → plugins-api-BGF9OybZ.js} +1 -1
  42. package/dist/public/assets/{preferences-service-CEWNV1w9.js → preferences-service-BC25oxA_.js} +1 -1
  43. package/dist/public/assets/{relay-entry-Cmc8vTlE.js → relay-entry-ErQKnI7B.js} +1 -1
  44. package/dist/public/assets/{useRegisteredDebugTemplates-FdmHG2S4.js → useRegisteredDebugTemplates-BTr3ATCZ.js} +1 -1
  45. package/dist/public/assets/{workbench-navigation-ED0157V-.js → workbench-navigation-hwM28xIb.js} +1 -1
  46. package/dist/public/index.html +2 -2
  47. package/dist/server/modules/client/client-controller.d.ts +1 -0
  48. package/dist/server/modules/client/client-controller.js +4 -0
  49. package/dist/server/modules/client/client-controller.js.map +1 -1
  50. package/dist/server/modules/client/client-service.d.ts +3 -0
  51. package/dist/server/modules/client/client-service.js +3 -0
  52. package/dist/server/modules/client/client-service.js.map +1 -1
  53. package/dist/server/modules/client/npm-global-package-service.js +32 -7
  54. package/dist/server/modules/client/npm-global-package-service.js.map +1 -1
  55. package/dist/server/modules/peer-host/host-ws-proxy-service.js +73 -12
  56. package/dist/server/modules/peer-host/host-ws-proxy-service.js.map +1 -1
  57. package/dist/server/modules/provider/provider-discovery-helper-client.d.ts +2 -0
  58. package/dist/server/modules/provider/provider-discovery-helper-client.js.map +1 -1
  59. package/dist/server/modules/provider/provider-discovery-helper-process.js +6 -3
  60. package/dist/server/modules/provider/provider-discovery-helper-process.js.map +1 -1
  61. package/dist/server/modules/provider/provider-discovery-runtime.js +4 -1
  62. package/dist/server/modules/provider/provider-discovery-runtime.js.map +1 -1
  63. package/dist/server/modules/sessions/session-history-service.d.ts +8 -0
  64. package/dist/server/modules/sessions/session-history-service.js +123 -5
  65. package/dist/server/modules/sessions/session-history-service.js.map +1 -1
  66. package/dist/server/modules/sessions/session-live-runtime-service.d.ts +13 -0
  67. package/dist/server/modules/sessions/session-live-runtime-service.js +354 -5
  68. package/dist/server/modules/sessions/session-live-runtime-service.js.map +1 -1
  69. package/dist/server/modules/sessions/session-permission-request-service.d.ts +16 -1
  70. package/dist/server/modules/sessions/session-permission-request-service.js +375 -9
  71. package/dist/server/modules/sessions/session-permission-request-service.js.map +1 -1
  72. package/dist/server/modules/sessions/workspace-session-runtime-context-service.js +10 -0
  73. package/dist/server/modules/sessions/workspace-session-runtime-context-service.js.map +1 -1
  74. package/dist/server/modules/tasks/task-helper-process-handlers.d.ts +1 -0
  75. package/dist/server/modules/tasks/task-helper-process-handlers.js +4 -1
  76. package/dist/server/modules/tasks/task-helper-process-handlers.js.map +1 -1
  77. package/dist/server/modules/workbench/workbench-service.js +7 -4
  78. package/dist/server/modules/workbench/workbench-service.js.map +1 -1
  79. package/dist/server/routes/client.js +1 -0
  80. package/dist/server/routes/client.js.map +1 -1
  81. package/dist/server/shared/utils/peer-host-proxy-log.d.ts +3 -0
  82. package/dist/server/shared/utils/peer-host-proxy-log.js +48 -0
  83. package/dist/server/shared/utils/peer-host-proxy-log.js.map +1 -0
  84. package/node_modules/@codingns/session-sync-core/dist/providers/claude-code.d.ts +2 -0
  85. package/node_modules/@codingns/session-sync-core/dist/providers/claude-code.js +93 -12
  86. package/node_modules/@codingns/session-sync-core/dist/providers/claude-code.js.map +1 -1
  87. package/node_modules/@codingns/session-sync-core/dist/providers/codex.d.ts +3 -0
  88. package/node_modules/@codingns/session-sync-core/dist/providers/codex.js +116 -2
  89. package/node_modules/@codingns/session-sync-core/dist/providers/codex.js.map +1 -1
  90. package/node_modules/@codingns/session-sync-core/dist/runtime/claude-runtime.d.ts +1 -0
  91. package/node_modules/@codingns/session-sync-core/dist/runtime/claude-runtime.js +19 -8
  92. package/node_modules/@codingns/session-sync-core/dist/runtime/claude-runtime.js.map +1 -1
  93. package/node_modules/@codingns/session-sync-core/dist/runtime/provider-runtime-service.d.ts +1 -0
  94. package/node_modules/@codingns/session-sync-core/dist/runtime/provider-runtime-service.js +30 -2
  95. package/node_modules/@codingns/session-sync-core/dist/runtime/provider-runtime-service.js.map +1 -1
  96. package/package.json +1 -1
  97. package/dist/public/assets/AdaptiveButlerPage-BYETYaIe.js +0 -2
  98. package/dist/public/assets/ConversationPage-BCrNml1k.js +0 -9
  99. package/dist/public/assets/SettingsPage-CQNCrgaj.js +0 -2
  100. package/dist/public/assets/WorkbenchLayout-Bo2BbMY6.js +0 -1081
  101. package/dist/public/assets/WorkbenchShellRoute-D3l4aWJS.js +0 -1
  102. package/dist/public/assets/WorkbenchShellRoute-D5fnyF8z.css +0 -1
  103. package/dist/public/assets/index-BilHJjYU.js +0 -50
  104. package/dist/public/assets/index-OR7OITpQ.css +0 -1
  105. package/dist/public/assets/peer-host-config-sync-d2ZcPC5P.js +0 -1
@@ -5,6 +5,7 @@ import { createId } from "../../shared/utils/id.js";
5
5
  import { nowIso } from "../../shared/utils/time.js";
6
6
  import { buildClaudeCompatibleRawStoreRef } from "./claude-compatible-provider-registry.js";
7
7
  const CLAUDE_PRE_TOOL_USE_TIMEOUT_MS = 90_000;
8
+ const CLAUDE_ASK_USER_QUESTION_TIMEOUT_MS = 90_000;
8
9
  const OPENCODE_RECONNECT_DELAY_MS = 1_500;
9
10
  export class SessionPermissionRequestService {
10
11
  sessionHistoryService;
@@ -70,11 +71,38 @@ export class SessionPermissionRequestService {
70
71
  }
71
72
  if (request.source.kind === "claude-pre-tool-use") {
72
73
  const action = normalizeText(input.action);
73
- if (action !== "allow" && action !== "allow_session" && action !== "deny") {
74
+ if (action !== "allow" &&
75
+ action !== "allow_session" &&
76
+ action !== "deny" &&
77
+ action !== "submit") {
74
78
  throw new AppError({
75
79
  statusCode: 400,
76
80
  errorCode: "INVALID_INPUT",
77
- detail: "Claude 权限申请只支持 allow、allow_session 或 deny",
81
+ detail: "Claude 请求只支持 allow、allow_session、denysubmit",
82
+ field: "action"
83
+ });
84
+ }
85
+ if (request.kind === "user_input" && action !== "submit") {
86
+ throw new AppError({
87
+ statusCode: 400,
88
+ errorCode: "INVALID_INPUT",
89
+ detail: "Claude 问题请求只支持提交答案",
90
+ field: "action"
91
+ });
92
+ }
93
+ if (request.kind !== "user_input" && action === "submit") {
94
+ throw new AppError({
95
+ statusCode: 400,
96
+ errorCode: "INVALID_INPUT",
97
+ detail: "只有问题请求可以提交答案",
98
+ field: "action"
99
+ });
100
+ }
101
+ if (request.kind === "plan_approval" && action === "allow_session") {
102
+ throw new AppError({
103
+ statusCode: 400,
104
+ errorCode: "INVALID_INPUT",
105
+ detail: "计划审批不支持设置整场会话默认允许",
78
106
  field: "action"
79
107
  });
80
108
  }
@@ -91,7 +119,8 @@ export class SessionPermissionRequestService {
91
119
  });
92
120
  }
93
121
  request.source.resolve({
94
- action: action === "deny" ? "deny" : "allow"
122
+ action: action === "deny" ? "deny" : "allow",
123
+ answers: request.kind === "user_input" ? input.answers : undefined
95
124
  });
96
125
  return await this.markResolved(request, action === "deny" ? "declined" : "approved");
97
126
  }
@@ -240,7 +269,7 @@ export class SessionPermissionRequestService {
240
269
  const timer = setTimeout(() => {
241
270
  resolvedByTimeout = true;
242
271
  resolve({ action: "ask" });
243
- }, CLAUDE_PRE_TOOL_USE_TIMEOUT_MS);
272
+ }, normalized.kind === "user_input" ? CLAUDE_ASK_USER_QUESTION_TIMEOUT_MS : CLAUDE_PRE_TOOL_USE_TIMEOUT_MS);
244
273
  const record = {
245
274
  ...normalized,
246
275
  source: {
@@ -273,7 +302,11 @@ export class SessionPermissionRequestService {
273
302
  accepted: true,
274
303
  ignored: false,
275
304
  sessionId: binding.sessionId,
276
- bridgeResponse: buildClaudePreToolUseBridgeResponse(decision.action, buildClaudeDecisionReason(decision.action, normalized.title, resolvedByTimeout))
305
+ bridgeResponse: normalized.kind === "user_input"
306
+ ? buildClaudeAskUserQuestionBridgeResponse(decision.action, decision.answers ?? {}, normalized.questions, payload.tool_input, buildClaudeDecisionReason(decision.action, normalized.title, resolvedByTimeout))
307
+ : normalized.kind === "plan_approval"
308
+ ? buildClaudeExitPlanModeBridgeResponse(decision.action, buildClaudeDecisionReason(decision.action, normalized.title, resolvedByTimeout))
309
+ : buildClaudePreToolUseBridgeResponse(decision.action, buildClaudeDecisionReason(decision.action, normalized.title, resolvedByTimeout))
277
310
  };
278
311
  }
279
312
  async handleClaudePermissionRequest(payload, provider = "claude-code") {
@@ -404,6 +437,96 @@ export class SessionPermissionRequestService {
404
437
  : "CodingNS 已拒绝本次权限申请")
405
438
  };
406
439
  }
440
+ async handleClaudeElicitation(payload, provider = "claude-code") {
441
+ logPermissionDebug("claude_permission.elicitation.begin", {
442
+ provider,
443
+ providerSessionId: payload.session_id ?? null,
444
+ cwd: payload.cwd ?? null,
445
+ transcriptPath: payload.transcript_path ?? null,
446
+ title: payload.title ?? null
447
+ });
448
+ const providerSessionId = requireNonEmptyText(payload.session_id, "session_id");
449
+ const workspacePath = requireNonEmptyText(payload.cwd, "cwd");
450
+ const workspace = this.workspaceService.findWorkspaceByPath(workspacePath);
451
+ if (!workspace) {
452
+ return {
453
+ accepted: true,
454
+ ignored: true,
455
+ sessionId: null,
456
+ bridgeResponse: buildClaudePreToolUseBridgeResponse("ask", "未匹配到工作区,回退 Claude 原生征询")
457
+ };
458
+ }
459
+ const transcriptPath = normalizeText(payload.transcript_path) || null;
460
+ const binding = await this.resolveClaudeBinding(provider, providerSessionId, workspace.id, workspace.path, transcriptPath, workspace.ownerUserId ?? null).catch(() => null)
461
+ ?? this.resolveClaudeWorkspaceSessionFallback({
462
+ provider,
463
+ providerSessionId,
464
+ workspaceId: workspace.id,
465
+ workspacePath: workspace.path,
466
+ transcriptPath,
467
+ userId: workspace.ownerUserId ?? null
468
+ })
469
+ ?? (this.resolveActiveClaudeSession
470
+ ? await this.resolveActiveClaudeSession({
471
+ provider,
472
+ providerSessionId,
473
+ workspaceId: workspace.id,
474
+ workspacePath: workspace.path,
475
+ transcriptPath
476
+ }).catch(() => null)
477
+ : null);
478
+ if (!binding) {
479
+ return {
480
+ accepted: true,
481
+ ignored: true,
482
+ sessionId: null,
483
+ bridgeResponse: buildClaudePreToolUseBridgeResponse("ask", "未匹配到会话绑定,回退 Claude 原生征询")
484
+ };
485
+ }
486
+ const now = nowIso();
487
+ const normalized = normalizeClaudeElicitationRequest({
488
+ provider,
489
+ sessionId: binding.sessionId,
490
+ providerSessionId,
491
+ payload,
492
+ createdAt: now
493
+ });
494
+ let resolvedByTimeout = false;
495
+ const decision = await new Promise((resolve) => {
496
+ const timer = setTimeout(() => {
497
+ resolvedByTimeout = true;
498
+ resolve({ action: "deny" });
499
+ }, CLAUDE_ASK_USER_QUESTION_TIMEOUT_MS);
500
+ const record = {
501
+ ...normalized,
502
+ source: {
503
+ kind: "claude-pre-tool-use",
504
+ resolve,
505
+ timer
506
+ }
507
+ };
508
+ this.upsertRequest(record);
509
+ void this.emitEnvelope({
510
+ type: "session.permission_request",
511
+ sessionId: binding.sessionId,
512
+ request: this.toRequestView(record)
513
+ });
514
+ });
515
+ const existing = this.requestsById.get(normalized.id);
516
+ if (existing) {
517
+ await this.markResolved(existing, resolvedByTimeout ? "expired" : "approved");
518
+ }
519
+ return {
520
+ accepted: true,
521
+ ignored: false,
522
+ sessionId: binding.sessionId,
523
+ bridgeResponse: buildClaudeAskUserQuestionBridgeResponse(decision.action, decision.answers ?? {}, normalized.questions, payload, decision.action === "allow"
524
+ ? "用户已提供补充信息"
525
+ : resolvedByTimeout
526
+ ? "用户补充信息超时,回退 Claude 原生处理"
527
+ : "用户拒绝补充信息")
528
+ };
529
+ }
407
530
  ingestCodexServerRequest(sessionId, providerSessionId, request) {
408
531
  const normalized = normalizeCodexServerRequest(sessionId, providerSessionId, request);
409
532
  if (!normalized) {
@@ -1017,7 +1140,7 @@ export function normalizeClaudePreToolUseRequest(input) {
1017
1140
  cwd: normalizeText(toRecord(toolInput)?.cwd) || null,
1018
1141
  paths: normalized.paths,
1019
1142
  permissionProfile: null,
1020
- questions: [],
1143
+ questions: normalized.questions,
1021
1144
  actions: buildClaudeActions({
1022
1145
  kind: normalized.kind,
1023
1146
  command: normalized.command,
@@ -1035,6 +1158,46 @@ export function normalizeClaudePreToolUseRequest(input) {
1035
1158
  }
1036
1159
  };
1037
1160
  }
1161
+ export function normalizeClaudeElicitationRequest(input) {
1162
+ const rawPayload = stringifyPayload(input.payload);
1163
+ const questions = readClaudeElicitationQuestions(input.payload);
1164
+ const requestKey = normalizeText(input.payload.title) ||
1165
+ normalizeText(input.payload.prompt) ||
1166
+ normalizeText(input.payload.question) ||
1167
+ normalizeText(input.payload.message) ||
1168
+ `Elicitation:${hashLike(rawPayload)}`;
1169
+ return {
1170
+ id: `permission-${createId()}`,
1171
+ sessionId: input.sessionId,
1172
+ provider: input.provider,
1173
+ providerSessionId: input.providerSessionId,
1174
+ requestKey,
1175
+ kind: "user_input",
1176
+ status: "pending",
1177
+ title: normalizeText(input.payload.title) || "Claude 需要你补充信息",
1178
+ summary: questions[0]?.question ?? "Claude 需要你补充信息后才能继续",
1179
+ detail: rawPayload,
1180
+ reason: normalizeText(input.payload.reason) || null,
1181
+ toolName: "Elicitation",
1182
+ command: null,
1183
+ cwd: normalizeText(input.payload.cwd) || null,
1184
+ paths: [],
1185
+ permissionProfile: null,
1186
+ questions,
1187
+ actions: [
1188
+ createAction("submit", "提交答案", "primary", "把补充信息交给 Claude 继续处理")
1189
+ ],
1190
+ rawPayload,
1191
+ createdAt: input.createdAt,
1192
+ updatedAt: input.createdAt,
1193
+ resolvedAt: null,
1194
+ source: {
1195
+ kind: "claude-pre-tool-use",
1196
+ resolve: () => undefined,
1197
+ timer: null
1198
+ }
1199
+ };
1200
+ }
1038
1201
  export function normalizeOpenCodePermissionRequest(input) {
1039
1202
  const requestKey = normalizeText(input.permission.id) || createId();
1040
1203
  const title = normalizeText(input.permission.title) || "OpenCode 请求权限";
@@ -1215,6 +1378,7 @@ export function normalizeCodexServerRequest(sessionId, providerSessionId, reques
1215
1378
  question: normalizeText(question.question) || "请输入答案",
1216
1379
  allowOther: Boolean(question.isOther),
1217
1380
  secret: Boolean(question.isSecret),
1381
+ multiSelect: Boolean(question.multiSelect),
1218
1382
  options: Array.isArray(question.options)
1219
1383
  ? question.options
1220
1384
  .map((option) => toRecord(option))
@@ -1268,6 +1432,25 @@ function buildClaudePreToolUseBridgeResponse(action, reason) {
1268
1432
  }
1269
1433
  };
1270
1434
  }
1435
+ function buildClaudeAskUserQuestionBridgeResponse(action, answers, questions, originalInput, reason) {
1436
+ const response = buildClaudePreToolUseBridgeResponse(action, reason);
1437
+ const originalInputRecord = toRecord(originalInput);
1438
+ if (action === "allow") {
1439
+ return {
1440
+ hookSpecificOutput: {
1441
+ ...response.hookSpecificOutput,
1442
+ updatedInput: {
1443
+ ...(originalInputRecord ?? {}),
1444
+ answers: buildClaudeAskUserQuestionAnswers(answers, questions)
1445
+ }
1446
+ }
1447
+ };
1448
+ }
1449
+ return response;
1450
+ }
1451
+ function buildClaudeExitPlanModeBridgeResponse(action, reason) {
1452
+ return buildClaudePreToolUseBridgeResponse(action, reason);
1453
+ }
1271
1454
  function buildClaudePermissionRequestBridgeResponse(action, message) {
1272
1455
  return {
1273
1456
  hookSpecificOutput: {
@@ -1422,6 +1605,7 @@ function buildClaudeKind(toolName, toolInput) {
1422
1605
  const command = normalizeText(inputRecord?.command) ||
1423
1606
  normalizeText(inputRecord?.cmd) ||
1424
1607
  null;
1608
+ const allowedPrompts = readClaudeAllowedPrompts(inputRecord);
1425
1609
  if (normalizedToolName === "bash" || normalizedToolName === "shell") {
1426
1610
  return {
1427
1611
  kind: "command",
@@ -1429,7 +1613,37 @@ function buildClaudeKind(toolName, toolInput) {
1429
1613
  summary: command ?? "Bash 工具需要确认",
1430
1614
  detail: stringifyPayload(toolInput),
1431
1615
  command,
1432
- paths: []
1616
+ paths: [],
1617
+ questions: []
1618
+ };
1619
+ }
1620
+ if (normalizedToolName === "askuserquestion") {
1621
+ const questions = readClaudeAskUserQuestionQuestions(inputRecord);
1622
+ return {
1623
+ kind: "user_input",
1624
+ title: "Claude 需要你回答问题",
1625
+ summary: questions[0]?.question ?? "Claude 需要你补充选择",
1626
+ detail: stringifyPayload(toolInput),
1627
+ command: null,
1628
+ paths: [],
1629
+ questions
1630
+ };
1631
+ }
1632
+ if (normalizedToolName === "exitplanmode") {
1633
+ const summary = normalizeText(inputRecord?.plan) ||
1634
+ normalizeText(inputRecord?.summary) ||
1635
+ normalizeText(inputRecord?.title) ||
1636
+ (allowedPrompts[0]
1637
+ ? `Claude 准备按计划继续执行:${allowedPrompts[0].prompt}`
1638
+ : "Claude 准备退出计划模式并继续执行");
1639
+ return {
1640
+ kind: "plan_approval",
1641
+ title: "Claude 请求确认执行计划",
1642
+ summary,
1643
+ detail: stringifyPayload(toolInput),
1644
+ command: null,
1645
+ paths: [],
1646
+ questions: []
1433
1647
  };
1434
1648
  }
1435
1649
  if (normalizedToolName === "edit" ||
@@ -1442,7 +1656,8 @@ function buildClaudeKind(toolName, toolInput) {
1442
1656
  summary: paths[0] ?? `${toolName} 工具需要确认`,
1443
1657
  detail: stringifyPayload(toolInput),
1444
1658
  command: null,
1445
- paths
1659
+ paths,
1660
+ questions: []
1446
1661
  };
1447
1662
  }
1448
1663
  return {
@@ -1451,9 +1666,134 @@ function buildClaudeKind(toolName, toolInput) {
1451
1666
  summary: toolName,
1452
1667
  detail: stringifyPayload(toolInput),
1453
1668
  command,
1454
- paths
1669
+ paths,
1670
+ questions: []
1455
1671
  };
1456
1672
  }
1673
+ function readClaudeAskUserQuestionQuestions(inputRecord) {
1674
+ if (!inputRecord) {
1675
+ return [];
1676
+ }
1677
+ const rawQuestions = Array.isArray(inputRecord.questions)
1678
+ ? inputRecord.questions
1679
+ : [
1680
+ {
1681
+ ...inputRecord,
1682
+ id: normalizeText(inputRecord.id) || "question"
1683
+ }
1684
+ ];
1685
+ return rawQuestions
1686
+ .map((question, index) => normalizeClaudeAskUserQuestion(question, index))
1687
+ .filter((question) => question !== null);
1688
+ }
1689
+ function normalizeClaudeAskUserQuestion(value, index) {
1690
+ const record = toRecord(value);
1691
+ if (!record) {
1692
+ return null;
1693
+ }
1694
+ const questionText = normalizeText(record.question) ||
1695
+ normalizeText(record.prompt) ||
1696
+ normalizeText(record.message) ||
1697
+ "请选择一个选项";
1698
+ const options = readClaudeAskUserQuestionOptions(record.options ?? record.choices ?? record.answers);
1699
+ return {
1700
+ id: normalizeText(record.id) ||
1701
+ normalizeText(record.name) ||
1702
+ `question-${index + 1}`,
1703
+ header: normalizeText(record.header) ||
1704
+ normalizeText(record.title) ||
1705
+ `问题 ${index + 1}`,
1706
+ question: questionText,
1707
+ allowOther: readBoolean(record.allowOther) ??
1708
+ readBoolean(record.allow_other) ??
1709
+ readBoolean(record.isOther) ??
1710
+ readBoolean(record.allowFreeform) ??
1711
+ readBoolean(record.allow_freeform) ??
1712
+ true,
1713
+ secret: readBoolean(record.secret) ??
1714
+ readBoolean(record.isSecret) ??
1715
+ false,
1716
+ multiSelect: readBoolean(record.multiSelect) ??
1717
+ readBoolean(record.multi_select) ??
1718
+ false,
1719
+ options
1720
+ };
1721
+ }
1722
+ function readClaudeAskUserQuestionOptions(value) {
1723
+ if (!Array.isArray(value)) {
1724
+ return [];
1725
+ }
1726
+ return value
1727
+ .map((item) => {
1728
+ if (typeof item === "string") {
1729
+ const label = item.trim();
1730
+ return label ? { label, description: null } : null;
1731
+ }
1732
+ const record = toRecord(item);
1733
+ const label = normalizeText(record?.label) ||
1734
+ normalizeText(record?.value) ||
1735
+ normalizeText(record?.text) ||
1736
+ normalizeText(record?.title);
1737
+ if (!label) {
1738
+ return null;
1739
+ }
1740
+ return {
1741
+ label,
1742
+ description: normalizeText(record?.description) || normalizeText(record?.detail) || null
1743
+ };
1744
+ })
1745
+ .filter((option) => option !== null);
1746
+ }
1747
+ function readClaudeElicitationQuestions(payload) {
1748
+ const options = readClaudeAskUserQuestionOptions(payload.options);
1749
+ const questionText = normalizeText(payload.question) ||
1750
+ normalizeText(payload.prompt) ||
1751
+ normalizeText(payload.message) ||
1752
+ "请补充 Claude 继续执行所需的信息";
1753
+ return [
1754
+ {
1755
+ id: "elicitation",
1756
+ header: normalizeText(payload.title) || "补充信息",
1757
+ question: questionText,
1758
+ allowOther: true,
1759
+ secret: false,
1760
+ multiSelect: false,
1761
+ options
1762
+ }
1763
+ ];
1764
+ }
1765
+ export function buildClaudeAskUserQuestionAnswers(answers, questions) {
1766
+ return Object.fromEntries(questions
1767
+ .map((question) => {
1768
+ const values = Array.isArray(answers[question.id])
1769
+ ? answers[question.id].map((value) => normalizeText(value)).filter(Boolean)
1770
+ : [];
1771
+ if (values.length === 0) {
1772
+ return null;
1773
+ }
1774
+ return [
1775
+ question.question,
1776
+ question.multiSelect ? values.join(", ") : values[0] ?? ""
1777
+ ];
1778
+ })
1779
+ .filter((entry) => entry !== null));
1780
+ }
1781
+ function readClaudeAllowedPrompts(inputRecord) {
1782
+ if (!inputRecord || !Array.isArray(inputRecord.allowedPrompts)) {
1783
+ return [];
1784
+ }
1785
+ return inputRecord.allowedPrompts
1786
+ .map((value) => {
1787
+ const record = toRecord(value);
1788
+ const tool = normalizeText(record?.tool);
1789
+ const prompt = normalizeText(record?.prompt);
1790
+ if (!tool || !prompt) {
1791
+ return null;
1792
+ }
1793
+ return { tool, prompt };
1794
+ })
1795
+ .filter((item) => item !== null);
1796
+ }
1457
1797
  function buildOpenCodeKind(title, metadata, pattern, fallbackToolName) {
1458
1798
  const command = normalizeText(metadata?.command);
1459
1799
  const toolName = normalizeText(metadata?.tool) || fallbackToolName;
@@ -1581,6 +1921,17 @@ function buildClaudeAllowedScopeKey(request) {
1581
1921
  return null;
1582
1922
  }
1583
1923
  function buildClaudeActions(request) {
1924
+ if (request.kind === "user_input") {
1925
+ return [
1926
+ createAction("submit", "提交选择", "primary", "把选择结果交给 Claude 继续处理")
1927
+ ];
1928
+ }
1929
+ if (request.kind === "plan_approval") {
1930
+ return [
1931
+ createAction("allow", "批准计划", "primary", "允许 Claude 按当前计划继续执行"),
1932
+ createAction("deny", "退回计划", "danger", "拒绝这次计划,要求 Claude 停在计划阶段")
1933
+ ];
1934
+ }
1584
1935
  const actions = [
1585
1936
  createAction("allow", "允许", "primary", "只允许这一次")
1586
1937
  ];
@@ -1908,6 +2259,21 @@ function normalizeText(value) {
1908
2259
  }
1909
2260
  return null;
1910
2261
  }
2262
+ function readBoolean(value) {
2263
+ if (typeof value === "boolean") {
2264
+ return value;
2265
+ }
2266
+ if (typeof value === "string") {
2267
+ const normalized = value.trim().toLowerCase();
2268
+ if (normalized === "true" || normalized === "1" || normalized === "yes") {
2269
+ return true;
2270
+ }
2271
+ if (normalized === "false" || normalized === "0" || normalized === "no") {
2272
+ return false;
2273
+ }
2274
+ }
2275
+ return null;
2276
+ }
1911
2277
  function toRecord(value) {
1912
2278
  if (!value || typeof value !== "object" || Array.isArray(value)) {
1913
2279
  return null;