@scotthuang/agent-knock-knock 0.2.46 → 0.2.48
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/CHANGELOG.md +39 -0
- package/README.md +93 -55
- package/dist/src/approval-policy.d.ts +3 -1
- package/dist/src/approval-policy.js +18 -4
- package/dist/src/approval-policy.js.map +1 -1
- package/dist/src/claude-hook-installer.d.ts +65 -0
- package/dist/src/claude-hook-installer.js +410 -0
- package/dist/src/claude-hook-installer.js.map +1 -0
- package/dist/src/claude-hook-protocol.d.ts +89 -0
- package/dist/src/claude-hook-protocol.js +243 -0
- package/dist/src/claude-hook-protocol.js.map +1 -0
- package/dist/src/claude-hook-store.d.ts +247 -0
- package/dist/src/claude-hook-store.js +1075 -0
- package/dist/src/claude-hook-store.js.map +1 -0
- package/dist/src/claude-terminal-agent-adapter.d.ts +47 -0
- package/dist/src/claude-terminal-agent-adapter.js +935 -0
- package/dist/src/claude-terminal-agent-adapter.js.map +1 -0
- package/dist/src/cli.js +2065 -316
- package/dist/src/cli.js.map +1 -1
- package/dist/src/openclaw-plugin-helpers.d.ts +49 -0
- package/dist/src/openclaw-plugin-helpers.js +246 -0
- package/dist/src/openclaw-plugin-helpers.js.map +1 -0
- package/dist/src/openclaw-plugin.js +98 -275
- package/dist/src/openclaw-plugin.js.map +1 -1
- package/dist/src/runtime-log.js +54 -2
- package/dist/src/runtime-log.js.map +1 -1
- package/dist/src/store.js +432 -12
- package/dist/src/store.js.map +1 -1
- package/dist/src/terminal-agent-adapter.d.ts +37 -0
- package/dist/src/terminal-agent-adapter.js.map +1 -1
- package/dist/src/terminal-agent-bridge.d.ts +51 -4
- package/dist/src/terminal-agent-bridge.js +326 -43
- package/dist/src/terminal-agent-bridge.js.map +1 -1
- package/dist/src/terminal-agent-registry.js +3 -1
- package/dist/src/terminal-agent-registry.js.map +1 -1
- package/dist/src/terminal-control-provider.d.ts +3 -1
- package/dist/src/terminal-control-provider.js +41 -37
- package/dist/src/terminal-control-provider.js.map +1 -1
- package/dist/src/terminal-process-source.d.ts +12 -3
- package/dist/src/terminal-process-source.js +37 -6
- package/dist/src/terminal-process-source.js.map +1 -1
- package/openclaw.plugin.json +5 -5
- package/package.json +10 -5
- package/templates/openclaw-skills/agent-knock-knock/SKILL.md +19 -30
|
@@ -2,9 +2,10 @@ import { spawnSync } from "node:child_process";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
|
|
5
|
-
import { EXECUTOR_KINDS,
|
|
5
|
+
import { EXECUTOR_KINDS, executorDefinitionForKind, parseLeadingExecutorAlias } from "./executors.js";
|
|
6
|
+
import { AKK_CALLBACK_METHOD, akkUsageText, buildAkkCommandCliArgs, formatAkkListCommandResult, parseAkkCommand, resolvePluginStoreDir, resolveConversationOverrides } from "./openclaw-plugin-helpers.js";
|
|
6
7
|
import { attemptAutoApproval } from "./approval-policy.js";
|
|
7
|
-
const CALLBACK_METHOD =
|
|
8
|
+
const CALLBACK_METHOD = AKK_CALLBACK_METHOD;
|
|
8
9
|
const pluginRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
|
|
9
10
|
const defaultBinPath = path.join(pluginRoot, "dist", "src", "cli.js");
|
|
10
11
|
const delegateParameters = {
|
|
@@ -23,11 +24,7 @@ const delegateParameters = {
|
|
|
23
24
|
},
|
|
24
25
|
workspace: {
|
|
25
26
|
type: "string",
|
|
26
|
-
description: "Workspace path for
|
|
27
|
-
},
|
|
28
|
-
storeDir: {
|
|
29
|
-
type: "string",
|
|
30
|
-
description: "Conversation store directory. Defaults to <workspace>/.agent-knock-knock/conversations."
|
|
27
|
+
description: "Workspace path for the selected coding agent. Defaults to plugin config or the Gateway process directory."
|
|
31
28
|
},
|
|
32
29
|
claudeSession: {
|
|
33
30
|
type: "string",
|
|
@@ -117,9 +114,6 @@ const listParameters = {
|
|
|
117
114
|
type: "boolean",
|
|
118
115
|
description: "When true, include tmux terminal discovery diagnostics for debugging Gateway environment issues."
|
|
119
116
|
},
|
|
120
|
-
storeDir: {
|
|
121
|
-
type: "string"
|
|
122
|
-
},
|
|
123
117
|
idleTimeoutMinutes: {
|
|
124
118
|
type: "number"
|
|
125
119
|
}
|
|
@@ -138,9 +132,6 @@ const renewParameters = {
|
|
|
138
132
|
type: "number",
|
|
139
133
|
exclusiveMinimum: 0,
|
|
140
134
|
description: "New terminal inactivity timeout in minutes."
|
|
141
|
-
},
|
|
142
|
-
storeDir: {
|
|
143
|
-
type: "string"
|
|
144
135
|
}
|
|
145
136
|
}
|
|
146
137
|
};
|
|
@@ -152,9 +143,6 @@ const retryCallbackParameters = {
|
|
|
152
143
|
conversation_id: {
|
|
153
144
|
type: "string",
|
|
154
145
|
description: "AKK-managed conversation whose persisted callback delivery is pending or failed."
|
|
155
|
-
},
|
|
156
|
-
storeDir: {
|
|
157
|
-
type: "string"
|
|
158
146
|
}
|
|
159
147
|
}
|
|
160
148
|
};
|
|
@@ -167,9 +155,6 @@ const statusParameters = {
|
|
|
167
155
|
type: "string",
|
|
168
156
|
description: "AKK-managed conversation id, or a terminal-controlled id from AKK list such as terminal:v2:tmux:codex:codex-work:0.1:33389."
|
|
169
157
|
},
|
|
170
|
-
storeDir: {
|
|
171
|
-
type: "string"
|
|
172
|
-
},
|
|
173
158
|
idleTimeoutMinutes: {
|
|
174
159
|
type: "number"
|
|
175
160
|
},
|
|
@@ -191,9 +176,6 @@ const describeParameters = {
|
|
|
191
176
|
type: "string",
|
|
192
177
|
description: "AKK-managed conversation id, native Codex id, or terminal-controlled id from AKK list. Use this when the user asks what a listed AKK/Codex session is about."
|
|
193
178
|
},
|
|
194
|
-
storeDir: {
|
|
195
|
-
type: "string"
|
|
196
|
-
},
|
|
197
179
|
idleTimeoutMinutes: {
|
|
198
180
|
type: "number"
|
|
199
181
|
},
|
|
@@ -230,9 +212,6 @@ const sendParameters = {
|
|
|
230
212
|
model: {
|
|
231
213
|
type: "string"
|
|
232
214
|
},
|
|
233
|
-
storeDir: {
|
|
234
|
-
type: "string"
|
|
235
|
-
},
|
|
236
215
|
idleTimeoutMinutes: {
|
|
237
216
|
type: "number"
|
|
238
217
|
},
|
|
@@ -259,9 +238,6 @@ const cancelParameters = {
|
|
|
259
238
|
allProxy: {
|
|
260
239
|
type: "string"
|
|
261
240
|
},
|
|
262
|
-
storeDir: {
|
|
263
|
-
type: "string"
|
|
264
|
-
},
|
|
265
241
|
idleTimeoutMinutes: {
|
|
266
242
|
type: "number"
|
|
267
243
|
}
|
|
@@ -284,9 +260,6 @@ const recoveryParameters = {
|
|
|
284
260
|
model: {
|
|
285
261
|
type: "string"
|
|
286
262
|
},
|
|
287
|
-
storeDir: {
|
|
288
|
-
type: "string"
|
|
289
|
-
},
|
|
290
263
|
idleTimeoutMinutes: {
|
|
291
264
|
type: "number"
|
|
292
265
|
}
|
|
@@ -302,9 +275,6 @@ const closeParameters = {
|
|
|
302
275
|
},
|
|
303
276
|
reason: {
|
|
304
277
|
type: "string"
|
|
305
|
-
},
|
|
306
|
-
storeDir: {
|
|
307
|
-
type: "string"
|
|
308
278
|
}
|
|
309
279
|
}
|
|
310
280
|
};
|
|
@@ -359,10 +329,6 @@ const agentTakeoverParameters = {
|
|
|
359
329
|
type: "string",
|
|
360
330
|
description: "Required when strategy=fork and createConversation=true. OpenClaw-approved summary of the bounded source context to inject into the new forked AKK session."
|
|
361
331
|
},
|
|
362
|
-
storeDir: {
|
|
363
|
-
type: "string",
|
|
364
|
-
description: "Conversation store directory. Defaults to plugin config or <workspace>/.agent-knock-knock/conversations."
|
|
365
|
-
},
|
|
366
332
|
openclawSession: {
|
|
367
333
|
type: "string",
|
|
368
334
|
description: "OpenClaw session label recorded in the created AKK conversation."
|
|
@@ -397,9 +363,6 @@ const approveParameters = {
|
|
|
397
363
|
expected_approval_fingerprint: {
|
|
398
364
|
type: "string",
|
|
399
365
|
description: "Exact approval fingerprint returned by the latest status or approval-required callback. The prompt is captured again and must still match before keys are sent."
|
|
400
|
-
},
|
|
401
|
-
storeDir: {
|
|
402
|
-
type: "string"
|
|
403
366
|
}
|
|
404
367
|
}
|
|
405
368
|
};
|
|
@@ -422,6 +385,31 @@ export default definePluginEntry({
|
|
|
422
385
|
});
|
|
423
386
|
}
|
|
424
387
|
}, { scope: "operator.write" });
|
|
388
|
+
try {
|
|
389
|
+
api.registerService?.({
|
|
390
|
+
id: "agent-knock-knock-monitor-reconciliation",
|
|
391
|
+
start() {
|
|
392
|
+
try {
|
|
393
|
+
const config = isRecord(api.pluginConfig) ? api.pluginConfig : {};
|
|
394
|
+
const args = ["reconcile-monitors"];
|
|
395
|
+
pushOptional(args, "--store-dir", resolvePluginStoreDir(config));
|
|
396
|
+
const result = runCli(api, args);
|
|
397
|
+
api.logger.info?.("agent-knock-knock monitor reconciliation: " +
|
|
398
|
+
`checked=${result.checked ?? 0} launched=${result.launched ?? 0} ` +
|
|
399
|
+
`already_running=${result.already_running ?? 0} skipped=${result.skipped ?? 0} ` +
|
|
400
|
+
`errors=${result.errors ?? 0}`);
|
|
401
|
+
}
|
|
402
|
+
catch (error) {
|
|
403
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
404
|
+
api.logger.warn?.(`agent-knock-knock monitor reconciliation skipped after startup error: ${message}`);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
catch (error) {
|
|
410
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
411
|
+
api.logger.warn?.(`agent-knock-knock monitor reconciliation service was not registered: ${message}`);
|
|
412
|
+
}
|
|
425
413
|
api.registerCommand?.({
|
|
426
414
|
name: "akk",
|
|
427
415
|
description: "Delegate coding work to Agent Knock Knock, list tasks, send follow-ups, cancel running work, and close tasks.",
|
|
@@ -453,11 +441,11 @@ export default definePluginEntry({
|
|
|
453
441
|
}), { name: "agent_knock_knock_delegate", optional: true });
|
|
454
442
|
registerCliTool(api, {
|
|
455
443
|
name: "agent_knock_knock_list",
|
|
456
|
-
description: "List Agent Knock Knock work and local active coding-agent sessions. Use this for AKK list,
|
|
444
|
+
description: "List Agent Knock Knock work and local active coding-agent sessions. Use this for AKK list, current AKK tasks, native Codex work, terminal-controlled Codex or Claude Code work, or asking which coding-agent sessions are open. The result separates delegated tasks, native processes, and terminal-controlled sessions; terminal entries include approval state when available.",
|
|
457
445
|
parameters: listParameters,
|
|
458
446
|
buildArgs: (params) => {
|
|
459
447
|
const args = ["list"];
|
|
460
|
-
pushOptional(args, "--store-dir",
|
|
448
|
+
pushOptional(args, "--store-dir", resolvePluginStoreDir(isRecord(api.pluginConfig) ? api.pluginConfig : {}));
|
|
461
449
|
pushOptional(args, "--idle-timeout-minutes", numberString(params.idleTimeoutMinutes) ?? numberString(api.pluginConfig?.idleTimeoutMinutes));
|
|
462
450
|
pushOptional(args, "--agent", stringValue(params.agent));
|
|
463
451
|
pushOptional(args, "--status", stringValue(params.status));
|
|
@@ -482,7 +470,7 @@ export default definePluginEntry({
|
|
|
482
470
|
parameters: statusParameters,
|
|
483
471
|
buildArgs: (params) => {
|
|
484
472
|
const args = ["status", "--conversation", requiredString(params.conversation_id, "conversation_id")];
|
|
485
|
-
pushOptional(args, "--store-dir",
|
|
473
|
+
pushOptional(args, "--store-dir", resolvePluginStoreDir(isRecord(api.pluginConfig) ? api.pluginConfig : {}));
|
|
486
474
|
pushOptional(args, "--idle-timeout-minutes", numberString(params.idleTimeoutMinutes) ?? numberString(api.pluginConfig?.idleTimeoutMinutes));
|
|
487
475
|
if (params.trace === true) {
|
|
488
476
|
args.push("--trace");
|
|
@@ -492,11 +480,11 @@ export default definePluginEntry({
|
|
|
492
480
|
});
|
|
493
481
|
registerCliTool(api, {
|
|
494
482
|
name: "agent_knock_knock_describe",
|
|
495
|
-
description: "Describe what a listed Agent Knock Knock or local
|
|
483
|
+
description: "Describe what a listed Agent Knock Knock or local coding-agent session is about. It summarizes AKK history when available, otherwise uses supported durable agent context or a conservative terminal-screen fallback with confidence and limitations.",
|
|
496
484
|
parameters: describeParameters,
|
|
497
485
|
buildArgs: (params) => {
|
|
498
486
|
const args = ["describe", "--conversation", requiredString(params.conversation_id, "conversation_id")];
|
|
499
|
-
pushOptional(args, "--store-dir",
|
|
487
|
+
pushOptional(args, "--store-dir", resolvePluginStoreDir(isRecord(api.pluginConfig) ? api.pluginConfig : {}));
|
|
500
488
|
pushOptional(args, "--idle-timeout-minutes", numberString(params.idleTimeoutMinutes) ?? numberString(api.pluginConfig?.idleTimeoutMinutes));
|
|
501
489
|
pushOptional(args, "--max-messages", numberString(params.maxMessages));
|
|
502
490
|
pushOptional(args, "--max-commands", numberString(params.maxCommands));
|
|
@@ -506,7 +494,7 @@ export default definePluginEntry({
|
|
|
506
494
|
});
|
|
507
495
|
registerCliTool(api, {
|
|
508
496
|
name: "agent_knock_knock_send",
|
|
509
|
-
description: "Send a message, follow-up, or new task to an existing open Agent Knock Knock
|
|
497
|
+
description: "Send a message, follow-up, or new task to an existing open Agent Knock Knock or terminal-controlled coding-agent session from AKK list, including Codex or Claude Code in tmux. Do not start a new delegate for those requests. This is asynchronous: after acceptance, end the OpenClaw turn and wait for the AKK callback or a later explicit status request.",
|
|
510
498
|
parameters: sendParameters,
|
|
511
499
|
buildArgs: (params, toolContext) => {
|
|
512
500
|
const config = isRecord(api.pluginConfig) ? api.pluginConfig : {};
|
|
@@ -522,15 +510,14 @@ export default definePluginEntry({
|
|
|
522
510
|
"--background"
|
|
523
511
|
];
|
|
524
512
|
pushOptional(args, "--type", stringValue(params.type));
|
|
525
|
-
|
|
526
|
-
pushOptional(args, "--
|
|
527
|
-
pushOptional(args, "--
|
|
513
|
+
const overrides = resolveConversationOverrides(params, config);
|
|
514
|
+
pushOptional(args, "--all-proxy", overrides.allProxy);
|
|
515
|
+
pushOptional(args, "--model", overrides.model);
|
|
516
|
+
pushOptional(args, "--store-dir", resolvePluginStoreDir(config));
|
|
528
517
|
pushOptional(args, "--idle-timeout-minutes", numberString(params.idleTimeoutMinutes) ?? numberString(config.idleTimeoutMinutes));
|
|
529
518
|
pushOptional(args, "--agent-timeout-minutes", numberString(params.agentTimeoutMinutes) ?? numberString(config.agentTimeoutMinutes));
|
|
530
519
|
pushOptional(args, "--agent-hard-timeout-minutes", numberString(params.agentHardTimeoutMinutes) ?? numberString(config.agentHardTimeoutMinutes));
|
|
531
520
|
pushOptional(args, "--openclaw-session", openclawSession);
|
|
532
|
-
pushOptional(args, "--gateway-url", stringValue(config.gatewayUrl));
|
|
533
|
-
pushOptional(args, "--token", stringValue(config.gatewayToken));
|
|
534
521
|
pushOptional(args, "--gateway-method", CALLBACK_METHOD);
|
|
535
522
|
pushOptional(args, "--gateway-session", openclawSession);
|
|
536
523
|
pushOptional(args, "--openclaw-bin", stringValue(config.openclawBin));
|
|
@@ -542,24 +529,24 @@ export default definePluginEntry({
|
|
|
542
529
|
});
|
|
543
530
|
registerCliTool(api, {
|
|
544
531
|
name: "agent_knock_knock_approve",
|
|
545
|
-
description: "Approve the current
|
|
532
|
+
description: "Approve the current AKK terminal permission request after showing it to the user and receiving explicit approval. Claude Code uses a revalidated structured one-time Hook decision; supported screen fallbacks use the detected primary shortcut and are never eligible for Claude auto-approval.",
|
|
546
533
|
parameters: approveParameters,
|
|
547
534
|
buildArgs: (params) => {
|
|
548
535
|
const args = ["approve", "--conversation", requiredString(params.conversation_id, "conversation_id")];
|
|
549
536
|
pushOptional(args, "--expected-approval-fingerprint", requiredString(params.expected_approval_fingerprint, "expected_approval_fingerprint"));
|
|
550
|
-
pushOptional(args, "--store-dir",
|
|
537
|
+
pushOptional(args, "--store-dir", resolvePluginStoreDir(isRecord(api.pluginConfig) ? api.pluginConfig : {}));
|
|
551
538
|
return args;
|
|
552
539
|
}
|
|
553
540
|
});
|
|
554
541
|
registerCliTool(api, {
|
|
555
542
|
name: "agent_knock_knock_renew",
|
|
556
|
-
description: "Renew monitoring for a stalled AKK-managed terminal bridge task without sending text or keys to
|
|
543
|
+
description: "Renew monitoring for a stalled AKK-managed terminal bridge task without sending text or keys to the coding agent. Use this when the user wants a still-live long-running terminal task to keep monitoring after an inactivity stall.",
|
|
557
544
|
parameters: renewParameters,
|
|
558
545
|
buildArgs: (params) => {
|
|
559
546
|
const config = isRecord(api.pluginConfig) ? api.pluginConfig : {};
|
|
560
547
|
const args = ["renew", "--conversation", requiredString(params.conversation_id, "conversation_id")];
|
|
561
548
|
pushOptional(args, "--minutes", numberString(params.minutes) ?? numberString(config.agentTimeoutMinutes));
|
|
562
|
-
pushOptional(args, "--store-dir",
|
|
549
|
+
pushOptional(args, "--store-dir", resolvePluginStoreDir(config));
|
|
563
550
|
return args;
|
|
564
551
|
}
|
|
565
552
|
});
|
|
@@ -570,19 +557,21 @@ export default definePluginEntry({
|
|
|
570
557
|
buildArgs: (params) => {
|
|
571
558
|
const config = isRecord(api.pluginConfig) ? api.pluginConfig : {};
|
|
572
559
|
const args = ["retry-callback", "--conversation", requiredString(params.conversation_id, "conversation_id")];
|
|
573
|
-
pushOptional(args, "--store-dir",
|
|
560
|
+
pushOptional(args, "--store-dir", resolvePluginStoreDir(config));
|
|
574
561
|
return args;
|
|
575
562
|
}
|
|
576
563
|
});
|
|
577
564
|
registerCliTool(api, {
|
|
578
565
|
name: "agent_knock_knock_cancel",
|
|
579
|
-
description: "
|
|
566
|
+
description: "Cancel an existing Agent Knock Knock Codex, Claude, or Cursor task. Delegated sessions use cooperative ACPX cancellation. Terminal-controlled Claude denies a pending structured permission or sends Escape; other adapters use their declared interrupt keys. The underlying tmux pane remains open.",
|
|
580
567
|
parameters: cancelParameters,
|
|
581
568
|
buildArgs: (params) => {
|
|
569
|
+
const config = isRecord(api.pluginConfig) ? api.pluginConfig : {};
|
|
570
|
+
const overrides = resolveConversationOverrides(params, config);
|
|
582
571
|
const args = ["cancel", "--conversation", requiredString(params.conversation_id, "conversation_id")];
|
|
583
|
-
pushOptional(args, "--all-proxy",
|
|
584
|
-
pushOptional(args, "--store-dir",
|
|
585
|
-
pushOptional(args, "--idle-timeout-minutes", numberString(params.idleTimeoutMinutes) ?? numberString(
|
|
572
|
+
pushOptional(args, "--all-proxy", overrides.allProxy);
|
|
573
|
+
pushOptional(args, "--store-dir", resolvePluginStoreDir(config));
|
|
574
|
+
pushOptional(args, "--idle-timeout-minutes", numberString(params.idleTimeoutMinutes) ?? numberString(config.idleTimeoutMinutes));
|
|
586
575
|
return args;
|
|
587
576
|
}
|
|
588
577
|
});
|
|
@@ -599,7 +588,7 @@ export default definePluginEntry({
|
|
|
599
588
|
buildArgs: (params) => {
|
|
600
589
|
const args = ["close", "--conversation", requiredString(params.conversation_id, "conversation_id")];
|
|
601
590
|
pushOptional(args, "--reason", stringValue(params.reason));
|
|
602
|
-
pushOptional(args, "--store-dir",
|
|
591
|
+
pushOptional(args, "--store-dir", resolvePluginStoreDir(isRecord(api.pluginConfig) ? api.pluginConfig : {}));
|
|
603
592
|
return args;
|
|
604
593
|
}
|
|
605
594
|
});
|
|
@@ -639,10 +628,8 @@ export default definePluginEntry({
|
|
|
639
628
|
pushOptional(args, "--terminal-target", stringValue(params.terminalTarget));
|
|
640
629
|
pushOptional(args, "--request", stringValue(params.request));
|
|
641
630
|
pushOptional(args, "--fork-summary", stringValue(params.forkSummary));
|
|
642
|
-
pushOptional(args, "--store-dir",
|
|
631
|
+
pushOptional(args, "--store-dir", resolvePluginStoreDir(config));
|
|
643
632
|
pushOptional(args, "--openclaw-session", openclawSession);
|
|
644
|
-
pushOptional(args, "--gateway-url", stringValue(config.gatewayUrl));
|
|
645
|
-
pushOptional(args, "--token", stringValue(config.gatewayToken));
|
|
646
633
|
pushOptional(args, "--gateway-method", CALLBACK_METHOD);
|
|
647
634
|
pushOptional(args, "--gateway-session", openclawSession);
|
|
648
635
|
pushOptional(args, "--openclaw-bin", stringValue(config.openclawBin));
|
|
@@ -674,88 +661,34 @@ async function handleAkkCommand(api, ctx) {
|
|
|
674
661
|
});
|
|
675
662
|
return { text: formatDelegateCommandResult(result) };
|
|
676
663
|
}
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
}
|
|
681
|
-
if (
|
|
682
|
-
|
|
683
|
-
return { text: formatStatusCommandResult(result) };
|
|
684
|
-
}
|
|
685
|
-
if (parsed.action === "describe") {
|
|
686
|
-
const result = runCli(api, ["describe", "--conversation", parsed.conversationId]);
|
|
687
|
-
return { text: formatDescribeCommandResult(result) };
|
|
688
|
-
}
|
|
689
|
-
if (parsed.action === "send") {
|
|
690
|
-
const args = [
|
|
691
|
-
"send",
|
|
692
|
-
"--conversation",
|
|
693
|
-
parsed.conversationId,
|
|
694
|
-
"--message",
|
|
695
|
-
parsed.message,
|
|
696
|
-
"--background"
|
|
697
|
-
];
|
|
698
|
-
const config = isRecord(api.pluginConfig) ? api.pluginConfig : {};
|
|
699
|
-
pushOptional(args, "--all-proxy", stringValue(config.codexAllProxy) ?? stringValue(config.allProxy));
|
|
700
|
-
pushOptional(args, "--model", stringValue(config.codexModel) ?? stringValue(config.model));
|
|
701
|
-
pushOptional(args, "--idle-timeout-minutes", numberString(config.idleTimeoutMinutes));
|
|
702
|
-
pushOptional(args, "--agent-timeout-minutes", numberString(config.agentTimeoutMinutes));
|
|
703
|
-
pushOptional(args, "--agent-hard-timeout-minutes", numberString(config.agentHardTimeoutMinutes));
|
|
704
|
-
const result = runCli(api, args);
|
|
705
|
-
return { text: formatSendCommandResult(result) };
|
|
706
|
-
}
|
|
707
|
-
if (parsed.action === "renew") {
|
|
708
|
-
const config = isRecord(api.pluginConfig) ? api.pluginConfig : {};
|
|
709
|
-
const args = ["renew", "--conversation", parsed.conversationId];
|
|
710
|
-
pushOptional(args, "--minutes", parsed.minutes ?? numberString(config.agentTimeoutMinutes));
|
|
711
|
-
pushOptional(args, "--store-dir", stringValue(config.storeDir));
|
|
712
|
-
const result = runCli(api, args);
|
|
713
|
-
return { text: formatRenewCommandResult(result) };
|
|
714
|
-
}
|
|
715
|
-
if (parsed.action === "retry-callback" || parsed.action === "retry") {
|
|
716
|
-
const config = isRecord(api.pluginConfig) ? api.pluginConfig : {};
|
|
717
|
-
const args = ["retry-callback", "--conversation", parsed.conversationId];
|
|
718
|
-
pushOptional(args, "--store-dir", stringValue(config.storeDir));
|
|
719
|
-
const result = runCli(api, args);
|
|
720
|
-
return { text: formatRetryCallbackCommandResult(result) };
|
|
721
|
-
}
|
|
722
|
-
if (parsed.action === "cancel") {
|
|
723
|
-
const args = [
|
|
724
|
-
"cancel",
|
|
725
|
-
"--conversation",
|
|
726
|
-
parsed.conversationId
|
|
727
|
-
];
|
|
728
|
-
const config = isRecord(api.pluginConfig) ? api.pluginConfig : {};
|
|
729
|
-
pushOptional(args, "--all-proxy", stringValue(config.codexAllProxy) ?? stringValue(config.allProxy));
|
|
730
|
-
pushOptional(args, "--idle-timeout-minutes", numberString(config.idleTimeoutMinutes));
|
|
731
|
-
const result = runCli(api, args);
|
|
732
|
-
return { text: formatCancelCommandResult(result) };
|
|
733
|
-
}
|
|
734
|
-
if (parsed.action === "recover") {
|
|
735
|
-
const config = isRecord(api.pluginConfig) ? api.pluginConfig : {};
|
|
736
|
-
const args = [
|
|
737
|
-
"recover",
|
|
738
|
-
"--conversation",
|
|
739
|
-
parsed.conversationId,
|
|
740
|
-
"--background"
|
|
741
|
-
];
|
|
742
|
-
pushOptional(args, "--all-proxy", stringValue(config.codexAllProxy) ?? stringValue(config.allProxy));
|
|
743
|
-
pushOptional(args, "--model", stringValue(config.codexModel) ?? stringValue(config.model));
|
|
744
|
-
pushOptional(args, "--idle-timeout-minutes", numberString(config.idleTimeoutMinutes));
|
|
745
|
-
const result = runCli(api, args);
|
|
746
|
-
return { text: formatRecoveryCommandResult(result) };
|
|
664
|
+
const config = isRecord(api.pluginConfig) ? api.pluginConfig : {};
|
|
665
|
+
const args = buildAkkCommandCliArgs(parsed, config, {
|
|
666
|
+
sessionKey: ctx.sessionKey
|
|
667
|
+
});
|
|
668
|
+
if (!args) {
|
|
669
|
+
return { text: akkUsageText(), isError: true };
|
|
747
670
|
}
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
671
|
+
const result = runCli(api, args);
|
|
672
|
+
switch (parsed.action) {
|
|
673
|
+
case "list":
|
|
674
|
+
return { text: formatAkkListCommandResult(result) };
|
|
675
|
+
case "status":
|
|
676
|
+
return { text: formatStatusCommandResult(result) };
|
|
677
|
+
case "describe":
|
|
678
|
+
return { text: formatDescribeCommandResult(result) };
|
|
679
|
+
case "send":
|
|
680
|
+
return { text: formatSendCommandResult(result) };
|
|
681
|
+
case "renew":
|
|
682
|
+
return { text: formatRenewCommandResult(result) };
|
|
683
|
+
case "retry-callback":
|
|
684
|
+
return { text: formatRetryCallbackCommandResult(result) };
|
|
685
|
+
case "cancel":
|
|
686
|
+
return { text: formatCancelCommandResult(result) };
|
|
687
|
+
case "recover":
|
|
688
|
+
return { text: formatRecoveryCommandResult(result) };
|
|
689
|
+
case "close":
|
|
690
|
+
return { text: formatCloseCommandResult(result) };
|
|
757
691
|
}
|
|
758
|
-
return { text: akkUsageText(), isError: true };
|
|
759
692
|
}
|
|
760
693
|
catch (error) {
|
|
761
694
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -765,109 +698,14 @@ async function handleAkkCommand(api, ctx) {
|
|
|
765
698
|
};
|
|
766
699
|
}
|
|
767
700
|
}
|
|
768
|
-
function parseAkkCommand(args) {
|
|
769
|
-
const input = String(args ?? "").trim();
|
|
770
|
-
if (!input || input === "help" || input === "-h" || input === "--help") {
|
|
771
|
-
return { action: "help" };
|
|
772
|
-
}
|
|
773
|
-
const { token, rest } = takeToken(input);
|
|
774
|
-
const action = String(token).toLowerCase();
|
|
775
|
-
if (action === "list" || action === "ls" || action === "tasks") {
|
|
776
|
-
return { action: "list" };
|
|
777
|
-
}
|
|
778
|
-
if (action === "status" || action === "show") {
|
|
779
|
-
const { token: conversationId } = takeRequiredToken(rest, "Usage: /akk status <conversation-id>");
|
|
780
|
-
return { action: "status", conversationId };
|
|
781
|
-
}
|
|
782
|
-
if (action === "describe" || action === "summary" || action === "about") {
|
|
783
|
-
const { token: conversationId } = takeRequiredToken(rest, "Usage: /akk describe <conversation-id>");
|
|
784
|
-
return { action: "describe", conversationId };
|
|
785
|
-
}
|
|
786
|
-
if (action === "send" || action === "reply") {
|
|
787
|
-
const { token: conversationId, rest: message } = takeRequiredToken(rest, "Usage: /akk send <conversation-id> <message>");
|
|
788
|
-
const body = message.trim();
|
|
789
|
-
if (!body) {
|
|
790
|
-
throw new Error("Usage: /akk send <conversation-id> <message>");
|
|
791
|
-
}
|
|
792
|
-
return { action: "send", conversationId, message: body };
|
|
793
|
-
}
|
|
794
|
-
if (action === "cancel" || action === "stop") {
|
|
795
|
-
const { token: conversationId } = takeRequiredToken(rest, "Usage: /akk cancel <conversation-id>");
|
|
796
|
-
return { action: "cancel", conversationId };
|
|
797
|
-
}
|
|
798
|
-
if (action === "renew") {
|
|
799
|
-
const { token: conversationId, rest: minutesInput } = takeRequiredToken(rest, "Usage: /akk renew <conversation-id> [minutes]");
|
|
800
|
-
const minutes = minutesInput.trim();
|
|
801
|
-
if (minutes && (!Number.isFinite(Number(minutes)) || Number(minutes) <= 0)) {
|
|
802
|
-
throw new Error("Usage: /akk renew <conversation-id> [positive-minutes]");
|
|
803
|
-
}
|
|
804
|
-
return { action: "renew", conversationId, minutes: minutes || undefined };
|
|
805
|
-
}
|
|
806
|
-
if (action === "retry-callback" || action === "retry") {
|
|
807
|
-
const { token: conversationId } = takeRequiredToken(rest, "Usage: /akk retry-callback <conversation-id>");
|
|
808
|
-
return { action: "retry-callback", conversationId };
|
|
809
|
-
}
|
|
810
|
-
if (action === "recover") {
|
|
811
|
-
const { token: conversationId } = takeRequiredToken(rest, "Usage: /akk recover <conversation-id>");
|
|
812
|
-
return { action: "recover", conversationId };
|
|
813
|
-
}
|
|
814
|
-
if (action === "close" || action === "done") {
|
|
815
|
-
const { token: conversationId, rest: reason } = takeRequiredToken(rest, "Usage: /akk close <conversation-id> [reason]");
|
|
816
|
-
return { action: "close", conversationId, reason: reason.trim() || "Closed from /akk command" };
|
|
817
|
-
}
|
|
818
|
-
const executorDefinition = executorDefinitionForAlias(action);
|
|
819
|
-
if (executorDefinition) {
|
|
820
|
-
const request = rest.trim();
|
|
821
|
-
if (!request) {
|
|
822
|
-
throw new Error(`Usage: /akk ${executorDefinition.kind} <task>`);
|
|
823
|
-
}
|
|
824
|
-
return { action: "delegate", agent: executorDefinition.kind, request };
|
|
825
|
-
}
|
|
826
|
-
return { action: "delegate", agent: "codex", request: input };
|
|
827
|
-
}
|
|
828
|
-
function takeRequiredToken(input, usage) {
|
|
829
|
-
const parsed = takeToken(input);
|
|
830
|
-
if (!parsed.token) {
|
|
831
|
-
throw new Error(usage);
|
|
832
|
-
}
|
|
833
|
-
return parsed;
|
|
834
|
-
}
|
|
835
|
-
function takeToken(input) {
|
|
836
|
-
const value = String(input ?? "").trimStart();
|
|
837
|
-
const match = value.match(/^(\S+)(?:\s+([\s\S]*))?$/);
|
|
838
|
-
if (!match) {
|
|
839
|
-
return { token: "", rest: "" };
|
|
840
|
-
}
|
|
841
|
-
return {
|
|
842
|
-
token: match[1],
|
|
843
|
-
rest: match[2] ?? ""
|
|
844
|
-
};
|
|
845
|
-
}
|
|
846
|
-
function akkUsageText() {
|
|
847
|
-
return [
|
|
848
|
-
"AKK usage:",
|
|
849
|
-
"/akk <task>",
|
|
850
|
-
"/akk codex <task>",
|
|
851
|
-
"/akk claude <task>",
|
|
852
|
-
"/akk list",
|
|
853
|
-
"/akk status <conversation-id>",
|
|
854
|
-
"/akk describe <conversation-id>",
|
|
855
|
-
"/akk send <conversation-id> <message>",
|
|
856
|
-
"/akk cancel <conversation-id>",
|
|
857
|
-
"/akk renew <conversation-id> [minutes]",
|
|
858
|
-
"/akk retry-callback <conversation-id>",
|
|
859
|
-
"/akk recover <conversation-id>",
|
|
860
|
-
"/akk close <conversation-id> [reason]"
|
|
861
|
-
].join("\n");
|
|
862
|
-
}
|
|
863
701
|
function formatDelegateCommandResult(result) {
|
|
864
702
|
const agent = executorDisplayName(result.agent);
|
|
865
703
|
return [
|
|
866
|
-
`AKK
|
|
704
|
+
`AKK delegated the task to ${agent}.`,
|
|
867
705
|
`conversation: ${result.conversation_id ?? "unknown"}`,
|
|
868
706
|
`session: ${result.session ?? "unknown"}`,
|
|
869
707
|
`status: ${result.conversation_status ?? result.status ?? "unknown"}`,
|
|
870
|
-
"
|
|
708
|
+
"The result will return to this OpenClaw session through the callback."
|
|
871
709
|
].join("\n");
|
|
872
710
|
}
|
|
873
711
|
function executorDisplayName(kind) {
|
|
@@ -878,23 +716,15 @@ function executorDisplayName(kind) {
|
|
|
878
716
|
return String(kind ?? "agent");
|
|
879
717
|
}
|
|
880
718
|
}
|
|
881
|
-
function formatListCommandResult(result) {
|
|
882
|
-
const tasks = Array.isArray(result.tasks) ? result.tasks : [];
|
|
883
|
-
if (!tasks.length) {
|
|
884
|
-
return "AKK 当前没有打开的会话。";
|
|
885
|
-
}
|
|
886
|
-
return [
|
|
887
|
-
`AKK open sessions (${tasks.length}):`,
|
|
888
|
-
...tasks.slice(0, 20).map(formatTaskLine)
|
|
889
|
-
].join("\n");
|
|
890
|
-
}
|
|
891
719
|
function formatStatusCommandResult(result) {
|
|
892
|
-
const summary = result.summary ?? result.conversation ?? {};
|
|
720
|
+
const summary = result.summary ?? result.conversation ?? result ?? {};
|
|
721
|
+
const terminalStatus = isRecord(result.terminal_status) ? result.terminal_status : {};
|
|
722
|
+
const terminalControl = isRecord(result.terminal_control) ? result.terminal_control : {};
|
|
893
723
|
const lines = [
|
|
894
|
-
`AKK status: ${summary.conversation_id ?? "unknown"}`,
|
|
895
|
-
`agent: ${summary.agent ?? summary.executor?.kind ?? "unknown"}`,
|
|
896
|
-
`status: ${summary.status ?? "unknown"}`,
|
|
897
|
-
`session: ${summary.session ?? summary.executor?.session ?? "unknown"}`
|
|
724
|
+
`AKK status: ${summary.conversation_id ?? result.conversation_id ?? "unknown"}`,
|
|
725
|
+
`agent: ${summary.agent ?? summary.executor?.kind ?? terminalStatus.agent ?? "unknown"}`,
|
|
726
|
+
`status: ${summary.status ?? terminalStatus.activity_state ?? "unknown"}`,
|
|
727
|
+
`session: ${summary.session ?? summary.executor?.session ?? terminalControl.target ?? "unknown"}`
|
|
898
728
|
];
|
|
899
729
|
if (summary.request) {
|
|
900
730
|
lines.push(`request: ${truncateText(summary.request, 180)}`);
|
|
@@ -953,12 +783,13 @@ function formatSendCommandResult(result) {
|
|
|
953
783
|
}
|
|
954
784
|
function formatCancelCommandResult(result) {
|
|
955
785
|
const conversation = result.conversation ?? {};
|
|
786
|
+
const terminalControl = isRecord(result.terminal_control) ? result.terminal_control : {};
|
|
956
787
|
return [
|
|
957
788
|
"AKK cancel requested.",
|
|
958
|
-
`conversation: ${conversation.conversation_id ?? "unknown"}`,
|
|
789
|
+
`conversation: ${conversation.conversation_id ?? result.conversation_id ?? "unknown"}`,
|
|
959
790
|
`agent: ${result.executor?.kind ?? conversation.executor?.kind ?? "unknown"}`,
|
|
960
|
-
`session: ${result.executor?.session ?? conversation.executor?.session ?? "unknown"}`,
|
|
961
|
-
`status: ${conversation.status ?? "
|
|
791
|
+
`session: ${result.executor?.session ?? conversation.executor?.session ?? terminalControl.target ?? "unknown"}`,
|
|
792
|
+
`status: ${conversation.status ?? (result.cancel_requested === true ? "cancel requested" : "not cancelled")}`
|
|
962
793
|
].join("\n");
|
|
963
794
|
}
|
|
964
795
|
function formatRecoveryCommandResult(result) {
|
|
@@ -979,14 +810,6 @@ function formatCloseCommandResult(result) {
|
|
|
979
810
|
`status: ${conversation.status ?? "unknown"}`
|
|
980
811
|
].join("\n");
|
|
981
812
|
}
|
|
982
|
-
function formatTaskLine(task) {
|
|
983
|
-
return [
|
|
984
|
-
task.conversation_id ?? "unknown",
|
|
985
|
-
task.agent ?? task.executor?.kind ?? "agent",
|
|
986
|
-
task.status ?? "unknown",
|
|
987
|
-
truncateText(task.request ?? "", 90)
|
|
988
|
-
].filter(Boolean).join(" | ");
|
|
989
|
-
}
|
|
990
813
|
function runDelegate(api, params, toolContext) {
|
|
991
814
|
const config = isRecord(api.pluginConfig) ? api.pluginConfig : {};
|
|
992
815
|
const binPath = stringValue(config.binPath) ?? defaultBinPath;
|
|
@@ -1022,13 +845,11 @@ function runDelegate(api, params, toolContext) {
|
|
|
1022
845
|
workspace,
|
|
1023
846
|
"--background"
|
|
1024
847
|
];
|
|
1025
|
-
pushOptional(args, "--store-dir",
|
|
848
|
+
pushOptional(args, "--store-dir", resolvePluginStoreDir(config));
|
|
1026
849
|
pushOptional(args, "--session", agentSession);
|
|
1027
850
|
pushOptional(args, "--all-proxy", allProxy);
|
|
1028
851
|
pushOptional(args, "--model", model);
|
|
1029
852
|
pushOptional(args, "--openclaw-session", openclawSession);
|
|
1030
|
-
pushOptional(args, "--gateway-url", stringValue(config.gatewayUrl));
|
|
1031
|
-
pushOptional(args, "--token", stringValue(config.gatewayToken));
|
|
1032
853
|
pushOptional(args, "--gateway-method", CALLBACK_METHOD);
|
|
1033
854
|
pushOptional(args, "--gateway-session", openclawSession);
|
|
1034
855
|
pushOptional(args, "--openclaw-bin", stringValue(config.openclawBin));
|
|
@@ -1096,12 +917,14 @@ function registerCliTool(api, { name, description, parameters, buildArgs }) {
|
|
|
1096
917
|
}), { name, optional: true });
|
|
1097
918
|
}
|
|
1098
919
|
function buildRecoveryArgs(api, command, params) {
|
|
920
|
+
const config = isRecord(api.pluginConfig) ? api.pluginConfig : {};
|
|
921
|
+
const overrides = resolveConversationOverrides(params, config);
|
|
1099
922
|
const args = [command, "--conversation", requiredString(params.conversation_id, "conversation_id"), "--background"];
|
|
1100
923
|
pushOptional(args, "--session", stringValue(params.session));
|
|
1101
|
-
pushOptional(args, "--all-proxy",
|
|
1102
|
-
pushOptional(args, "--model",
|
|
1103
|
-
pushOptional(args, "--store-dir",
|
|
1104
|
-
pushOptional(args, "--idle-timeout-minutes", numberString(params.idleTimeoutMinutes) ?? numberString(
|
|
924
|
+
pushOptional(args, "--all-proxy", overrides.allProxy);
|
|
925
|
+
pushOptional(args, "--model", overrides.model);
|
|
926
|
+
pushOptional(args, "--store-dir", resolvePluginStoreDir(config));
|
|
927
|
+
pushOptional(args, "--idle-timeout-minutes", numberString(params.idleTimeoutMinutes) ?? numberString(config.idleTimeoutMinutes));
|
|
1105
928
|
return args;
|
|
1106
929
|
}
|
|
1107
930
|
function runCli(api, cliArgs, { cwd = process.cwd() } = {}) {
|