






























11import crypto from "node:crypto";
22import { resolveAgentDir, resolveSessionAgentIds } from "openclaw/plugin-sdk/agent-runtime";
3-import type { MessagePresentation } from "openclaw/plugin-sdk/interactive-runtime";
43import { parseStrictPositiveInteger } from "openclaw/plugin-sdk/number-runtime";
54import type { PluginCommandContext, PluginCommandResult } from "openclaw/plugin-sdk/plugin-entry";
65import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
@@ -40,6 +39,10 @@ import {
4039handleCodexPluginsSubcommand,
4140type CodexPluginsManagementIO,
4241} from "./command-plugins-management.js";
42+import {
43+buildCodexCommandPickerPresentation,
44+type CodexCommandPickerButton,
45+} from "./command-presentation.js";
4346import {
4447codexControlRequest,
4548readCodexStatusProbes,
@@ -241,30 +244,12 @@ export function resetCodexDiagnosticsFeedbackStateForTests(): void {
241244pendingCodexDiagnosticsConfirmationTokensByScope.clear();
242245}
243246244-type CodexPickerButton = { label: string; command: string };
245-246-function buildPickerPresentation(title: string, prompt: string, buttons: CodexPickerButton[]) {
247-return {
248- title,
249-blocks: [
250-{ type: "text", text: prompt },
251-{
252-type: "buttons",
253-buttons: buttons.map((button) => ({
254-label: button.label,
255-value: button.command,
256-})),
257-},
258-],
259-} satisfies MessagePresentation;
260-}
261-262247/**
263- * No-arg `/codex` picker. Core owns the native command tree; channels render
264- * the portable buttons as inline controls when their transport can.
248+ * No-arg `/codex` picker. Codex owns the command tree; channels render the
249+ * portable command actions as inline controls when their transport can.
265250 */
266251function buildCodexSubcommandPickerReply(): PluginCommandResult {
267-const verbs: CodexPickerButton[] = [
252+const verbs: CodexCommandPickerButton[] = [
268253{ label: "plugins", command: "/codex plugins menu" },
269254{ label: "permissions", command: "/codex permissions menu" },
270255{ label: "fast", command: "/codex fast menu" },
@@ -287,14 +272,18 @@ function buildCodexSubcommandPickerReply(): PluginCommandResult {
287272288273return {
289274text: fallbackTextLines.join("\n"),
290-presentation: buildPickerPresentation("Codex commands", "Pick a Codex subcommand:", verbs),
275+presentation: buildCodexCommandPickerPresentation(
276+"Codex commands",
277+"Pick a Codex subcommand:",
278+verbs,
279+),
291280};
292281}
293282294283/** Sub-picker for `/codex fast menu` (on / off / status). */
295284function buildCodexFastMenuReply(): PluginCommandResult {
296285const modes = ["on", "off", "status"] as const;
297-const buttons: CodexPickerButton[] = [
286+const buttons: CodexCommandPickerButton[] = [
298287 ...modes.map((mode) => ({ label: mode, command: `/codex fast ${mode}` })),
299288{ label: "back", command: "/codex" },
300289];
@@ -307,14 +296,18 @@ function buildCodexFastMenuReply(): PluginCommandResult {
307296];
308297return {
309298text: fallbackTextLines.join("\n"),
310-presentation: buildPickerPresentation("Codex fast mode", "Pick a Codex fast mode:", buttons),
299+presentation: buildCodexCommandPickerPresentation(
300+"Codex fast mode",
301+"Pick a Codex fast mode:",
302+buttons,
303+),
311304};
312305}
313306314307/** Sub-picker for `/codex permissions menu` (default / yolo / status). */
315308function buildCodexPermissionsMenuReply(): PluginCommandResult {
316309const modes = ["default", "yolo", "status"] as const;
317-const buttons: CodexPickerButton[] = [
310+const buttons: CodexCommandPickerButton[] = [
318311 ...modes.map((mode) => ({ label: mode, command: `/codex permissions ${mode}` })),
319312{ label: "back", command: "/codex" },
320313];
@@ -327,7 +320,7 @@ function buildCodexPermissionsMenuReply(): PluginCommandResult {
327320];
328321return {
329322text: fallbackTextLines.join("\n"),
330-presentation: buildPickerPresentation(
323+presentation: buildCodexCommandPickerPresentation(
331324"Codex permissions",
332325"Pick a Codex permissions mode:",
333326buttons,
@@ -338,7 +331,7 @@ function buildCodexPermissionsMenuReply(): PluginCommandResult {
338331/** Sub-picker for `/codex computer-use menu` (status / install). */
339332function buildCodexComputerUseMenuReply(): PluginCommandResult {
340333const actions = ["status", "install"] as const;
341-const buttons: CodexPickerButton[] = [
334+const buttons: CodexCommandPickerButton[] = [
342335 ...actions.map((action) => ({
343336label: action,
344337command: `/codex computer-use ${action}`,
@@ -356,7 +349,7 @@ function buildCodexComputerUseMenuReply(): PluginCommandResult {
356349];
357350return {
358351text: fallbackTextLines.join("\n"),
359-presentation: buildPickerPresentation(
352+presentation: buildCodexCommandPickerPresentation(
360353"Codex computer-use",
361354"Pick a Codex computer-use action:",
362355buttons,
@@ -1149,8 +1142,18 @@ async function requestCodexDiagnosticsFeedbackApproval(
11491142{
11501143type: "buttons",
11511144buttons: [
1152-{ label: "Send diagnostics", value: confirmCommand, style: "danger" },
1153-{ label: "Cancel", value: cancelCommand, style: "secondary" },
1145+{
1146+label: "Send diagnostics",
1147+action: { type: "command", command: confirmCommand },
1148+value: confirmCommand,
1149+style: "danger",
1150+},
1151+{
1152+label: "Cancel",
1153+action: { type: "command", command: cancelCommand },
1154+value: cancelCommand,
1155+style: "secondary",
1156+},
11541157],
11551158},
11561159],
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。