@scotthuang/agent-knock-knock 0.12.13 → 0.12.15

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 (170) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/README.md +13 -13
  3. package/dist/src/callback-cli-adapter.d.ts +9 -6
  4. package/dist/src/callback-cli-adapter.js +119 -30
  5. package/dist/src/callback-cli-adapter.js.map +1 -1
  6. package/dist/src/callback-outbox-policy.d.ts +39 -0
  7. package/dist/src/callback-outbox-policy.js +163 -6
  8. package/dist/src/callback-outbox-policy.js.map +1 -1
  9. package/dist/src/callback-outbox-service.d.ts +28 -1
  10. package/dist/src/callback-outbox-service.js +413 -82
  11. package/dist/src/callback-outbox-service.js.map +1 -1
  12. package/dist/src/callback-outbox-settlement.d.ts +14 -1
  13. package/dist/src/callback-outbox-settlement.js +151 -30
  14. package/dist/src/callback-outbox-settlement.js.map +1 -1
  15. package/dist/src/callback-route-authority.d.ts +59 -0
  16. package/dist/src/callback-route-authority.js +123 -0
  17. package/dist/src/callback-route-authority.js.map +1 -0
  18. package/dist/src/callback-transport.d.ts +134 -0
  19. package/dist/src/callback-transport.js +256 -0
  20. package/dist/src/callback-transport.js.map +1 -0
  21. package/dist/src/cli-core.js +56 -18
  22. package/dist/src/cli-core.js.map +1 -1
  23. package/dist/src/cli-runtime-context.d.ts +2 -0
  24. package/dist/src/cli-runtime-context.js.map +1 -1
  25. package/dist/src/codex-lifecycle-compatibility.js +2 -1
  26. package/dist/src/codex-lifecycle-compatibility.js.map +1 -1
  27. package/dist/src/deferred-foreground-application-service.d.ts +18 -0
  28. package/dist/src/deferred-foreground-application-service.js +72 -0
  29. package/dist/src/deferred-foreground-application-service.js.map +1 -1
  30. package/dist/src/deferred-foreground-authority-cli-adapter.js +10 -1
  31. package/dist/src/deferred-foreground-authority-cli-adapter.js.map +1 -1
  32. package/dist/src/deferred-foreground-recovery-cli-adapter.d.ts +1 -1
  33. package/dist/src/deferred-foreground-recovery-cli-adapter.js +108 -37
  34. package/dist/src/deferred-foreground-recovery-cli-adapter.js.map +1 -1
  35. package/dist/src/deferred-foreground-recovery-service.d.ts +1 -1
  36. package/dist/src/deferred-foreground-recovery-service.js +10 -3
  37. package/dist/src/deferred-foreground-recovery-service.js.map +1 -1
  38. package/dist/src/deferred-foreground-transfer-policy.d.ts +1 -1
  39. package/dist/src/deferred-foreground-transfer-policy.js +3 -2
  40. package/dist/src/deferred-foreground-transfer-policy.js.map +1 -1
  41. package/dist/src/deferred-foreground-transfer.d.ts +17 -1
  42. package/dist/src/deferred-foreground-transfer.js +244 -35
  43. package/dist/src/deferred-foreground-transfer.js.map +1 -1
  44. package/dist/src/deferred-foreground-user-close.d.ts +18 -0
  45. package/dist/src/deferred-foreground-user-close.js +180 -0
  46. package/dist/src/deferred-foreground-user-close.js.map +1 -0
  47. package/dist/src/install-doctor-command-adapter.js +1 -1
  48. package/dist/src/install-doctor-command-adapter.js.map +1 -1
  49. package/dist/src/openclaw-callback-transport.d.ts +4 -1
  50. package/dist/src/openclaw-callback-transport.js +403 -10
  51. package/dist/src/openclaw-callback-transport.js.map +1 -1
  52. package/dist/src/openclaw-doctor.js +16 -2
  53. package/dist/src/openclaw-doctor.js.map +1 -1
  54. package/dist/src/openclaw-managed-callback-cli-adapter.d.ts +23 -0
  55. package/dist/src/openclaw-managed-callback-cli-adapter.js +77 -0
  56. package/dist/src/openclaw-managed-callback-cli-adapter.js.map +1 -0
  57. package/dist/src/openclaw-plugin-command-adapter.js +93 -39
  58. package/dist/src/openclaw-plugin-command-adapter.js.map +1 -1
  59. package/dist/src/openclaw-plugin-helpers.d.ts +1 -0
  60. package/dist/src/openclaw-plugin-helpers.js +9 -1
  61. package/dist/src/openclaw-plugin-helpers.js.map +1 -1
  62. package/dist/src/openclaw-plugin-schemas.d.ts +20 -1
  63. package/dist/src/openclaw-plugin-schemas.js +27 -3
  64. package/dist/src/openclaw-plugin-schemas.js.map +1 -1
  65. package/dist/src/protocol.d.ts +3 -0
  66. package/dist/src/protocol.js +4 -0
  67. package/dist/src/protocol.js.map +1 -1
  68. package/dist/src/store.d.ts +12 -1
  69. package/dist/src/store.js +81 -3
  70. package/dist/src/store.js.map +1 -1
  71. package/dist/src/terminal-acceptance-cli-adapter.d.ts +2 -0
  72. package/dist/src/terminal-acceptance-cli-adapter.js +62 -12
  73. package/dist/src/terminal-acceptance-cli-adapter.js.map +1 -1
  74. package/dist/src/terminal-action-projection.d.ts +31 -3
  75. package/dist/src/terminal-action-projection.js +64 -9
  76. package/dist/src/terminal-action-projection.js.map +1 -1
  77. package/dist/src/terminal-agent-bridge.d.ts +82 -0
  78. package/dist/src/terminal-agent-bridge.js +553 -109
  79. package/dist/src/terminal-agent-bridge.js.map +1 -1
  80. package/dist/src/terminal-command-cli-adapter.d.ts +26 -2
  81. package/dist/src/terminal-command-cli-adapter.js +3162 -214
  82. package/dist/src/terminal-command-cli-adapter.js.map +1 -1
  83. package/dist/src/terminal-delegate-cli-adapter.d.ts +4 -22
  84. package/dist/src/terminal-delegate-cli-adapter.js +239 -192
  85. package/dist/src/terminal-delegate-cli-adapter.js.map +1 -1
  86. package/dist/src/terminal-delegate-send-binding.d.ts +63 -0
  87. package/dist/src/terminal-delegate-send-binding.js +360 -0
  88. package/dist/src/terminal-delegate-send-binding.js.map +1 -0
  89. package/dist/src/terminal-dispatch-application.d.ts +4 -1
  90. package/dist/src/terminal-dispatch-application.js +11 -2
  91. package/dist/src/terminal-dispatch-application.js.map +1 -1
  92. package/dist/src/terminal-dispatch-composition.d.ts +5 -0
  93. package/dist/src/terminal-dispatch-execution.js +3 -1
  94. package/dist/src/terminal-dispatch-execution.js.map +1 -1
  95. package/dist/src/terminal-dispatch-ledger-codec.d.ts +3 -0
  96. package/dist/src/terminal-dispatch-ledger-codec.js +46 -19
  97. package/dist/src/terminal-dispatch-ledger-codec.js.map +1 -1
  98. package/dist/src/terminal-dispatch-presenter.js +5 -3
  99. package/dist/src/terminal-dispatch-presenter.js.map +1 -1
  100. package/dist/src/terminal-dispatch-receipt.d.ts +3 -0
  101. package/dist/src/terminal-dispatch-receipt.js +15 -1
  102. package/dist/src/terminal-dispatch-receipt.js.map +1 -1
  103. package/dist/src/terminal-dispatch-recovery-cli-adapter.js +68 -7
  104. package/dist/src/terminal-dispatch-recovery-cli-adapter.js.map +1 -1
  105. package/dist/src/terminal-dispatch-recovery-service.d.ts +2 -0
  106. package/dist/src/terminal-dispatch-recovery-service.js +9 -0
  107. package/dist/src/terminal-dispatch-recovery-service.js.map +1 -1
  108. package/dist/src/terminal-dispatch-repository-cli-adapter.d.ts +4 -2
  109. package/dist/src/terminal-dispatch-repository-cli-adapter.js +10 -3
  110. package/dist/src/terminal-dispatch-repository-cli-adapter.js.map +1 -1
  111. package/dist/src/terminal-identity-authority-cli-adapter.d.ts +2 -0
  112. package/dist/src/terminal-identity-authority-cli-adapter.js +34 -27
  113. package/dist/src/terminal-identity-authority-cli-adapter.js.map +1 -1
  114. package/dist/src/terminal-list-cli-adapter.d.ts +6 -0
  115. package/dist/src/terminal-list-cli-adapter.js +391 -177
  116. package/dist/src/terminal-list-cli-adapter.js.map +1 -1
  117. package/dist/src/terminal-list-renderer.d.ts +9 -1
  118. package/dist/src/terminal-list-renderer.js +226 -104
  119. package/dist/src/terminal-list-renderer.js.map +1 -1
  120. package/dist/src/terminal-maintenance-cli-adapter.js +253 -326
  121. package/dist/src/terminal-maintenance-cli-adapter.js.map +1 -1
  122. package/dist/src/terminal-monitor-application-service.d.ts +5 -0
  123. package/dist/src/terminal-monitor-application-service.js +5 -0
  124. package/dist/src/terminal-monitor-application-service.js.map +1 -1
  125. package/dist/src/terminal-monitor-cli-adapter.d.ts +25 -1
  126. package/dist/src/terminal-monitor-cli-adapter.js +170 -27
  127. package/dist/src/terminal-monitor-cli-adapter.js.map +1 -1
  128. package/dist/src/terminal-monitor-reconciliation-eligibility.d.ts +1 -1
  129. package/dist/src/terminal-monitor-reconciliation-eligibility.js +220 -32
  130. package/dist/src/terminal-monitor-reconciliation-eligibility.js.map +1 -1
  131. package/dist/src/terminal-monitor-state-cli-adapter.d.ts +1 -1
  132. package/dist/src/terminal-monitor-state-cli-adapter.js +808 -147
  133. package/dist/src/terminal-monitor-state-cli-adapter.js.map +1 -1
  134. package/dist/src/terminal-monitor-state-reconciliation-service.d.ts +2 -1
  135. package/dist/src/terminal-monitor-state-reconciliation-service.js +12 -0
  136. package/dist/src/terminal-monitor-state-reconciliation-service.js.map +1 -1
  137. package/dist/src/terminal-monitor-supervision-cli-adapter.d.ts +2 -0
  138. package/dist/src/terminal-monitor-supervision-cli-adapter.js +31 -11
  139. package/dist/src/terminal-monitor-supervision-cli-adapter.js.map +1 -1
  140. package/dist/src/terminal-process-source.d.ts +13 -0
  141. package/dist/src/terminal-process-source.js +37 -0
  142. package/dist/src/terminal-process-source.js.map +1 -1
  143. package/dist/src/terminal-runtime-cli-adapter.js +14 -2
  144. package/dist/src/terminal-runtime-cli-adapter.js.map +1 -1
  145. package/dist/src/terminal-status-cli-adapter.d.ts +1 -0
  146. package/dist/src/terminal-status-cli-adapter.js +30 -28
  147. package/dist/src/terminal-status-cli-adapter.js.map +1 -1
  148. package/dist/src/terminal-submission-acceptance.js +78 -25
  149. package/dist/src/terminal-submission-acceptance.js.map +1 -1
  150. package/dist/src/terminal-submission-retry-service.d.ts +114 -0
  151. package/dist/src/terminal-submission-retry-service.js +589 -0
  152. package/dist/src/terminal-submission-retry-service.js.map +1 -0
  153. package/dist/src/terminal-user-send-intent.d.ts +65 -0
  154. package/dist/src/terminal-user-send-intent.js +317 -0
  155. package/dist/src/terminal-user-send-intent.js.map +1 -0
  156. package/dist/src/terminal-watch-callback-cli-adapter.d.ts +10 -2
  157. package/dist/src/terminal-watch-callback-cli-adapter.js +76 -37
  158. package/dist/src/terminal-watch-callback-cli-adapter.js.map +1 -1
  159. package/dist/src/terminal-watch-cli-adapter.js +41 -17
  160. package/dist/src/terminal-watch-cli-adapter.js.map +1 -1
  161. package/dist/src/terminal-watch-service.d.ts +11 -6
  162. package/dist/src/terminal-watch-service.js +210 -41
  163. package/dist/src/terminal-watch-service.js.map +1 -1
  164. package/dist/src/terminal-watch-store.d.ts +23 -0
  165. package/dist/src/terminal-watch-store.js +162 -4
  166. package/dist/src/terminal-watch-store.js.map +1 -1
  167. package/docs/quickstart-herdr.md +1 -1
  168. package/docs/quickstart-tmux.md +3 -3
  169. package/package.json +1 -1
  170. package/templates/openclaw-skills/agent-knock-knock/SKILL.md +14 -11
