@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.
- package/dist/public/assets/AdaptiveButlerPage-BHUAx_24.js +2 -0
- package/dist/public/assets/{App-CHsm-VrM.js → App-D5hc6KuU.js} +6 -6
- package/dist/public/assets/{BootstrapPage-Bp0KfySv.js → BootstrapPage-C2sMZMJa.js} +1 -1
- package/dist/public/assets/ConversationPage-CDpyEOUA.js +9 -0
- package/dist/public/assets/{DesktopDetachPreviewPage-DlDSb_tf.js → DesktopDetachPreviewPage-D9Abm5NU.js} +1 -1
- package/dist/public/assets/{DesktopModal-Csj5AdAN.js → DesktopModal-BCVZq_PQ.js} +1 -1
- package/dist/public/assets/{DesktopWindowPage-CacXiWjV.js → DesktopWindowPage-Cotl5fte.js} +1 -1
- package/dist/public/assets/{FileContextPanel-DzMUQvE5.js → FileContextPanel-DbPOq5w-.js} +1 -1
- package/dist/public/assets/{GitSidebar-C8IC18GH.js → GitSidebar-Cuxi2R93.js} +1 -1
- package/dist/public/assets/{MobileCreateSessionSheet-BtqR_hKc.js → MobileCreateSessionSheet-DYqarJqO.js} +1 -1
- package/dist/public/assets/{MobileSheet-Co-qPMBD.js → MobileSheet-DPYtp5Ze.js} +1 -1
- package/dist/public/assets/{PluginAccessOverview-D-KXkcyj.js → PluginAccessOverview-CiVzb_NI.js} +1 -1
- package/dist/public/assets/{PluginContainerPage-BKwCIs4r.js → PluginContainerPage-BfZ3E41c.js} +1 -1
- package/dist/public/assets/{PluginDetailPage-Djv_swcO.js → PluginDetailPage-DQQAg_ba.js} +1 -1
- package/dist/public/assets/{PluginsListPage-DAECNoN6.js → PluginsListPage-bF1NmA_r.js} +1 -1
- package/dist/public/assets/{PureConversationPage-DP1X7Hix.js → PureConversationPage-CWji-ARJ.js} +1 -1
- package/dist/public/assets/{RelayConnectEntryPage-xL_IPH8a.js → RelayConnectEntryPage-D4-3Fher.js} +1 -1
- package/dist/public/assets/{ServerSettingsModal-CyhMgk10.js → ServerSettingsModal-BUY1Y3g6.js} +1 -1
- package/dist/public/assets/{SessionIndexPage-CVEz50tc.js → SessionIndexPage-zVB9jnzP.js} +1 -1
- package/dist/public/assets/SettingsPage-DeqR2p7d.js +2 -0
- package/dist/public/assets/{TerminalManagerPanel-wVnoRA8u.js → TerminalManagerPanel-BjnC70ga.js} +1 -1
- package/dist/public/assets/{ToolFilesPage-BospXumK.js → ToolFilesPage-BZseQqvZ.js} +1 -1
- package/dist/public/assets/{ToolGitPage-B2zOeCAD.js → ToolGitPage-SrOO8Ftz.js} +1 -1
- package/dist/public/assets/{ToolProcessesPage-BDShao4b.js → ToolProcessesPage-Dbzlqjdy.js} +1 -1
- package/dist/public/assets/{ToolsHomePage-s4zH7D9M.js → ToolsHomePage-BBilUc0P.js} +1 -1
- package/dist/public/assets/{WorkbenchLandingPage-D51QCU_u.js → WorkbenchLandingPage-FdsBC8WN.js} +1 -1
- package/dist/public/assets/WorkbenchLayout-yGxGKcG1.js +1081 -0
- package/dist/public/assets/{WorkbenchModal-YsyEdJ_m.js → WorkbenchModal-Cm-ciXO9.js} +1 -1
- package/dist/public/assets/WorkbenchShellRoute-CijuAd9-.js +1 -0
- package/dist/public/assets/WorkbenchShellRoute-DpycFsbp.css +1 -0
- package/dist/public/assets/{WorkspaceDebugDetailPage-CMjNLqFq.js → WorkspaceDebugDetailPage-CZtpOiY0.js} +1 -1
- package/dist/public/assets/{WorkspaceDetailPage-CKxTbPKh.js → WorkspaceDetailPage-CbbgUz1H.js} +1 -1
- package/dist/public/assets/{WorkspaceHomePage-CEy4ShCu.js → WorkspaceHomePage-DMNJKAYe.js} +1 -1
- package/dist/public/assets/{client-runtime-manager-BFXU9DmS.js → client-runtime-manager-tsFkLtO_.js} +1 -1
- package/dist/public/assets/{host-alias-Zb2xyVrf.js → host-alias-df5bYDlE.js} +1 -1
- package/dist/public/assets/index-CILPuSCp.js +50 -0
- package/dist/public/assets/index-CSlwKnM4.css +1 -0
- package/dist/public/assets/{login-direct-candidate-resolver-DL8DS-Si.js → login-direct-candidate-resolver-pkfXrMJy.js} +1 -1
- package/dist/public/assets/peer-host-config-sync-nS_66OLg.js +1 -0
- package/dist/public/assets/{plugin-permission-copy-DrLk22m5.js → plugin-permission-copy-LDy-lW7h.js} +1 -1
- package/dist/public/assets/{plugins-api-COF4oh24.js → plugins-api-BGF9OybZ.js} +1 -1
- package/dist/public/assets/{preferences-service-CEWNV1w9.js → preferences-service-BC25oxA_.js} +1 -1
- package/dist/public/assets/{relay-entry-Cmc8vTlE.js → relay-entry-ErQKnI7B.js} +1 -1
- package/dist/public/assets/{useRegisteredDebugTemplates-FdmHG2S4.js → useRegisteredDebugTemplates-BTr3ATCZ.js} +1 -1
- package/dist/public/assets/{workbench-navigation-ED0157V-.js → workbench-navigation-hwM28xIb.js} +1 -1
- package/dist/public/index.html +2 -2
- package/dist/server/modules/client/client-controller.d.ts +1 -0
- package/dist/server/modules/client/client-controller.js +4 -0
- package/dist/server/modules/client/client-controller.js.map +1 -1
- package/dist/server/modules/client/client-service.d.ts +3 -0
- package/dist/server/modules/client/client-service.js +3 -0
- package/dist/server/modules/client/client-service.js.map +1 -1
- package/dist/server/modules/client/npm-global-package-service.js +32 -7
- package/dist/server/modules/client/npm-global-package-service.js.map +1 -1
- package/dist/server/modules/peer-host/host-ws-proxy-service.js +73 -12
- package/dist/server/modules/peer-host/host-ws-proxy-service.js.map +1 -1
- package/dist/server/modules/provider/provider-discovery-helper-client.d.ts +2 -0
- package/dist/server/modules/provider/provider-discovery-helper-client.js.map +1 -1
- package/dist/server/modules/provider/provider-discovery-helper-process.js +6 -3
- package/dist/server/modules/provider/provider-discovery-helper-process.js.map +1 -1
- package/dist/server/modules/provider/provider-discovery-runtime.js +4 -1
- package/dist/server/modules/provider/provider-discovery-runtime.js.map +1 -1
- package/dist/server/modules/sessions/session-history-service.d.ts +8 -0
- package/dist/server/modules/sessions/session-history-service.js +123 -5
- package/dist/server/modules/sessions/session-history-service.js.map +1 -1
- package/dist/server/modules/sessions/session-live-runtime-service.d.ts +13 -0
- package/dist/server/modules/sessions/session-live-runtime-service.js +354 -5
- package/dist/server/modules/sessions/session-live-runtime-service.js.map +1 -1
- package/dist/server/modules/sessions/session-permission-request-service.d.ts +16 -1
- package/dist/server/modules/sessions/session-permission-request-service.js +375 -9
- package/dist/server/modules/sessions/session-permission-request-service.js.map +1 -1
- package/dist/server/modules/sessions/workspace-session-runtime-context-service.js +10 -0
- package/dist/server/modules/sessions/workspace-session-runtime-context-service.js.map +1 -1
- package/dist/server/modules/tasks/task-helper-process-handlers.d.ts +1 -0
- package/dist/server/modules/tasks/task-helper-process-handlers.js +4 -1
- package/dist/server/modules/tasks/task-helper-process-handlers.js.map +1 -1
- package/dist/server/modules/workbench/workbench-service.js +7 -4
- package/dist/server/modules/workbench/workbench-service.js.map +1 -1
- package/dist/server/routes/client.js +1 -0
- package/dist/server/routes/client.js.map +1 -1
- package/dist/server/shared/utils/peer-host-proxy-log.d.ts +3 -0
- package/dist/server/shared/utils/peer-host-proxy-log.js +48 -0
- package/dist/server/shared/utils/peer-host-proxy-log.js.map +1 -0
- package/node_modules/@codingns/session-sync-core/dist/providers/claude-code.d.ts +2 -0
- package/node_modules/@codingns/session-sync-core/dist/providers/claude-code.js +93 -12
- package/node_modules/@codingns/session-sync-core/dist/providers/claude-code.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/providers/codex.d.ts +3 -0
- package/node_modules/@codingns/session-sync-core/dist/providers/codex.js +116 -2
- package/node_modules/@codingns/session-sync-core/dist/providers/codex.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/runtime/claude-runtime.d.ts +1 -0
- package/node_modules/@codingns/session-sync-core/dist/runtime/claude-runtime.js +19 -8
- package/node_modules/@codingns/session-sync-core/dist/runtime/claude-runtime.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/runtime/provider-runtime-service.d.ts +1 -0
- package/node_modules/@codingns/session-sync-core/dist/runtime/provider-runtime-service.js +30 -2
- package/node_modules/@codingns/session-sync-core/dist/runtime/provider-runtime-service.js.map +1 -1
- package/package.json +1 -1
- package/dist/public/assets/AdaptiveButlerPage-BYETYaIe.js +0 -2
- package/dist/public/assets/ConversationPage-BCrNml1k.js +0 -9
- package/dist/public/assets/SettingsPage-CQNCrgaj.js +0 -2
- package/dist/public/assets/WorkbenchLayout-Bo2BbMY6.js +0 -1081
- package/dist/public/assets/WorkbenchShellRoute-D3l4aWJS.js +0 -1
- package/dist/public/assets/WorkbenchShellRoute-D5fnyF8z.css +0 -1
- package/dist/public/assets/index-BilHJjYU.js +0 -50
- package/dist/public/assets/index-OR7OITpQ.css +0 -1
- 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" &&
|
|
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
|
|
81
|
+
detail: "Claude 请求只支持 allow、allow_session、deny 或 submit",
|
|
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:
|
|
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;
|