@prohost/cli 0.13.3 → 0.15.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.
- package/CHANGELOG.md +90 -0
- package/README.md +129 -0
- package/dist/agent/command.d.ts +8 -0
- package/dist/agent/command.js +40 -7
- package/dist/agent/daemon.d.ts +3 -1
- package/dist/agent/daemon.js +1 -2
- package/dist/agent/run.d.ts +30 -1
- package/dist/agent/run.js +230 -9
- package/dist/agent/runtime_status.d.ts +99 -3
- package/dist/agent/runtime_status.js +173 -5
- package/dist/agent/worktrees.d.ts +2 -0
- package/dist/agent/worktrees.js +3 -2
- package/dist/codehost/activity.d.ts +64 -0
- package/dist/codehost/activity.js +135 -0
- package/dist/codehost/agents.d.ts +31 -0
- package/dist/codehost/agents.js +57 -0
- package/dist/codehost/checkouts.d.ts +130 -0
- package/dist/codehost/checkouts.js +270 -0
- package/dist/codehost/claude_trust.d.ts +40 -0
- package/dist/codehost/claude_trust.js +129 -0
- package/dist/codehost/command.d.ts +25 -0
- package/dist/codehost/command.js +136 -0
- package/dist/codehost/decision.d.ts +156 -0
- package/dist/codehost/decision.js +553 -0
- package/dist/codehost/events.d.ts +49 -0
- package/dist/codehost/events.js +87 -0
- package/dist/codehost/folders.d.ts +122 -0
- package/dist/codehost/folders.js +317 -0
- package/dist/codehost/history.d.ts +80 -0
- package/dist/codehost/history.js +98 -0
- package/dist/codehost/hooks.d.ts +186 -0
- package/dist/codehost/hooks.js +737 -0
- package/dist/codehost/host.d.ts +297 -0
- package/dist/codehost/host.js +635 -0
- package/dist/codehost/host_stats.d.ts +71 -0
- package/dist/codehost/host_stats.js +166 -0
- package/dist/codehost/invocations.d.ts +12 -0
- package/dist/codehost/invocations.js +82 -0
- package/dist/codehost/ledger.d.ts +35 -0
- package/dist/codehost/ledger.js +91 -0
- package/dist/codehost/local_server.d.ts +106 -0
- package/dist/codehost/local_server.js +339 -0
- package/dist/codehost/pty.d.ts +38 -0
- package/dist/codehost/pty.js +47 -0
- package/dist/codehost/ready.d.ts +31 -0
- package/dist/codehost/ready.js +109 -0
- package/dist/codehost/relay.d.ts +175 -0
- package/dist/codehost/relay.js +598 -0
- package/dist/codehost/settings.d.ts +52 -0
- package/dist/codehost/settings.js +114 -0
- package/dist/codehost/sizing.d.ts +181 -0
- package/dist/codehost/sizing.js +434 -0
- package/dist/codehost/terminals.d.ts +421 -0
- package/dist/codehost/terminals.js +1027 -0
- package/dist/codehost/tmux.d.ts +201 -0
- package/dist/codehost/tmux.js +394 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +21 -0
- package/dist/version.d.ts +2 -2
- package/dist/version.js +1 -1
- package/package.json +4 -1
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A viewer's local scroll-back (CONTRACTS-R2 R1): the pane's history as text, so the viewer
|
|
3
|
+
* scrolls it on its own screen instead of driving tmux copy mode over the network (one wheel
|
|
4
|
+
* step per round trip, and copy mode is the PANE's: one viewer's scroll froze everyone's view).
|
|
5
|
+
*
|
|
6
|
+
* - client → server: `{"type":"history","id":<string>,"lines":<int, capped 10000>}`;
|
|
7
|
+
* - server → that client only: `{"type":"history","id","text","cols","rows"}`, the history and
|
|
8
|
+
* visible screen as `tmux capture-pane -p -e -J -S -<lines>` prints them (SGR colours kept,
|
|
9
|
+
* wrapped lines joined), or `{"type":"history","id","error":"<code>"}`.
|
|
10
|
+
*
|
|
11
|
+
* Answered only to a viewer that said `hello` (an older page never sees one), and bounded: a
|
|
12
|
+
* frame never exceeds {@link HISTORY_MAX_FRAME_BYTES}; the oldest lines go first.
|
|
13
|
+
*/
|
|
14
|
+
import { windowTarget } from './tmux.js';
|
|
15
|
+
/** Most lines a viewer may ask for. */
|
|
16
|
+
export const HISTORY_MAX_LINES = 10_000;
|
|
17
|
+
/** Lines asked for when a request names none (or an unusable number). */
|
|
18
|
+
export const HISTORY_DEFAULT_LINES = 2_000;
|
|
19
|
+
/**
|
|
20
|
+
* Largest answer, as sent (JSON): the relay carries it over Redis and the cloud pipe's upstream
|
|
21
|
+
* socket takes at most 1 MiB, so this stays well under both.
|
|
22
|
+
*/
|
|
23
|
+
export const HISTORY_MAX_FRAME_BYTES = 768 * 1024;
|
|
24
|
+
/** A request id: what the viewer matches its answer by. */
|
|
25
|
+
export const HISTORY_ID_PATTERN = /^[A-Za-z0-9_-]{1,64}$/;
|
|
26
|
+
/** `lines` as asked, within 1..{@link HISTORY_MAX_LINES}. */
|
|
27
|
+
export function clampHistoryLines(raw) {
|
|
28
|
+
const n = typeof raw === 'number' && Number.isFinite(raw) ? Math.trunc(raw) : Number.NaN;
|
|
29
|
+
if (!Number.isFinite(n) || n < 1)
|
|
30
|
+
return HISTORY_DEFAULT_LINES;
|
|
31
|
+
return Math.min(n, HISTORY_MAX_LINES);
|
|
32
|
+
}
|
|
33
|
+
/** A `history` request frame's fields, or `null` when it can't be answered (no usable id). */
|
|
34
|
+
export function parseHistoryRequest(frame) {
|
|
35
|
+
if (frame.type !== 'history' || typeof frame.id !== 'string' || !HISTORY_ID_PATTERN.test(frame.id))
|
|
36
|
+
return null;
|
|
37
|
+
return { type: 'history', id: frame.id, lines: clampHistoryLines(frame.lines) };
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* `-p` print, `-e` keep the SGR escapes (colours, bold), `-J` join wrapped lines (the viewer
|
|
41
|
+
* wraps them at its own width), `-S -<lines>` from that far back in the history to the screen's end.
|
|
42
|
+
*/
|
|
43
|
+
export function captureHistoryArgs(name, lines) {
|
|
44
|
+
return ['capture-pane', '-p', '-e', '-J', '-S', `-${clampHistoryLines(lines)}`, '-t', windowTarget(name)];
|
|
45
|
+
}
|
|
46
|
+
/** The pane's size, and whether a program (vim, less) holds its alternate screen: `<cols> <rows> <0|1>`. */
|
|
47
|
+
export function paneGeometryArgs(name) {
|
|
48
|
+
return ['display-message', '-p', '-t', windowTarget(name), '#{pane_width} #{pane_height} #{alternate_on}'];
|
|
49
|
+
}
|
|
50
|
+
export function parsePaneGeometry(stdout) {
|
|
51
|
+
const match = /^(\d+) (\d+) ([01])$/.exec(stdout.trim());
|
|
52
|
+
if (!match)
|
|
53
|
+
return null;
|
|
54
|
+
const cols = Number(match[1]);
|
|
55
|
+
const rows = Number(match[2]);
|
|
56
|
+
if (cols < 1 || rows < 1)
|
|
57
|
+
return null;
|
|
58
|
+
return { cols, rows, alternate: match[3] === '1' };
|
|
59
|
+
}
|
|
60
|
+
const frameBytes = (frame) => Buffer.byteLength(JSON.stringify(frame), 'utf8');
|
|
61
|
+
/**
|
|
62
|
+
* The answer to request `id`, at most `maxBytes` as JSON: whole lines are dropped from the top
|
|
63
|
+
* (the oldest) until it fits. tmux ends its capture with a newline, which is not a line.
|
|
64
|
+
*/
|
|
65
|
+
export function historyFrame(id, result, maxBytes = HISTORY_MAX_FRAME_BYTES) {
|
|
66
|
+
if (!result.ok)
|
|
67
|
+
return { type: 'history', id, error: result.error };
|
|
68
|
+
let lines = result.text.replace(/\r/g, '').replace(/\n$/, '').split('\n');
|
|
69
|
+
const build = () => ({ type: 'history', id, text: lines.join('\n'), cols: result.cols, rows: result.rows });
|
|
70
|
+
let frame = build();
|
|
71
|
+
let size = frameBytes(frame);
|
|
72
|
+
while (size > maxBytes && lines.length > 1) {
|
|
73
|
+
// Proportionally, with a margin, so a big history takes a few passes rather than thousands.
|
|
74
|
+
const keep = Math.max(1, Math.min(lines.length - 1, Math.floor((lines.length * maxBytes) / size) - 1));
|
|
75
|
+
lines = lines.slice(lines.length - keep);
|
|
76
|
+
frame = build();
|
|
77
|
+
size = frameBytes(frame);
|
|
78
|
+
}
|
|
79
|
+
if (size > maxBytes)
|
|
80
|
+
return { type: 'history', id, error: 'capture_failed' };
|
|
81
|
+
return frame;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Read `lines` of window `name`'s history. A pane in the alternate screen (a full-screen program)
|
|
85
|
+
* has no scroll-back to show: the viewer falls back to sending it the wheel.
|
|
86
|
+
*/
|
|
87
|
+
export async function readHistory(tmux, name, lines) {
|
|
88
|
+
const geometryRead = await tmux(paneGeometryArgs(name));
|
|
89
|
+
const geometry = geometryRead.ok ? parsePaneGeometry(geometryRead.stdout ?? '') : null;
|
|
90
|
+
if (!geometry)
|
|
91
|
+
return { ok: false, error: 'capture_failed' };
|
|
92
|
+
if (geometry.alternate)
|
|
93
|
+
return { ok: false, error: 'alternate_screen' };
|
|
94
|
+
const capture = await tmux(captureHistoryArgs(name, lines));
|
|
95
|
+
if (!capture.ok)
|
|
96
|
+
return { ok: false, error: 'capture_failed' };
|
|
97
|
+
return { ok: true, text: capture.stdout ?? '', cols: geometry.cols, rows: geometry.rows };
|
|
98
|
+
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code hooks and Codex `notify` for Mac-hosted Code threads.
|
|
3
|
+
*
|
|
4
|
+
* **Nothing global is installed.** The operator's `~/.claude/settings.json`
|
|
5
|
+
* and `~/.codex/config.toml` are never edited. Each thread's agent is launched
|
|
6
|
+
* with the hooks on its own command line — `claude --settings <file>`, `codex -c
|
|
7
|
+
* notify=[...]` — so they exist only in the sessions this host starts, and the
|
|
8
|
+
* one command they run is a shim that exits at once unless
|
|
9
|
+
* `$PROHOST_TERMINAL_ID` is set. A `claude` the operator starts in their own
|
|
10
|
+
* terminal sees none of it.
|
|
11
|
+
*
|
|
12
|
+
* The shim (`$PROHOST_HOME/code-host/bin/prohost-hook`) is rewritten on every
|
|
13
|
+
* daemon start to name the CLI that is installed now, so a session started
|
|
14
|
+
* under an older CLI (npx caches move) keeps working after an upgrade.
|
|
15
|
+
*
|
|
16
|
+
* What each hook reports (contract "Hook / host ingest"):
|
|
17
|
+
*
|
|
18
|
+
* | Hook | Event |
|
|
19
|
+
* | --- | --- |
|
|
20
|
+
* | `UserPromptSubmit` | `prompt {text}` |
|
|
21
|
+
* | `Stop` | `stop {finalText, question}` then `stats {...}` |
|
|
22
|
+
* | `PermissionRequest --wait <s>` | `permission_request {approvalId, command, options, capabilities: ['hook_decision'], waitMs, deadlineMs, sentAtMs}`, then waits for the decision and prints it (`decision.ts`); `prompt_local` if its wait runs out |
|
|
23
|
+
* | `PermissionRequest` (a window launched before `--wait`) | `permission_request`, then at once `prompt_local {reason: 'launched_before_update'}`: its Claude Code would kill a waiting hook at 10 s |
|
|
24
|
+
* | `Notification` (`permission_prompt`) | for a Claude Code without `PermissionRequest`: `permission_request`, then `prompt_local {reason: 'no_hook'}` |
|
|
25
|
+
* | `SessionStart` | nothing posted; like every hook, it marks the window past the trust dialog (`ready.ts`) |
|
|
26
|
+
* | Codex `agent-turn-complete` | `prompt` (when it carries one) then `stop` |
|
|
27
|
+
*
|
|
28
|
+
* `question` is always true for an interactive turn: when an interactive agent
|
|
29
|
+
* stops, its turn is over and nothing more happens until a person types — that
|
|
30
|
+
* is a hand-off by construction, not a reading of what it said.
|
|
31
|
+
*
|
|
32
|
+
* Ordinary hooks print nothing (a `UserPromptSubmit` hook's stdout becomes part of the
|
|
33
|
+
* prompt), except a waiting `PermissionRequest` hook's decision from ProhostAI,
|
|
34
|
+
* which never blocks the menu (Claude Code draws it while the hook runs, and
|
|
35
|
+
* applies whichever answers first). The verified modern profile also records
|
|
36
|
+
* PreToolUse IDs; recording failures block the tool rather than returning success. Claude Code and
|
|
37
|
+
* Codex credentials are never read; the only Claude file read is the session's
|
|
38
|
+
* own transcript, for the turn's final text and token counts, and for whether a
|
|
39
|
+
* held prompt's call is over (`decision.ts`).
|
|
40
|
+
*/
|
|
41
|
+
import type { CodeThreadEvent } from './events.js';
|
|
42
|
+
import type { HostDecision } from './decision.js';
|
|
43
|
+
export declare const TERMINAL_ID_ENV = "PROHOST_TERMINAL_ID";
|
|
44
|
+
export declare const CODE_THREAD_ID_ENV = "PROHOST_CODE_THREAD_ID";
|
|
45
|
+
/** Claude Code hook events this host registers. */
|
|
46
|
+
export declare const CLAUDE_HOOK_EVENTS: readonly ["SessionStart", "UserPromptSubmit", "Stop", "PermissionRequest", "Notification"];
|
|
47
|
+
export type ClaudeHookEvent = (typeof CLAUDE_HOOK_EVENTS)[number];
|
|
48
|
+
export declare const APPROVAL_OPTIONS: readonly ["allow", "allow_session", "deny"];
|
|
49
|
+
/**
|
|
50
|
+
* Declared on a `permission_request` whose decision the hook itself returns
|
|
51
|
+
* (`decision.ts`): the server may relay a decision the moment it has the
|
|
52
|
+
* prompt, since it can only ever answer that prompt.
|
|
53
|
+
*/
|
|
54
|
+
export declare const HOOK_DECISION_CAPABILITY = "hook_decision";
|
|
55
|
+
/** Waits between `permission_request` attempts whose outcome is unknown, within the hook's wait. */
|
|
56
|
+
export declare const POST_RETRY_DELAYS_MS: number[];
|
|
57
|
+
/** Waits between `approval_overridden_locally` attempts, all within {@link OVERRIDE_BUDGET_MS}. */
|
|
58
|
+
export declare const OVERRIDE_RETRY_DELAYS_MS: number[];
|
|
59
|
+
/** Every correction attempt ends this soon after the PostToolUse hook started, under its 10 s timeout. */
|
|
60
|
+
export declare const OVERRIDE_BUDGET_MS = 8000;
|
|
61
|
+
/**
|
|
62
|
+
* How long the `PermissionRequest` hook waits for a decision from ProhostAI.
|
|
63
|
+
* The menu is up in the terminal all along (Claude Code draws it while the hook
|
|
64
|
+
* runs), so the person at the Mac is never kept waiting by it: this bounds only
|
|
65
|
+
* how long a decision from ProhostAI may still answer the prompt.
|
|
66
|
+
*/
|
|
67
|
+
export declare const HOOK_DECISION_WAIT_S = 120;
|
|
68
|
+
/** The hook's own timeout, past which Claude Code kills it: above its wait. */
|
|
69
|
+
export declare const PERMISSION_HOOK_TIMEOUT_S = 150;
|
|
70
|
+
export declare const MAX_PREVIEW_CHARS = 280;
|
|
71
|
+
export declare function hookBinDir(env?: NodeJS.ProcessEnv): string;
|
|
72
|
+
export declare function hookShimPath(env?: NodeJS.ProcessEnv): string;
|
|
73
|
+
export declare function claudeSettingsPath(env?: NodeJS.ProcessEnv): string;
|
|
74
|
+
/** The shim script: env-guarded, then the current CLI's `hook` command. */
|
|
75
|
+
export declare function hookShimScript(nodePath: string, cliEntrypoint: string): string;
|
|
76
|
+
/**
|
|
77
|
+
* The `--settings` document Claude Code is launched with: hooks only, and, for a window started
|
|
78
|
+
* without permission prompts (`skipsPermissions`), the owner's acceptance of Claude Code's one-time
|
|
79
|
+
* bypass-mode warning: `skipDangerousModePermissionPrompt` ("whether the user has accepted the
|
|
80
|
+
* bypass permissions mode dialog", Claude Code's settings schema; read from `--settings` too). Only
|
|
81
|
+
* that window's document carries it: every other window launches without bypass mode, as before.
|
|
82
|
+
*/
|
|
83
|
+
export declare function claudeHookSettings(shimPath: string, invocationProtocol?: boolean, skipsPermissions?: boolean): Record<string, unknown>;
|
|
84
|
+
/** Codex `-c notify=[...]` value (TOML array), naming the shim. */
|
|
85
|
+
export declare function codexNotifyOverride(shimPath: string): string;
|
|
86
|
+
/** Write the shim and Claude settings. Called on every daemon start. */
|
|
87
|
+
export declare function installHookFiles(nodePath: string, cliEntrypoint: string, env?: NodeJS.ProcessEnv): {
|
|
88
|
+
shim: string;
|
|
89
|
+
claudeSettings: string;
|
|
90
|
+
claudeInvocationSettings: string;
|
|
91
|
+
claudeSkipSettings: string;
|
|
92
|
+
claudeInvocationSkipSettings: string;
|
|
93
|
+
};
|
|
94
|
+
/** Last non-empty line, clipped — the inbox row's preview. */
|
|
95
|
+
export declare function previewOf(text: string): string | undefined;
|
|
96
|
+
export interface TranscriptTurn {
|
|
97
|
+
finalText?: string;
|
|
98
|
+
tokensTotal?: number;
|
|
99
|
+
tokensCachedPct?: number;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* The last assistant turn of a Claude Code transcript (JSONL): its text and
|
|
103
|
+
* token usage. Unknown shapes yield nothing rather than zeros.
|
|
104
|
+
*/
|
|
105
|
+
export declare function parseTranscriptTail(content: string): TranscriptTurn;
|
|
106
|
+
/** `git diff --shortstat` numbers for a worktree, against where its branch left the default branch. */
|
|
107
|
+
export declare function parseShortstat(text: string): {
|
|
108
|
+
filesChanged: number;
|
|
109
|
+
additions: number;
|
|
110
|
+
deletions: number;
|
|
111
|
+
};
|
|
112
|
+
export type GitRunner = (args: string[], cwd: string) => Promise<string | undefined>;
|
|
113
|
+
/**
|
|
114
|
+
* What the thread changed in its worktree, against where its branch left the
|
|
115
|
+
* default branch: commits, uncommitted edits, and new files not yet added
|
|
116
|
+
* (`git diff` alone never counts an untracked file, so a thread that made one
|
|
117
|
+
* would read "No changes yet").
|
|
118
|
+
*/
|
|
119
|
+
export declare function diffStats(cwd: string, git?: GitRunner, countLines?: (file: string) => number): Promise<{
|
|
120
|
+
filesChanged: number;
|
|
121
|
+
additions: number;
|
|
122
|
+
deletions: number;
|
|
123
|
+
} | undefined>;
|
|
124
|
+
/** Stable approval id for one permission prompt, so a retried hook doesn't make two. */
|
|
125
|
+
export declare function approvalIdFor(parts: (string | undefined)[]): string;
|
|
126
|
+
/** A one-line description of what a tool wants to do. */
|
|
127
|
+
export declare function permissionCommand(toolName: string | undefined, toolInput: unknown): string;
|
|
128
|
+
export interface HookContext {
|
|
129
|
+
env: NodeJS.ProcessEnv;
|
|
130
|
+
now: () => number;
|
|
131
|
+
git: GitRunner;
|
|
132
|
+
readTranscript: (file: string) => string | undefined;
|
|
133
|
+
}
|
|
134
|
+
/** Events for one Claude Code hook invocation. Pure apart from the context's readers. */
|
|
135
|
+
export declare function claudeHookEvents(hook: string, input: Record<string, unknown>, ctx: HookContext): Promise<CodeThreadEvent[]>;
|
|
136
|
+
/** Events for one Codex `notify` call; `payload` is the JSON Codex passes as the last argument. */
|
|
137
|
+
export declare function codexNotifyEvents(payload: string, now: number): CodeThreadEvent[];
|
|
138
|
+
/**
|
|
139
|
+
* One hook can report several events at the moment it fired (`stop` then
|
|
140
|
+
* `stats`). Ingest drops an event older than the newest it applied for the
|
|
141
|
+
* thread, so each later event gets a later `at` — a millisecond apart.
|
|
142
|
+
*/
|
|
143
|
+
export declare function strictlyIncreasing(events: CodeThreadEvent[]): CodeThreadEvent[];
|
|
144
|
+
export interface RunHookOptions {
|
|
145
|
+
env?: NodeJS.ProcessEnv;
|
|
146
|
+
stdin?: NodeJS.ReadableStream;
|
|
147
|
+
fetchImpl?: typeof fetch;
|
|
148
|
+
now?: () => number;
|
|
149
|
+
git?: GitRunner;
|
|
150
|
+
sleep?: (ms: number) => Promise<void>;
|
|
151
|
+
/** A waiting `PermissionRequest` hook's decision output (default: stdout). */
|
|
152
|
+
stdout?: (text: string) => void;
|
|
153
|
+
/** Registers what runs when Claude Code stops a waiting hook (default: the signal handlers). */
|
|
154
|
+
onStop?: (handler: () => void) => void;
|
|
155
|
+
claudeVersion?: () => Promise<string | undefined>;
|
|
156
|
+
}
|
|
157
|
+
/** `--wait <seconds>` on the hook's command line, capped below its timeout; 0 without one. */
|
|
158
|
+
export declare function waitArg(args: string[]): number;
|
|
159
|
+
/**
|
|
160
|
+
* "Allow for this session", as Claude Code offers it for this prompt: its first
|
|
161
|
+
* suggestion that adds an allow rule, kept to the session. Only that kind: a
|
|
162
|
+
* suggestion to add a directory or switch mode grants more than the one call
|
|
163
|
+
* the person decided on. None: the option isn't offered.
|
|
164
|
+
*/
|
|
165
|
+
export declare function sessionRule(suggestions: unknown): Record<string, unknown> | undefined;
|
|
166
|
+
/** The hook's stdout for a decision: what Claude Code applies to the prompt. */
|
|
167
|
+
export declare function decisionOutput(decision: HostDecision, rule: Record<string, unknown> | undefined): string;
|
|
168
|
+
export interface PermissionWait {
|
|
169
|
+
/** How long to wait for a decision from ProhostAI. */
|
|
170
|
+
waitMs: number;
|
|
171
|
+
/**
|
|
172
|
+
* Why the prompt is the terminal's when the hook doesn't wait (`waitMs` 0), as `prompt_local`
|
|
173
|
+
* says it: remote control is off, or the window was launched before hooks waited.
|
|
174
|
+
*/
|
|
175
|
+
localReason: PromptLocalReason;
|
|
176
|
+
stdout: (text: string) => void;
|
|
177
|
+
/** Called with a handler for SIGTERM/SIGINT/SIGHUP: Claude Code stopping the hook (Escape, "No"). */
|
|
178
|
+
onStop: (handler: () => void) => void;
|
|
179
|
+
}
|
|
180
|
+
/** Why a prompt is answered in the terminal, as `prompt_local {reason}` tells the server. */
|
|
181
|
+
export type PromptLocalReason = 'timeout' | 'remote_off' | 'launched_before_update' | 'no_hook';
|
|
182
|
+
/**
|
|
183
|
+
* `prohost hook claude <Event>` / `prohost hook codex <payload>`. Critical invocation
|
|
184
|
+
* recording failures are nonzero; ordinary reporting failures stay nonblocking.
|
|
185
|
+
*/
|
|
186
|
+
export declare function runHook(args: string[], options?: RunHookOptions): Promise<number>;
|