@@ -0,0 +1,23 @@
1
+ import { type OpenClawCallbackTransport } from "./openclaw-callback-transport.js";
2
+ import { type DeliverCallbackInput } from "./callback-outbox-policy.js";
3
+ import { type CallbackTransportDeliverInput } from "./callback-transport.js";
4
+ import type { Conversation } from "./protocol.js";
5
+ type ResolvedCallbackTransportDelivery = Omit<CallbackTransportDeliverInput, "reportCheckpoint">;
6
+ export interface OpenClawManagedCallbackCliAdapterPorts {
7
+ now(): Date;
8
+ environment(): NodeJS.ProcessEnv;
9
+ redactConversation(conversation: Conversation): unknown;
10
+ textSummary(value: unknown): unknown;
11
+ log(level: "info" | "warn" | "error", event: string, fields: Record<string, unknown>): void;
12
+ }
13
+ export interface OpenClawManagedCallbackCliAdapter {
14
+ transport: OpenClawCallbackTransport;
15
+ resolve(input: DeliverCallbackInput): ResolvedCallbackTransportDelivery;
16
+ }
17
+ /**
18
+ * Compose the legacy OpenClaw process adapter behind the host-neutral callback
19
+ * transport port. The CLI root supplies runtime capabilities but owns no
20
+ * delivery parsing, logging, or route-resolution policy.
21
+ */
22
+ export declare function createOpenClawManagedCallbackCliAdapter(ports: OpenClawManagedCallbackCliAdapterPorts): OpenClawManagedCallbackCliAdapter;
23
+ export {};
@@ -0,0 +1,77 @@
1
+ import { createOpenClawCallbackTransport } from "./openclaw-callback-transport.js";
2
+ import { classifyCallbackProcessFailure } from "./callback-outbox-policy.js";
3
+ import { parseCallbackRoute } from "./callback-transport.js";
4
+ import { redactString } from "./runtime-log.js";
5
+ import { appendEvent } from "./store.js";
6
+ import { nonBlankString } from "./value-guards.js";
7
+ /**
8
+ * Compose the legacy OpenClaw process adapter behind the host-neutral callback
9
+ * transport port. The CLI root supplies runtime capabilities but owns no
10
+ * delivery parsing, logging, or route-resolution policy.
11
+ */
12
+ export function createOpenClawManagedCallbackCliAdapter(ports) {
13
+ const transport = createOpenClawCallbackTransport({
14
+ now: ports.now,
15
+ environment: ports.environment,
16
+ redactConversation: ports.redactConversation,
17
+ recordCallbackProcessDelivery
18
+ });
19
+ return Object.freeze({ transport, resolve });
20
+ function recordCallbackProcessDelivery(observation) {
21
+ const { logPath, conversation, message, event, runtimeEvent, delivery } = observation;
22
+ const detail = observation.detail ?? {};
23
+ appendEvent(logPath, {
24
+ ts: ports.now().toISOString(),
25
+ conversation_id: conversation.conversation_id,
26
+ event,
27
+ from: message.from,
28
+ to: "openclaw",
29
+ round: message.round,
30
+ ...detail,
31
+ status: delivery.status,
32
+ stdout: redactString(delivery.stdout),
33
+ stderr: redactString(delivery.stderr)
34
+ });
35
+ ports.log("info", runtimeEvent, {
36
+ conversation_id: conversation.conversation_id,
37
+ ...detail,
38
+ status: delivery.status,
39
+ failure_kind: classifyCallbackProcessFailure(delivery),
40
+ stdout: ports.textSummary(delivery.stdout),
41
+ stderr: ports.textSummary(delivery.stderr)
42
+ });
43
+ }
44
+ function resolve(input) {
45
+ const route = parseCallbackRoute(input.route ?? input.options.callbackRoute);
46
+ if (!input.envelope) {
47
+ throw new Error("managed callback envelope is required for delivery");
48
+ }
49
+ const attemptNumber = Number(input.attempt?.number);
50
+ const attemptId = nonBlankString(input.attempt?.id);
51
+ if (!Number.isSafeInteger(attemptNumber) ||
52
+ attemptNumber < 1 ||
53
+ !attemptId) {
54
+ throw new Error("managed callback attempt identity is invalid");
55
+ }
56
+ return {
57
+ route,
58
+ envelope: input.envelope,
59
+ attempt: { number: attemptNumber, id: attemptId },
60
+ context: {
61
+ statePath: input.statePath,
62
+ logPath: input.logPath,
63
+ conversation: input.conversation,
64
+ message: input.message,
65
+ legacyOptions: {
66
+ gatewayMethod: input.options.gatewayMethod,
67
+ gatewaySession: input.options.gatewaySession,
68
+ openclawSession: input.options.openclawSession,
69
+ openclawBin: input.options.openclawBin,
70
+ gatewayUrl: input.options.gatewayUrl,
71
+ token: input.options.token
72
+ }
73
+ }
74
+ };
75
+ }
76
+ }
77
+ //# sourceMappingURL=openclaw-managed-callback-cli-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openclaw-managed-callback-cli-adapter.js","sourceRoot":"","sources":["../../src/openclaw-managed-callback-cli-adapter.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { spawn, spawnSync } from "node:child_process";
2
- import { createHash } from "node:crypto";
2
+ import { createHash, randomUUID } from "node:crypto";
3
3
  import { fileURLToPath } from "node:url";
