@relaymessenger/cli 0.3.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 (74) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +139 -0
  3. package/claude-plugin/marketplace/.claude-plugin/marketplace.json +14 -0
  4. package/claude-plugin/marketplace/plugins/relay/.claude-plugin/plugin.json +18 -0
  5. package/claude-plugin/marketplace/plugins/relay/LICENSE +21 -0
  6. package/claude-plugin/marketplace/plugins/relay/README.md +173 -0
  7. package/claude-plugin/marketplace/plugins/relay/commands/configure.md +71 -0
  8. package/claude-plugin/marketplace/plugins/relay/runtime/server.mjs +26107 -0
  9. package/dist/api.d.ts +74 -0
  10. package/dist/api.d.ts.map +1 -0
  11. package/dist/api.js +129 -0
  12. package/dist/api.js.map +1 -0
  13. package/dist/claude-settings.d.ts +14 -0
  14. package/dist/claude-settings.d.ts.map +1 -0
  15. package/dist/claude-settings.js +47 -0
  16. package/dist/claude-settings.js.map +1 -0
  17. package/dist/cli.d.ts +3 -0
  18. package/dist/cli.d.ts.map +1 -0
  19. package/dist/cli.js +162 -0
  20. package/dist/cli.js.map +1 -0
  21. package/dist/codex.d.ts +25 -0
  22. package/dist/codex.d.ts.map +1 -0
  23. package/dist/codex.js +227 -0
  24. package/dist/codex.js.map +1 -0
  25. package/dist/doctor.d.ts +2 -0
  26. package/dist/doctor.d.ts.map +1 -0
  27. package/dist/doctor.js +122 -0
  28. package/dist/doctor.js.map +1 -0
  29. package/dist/engine/acp.d.ts +69 -0
  30. package/dist/engine/acp.d.ts.map +1 -0
  31. package/dist/engine/acp.js +402 -0
  32. package/dist/engine/acp.js.map +1 -0
  33. package/dist/engine/catalog.d.ts +26 -0
  34. package/dist/engine/catalog.d.ts.map +1 -0
  35. package/dist/engine/catalog.js +41 -0
  36. package/dist/engine/catalog.js.map +1 -0
  37. package/dist/engine/process.d.ts +12 -0
  38. package/dist/engine/process.d.ts.map +1 -0
  39. package/dist/engine/process.js +54 -0
  40. package/dist/engine/process.js.map +1 -0
  41. package/dist/engine/types.d.ts +57 -0
  42. package/dist/engine/types.d.ts.map +1 -0
  43. package/dist/engine/types.js +8 -0
  44. package/dist/engine/types.js.map +1 -0
  45. package/dist/flags.d.ts +9 -0
  46. package/dist/flags.d.ts.map +1 -0
  47. package/dist/flags.js +34 -0
  48. package/dist/flags.js.map +1 -0
  49. package/dist/install.d.ts +69 -0
  50. package/dist/install.d.ts.map +1 -0
  51. package/dist/install.js +510 -0
  52. package/dist/install.js.map +1 -0
  53. package/dist/mcp.d.ts +16 -0
  54. package/dist/mcp.d.ts.map +1 -0
  55. package/dist/mcp.js +127 -0
  56. package/dist/mcp.js.map +1 -0
  57. package/dist/pair.d.ts +20 -0
  58. package/dist/pair.d.ts.map +1 -0
  59. package/dist/pair.js +135 -0
  60. package/dist/pair.js.map +1 -0
  61. package/dist/permissions.d.ts +87 -0
  62. package/dist/permissions.d.ts.map +1 -0
  63. package/dist/permissions.js +342 -0
  64. package/dist/permissions.js.map +1 -0
  65. package/dist/receive.d.ts +54 -0
  66. package/dist/receive.d.ts.map +1 -0
  67. package/dist/receive.js +353 -0
  68. package/dist/receive.js.map +1 -0
  69. package/dist/store.d.ts +260 -0
  70. package/dist/store.d.ts.map +1 -0
  71. package/dist/store.js +550 -0
  72. package/dist/store.js.map +1 -0
  73. package/openclaw-plugin/relaymessenger-openclaw-plugin-0.1.0.tgz +0 -0
  74. package/package.json +51 -0
