@scotthuang/agent-knock-knock 0.11.7 → 0.12.0

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 (38) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +21 -15
  3. package/dist/src/cli-core.d.ts +48 -0
  4. package/dist/src/cli-core.js +20089 -0
  5. package/dist/src/cli-core.js.map +1 -0
  6. package/dist/src/cli.js +12 -19896
  7. package/dist/src/cli.js.map +1 -1
  8. package/dist/src/doctor-capabilities.d.ts +10 -2
  9. package/dist/src/doctor-capabilities.js +48 -7
  10. package/dist/src/doctor-capabilities.js.map +1 -1
  11. package/dist/src/herdr-terminal-control-provider.d.ts +115 -0
  12. package/dist/src/herdr-terminal-control-provider.js +961 -0
  13. package/dist/src/herdr-terminal-control-provider.js.map +1 -0
  14. package/dist/src/managed-session.js +37 -11
  15. package/dist/src/managed-session.js.map +1 -1
  16. package/dist/src/native-thread-resume-snapshot.d.ts +9 -2
  17. package/dist/src/native-thread-resume-snapshot.js +46 -7
  18. package/dist/src/native-thread-resume-snapshot.js.map +1 -1
  19. package/dist/src/openclaw-plugin-helpers.js +4 -4
  20. package/dist/src/openclaw-plugin-helpers.js.map +1 -1
  21. package/dist/src/openclaw-plugin.js +28 -26
  22. package/dist/src/openclaw-plugin.js.map +1 -1
  23. package/dist/src/terminal-agent-adapter.d.ts +3 -2
  24. package/dist/src/terminal-agent-adapter.js +10 -6
  25. package/dist/src/terminal-agent-adapter.js.map +1 -1
  26. package/dist/src/terminal-agent-bridge.d.ts +4 -0
  27. package/dist/src/terminal-agent-bridge.js +23 -15
  28. package/dist/src/terminal-agent-bridge.js.map +1 -1
  29. package/dist/src/terminal-control-provider.d.ts +11 -0
  30. package/dist/src/terminal-control-provider.js +127 -3
  31. package/dist/src/terminal-control-provider.js.map +1 -1
  32. package/dist/src/terminal-control-ref.d.ts +28 -6
  33. package/dist/src/terminal-control-ref.js +151 -4
  34. package/dist/src/terminal-control-ref.js.map +1 -1
  35. package/docs/quickstart-herdr.md +37 -0
  36. package/openclaw.plugin.json +2 -2
  37. package/package.json +4 -2
  38. package/templates/openclaw-skills/agent-knock-knock/SKILL.md +17 -17
package/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.12.0 - 2026-08-10
4
+
5
+ ### Added
6
+
7
+ - Add exact local Herdr `0.8.0` / protocol 19 support as a second terminal provider alongside tmux, including discovery, screen capture, bracketed-paste-aware text delivery, key dispatch, lifecycle state, Resume snapshots, native inspection, monitoring, and OpenClaw actions.
8
+ - Add a routed terminal-provider registry, Herdr-aware doctor diagnostics, packaged setup documentation, and provider-neutral terminal identities throughout the Store and public terminal list.
9
+
10
+ ### Changed
11
+
12
+ - Split the CLI entrypoint from its injectable command core, move the slowest lifecycle and rollout semantics into deterministic in-process fixtures while retaining their real-process contract tests, and add a fail-closed affected-test runner for faster local iteration.
13
+ - Isolate terminal-provider discovery and diagnostics failures so an unavailable Herdr session contributes no candidates without hiding healthy tmux terminals.
14
+
15
+ ### Security
16
+
17
+ - Bind Herdr control to the local Unix-socket incarnation, stable `terminal_id`, refreshable pane route, shell and agent process ancestry, cwd, native coding-agent identity, and the existing Session/Turn binding fences before every side effect.
18
+ - Preserve the durable `prepared → text_injected → enter_dispatched → agent_accepted` boundary, keep lost acknowledgements uncertain without blind retries, fail closed when multiple providers could own one process, and isolate a failed provider discovery without hiding healthy transports.
19
+
3
20
  ## 0.11.7 - 2026-08-10
4
21
 
5
22
  ### Changed