4
4
  import { executorDefinitionForKind } from "./executors.js";
5
5
  import { isRecord, nonBlankString as stringValue } from "./value-guards.js";
@@ -25,13 +25,13 @@ export function registerOpenClawCommands(api, displayedResumeSnapshots) {
25
25
  default: "AKK is handling the request..."
26
26
  },
27
27
  agentPromptGuidance: [
28
- "Use /akk <task> when exactly one eligible idle coding-agent terminal pane should receive new work. Structured tools use only semantic identifiers returned by AKK: session_id for an exact managed context, terminal_id for the currently verified pane, turn_id for one managed Turn, watch_id for one Terminal Watch, and native_thread_id for one resumable native thread. AKK keeps all opaque freshness authority private and revalidates it under its locks. Use /akk watch only from a currently advertised watch action to observe one human-started active task; it sends no input and creates no Session or Turn. New/clear/resume, approval, reconciliation, handoff, and recovery still require the documented user intent or explicit confirmation. AKK never starts a coding-agent process."
28
+ "Use /akk <task> when exactly one send-ready coding-agent terminal pane should receive new work. Send-ready means an exact live process and terminal, a verified non-blocked approval state, and an exactly empty composer; parsed activity and broken AKK management state do not veto the user's Send. Structured tools use only semantic identifiers returned by AKK: session_id for an exact managed context, terminal_id for the currently verified pane, turn_id for one managed Turn, watch_id for one Terminal Watch, and native_thread_id for one resumable native thread. AKK keeps all opaque freshness authority private and revalidates it under its locks. Use /akk watch only from a currently advertised watch action to observe one human-started active task; it sends no input and creates no Session or Turn. New/clear/resume, approval, reconciliation, handoff, and recovery still require the documented user intent or explicit confirmation. AKK never starts a coding-agent process."
29
29
  ],