package/dist/codex.js ADDED
@@ -0,0 +1,227 @@
1
+ /**
2
+ * Codex-side entrypoints installed by `relaymessenger install-codex`:
3
+ *
4
+ * `relaymessenger notify` — Codex appends its notification JSON as the final argv
5
+ * arg (kebab-case): {"type":"agent-turn-complete","thread-id":…,"turn-id":…,
6
+ * "cwd":…,"input-messages":[…],"last-assistant-message":…}. That is the only
7
+ * notify event Codex emits; approvals come through the PermissionRequest hook.
8
+ *
9
+ * `relaymessenger hook permission-request` — Codex's hooks engine pipes
10
+ * {session_id, turn_id, cwd, tool_name, tool_input, permission_mode} on stdin
11
+ * and accepts a decision on stdout (developers.openai.com/codex/hooks):
12
+ * exit 0 + {"hookSpecificOutput":{"hookEventName":"PermissionRequest",
13
+ * "decision":{"behavior":"allow"|"deny"}}}
14
+ * exit 0 + no decision → fall through to Codex's normal approval flow
15
+ * The hook posts an Allow/Deny card to Relay and blocks on the phone tap
16
+ * (watching its per-request approval file — which a running `relaymessenger start`
17
+ * loop resolves — and polling the conversation directly). Timeout → deny.
18
+ *
19
+ * These entrypoints run in their own processes and never write state.json;
20
+ * that file is owned exclusively by the `start` loop. They read the pinned
21
+ * owner conversation via readStateSnapshot() and coordinate approvals only
22
+ * through per-request files in the active account runtime's approvals/.
23
+ */
24
+ import { randomBytes } from "node:crypto";
25
+ import { basename, dirname } from "node:path";
26
+ import { RelayClient } from "./api.js";
27
+ import { buildPermissionCard, newRequestId, verdictFromMessage } from "./permissions.js";
28
+ import { ApprovalStore, CodexNotifyPolicyStore, ConfigStore, readStateSnapshot, resolveOwnerUserId, runtimeHomeForConfig, relayIdentityForConfig, } from "./store.js";
29
+ export function requireClient(config = new ConfigStore()) {
30
+ const projectRoot = new CodexNotifyPolicyStore().matchProject(process.cwd());
31
+ if (!projectRoot) {
32
+ throw new Error("This project is not opted in to Relay. Run `relaymessenger install-codex` from its root first.");
33
+ }
34
+ const loaded = config.load();
35
+ if (!loaded?.agent_token) {
36
+ throw new Error("Not paired. Run `relaymessenger pair` first.");
37
+ }
38
+ let ownerUserId;
39
+ try {
40
+ ownerUserId = resolveOwnerUserId(loaded);
41
+ }
42
+ catch {
43
+ ownerUserId = undefined;
44
+ }
45
+ return {
46
+ client: new RelayClient(loaded.api_origin, loaded.agent_token),
47
+ ownerUserId,
48
+ // The owner's conversation, pinned by the loop at the first owner
49
+ // message — never the most recent writer.
50
+ conversationId: readStateSnapshot(runtimeHomeForConfig(loaded, dirname(config.path))).owner_conversation_id,
51
+ projectRoot,
52
+ runtimeHome: runtimeHomeForConfig(loaded, dirname(config.path)),
53
+ apiOrigin: loaded.api_origin,
54
+ accountIdentity: relayIdentityForConfig(loaded),
55
+ };
56
+ }
57
+ export async function notifyCommand(argv, out = console.log, dependencies = {}) {
58
+ const raw = argv[argv.length - 1];
59
+ let payload = {};
60
+ try {
61
+ payload = raw ? JSON.parse(raw) : {};
62
+ }
63
+ catch {
64
+ // Not JSON — treat as free text.
65
+ payload = { "last-assistant-message": raw };
66
+ }
67
+ if (payload.type && payload.type !== "agent-turn-complete")
68
+ return;
69
+ const projectRoot = (dependencies.policy ?? new CodexNotifyPolicyStore()).matchProject(payload.cwd);
70
+ if (!projectRoot) {
71
+ out("relaymessenger notify: suppressed — this project was not explicitly opted in.");
72
+ return;
73
+ }
74
+ const config = dependencies.config ?? new ConfigStore();
75
+ const loaded = config.load();
76
+ if (!loaded?.agent_token)
77
+ throw new Error("Not paired. Run `relaymessenger pair` first.");
78
+ const conversationId = readStateSnapshot(runtimeHomeForConfig(loaded, dirname(config.path))).owner_conversation_id;
79
+ const client = dependencies.client ?? new RelayClient(loaded.api_origin, loaded.agent_token);
80
+ if (!conversationId) {
81
+ out("relaymessenger notify: no pinned owner conversation yet — run `relaymessenger start` once and " +
82
+ "message the agent from the Relay app first.");
83
+ return;
84
+ }
85
+ const last = payload["last-assistant-message"];
86
+ const summary = typeof last === "string" && last.trim().length > 0
87
+ ? last.trim()
88
+ : "Codex finished a turn.";
89
+ const turnId = payload["turn-id"] ?? randomBytes(6).toString("hex");
90
+ await client.postMessage({
91
+ conversation_id: conversationId,
92
+ parts: [{ type: "text", text: `Codex (${basename(projectRoot)}): ${summary}`.slice(0, 7900) }],
93
+ }, `relay-notify-${turnId}`);
94
+ }
95
+ async function readStdin() {
96
+ const chunks = [];
97
+ for await (const chunk of process.stdin)
98
+ chunks.push(chunk);
99
+ return Buffer.concat(chunks).toString("utf8");
100
+ }
101
+ const HOOK_TIMEOUT_MS = 9 * 60 * 1000; // under Codex's 600 s handler default
102
+ export async function permissionRequestHook(write = (json) => process.stdout.write(`${JSON.stringify(json)}\n`)) {
103
+ let input = {};
104
+ try {
105
+ input = JSON.parse(await readStdin());
106
+ }
107
+ catch {
108
+ return 0; // Unparseable input → no decision, Codex falls back to local approval.
109
+ }
110
+ const config = new ConfigStore().load();
111
+ const projectRoot = new CodexNotifyPolicyStore().matchProject(input.cwd);
112
+ if (!projectRoot)
113
+ return 0;
114
+ const conversationId = config?.agent_token
115
+ ? readStateSnapshot(runtimeHomeForConfig(config)).owner_conversation_id
116
+ : undefined;
117
+ let ownerUserId;
118
+ try {
119
+ ownerUserId = config ? resolveOwnerUserId(config) : undefined;
120
+ }
121
+ catch {
122
+ ownerUserId = undefined;
123
+ }
124
+ if (!config?.agent_token || !conversationId || !ownerUserId) {
125
+ // Not paired / no pinned owner or conversation → we cannot verify who
126
+ // would answer, so fall through to Codex's local approval flow.
127
+ return 0;
128
+ }
129
+ const client = new RelayClient(config.api_origin, config.agent_token);
130
+ const approvals = new ApprovalStore();
131
+ const requestId = newRequestId();
132
+ const approval = {
133
+ request_id: requestId,
134
+ conversation_id: conversationId,
135
+ engine: "codex",
136
+ tool_name: input.tool_name,
137
+ created_at: new Date().toISOString(),
138
+ deadline_at: new Date(Date.now() + HOOK_TIMEOUT_MS).toISOString(),
139
+ options: [
140
+ { option_id: "allow", label: "Allow", kind: "allow_once" },
141
+ { option_id: "deny", label: "Deny", kind: "reject_once" },
142
+ ],
143
+ source: "hook",
144
+ };
145
+ let card;
146
+ try {
147
+ card = buildPermissionCard({
148
+ requestId,
149
+ conversationId,
150
+ engineLabel: "Codex",
151
+ toolName: input.tool_name,
152
+ inputPreview: input.tool_input !== undefined ? JSON.stringify(input.tool_input) : undefined,
153
+ });
154
+ }
155
+ catch (error) {
156
+ process.stderr.write(`relaymessenger: refusing concealed approval input (${error}) — denying.\n`);
157
+ write(decisionJson(false));
158
+ return 0;
159
+ }
160
+ // Durable (create-once) before the card goes out. A running `relaymessenger
161
+ // start` loop sees the tap on the event stream and writes the resolution
162
+ // into this file; this process is the waiter that consumes it.
163
+ approvals.create(approval);
164
+ let posted;
165
+ try {
166
+ posted = await client.postMessage(card.body, card.idempotencyKey);
167
+ }
168
+ catch (error) {
169
+ approvals.consume(requestId);
170
+ process.stderr.write(`relaymessenger: approval card could not be delivered (${error}) — denying.\n`);
171
+ write(decisionJson(false));
172
+ return 0;
173
+ }
174
+ const cardSequence = posted.message.sequence;
175
+ const finish = (allow) => {
176
+ approvals.consume(requestId);
177
+ write(decisionJson(allow));
178
+ return 0;
179
+ };
180
+ const deadline = Date.now() + HOOK_TIMEOUT_MS;
181
+ while (Date.now() < deadline) {
182
+ await new Promise((resolve) => setTimeout(resolve, 2500));
183
+ // Path 1: a running start loop resolved our approval file.
184
+ const shared = approvals.get(requestId);
185
+ if (shared?.resolution)
186
+ return finish(shared.resolution.behavior === "allow");
187
+ if (!shared) {
188
+ // Aged out from under us — treat as deny.
189
+ break;
190
+ }
191
+ // Path 2: poll the conversation directly (works without `relaymessenger start`).
192
+ try {
193
+ const { messages } = await client.listMessages(conversationId, 10);
194
+ const verdict = messages
195
+ .filter((message) => message.sender.kind === "user" &&
196
+ message.sender.id === ownerUserId &&
197
+ message.conversation_id === conversationId &&
198
+ message.sequence > cardSequence)
199
+ .sort((a, b) => a.sequence - b.sequence)
200
+ .map((message) => verdictFromMessage(message))
201
+ .find((candidate) => candidate?.request_id === requestId);
202
+ if (verdict)
203
+ return finish(verdict.behavior === "allow");
204
+ }
205
+ catch {
206
+ // transient — keep polling until deadline
207
+ }
208
+ }
209
+ process.stderr.write("relaymessenger: no approval from Relay within the window — denying.\n");
210
+ return finish(false);
211
+ }
212
+ /**
213
+ * Exact PermissionRequest hook envelope from the Codex hooks reference:
214
+ * hookSpecificOutput.hookEventName is required — without it Codex treats the
215
+ * output as invalid and the phone decision is dropped.
216
+ */
217
+ export function decisionJson(allow) {
218
+ return {
219
+ hookSpecificOutput: {
220
+ hookEventName: "PermissionRequest",
221
+ decision: allow
222
+ ? { behavior: "allow" }
223
+ : { behavior: "deny", message: "Denied from the Relay app." },
224
+ },
225
+ };
226
+ }
227
+ //# sourceMappingURL=codex.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex.js","sourceRoot":"","sources":["../src/codex.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function doctor(out?: (line: string) => void): Promise<boolean>;
2
+ //# sourceMappingURL=doctor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"AAgBA,wBAAsB,MAAM,CAAC,GAAG,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAkB,GAAG,OAAO,CAAC,OAAO,CAAC,CA4IxF"}
package/dist/doctor.js ADDED
@@ -0,0 +1,122 @@
1
+ /** `relaymessenger doctor` — environment and pairing health checks. */
2
+ import { existsSync, statSync } from "node:fs";
3
+ import { homedir } from "node:os";
4
+ import { dirname, join } from "node:path";
5
+ import crossSpawn from "cross-spawn";
6
+ import { resolveApiOrigin, RelayClient } from "./api.js";
7
+ import { claudeBypassWarning } from "./claude-settings.js";
8
+ import { ADAPTER_PACKAGES, ADAPTER_VERSIONS, adapterEntrypoint } from "./engine/acp.js";
9
+ import { EXTERNAL_ENGINE_SPECS } from "./engine/catalog.js";
10
+ import { ApprovalStore, ConfigStore, readStateSnapshot, runtimeHomeForConfig, } from "./store.js";
11
+ export async function doctor(out = console.log) {
12
+ let healthy = true;
13
+ const check = (ok, label, detail) => {
14
+ healthy = healthy && ok;
15
+ out(`${ok ? "ok " : "FAIL"} ${label}${detail ? ` — ${detail}` : ""}`);
16
+ return ok;
17
+ };
18
+ const [nodeMajor, nodeMinor] = process.versions.node.split(".").map(Number);
19
+ check((nodeMajor ?? 0) > 22 || (nodeMajor === 22 && (nodeMinor ?? 0) >= 18), "node >= 22.18", `running ${process.versions.node}`);
20
+ const config = new ConfigStore();
21
+ const loaded = config.load();
22
+ if (check(Boolean(loaded?.agent_token), "paired (config.json has agent_token)", config.path)) {
23
+ if (process.platform !== "win32") {
24
+ const mode = statSync(config.path).mode & 0o777;
25
+ check(mode === 0o600, "config.json is chmod 600", `mode ${mode.toString(8)}`);
26
+ }
27
+ const owner = process.env.RELAY_OWNER_USER_ID ?? loaded?.owner_user_id;
28
+ check(Boolean(owner), "owner pinned (owner_user_id)", owner ?? "missing — re-run `relaymessenger pair` or set RELAY_OWNER_USER_ID");
29
+ let origin = loaded.api_origin;
30
+ try {
31
+ origin = resolveApiOrigin(loaded.api_origin);
32
+ if (process.env.RELAY_API_ORIGIN) {
33
+ out(`info RELAY_API_ORIGIN override active (${origin}) — development/testing only`);
34
+ }
35
+ }
36
+ catch (error) {
37
+ check(false, "RELAY_API_ORIGIN valid", String(error?.message ?? error));
38
+ }
39
+ try {
40
+ const client = new RelayClient(origin, loaded.agent_token);
41
+ const me = (await client.getMe());
42
+ const handle = me?.agent?.handle ?? me?.handle;
43
+ check(true, `API reachable (${origin})`, handle ? `@${handle}` : undefined);
44
+ }
45
+ catch (error) {
46
+ check(false, `API reachable (${origin})`, String(error?.message ?? error));
47
+ }
48
+ }
49
+ else {
50
+ out(" run `relaymessenger pair` to connect this machine to a Relay agent");
51
+ }
52
+ if (loaded?.agent_token) {
53
+ // Match `start`: durable state is scoped to the effective origin.
54
+ let effectiveOrigin = loaded.api_origin;
55
+ try {
56
+ effectiveOrigin = resolveApiOrigin(loaded.api_origin);
57
+ }
58
+ catch {
59
+ // Invalid override already reported above; fall back to the paired origin.
60
+ }
61
+ const runtimeHome = runtimeHomeForConfig({ ...loaded, api_origin: effectiveOrigin }, dirname(config.path));
62
+ try {
63
+ const state = readStateSnapshot(runtimeHome);
64
+ const pendingEvents = Object.values(state.pending_events).reduce((sum, queue) => sum + queue.length, 0);
65
+ const pendingApprovals = new ApprovalStore(runtimeHome).list().length;
66
+ out(`info state: cursor=${state.cursor}, pending_events=${pendingEvents}, ` +
67
+ `pending_approvals=${pendingApprovals}, owner_conversation=${state.owner_conversation_id ?? "unset"} ` +
68
+ `(${join(runtimeHome, "state.json")})`);
69
+ }
70
+ catch (error) {
71
+ check(false, "runtime state readable", String(error));
72
+ }
73
+ }
74
+ else {
75
+ out("info runtime state unavailable until this machine is paired");
76
+ }
77
+ for (const [engine, pkg] of Object.entries(ADAPTER_PACKAGES)) {
78
+ try {
79
+ const entrypoint = adapterEntrypoint(engine);
80
+ check(existsSync(entrypoint), `${engine} adapter installed (${pkg}@${ADAPTER_VERSIONS[engine]})`, entrypoint);
81
+ }
82
+ catch (error) {
83
+ check(false, `${engine} adapter installed (${pkg}@${ADAPTER_VERSIONS[engine]})`, String(error));
84
+ }
85
+ }
86
+ for (const [engine, spec] of Object.entries(EXTERNAL_ENGINE_SPECS)) {
87
+ const lookup = crossSpawn.sync(process.platform === "win32" ? "where.exe" : "which", [spec.command], {
88
+ encoding: "utf8",
89
+ windowsHide: true,
90
+ });
91
+ if (lookup.status !== 0) {
92
+ out(`info ${engine}: not installed — ${spec.docsUrl}`);
93
+ continue;
94
+ }
95
+ const version = crossSpawn.sync(spec.command, spec.versionArgs, {
96
+ encoding: "utf8",
97
+ timeout: 20_000,
98
+ windowsHide: true,
99
+ });
100
+ check(version.status === 0, `${engine} binary present`, version.stdout?.trim() || version.stderr?.trim());
101
+ if (spec.checkArgs) {
102
+ const readiness = crossSpawn.sync(spec.command, spec.checkArgs, {
103
+ encoding: "utf8",
104
+ timeout: 30_000,
105
+ windowsHide: true,
106
+ });
107
+ check(readiness.status === 0, `${engine} ACP readiness`, readiness.stdout?.trim() || readiness.stderr?.trim());
108
+ }
109
+ }
110
+ // Warn (not fail) when Claude settings disable phone approvals entirely.
111
+ const bypass = claudeBypassWarning();
112
+ if (bypass)
113
+ out(`warn ${bypass}`);
114
+ const codexConfig = join(homedir(), ".codex", "config.toml");
115
+ out(existsSync(codexConfig)
116
+ ? `info codex config present (${codexConfig}); run \`relaymessenger install-codex\` to wire notify + approvals`
117
+ : "info no ~/.codex/config.toml — install Codex or skip install-codex");
118
+ out("");
119
+ out(healthy ? "All checks passed." : "Some checks failed — see above.");
120
+ return healthy;
121
+ }
122
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,69 @@
1
+ import { type RequestPermissionRequest, type ToolCallUpdate } from "@agentclientprotocol/sdk";
2
+ import type { EngineAdapter, SessionRef, TurnCallbacks, TurnResult } from "./types.js";
3
+ import type { SessionStore } from "../store.js";
4
+ import { type EngineName } from "./catalog.js";
5
+ export declare const ADAPTER_PACKAGES: Record<string, string>;
6
+ /** Versions must exactly match package.json; tests enforce the lock. */
7
+ export declare const ADAPTER_VERSIONS: Record<string, string>;
8
+ /** Resolve the installed, lockfile-pinned executable without invoking npm. */
9
+ export declare function adapterEntrypoint(engine: "claude" | "codex"): string;
10
+ export interface EngineProcessSpec {
11
+ command: string;
12
+ args: string[];
13
+ display: string;
14
+ }
15
+ /** Shell-free, deterministic process descriptor for one ACP runtime. */
16
+ export declare function engineProcessSpec(engine: EngineName): EngineProcessSpec;
17
+ export declare function engineEnv(parent?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
18
+ /**
19
+ * Accumulates one turn's streamed assistant text. Chunks stream into the
20
+ * current message segment; a tool-call boundary ends the segment, so the next
21
+ * chunk starts a distinct message. Distinct segments join with a blank line —
22
+ * a plain "" join would fuse back-to-back messages into one word
23
+ * ("…the file." + "Created…" → "file.Created").
24
+ */
25
+ export declare class AgentTextBuffer {
26
+ private readonly segments;
27
+ private open;
28
+ append(chunk: string): void;
29
+ /** Mark a message boundary: the next appended chunk starts a new segment. */
30
+ endSegment(): void;
31
+ /** Segments trimmed (no doubled blank lines), empty segments dropped. */
32
+ toString(): string;
33
+ }
34
+ /** Merge a sparse ACP tool-call update without erasing previously known fields. */
35
+ export declare function mergeToolCall(previous: ToolCallUpdate | undefined, incoming: ToolCallUpdate): ToolCallUpdate;
36
+ /**
37
+ * Flatten the security-relevant parts of an ACP tool call — raw input,
38
+ * affected locations, content — into one preview string for the approval
39
+ * card. Length is clamped downstream (head + tail) by the card builder.
40
+ */
41
+ export declare function permissionDetail(toolCall: RequestPermissionRequest["toolCall"]): string | undefined;
42
+ /** True only when the phone can display the full operation being approved. */
43
+ export declare function permissionInputComplete(toolCall: RequestPermissionRequest["toolCall"]): boolean;
44
+ export declare class AcpEngine implements EngineAdapter {
45
+ readonly engine: EngineName;
46
+ private readonly sessions;
47
+ private readonly log;
48
+ private child;
49
+ private connection;
50
+ private ctx;
51
+ private initialization;
52
+ private loadSessionSupported;
53
+ /** Live turn state keyed by ACP session id. */
54
+ private readonly turns;
55
+ /** conversation_id → ACP session + repository for the live process. */
56
+ private readonly liveSessions;
57
+ private permissionSeq;
58
+ constructor(engine: EngineName, sessions: SessionStore, log?: (line: string) => void);
59
+ private ensureConnected;
60
+ private connect;
61
+ private resetConnection;
62
+ private handleUpdate;
63
+ private handlePermission;
64
+ private openSession;
65
+ startTurn(ref: SessionRef, promptText: string, callbacks: TurnCallbacks): Promise<TurnResult>;
66
+ abort(ref: SessionRef): Promise<void>;
67
+ dispose(): Promise<void>;
68
+ }
69
+ //# sourceMappingURL=acp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"acp.d.ts","sourceRoot":"","sources":["../../src/engine/acp.ts"],"names":[],"mappings":"AAiBA,OAAO,EAML,KAAK,wBAAwB,EAG7B,KAAK,cAAc,EACpB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EACV,aAAa,EAEb,UAAU,EACV,aAAa,EACb,UAAU,EACX,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,OAAO,EAGL,KAAK,UAAU,EAChB,MAAM,cAAc,CAAC;AAEtB,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAGnD,CAAC;AAEF,wEAAwE;AACxE,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAGnD,CAAC;AAIF,8EAA8E;AAC9E,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,QAAQ,GAAG,OAAO,GAAG,MAAM,CAKpE;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wEAAwE;AACxE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,UAAU,GAAG,iBAAiB,CAcvE;AAwDD,wBAAgB,SAAS,CAAC,MAAM,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAAC,UAAU,CAoBpF;AAED;;;;;;GAMG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgB;IACzC,OAAO,CAAC,IAAI,CAAS;IAErB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAQ3B,6EAA6E;IAC7E,UAAU,IAAI,IAAI;IAIlB,yEAAyE;IACzE,QAAQ,IAAI,MAAM;CAMnB;AASD,mFAAmF;AACnF,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,cAAc,GAAG,SAAS,EACpC,QAAQ,EAAE,cAAc,GACvB,cAAc,CAOhB;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,wBAAwB,CAAC,UAAU,CAAC,GAC7C,MAAM,GAAG,SAAS,CA+BpB;AAED,8EAA8E;AAC9E,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,wBAAwB,CAAC,UAAU,CAAC,GAC7C,OAAO,CAQT;AAED,qBAAa,SAAU,YAAW,aAAa;IAa3C,QAAQ,CAAC,MAAM,EAAE,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,GAAG;IAdtB,OAAO,CAAC,KAAK,CAA2B;IACxC,OAAO,CAAC,UAAU,CAA+B;IACjD,OAAO,CAAC,GAAG,CAA4B;IACvC,OAAO,CAAC,cAAc,CAA4B;IAClD,OAAO,CAAC,oBAAoB,CAAS;IACrC,+CAA+C;IAC/C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgC;IACtD,uEAAuE;IACvE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAyD;IACtF,OAAO,CAAC,aAAa,CAAK;gBAGf,MAAM,EAAE,UAAU,EACV,QAAQ,EAAE,YAAY,EACtB,GAAG,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAe;YAG3C,eAAe;YAcf,OAAO;IAkDrB,OAAO,CAAC,eAAe;IASvB,OAAO,CAAC,YAAY;YAsBN,gBAAgB;YAmChB,WAAW;IAmCnB,SAAS,CAAC,GAAG,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,GAAG,OAAO,CAAC,UAAU,CAAC;IAkB7F,KAAK,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAMrC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAM/B"}