package/README.md CHANGED
@@ -4,13 +4,13 @@
4
4
  [![Node.js](https://img.shields.io/badge/Node.js-%3E%3D22.19-339933)](https://nodejs.org/)
5
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/scotthuang/agent-knock-knock/blob/main/LICENSE)
6
6
 
7
- Agent Knock Knock lets OpenClaw control local Codex and Claude Code through shared tmux terminals, so you can take over and hand work back without losing context.
7
+ Agent Knock Knock lets OpenClaw control local Codex and Claude Code through shared tmux or Herdr terminals, so you can take over and hand work back without losing context.
8
8
 
9
9
  **No hooks. No agent-side plugins. Just share a terminal and stay in control. No YOLO. Automate the trusted. Review the rest.**
10
10
 
11
11
  ## Quick Start with ClawHub
12
12
 
13
- AKK reuses Codex or Claude Code already running in tmux; it never launches a coding agent. You need OpenClaw `2026.6.5`+, tmux, and an authenticated `codex` or `claude` CLI, all running as the same OS user.
13
+ AKK reuses Codex or Claude Code already running in tmux or a supported Herdr session; it never launches a coding agent. You need OpenClaw `2026.6.5`+, a supported terminal host, and an authenticated `codex` or `claude` CLI, all running as the same OS user.
14
14
 
15
15
  Install AKK and restart the Gateway:
16
16
 
@@ -28,6 +28,8 @@ tmux new-session -s akk-work -c "$(pwd -P)" codex
28
28
 
29
29
  Use `claude` instead of `codex` if preferred. Wait for the coding agent's idle prompt, then detach from tmux with `Ctrl-b`, followed by `d`.
30
30
 
31
+ Herdr `0.8.0` is also supported as an exact-version local terminal provider. See [Quick Start with Herdr](docs/quickstart-herdr.md).
32
+
31
33
  From any configured OpenClaw channel, first send:
32
34
 
33
35
  ```text
@@ -58,13 +60,13 @@ The second command proves that AKK can find the one eligible idle pane, revalida
58
60
 
59
61
  ## How It Works
60
62
 
61
- AKK connects OpenClaw to Codex or Claude Code already running inside tmux:
63
+ AKK connects OpenClaw to Codex or Claude Code already running inside a supported shared terminal:
62
64
 
63
65
  1. OpenClaw selects an AKK session and sends the next user-facing request.
64
66
  2. AKK verifies the bound agent pane, creates a new Turn, and writes only that request into the terminal.
65
67
  3. AKK monitors the same pane for reliable approval, completion, cancellation, and failure evidence correlated to that Turn.
66
68
  4. AKK reports the result, `session_id`, and `turn_id` to the originating OpenClaw conversation.
67
- 5. A human can attach to the same tmux terminal at any time and continue directly.
69
+ 5. A human can attach to the same tmux or Herdr terminal at any time and continue directly.
68
70
 
69
71
  AKK is local-first. It has no hosted control plane or telemetry and does not change the coding agent's configured permission mode.
70
72
 
@@ -73,7 +75,7 @@ AKK is local-first. It has no hosted control plane or telemetry and does not cha
73
75
  AKK keeps four identities separate:
74
76
 
75
77
  ```text
76
- tmux terminal / process incarnation
78
+ terminal resource / process incarnation
77
79
  └─ native Codex or Claude Code session
78
80
  └─ AKK session (session_id)
79
81
  ├─ Turn 1 (turn_id)
@@ -114,9 +116,9 @@ Requirements:
114
116
 
115
117
  - A Node.js version supported by your OpenClaw release (Node.js 24 LTS is recommended)
116
118
  - [OpenClaw](https://docs.openclaw.ai/) `2026.6.5` or newer
117
- - `tmux`
119
+ - At least one supported terminal host: tmux, or local Herdr `0.8.0` (protocol 19)
118
120
  - At least one authenticated coding-agent CLI: Codex or Claude Code
119
- - OpenClaw, AKK, tmux, and the coding agent running as the same OS user
121
+ - OpenClaw, AKK, the selected terminal host, and the coding agent running as the same OS user
120
122
 
121
123
  | Compatibility layer | Version | Evidence |
122
124
  | --- | --- | --- |
@@ -153,6 +155,8 @@ agent-knock-knock install-openclaw --openclaw-bin /path/to/openclaw/openclaw.mjs
153
155
 
154
156
  ## Shared Terminal Details
155
157
 
158
+ AKK discovers both tmux and local Herdr sessions. If a process appears under more than one provider, AKK fails closed instead of guessing which terminal owns it. Remote Herdr sessions and Windows named-pipe transport are not supported yet.
159
+
156
160
  Install tmux on macOS:
157
161
 
158
162
  ```bash
@@ -175,6 +179,8 @@ Use `claude` instead of `codex` for Claude Code. Detach with `Ctrl-b`, then `d`.
175
179
 
176
180
  Claude tmux support requires no hooks and does not modify Claude Code settings. Hook-free completion monitoring is verified on Claude Code `2.1.198`, `2.1.218`, and `2.1.226`; newer versions remain eligible when their interactive transcripts preserve the required identity and completion structure. Hookless auto-approval is deliberately narrower: approval evidence currently requires Claude Code `2.1.x` at `2.1.198` or later, and other versions fall back to manual handling.
177
181
 
182
+ For Herdr, AKK talks directly to each local session's Unix socket. It binds the stable Herdr `terminal_id`, refreshes the current `pane_id` before every operation, verifies the shell/agent process ancestry and cwd, reads the detector screen, and uses the bracketed-paste-aware `pane.send_input` API. Text injection and Enter remain separate operations so AKK can persist and revalidate the dispatch boundary between them.
183
+
178
184
  Run the diagnostic:
179
185
 
180
186
  ```bash
@@ -191,7 +197,7 @@ For one complete first run, follow [Agent Knock Knock in 5 minutes](https://gith
191
197
 
192
198
  ## Usage
193
199
 
194
- AKK discovers verified Codex and Claude Code panes across workspaces. It sends work only to a pane that is already running in tmux and at a verified idle prompt; it never starts a coding agent for you.
200
+ AKK discovers verified Codex and Claude Code panes across workspaces. It sends work only to a pane that is already running in tmux or supported Herdr and at a verified idle prompt; it never starts a coding agent for you.
195
201
 
196
202
  If exactly one eligible idle coding-agent pane exists across all workspaces, send a task directly:
197
203
 
@@ -224,9 +230,9 @@ The core command surface is intentionally small:
224
230
 
225
231
  `/akk list` performs a controlled reconciliation across managed turns, and `/akk status` limits reconciliation to the selected turn. This can close records whose idle retention has elapsed and restore eligible missing monitors, but it does not send terminal input or retry callback delivery. Independently, the running OpenClaw plugin supervises eligible `waiting_for_agent` monitors every five seconds; this liveness pass only restores missing monitors and likewise never retries callback transport. Standalone shell queries are read-only unless `--reconcile` is explicitly passed, and resolving a selector never changes turn state.
226
232
 
227
- Selectors fail closed: `only` works only with one actionable target, `latest` requires a unique newest target, and `codex` or `claude` must identify exactly one eligible pane. These names and `@short-ref` are human-facing resolution inputs; a natural-language tool call may preserve one explicitly named by the user, but must not infer one. Managed JSON actions contain the authoritative full `session_id` or `turn_id`. For first attach, an unmanaged raw-terminal row's send action may instead contain its own prefilled `selector`; its advertised raw controls may contain that row's prefilled `conversation_id`. Neither compatibility selector may be guessed, copied from another row, or passed in an authoritative ID field. Before every terminal operation, AKK revalidates the expected agent PID and tmux pane identity, then confirms that the process and pane working directories still match; every send also revalidates the idle prompt immediately before typing.
233
+ Selectors fail closed: `only` works only with one actionable target, `latest` requires a unique newest target, and `codex` or `claude` must identify exactly one eligible pane. These names and `@short-ref` are human-facing resolution inputs; a natural-language tool call may preserve one explicitly named by the user, but must not infer one. Managed JSON actions contain the authoritative full `session_id` or `turn_id`. For first attach, an unmanaged raw-terminal row's send action may instead contain its own prefilled `selector`; its advertised raw controls may contain that row's prefilled `conversation_id`. Neither compatibility selector may be guessed, copied from another row, or passed in an authoritative ID field. Before every terminal operation, AKK revalidates the expected agent PID and provider-owned terminal identity, then confirms that the process and pane working directories still match; every send also revalidates the idle prompt immediately before typing.
228
234
 
229
- To change native context, first copy the full `terminal_id` from `/akk list`; lifecycle commands do not accept an ordinary-send `@short-ref` or loose agent selector. `/akk threads <exact-terminal-id>` lists exact, same-workspace candidates with a deterministic number, a collision-safe display-only `@short-id`, an opaque snapshot handle, and the complete UUID. `/akk resume-thread <exact-terminal-id>` without a selection shows that list. A complete UUID remains compatible. A number or short ID resolves only against the latest list displayed in the same OpenClaw session, while an opaque handle names its exact snapshot; all expire after five minutes and fail after terminal, process, workspace, binding, candidate-set, or relevant action changes. None is ever passed to Codex or Claude Code as native identity: AKK resolves the saved tuple back to its full UUID and fresh evidence tokens first. `previous` (or `刚才那个`) is advertised only when the current Session's latest committed lifecycle transition identifies exactly one currently verified resumable source; it never guesses from title, recency, or static lineage. `/akk new-thread` and its human alias `/akk clear-thread` start a clean context. AKK does not poll bindings in the background: if a recorded owner process exits, the next lifecycle listing can classify that sole historical binding as resumable, and the resume mutation compare-and-swap detaches it before touching the terminal. Live, stale, expired, unsupported, busy, ambiguous, active-elsewhere, or unverifiable transitions fail closed. Do not send `/clear`, `/new`, `/resume`, `/status`, Codex `/fork`, `/side`, or `/btw`, Claude `/branch`, or any other first-line native slash command as an ordinary task or answer; use an advertised AKK action, express the request in natural language, or enter an unsupported native command manually in tmux.
235
+ To change native context, first copy the full `terminal_id` from `/akk list`; lifecycle commands do not accept an ordinary-send `@short-ref` or loose agent selector. `/akk threads <exact-terminal-id>` lists exact, same-workspace candidates with a deterministic number, a collision-safe display-only `@short-id`, an opaque snapshot handle, and the complete UUID. `/akk resume-thread <exact-terminal-id>` without a selection shows that list. A complete UUID remains compatible. A number or short ID resolves only against the latest list displayed in the same OpenClaw session, while an opaque handle names its exact snapshot; all expire after five minutes and fail after terminal, process, workspace, binding, candidate-set, or relevant action changes. None is ever passed to Codex or Claude Code as native identity: AKK resolves the saved tuple back to its full UUID and fresh evidence tokens first. `previous` (or `刚才那个`) is advertised only when the current Session's latest committed lifecycle transition identifies exactly one currently verified resumable source; it never guesses from title, recency, or static lineage. `/akk new-thread` and its human alias `/akk clear-thread` start a clean context. AKK does not poll bindings in the background: if a recorded owner process exits, the next lifecycle listing can classify that sole historical binding as resumable, and the resume mutation compare-and-swap detaches it before touching the terminal. Live, stale, expired, unsupported, busy, ambiguous, active-elsewhere, or unverifiable transitions fail closed. Do not send `/clear`, `/new`, `/resume`, `/status`, Codex `/fork`, `/side`, or `/btw`, Claude `/branch`, or any other first-line native slash command as an ordinary task or answer; use an advertised AKK action, express the request in natural language, or enter an unsupported native command manually in the terminal UI.
230
236
 
231
237
  To request a native Codex status card or Claude Status panel, first run `agent_knock_knock_list` and use only that terminal row's advertised `native_inspect` action. The structured tool schema is closed to `inspection="status"`; callers cannot provide `/status` or another slash command as text. AKK serializes the inspection with terminal mutations, revalidates the fresh token and exact terminal identity, and returns only after it proves one fresh bounded status result and an idle postcondition. For Claude, that includes safely dismissing the exact modal once. It never turns ordinary `send` or `respond` into a slash-command escape hatch.
232
238
 
@@ -250,7 +256,7 @@ AKK works without project-specific plugin configuration. It reads these optional
250
256
  | --- | --- | --- |
251
257
  | `storeDir` | `~/.agent-knock-knock/store` | Stable Store root for the compatibility manifest, authoritative managed Sessions, and Turn records. |
252
258
  | `openclawBin` | Auto-detected | OpenClaw CLI used for callback delivery. |
253
- | `codexHome` | Auto-detected | Optional Codex home used to identify Codex sessions running in tmux. |
259
+ | `codexHome` | Auto-detected | Optional Codex home used to identify Codex sessions running in a supported terminal. |
254
260
  | `idleTimeoutMinutes` | `10080` | Idle retention checked during controlled reconciliation. |
255
261
  | `agentTimeoutMinutes` | `60` | Terminal inactivity timeout. |
256
262
  | `agentHardTimeoutMinutes` | `720` | Maximum terminal monitor lifetime. |
@@ -267,7 +273,7 @@ For Claude Code, manual approval is deliberately narrow:
267
273
 
268
274
  - It is available only for the current AKK-managed turn.
269
275
  - AKK accepts only an exact, current Bash dialog with the one-time **Yes** choice already highlighted, correlated to one unresolved foreground Bash tool request in the anchored owner-private transcript. Persistent permission choices are rejected.
270
- - When no trusted rule matches, the callback takes the manual path. The user must personally inspect the named tmux pane, explicitly confirm the exact request, and then run `/akk approve @a1b2c3d4 --expected-approval-fingerprint <fresh-fingerprint>` using the fingerprint from that current notification; the hash-only callback is not sufficient for review.
276
+ - When no trusted rule matches, the callback takes the manual path. The user must personally inspect the named terminal pane, explicitly confirm the exact request, and then run `/akk approve @a1b2c3d4 --expected-approval-fingerprint <fresh-fingerprint>` using the fingerprint from that current notification; the hash-only callback is not sufficient for review.
271
277
  - AKK re-evaluates the evidence and revalidates the process and pane immediately before sending one Enter.
272
278
 
273
279
  Unknown, stale, changed, ambiguous, or unmanaged dialogs fail closed and must be resolved in the terminal.
@@ -295,7 +301,7 @@ Place `autoApprove` inside the plugin `config` object. It is disabled by default
295
301
 
296
302
  AKK has no hosted control plane or telemetry and does not modify coding-agent settings. Its terminal state and logs stay on your machine; Claude approval callbacks omit raw commands, while Codex may include the visible command details OpenClaw needs to present for review.
297
303
 
298
- At startup, AKK registers its tools and reconciles monitors for existing managed turns. While the OpenClaw Gateway remains healthy, its single-flight supervisor schedules the next reconciliation five seconds after the previous sweep finishes, so an unexpectedly exited monitor is recreated without a `list` or `status` call. With the Store writable, reconciliation returning normally, and the same Turn binding still current, AKK prepares one immutable `done` message/outbox entry within 30 seconds after reliable native completion evidence becomes stable. External callback transport and wake acknowledgement are outside this bound. It never launches a coding agent; new work reuses exactly one eligible agent pane that you already started in tmux.
304
+ At startup, AKK registers its tools and reconciles monitors for existing managed turns. While the OpenClaw Gateway remains healthy, its single-flight supervisor schedules the next reconciliation five seconds after the previous sweep finishes, so an unexpectedly exited monitor is recreated without a `list` or `status` call. With the Store writable, reconciliation returning normally, and the same Turn binding still current, AKK prepares one immutable `done` message/outbox entry within 30 seconds after reliable native completion evidence becomes stable. External callback transport and wake acknowledgement are outside this bound. It never launches a coding agent; new work reuses exactly one eligible agent pane that you already started in a supported terminal host.
299
305
 
300
306
  Your task content is still processed by OpenClaw and the coding-agent or model providers you configure. Review agent permissions and keep secrets out of task prompts.
301
307
 
@@ -305,12 +311,12 @@ With the global npm CLI installed, start with `agent-knock-knock doctor`. It run
305
311
 
306
312
  | Symptom | Action |
307
313
  | --- | --- |
308
- | No eligible terminal is available | Start Codex or Claude Code inside tmux as the same OS user, then run `AKK list`. |
314
+ | No eligible terminal is available | Start Codex or Claude Code inside tmux or supported Herdr as the same OS user, then run `AKK list`. |
309
315
  | The npm installer or callbacks cannot find a local OpenClaw CLI | Set `openclawBin` and pass `--openclaw-bin` to `install-openclaw`. |
310
316
  | Source changes do not appear | Build, reinstall from the checkout, and restart the Gateway. |
311
317
  | Terminal Turn is `stalled` | Inspect `status` and the terminal; use `/akk renew only <minutes>` only when exactly one live stalled Turn needs more monitoring time. |
312
318
  | Turn is `callback_failed` | Run `/akk retry-callback only` when it is the only actionable failed callback, or use its `@short-ref`. |
313
- | `AKK list` reports an orphaned terminal dispatch or lifecycle transition | Inspect the named pane first, then run the exact `/akk close ...` recovery command returned by `list`. It contains exactly one fresh `--expected-message-id ...` or `--expected-transition-id ...` fence; do not construct, substitute, or reuse it. AKK leaves the coding agent and tmux pane running. |
319
+ | `AKK list` reports an orphaned terminal dispatch or lifecycle transition | Inspect the named pane first, then run the exact `/akk close ...` recovery command returned by `list`. It contains exactly one fresh `--expected-message-id ...` or `--expected-transition-id ...` fence; do not construct, substitute, or reuse it. AKK leaves the coding agent and terminal pane running. |
314
320
  | Claude permission is not offered through AKK | Resolve unsupported dialogs in the terminal. The AKK path requires the exact supported one-time Bash prompt for the current managed turn. |
315
321
  | Claude request was not auto-approved | Check `autoApprove.enabled`, the agent, the rule's canonical `workspaces`, and the exact command vector. The request must also have matching current screen and local transcript evidence. |
316
322
  | Claude monitor becomes `stalled` | Check the Claude version and `status`, then inspect the terminal. Unknown transcript schemas, background work, identity changes, and ambiguous turns intentionally fail closed. |
@@ -0,0 +1,48 @@
1
+ import { type ClaudeAgentRow } from "./claude-terminal-agent-adapter.js";
2
+ import { type CodexLocalSessionAdapter } from "./codex-local-session-provider.js";
3
+ import type { CodingAgentSessionProvider } from "./agent-session-provider.js";
4
+ import { type ExecutorKind } from "./executors.js";
5
+ import { type TerminalControlProviderRegistry } from "./terminal-control-provider.js";
6
+ import { type TerminalThreadLifecycleCandidateProvider } from "./terminal-agent-adapter.js";
7
+ import { type TerminalProcessSource } from "./terminal-process-source.js";
8
+ export type CliCommandOptions = Record<string, any>;
9
+ /**
10
+ * Process-level dependencies used by an imported CLI command execution.
11
+ *
12
+ * Every dependency is scoped to one async execution. This deliberately avoids
13
+ * mutating process globals, so independent in-process tests can run in
14
+ * parallel without sharing providers, output, environment, or clocks.
15
+ */
16
+ export interface CliCommandDependencies {
17
+ terminalControlProviderRegistry?: TerminalControlProviderRegistry;
18
+ terminalProcessSource?: TerminalProcessSource;
19
+ createAgentSessionProvider?: (agent: "codex", options: Readonly<CliCommandOptions>) => CodingAgentSessionProvider;
20
+ codexLocalSessionAdapter?: CodexLocalSessionAdapter | ((options: Readonly<CliCommandOptions>) => CodexLocalSessionAdapter);
21
+ codexThreadLifecycleProvider?: TerminalThreadLifecycleCandidateProvider;
22
+ loadClaudeAgentRows?: (options: Readonly<CliCommandOptions>, observation: {
23
+ required?: boolean;
24
+ }) => ClaudeAgentRow[];
25
+ agentVersionForRunningProcess?: (agent: ExecutorKind, pid: number, options: Readonly<CliCommandOptions>) => string | undefined;
26
+ codexProcessBirthForPid?: (pid: number) => string;
27
+ stdout?: (text: string) => void;
28
+ cwd?: string | (() => string);
29
+ env?: NodeJS.ProcessEnv;
30
+ pid?: number;
31
+ now?: () => Date | number;
32
+ /** Monotonic clock for terminal composer settling; production uses performance.now. */
33
+ monotonicNowMs?: () => number;
34
+ sleep?: (milliseconds: number) => Promise<void>;
35
+ sleepSync?: (milliseconds: number) => void;
36
+ exit?: (code: number) => never;
37
+ runtimeLog?: (level: "info" | "warn" | "error", event: string, fields: Record<string, unknown>) => void;
38
+ }
39
+ export interface ParsedCliCommand {
40
+ command?: string;
41
+ options: CliCommandOptions;
42
+ }
43
+ export interface CliCommandExecutionResult {
44
+ exitCode: number;
45
+ stdout: string;
46
+ }
47
+ export declare function parseCliCommand(argv: readonly string[]): ParsedCliCommand;
48
+ export declare function executeCliCommand(commandName: string | undefined, options?: CliCommandOptions, dependencies?: CliCommandDependencies): Promise<CliCommandExecutionResult>;