30
30
  handler: async (ctx) => handleAkkCommand(api, ctx, displayedResumeSnapshots)
31
31
  });
32
32
  registerCliTool(api, {
33
33
  name: "agent_knock_knock_list",
34
- description: "List existing Codex and Claude Code tmux or Herdr panes as the primary terminals[] resources, plus durable terminal_watches[] records. Use only advertised actions and their semantic IDs. AKK keeps opaque freshness authority private and revalidates terminal, binding, candidate, approval, and handoff state before every side effect. A session_exact send uses session_id; terminal_follow_current and Watch use terminal_id; managed controls use turn_id; lifecycle resume additionally uses the complete native_thread_id. Recovery actions remain explicit-confirmation operations. AKK never starts a coding-agent process.",
34
+ description: "List existing Codex and Claude Code tmux or Herdr panes as the primary terminals[] resources, plus durable terminal_watches[] records. Use only advertised actions and their semantic IDs. A terminal_user_explicit send is user-priority authority for one exact live physical prompt with no active approval and an empty composer; broken AKK Turn, Session, transfer, ledger, or Store state does not veto a new user Send. AKK tries the managed fast path first, then delivers once as unmanaged work with no callback before best-effort management release. Existing or possibly existing same-message idempotency evidence rejects replay. If fresh durability is unavailable, AKK proceeds with a warning and the result must not be automatically retried. Refresh list afterward and use Watch. A session_exact send uses session_id; terminal_follow_current and terminal_user_explicit Send use terminal_id; Watch uses terminal_id; managed controls use turn_id; lifecycle resume additionally uses the complete native_thread_id. AKK keeps opaque freshness authority private and never starts a coding-agent process.",
35
35
  parameters: listParameters,
36
36
  buildArgs: (params) => {
37
37
  const config = isRecord(api.pluginConfig) ? api.pluginConfig : {};
@@ -253,7 +253,7 @@ export function registerOpenClawCommands(api, displayedResumeSnapshots) {
253
253
  api.registerTool((toolContext) => ({
254
254
  label: "AKK Send",
255
255
  name: "agent_knock_knock_send",
256
- description: "Start a new AKK Turn. Use session_id only for an advertised session_exact action, or terminal_id for an advertised terminal_follow_current action; omit both only when AKK should require one unique eligible idle pane. AKK derives all terminal freshness authority privately, revalidates the exact pane/process/context under lock, sends once, and binds only the unique accepting native thread. Never pass a Turn id as a destination. This is asynchronous: after acceptance, yield and wait for the callback or an explicit status request.",
256
+ description: "Start a new AKK Turn, use one advertised terminal_user_explicit user-priority send, or explicitly recover one current uncertain submission only through its advertised retry_submission action. Ordinary send requires request and may use session_id or terminal_id exactly as advertised. terminal_user_explicit is gated only by one exact live physical prompt, no active approval prompt, and an empty composer. AKK tries its managed fast path first; if broken internal AKK state prevents it, AKK delivers once as unmanaged work with no callback Turn or callback before best-effort management release. Refresh list afterward and use Watch. Retry submission is the mutually exclusive exact {turn_id} form and cannot change request text or routing. AKK derives all freshness authority privately. A Turn id is never an ordinary-send destination. Managed acceptance is asynchronous: yield and wait for its callback or an explicit status request.",
257
257
  parameters: sendParameters,
258
258
  async execute(toolCallId, params) {
259
259
  try {
@@ -344,38 +344,17 @@ export function registerOpenClawCommands(api, displayedResumeSnapshots) {
344
344
  });
345
345
  registerCliTool(api, {
346
346
  name: "agent_knock_knock_close",
347
- description: "Close one managed Turn record without terminating the shared pane. Ordinary close uses turn_id. Orphan dispatch/lifecycle recovery may additionally use its exact expected_message_id or expected_transition_id. Human-context handoff uses the advertised turn_id plus reason=superseded_by_human_context_switch after explicit confirmation; AKK resolves the current handoff authority privately. Refresh list afterward.",
347
+ description: "Honor an explicit user request to close one managed turn_id and release AKK management. Raw orphan recovery may instead use conversation_id with expected_message_id or expected_transition_id. Close never sends terminal input, stops the coding agent, or closes the shared pane. Deferred transfer, Session, ledger, and callback cleanup is best-effort and cannot veto closing the Turn; warnings identify metadata AKK preserved. Refresh list afterward and use Watch if the coding agent is still working.",
348
348
  parameters: closeParameters,
349
349
  isErrorResult: isBlockedTerminalDispatchResult,
350
- buildArgs: (params, toolContext) => {
350
+ buildArgs: (params) => {
351
351
  const config = isRecord(api.pluginConfig) ? api.pluginConfig : {};
352
352
  const args = ["close"];
353
353
  assertExclusiveRecoveryFence(params);
354
- const handoffReason = stringValue(params.reason) ===
355
- "superseded_by_human_context_switch";
356
- const handoffAction = handoffReason
357
- ? consumeDisplayedPrivateAction(api, {
358
- sessionKey: requiredOpenClawSessionKey(toolContext?.sessionKey),
359
- sessionId: requiredOpenClawSessionId(toolContext?.sessionId),
360
- kind: OPENCLAW_HANDOFF_AUTHORITY_KIND,
361
- target: {
362
- type: "turn_id",
363
- id: requiredString(params.turn_id, "turn_id")
364
- },
365
- tool: "agent_knock_knock_close",
366
- matches: (argumentsValue) => stringValue(argumentsValue.turn_id) ===
367
- stringValue(params.turn_id) &&
368
- stringValue(argumentsValue.reason) ===
369
- "superseded_by_human_context_switch"
370
- })
371
- : undefined;
372
354
  pushTurnTarget(args, params);
373
355
  pushOptional(args, "--reason", stringValue(params.reason));
374
356
  pushOptional(args, "--expected-message-id", stringValue(params.expected_message_id));
375
357
  pushOptional(args, "--expected-transition-id", stringValue(params.expected_transition_id));
376
- pushOptional(args, "--expected-handoff-token", handoffAction
377
- ? requiredString(handoffAction.expected_handoff_token, "current internal handoff authority")
378
- : undefined);
379
358
  pushOptional(args, "--store-dir", resolvePluginStoreDir(config));
380
359
  return args;
381
360
  }
@@ -428,10 +407,17 @@ async function handleAkkCommand(api, ctx, displayedResumeSnapshots) {
428
407
  }
429
408
  if (parsed.action === "delegate") {
430
409
  const result = await runDelegate(api, {
431
- request: parsed.request
410
+ request: parsed.request,
411
+ messageId: `openclaw-command-${randomUUID()}`
432
412
  }, {
433
413
  sessionKey: ctx.sessionKey
434
414
  });
415
+ if (result.scope === "terminal_user_explicit") {
416
+ return {
417
+ text: formatSendCommandResult(result),
418
+ isError: sendCommandResultIsError(result)
419
+ };
420
+ }
435
421
  return {
436
422
  text: formatDelegateCommandResult(result),
437
423
  isError: result.status !== "async_pending"
@@ -449,7 +435,10 @@ async function handleAkkCommand(api, ctx, displayedResumeSnapshots) {
449
435
  sessionId: requiredOpenClawSessionId(ctx.sessionId)
450
436
  })
451
437
  : buildAkkCommandCliArgs(parsed, config, {
452
- sessionKey: ctx.sessionKey
438
+ sessionKey: ctx.sessionKey,
439
+ messageId: parsed.action === "send"
440
+ ? `openclaw-command-${randomUUID()}`
441
+ : undefined
453
442
  });
454
443
  if (!args) {
455
444
  return { text: akkUsageText(), isError: true };
@@ -476,9 +465,7 @@ async function handleAkkCommand(api, ctx, displayedResumeSnapshots) {
476
465
  case "send":
477
466
  return {
478
467
  text: formatSendCommandResult(result),
479
- isError: terminalSubmissionReported(result)
480
- ? !isAkkNativeSubmissionAccepted(result)
481
- : result.status === "delivered_unfenced"
468
+ isError: sendCommandResultIsError(result)
482
469
  };
483
470
  case "respond":
484
471
  return formatAkkRespondCommandResult(result);
@@ -505,6 +492,14 @@ async function handleAkkCommand(api, ctx, displayedResumeSnapshots) {
505
492
  };
506
493
  }
507
494
  }
495
+ function sendCommandResultIsError(result) {
496
+ return result.delivered === true &&
497
+ result.scope === "terminal_user_explicit"
498
+ ? false
499
+ : terminalSubmissionReported(result)
500
+ ? !isAkkNativeSubmissionAccepted(result)
501
+ : result.status === "delivered_unfenced";
502
+ }
508
503
  async function handleAkkLifecycleCommand(api, ctx, parsed, config, displayedResumeSnapshots) {
509
504
  const selectionScope = resumeSelectionScope(ctx.sessionKey, ctx.sessionId);
510
505
  const snapshotCacheKey = resumeSnapshotCacheKey(ctx.sessionKey, ctx.sessionId, parsed.terminalId);
@@ -808,6 +803,37 @@ function formatRetryCallbackCommandResult(result) {
808
803
  ].join("\n");
809
804
  }
810
805
  function formatSendCommandResult(result) {
806
+ if (result.scope === "terminal_user_explicit") {
807
+ const unmanaged = result.delivered_unmanaged === true;
808
+ const replayed = result.replayed === true;
809
+ if (result.delivered !== true) {
810
+ return [
811
+ "AKK already dispatched this managed terminal Send; native acceptance is still pending.",
812
+ `terminal: ${result.terminal_id ?? "unknown"}`,
813
+ `message: ${result.message_id ?? "unknown"}`,
814
+ "delivery: Enter dispatched; do not resend this message id.",
815
+ "next: inspect AKK status or the terminal; wait for the existing managed Turn."
816
+ ].join("\n");
817
+ }
818
+ return [
819
+ unmanaged
820
+ ? replayed
821
+ ? "AKK confirmed this direct terminal Send was already delivered."
822
+ : "AKK delivered the user's request directly to the coding agent."
823
+ : replayed
824
+ ? "AKK confirmed this managed terminal Send was already delivered."
825
+ : "AKK delivered the user's terminal Send through managed routing.",
826
+ `terminal: ${result.terminal_id ?? "unknown"}`,
827
+ `message: ${result.message_id ?? "unknown"}`,
828
+ `delivery: ${unmanaged ? "unmanaged fallback" : "managed"}`,
829
+ ...(unmanaged
830
+ ? ["callback: none; no AKK Turn was created for this delivery."]
831
+ : []),
832
+ unmanaged
833
+ ? "next: refresh AKK list and use Watch to observe the still-running coding-agent task."
834
+ : "next: refresh AKK list; do not resend this message id."
835
+ ].join("\n");
836
+ }
811
837
  const conversation = result.conversation ?? {};
812
838
  const conversationId = conversation.conversation_id ?? result.conversation_id ?? "unknown";
813
839
  const sessionId = conversation.session_id ?? result.session_id ?? conversationId;
@@ -948,7 +974,12 @@ function formatCloseCommandResult(result) {
948
974
  "AKK Turn record closed.",
949
975
  `session: ${sessionId}`,
950
976
  `turn: ${turnId}`,
951
- `status: ${conversation.status ?? "unknown"}`
977
+ `status: ${conversation.status ?? "unknown"}`,
978
+ "AKK management was released; the coding agent and terminal pane were not stopped.",
979
+ ...(Array.isArray(result.warnings) && result.warnings.length > 0
980
+ ? [`cleanup warnings: ${result.warnings.map((warning) => sanitizeAkkModelFacingDiagnosticText(String(warning))).join("; ")}`]
981
+ : []),
982
+ "Refresh the AKK list; if the coding agent is still working, Watch can attach to it again."
952
983
  ].join("\n");
953
984
  }
954
985
  function publicTurnIdentity(result) {
@@ -1016,6 +1047,22 @@ function terminalScreenExcerpt(result) {
1016
1047
  : `…${text.slice(-1599)}`;
1017
1048
  }
1018
1049
  async function runSendRequest(api, params, toolContext, messageId) {
1050
+ if (Object.hasOwn(params, "turn_id")) {
1051
+ const unexpected = Object.keys(params).filter((key) => key !== "turn_id");
1052
+ if (unexpected.length > 0) {
1053
+ throw new Error("send retry_submission accepts exactly turn_id; do not pass request, terminal_id, session_id, timeout overrides, or callback route data");
1054
+ }
1055
+ const turnId = authoritativeManagedId(params.turn_id, "turn_id");
1056
+ privateActionArguments(api, {
1057
+ tool: "agent_knock_knock_send",
1058
+ matches: (argumentsValue) => Object.keys(argumentsValue).length === 1 &&
1059
+ stringValue(argumentsValue.turn_id) === turnId
1060
+ });
1061
+ const config = isRecord(api.pluginConfig) ? api.pluginConfig : {};
1062
+ const args = ["send", "--turn", turnId];
1063
+ pushOptional(args, "--store-dir", resolvePluginStoreDir(config));
1064
+ return runCli(api, args);
1065
+ }
1019
1066
  const requestedType = Object.hasOwn(params, "type")
1020
1067
  ? stringValue(params.type)
1021
1068
  : "task";
@@ -1410,6 +1457,10 @@ function isSubmissionError(result) {
1410
1457
  if (!isRecord(result)) {
1411
1458
  return false;
1412
1459
  }
1460
+ if (result.delivered === true &&
1461
+ result.scope === "terminal_user_explicit") {
1462
+ return false;
1463
+ }
1413
1464
  if (terminalSubmissionReported(result)) {
1414
1465
  return !isAkkNativeSubmissionAccepted(result);
1415
1466
  }
@@ -1512,6 +1563,12 @@ async function runDelegate(api, params, toolContext) {
1512
1563
  if (!isRecord(parsed)) {
1513
1564
  throw new Error("agent-knock-knock delegate returned a non-object result");
1514
1565
  }
1566
+ if (parsed.scope === "terminal_user_explicit") {
1567
+ // A uniquely delegated user-priority Send may deliberately complete
1568
+ // without creating a managed Turn. Preserve that terminal receipt for the
1569
+ // shared Send formatter instead of inventing Session/Turn identity.
1570
+ return parsed;
1571
+ }
1515
1572
  const conversationId = stringValue(parsed.conversation_id) ??
1516
1573
  (isRecord(parsed.conversation)
1517
1574
  ? stringValue(parsed.conversation.conversation_id)
@@ -1819,12 +1876,9 @@ function assertExclusiveRecoveryFence(params) {
1819
1876
  if (closeFenceCount > 1) {
1820
1877
  throw new Error("close accepts only one of expected_message_id or expected_transition_id");
1821
1878
  }
1822
- const handoffReason = stringValue(params.reason) ===
1823
- "superseded_by_human_context_switch";
1824
- if (handoffReason && (!stringValue(params.turn_id) ||
1825
- stringValue(params.conversation_id) ||
1826
- closeFenceCount > 0)) {
1827
- throw new Error("human-context handoff requires only the exact managed turn_id and supersede reason");
1879
+ if (stringValue(params.reason) === "superseded_by_human_context_switch" &&
1880
+ (!stringValue(params.turn_id) || stringValue(params.conversation_id))) {
1881
+ throw new Error("human-context handoff Close requires the exact managed turn_id");
1828
1882
  }
1829
1883
  }
1830
1884
  export function pushOptional(args, flag, value) {