@agentrq/codex-gateway 0.1.3 → 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.
package/README.md CHANGED
@@ -1,186 +1,29 @@
1
1
  # @agentrq/codex-gateway
2
2
 
3
- MCP bridge CLI that connects [OpenAI Codex](https://github.com/openai/codex) to [agentrq](https://agentrq.com) workspaces.
4
-
5
- > [!WARNING]
6
- > **Pre-Alpha**: This project is in early development. APIs, configurations, and behaviors are subject to change without notice.
7
-
8
- ## Overview
9
-
10
- `@agentrq/codex-gateway` bridges the [Model Context Protocol (MCP)](https://modelcontextprotocol.io) with the [Codex app-server protocol](https://github.com/openai/codex/blob/main/codex-rs/app-server/README.md) (JSON-RPC 2.0 over stdio).
11
-
12
- It automates task execution by:
13
-
14
- 1. Loading your workspace's `.mcp.json` configuration.
15
- 2. Connecting to the agentrq MCP server.
16
- 3. Spawning `codex app-server` as a subprocess.
17
- 4. Routing tasks from agentrq to Codex threads/turns.
18
- 5. Collecting agent replies and sending them back to agentrq.
19
- 6. Auto-reconnecting the MCP transport on disconnection.
20
-
21
- ## Prerequisites
22
-
23
- - **Node.js** >= 20
24
- - **OpenAI Codex CLI** (`npm install -g @openai/codex`)
25
- - An [agentrq](https://agentrq.com) workspace with an HTTP MCP server
26
-
27
- ## Installation
28
-
29
- ```bash
30
- npm install -g @agentrq/codex-gateway@latest
31
- ```
32
-
33
- ## Setup
34
-
35
- ### 1. Configure agentrq MCP server for Codex (project-level)
36
-
37
- Codex reads project-level MCP server config from `.codex/config.toml`. Create this file so the Codex agent can use agentrq tools directly during task execution (replace `<WORKSPACEID>` and `<TOKEN>` with your values from the agentrq dashboard):
38
-
39
- ```bash
40
- mkdir -p .codex
41
- cat >> .codex/config.toml << 'EOF'
42
-
43
- [mcp_servers.agentrq-workspace]
44
- url = "https://<WORKSPACEID>.mcp.agentrq.com/mcp?token=<TOKEN>"
45
- EOF
46
- ```
47
-
48
- ### 2. Configure the gateway's agentrq connection
49
-
50
- Create a `.mcp.json` in your project root so `codex-gateway` can connect to the same agentrq workspace:
51
-
52
- ```json
53
- {
54
- "mcpServers": {
55
- "agentrq": {
56
- "type": "http",
57
- "url": "https://<WORKSPACEID>.mcp.agentrq.com/mcp?token=<TOKEN>"
58
- }
59
- }
60
- }
61
- ```
62
-
63
- > **Note:** `.mcp.json` is used by `codex-gateway` to receive tasks. `.codex/config.toml` is used by the Codex agent itself to call agentrq tools (e.g. `reply`, `updateTaskStatus`) during execution.
3
+ > [!CAUTION]
4
+ > **Deprecated.** `@agentrq/codex-gateway` is no longer maintained and has been
5
+ > replaced by [`@agentrq/acp-gateway`](https://www.npmjs.com/package/@agentrq/acp-gateway),
6
+ > which speaks the [Agent Client Protocol](https://agentclientprotocol.com) and
7
+ > supports Codex through the `codex-acp` agent (plus other ACP agents).
8
+ > Please migrate — this package will receive no further releases.
64
9
 
65
10
  ## Usage
66
11
 
67
- Run `codex-gateway` from your agentrq workspace root (the directory containing `.mcp.json`):
12
+ Authenticate once, then run the gateway from your agentrq workspace root:
68
13
 
69
14
  ```bash
70
- # Default: runs `codex app-server`
71
- codex-gateway
72
-
73
- # Custom codex command
74
- codex-gateway -- codex app-server
75
- ```
76
-
77
- ### Environment Variables
78
-
79
- | Variable | Description | Default |
80
- |---|---|---|
81
- | `CODEX_MODEL` | Override the model used for all threads/turns | _(codex default)_ |
82
-
83
- ### Configuration
84
-
85
- `codex-gateway` searches for `.mcp.json` starting in the current working directory and up to 3 parent directories.
86
-
87
- Example `.mcp.json`:
88
-
89
- ```json
90
- {
91
- "mcpServers": {
92
- "agentrq": {
93
- "type": "http",
94
- "url": "https://your-workspace.mcp.agentrq.com?token=..."
95
- }
96
- }
97
- }
15
+ npx @agentrq/acp-gateway@latest --login --agent codex-acp
16
+ npx @agentrq/acp-gateway@latest --agent codex-acp
98
17
  ```
99
18
 
100
- `codex-gateway` prefers servers with `agentrq` in the name; falls back to the first HTTP server with a `url`.
101
-
102
- ## How It Works
103
-
104
- ```
105
- ┌──────────────────────────┐ JSON-RPC 2.0 / JSONL ┌─────────────────┐
106
- │ codex app-server │ ◄─────────────────────────► │ │
107
- │ (OpenAI Codex agent) │ │ codex-gateway │
108
- └──────────────────────────┘ │ │
109
- │ MCP Bridge │
110
- │ │
111
- ┌───────────────────┤ │
112
- │ │ │
113
- ▼ └─────────────────┘
114
- ┌───────────────────────────┐
115
- │ agentrq MCP Server │
116
- │ (HTTP / StreamableHTTP) │
117
- └───────────────────────────┘
118
- ```
119
-
120
- ### Flow
121
-
122
- 1. **Config Loading** — Reads `.mcp.json` to find the agentrq MCP server.
123
- 2. **MCP Connection** — Establishes a `StreamableHTTPClientTransport` with automatic retry and reconnection.
124
- 3. **Codex Spawning** — Launches `codex app-server` via stdio.
125
- 4. **Handshake** — Sends `initialize` + `initialized` to the Codex app-server.
126
- 5. **Task Routing** — When a task arrives from agentrq:
127
- - Extracts `chat_id` as the task identifier.
128
- - Creates a new Codex thread for the chat (or reuses one if the same `chat_id` arrives again).
129
- - Starts a turn with the task content.
130
- - Streams `item/agentMessage/delta` notifications into a reply buffer.
131
- 6. **Reply** — When `turn/completed` fires, sends the buffered text back via agentrq's `reply` tool.
132
- 7. **Recursive Execution** — After each task, checks for the next pending task automatically.
133
-
134
- ### Key Components
135
-
136
- | File | Description |
137
- |---|---|
138
- | `src/index.ts` | Entry point; orchestrates config loading, MCP connection, Codex spawning, and task lifecycle. |
139
- | `src/codexClient.ts` | JSON-RPC 2.0 client for the Codex app-server — handles JSONL I/O, request correlation, and turn completion. |
140
- | `src/mcpClient.ts` | `EventEmitter`-based MCP client with auto-reconnection, notification handling, and tool call dispatch. |
141
- | `src/config.ts` | Parses `.mcp.json` from the current directory tree up to 3 levels deep. |
142
- | `src/taskIdentity.ts` | Extracts `chat_id` from MCP notification metadata or task text. |
143
-
144
- ## Development
19
+ If you installed the old CLI globally, uninstall it:
145
20
 
146
21
  ```bash
147
- # Install dependencies
148
- npm install
149
-
150
- # Run in development mode
151
- npm run dev
152
-
153
- # Type-check
154
- npm run typecheck
155
-
156
- # Run tests
157
- npm test
22
+ npm uninstall -g @agentrq/codex-gateway
158
23
  ```
159
24
 
160
- ## Contributing
161
-
162
- Contributions are welcome! Please feel free to submit pull requests or open issues.
163
-
164
- 1. Fork the repository
165
- 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
166
- 3. Commit your changes (`git commit -m 'Add: amazing feature'`)
167
- 4. Push to the branch (`git push origin feature/amazing-feature`)
168
- 5. Open a Pull Request
169
-
170
- ## Contributing License
171
-
172
- By contributing to this project, you agree that your contributions will be licensed under the project's Apache License 2.0.
173
-
174
- ---
175
-
176
25
  ## License
177
26
 
178
27
  Apache License 2.0
179
28
 
180
29
  Copyright (c) 2026 Contextual, Inc.
181
-
182
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
183
-
184
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
185
-
186
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,152 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { resolveThreadPolicy, describeItem, ThreadItemRegistry, DEFAULT_APPROVAL_POLICY, DEFAULT_SANDBOX, } from "../approvals.js";
3
+ describe("resolveThreadPolicy", () => {
4
+ it("should default to the conservative policy/sandbox pair", () => {
5
+ const policy = resolveThreadPolicy({});
6
+ expect(policy.approvalPolicy).toBe(DEFAULT_APPROVAL_POLICY);
7
+ expect(policy.sandbox).toBe(DEFAULT_SANDBOX);
8
+ expect(policy.warnings).toEqual([]);
9
+ });
10
+ it("should honor CODEX_APPROVAL_POLICY", () => {
11
+ const policy = resolveThreadPolicy({ CODEX_APPROVAL_POLICY: "untrusted" });
12
+ expect(policy.approvalPolicy).toBe("untrusted");
13
+ expect(policy.warnings).toEqual([]);
14
+ });
15
+ it("should honor CODEX_SANDBOX", () => {
16
+ const policy = resolveThreadPolicy({ CODEX_SANDBOX: "workspace-write" });
17
+ expect(policy.sandbox).toBe("workspace-write");
18
+ expect(policy.warnings).toEqual([]);
19
+ });
20
+ it("should treat an empty value as unset", () => {
21
+ const policy = resolveThreadPolicy({ CODEX_APPROVAL_POLICY: "", CODEX_SANDBOX: "" });
22
+ expect(policy.approvalPolicy).toBe(DEFAULT_APPROVAL_POLICY);
23
+ expect(policy.sandbox).toBe(DEFAULT_SANDBOX);
24
+ expect(policy.warnings).toEqual([]);
25
+ });
26
+ it("should fall back to the default and warn on an unrecognized policy", () => {
27
+ const policy = resolveThreadPolicy({ CODEX_APPROVAL_POLICY: "yolo" });
28
+ expect(policy.approvalPolicy).toBe(DEFAULT_APPROVAL_POLICY);
29
+ expect(policy.warnings.join(" ")).toContain("CODEX_APPROVAL_POLICY");
30
+ });
31
+ it("should fall back to the default and warn on an unrecognized sandbox", () => {
32
+ const policy = resolveThreadPolicy({ CODEX_SANDBOX: "wide-open" });
33
+ expect(policy.sandbox).toBe(DEFAULT_SANDBOX);
34
+ expect(policy.warnings.join(" ")).toContain("CODEX_SANDBOX");
35
+ });
36
+ it("should warn that a 'never' policy keeps approvals away from the human", () => {
37
+ const policy = resolveThreadPolicy({ CODEX_APPROVAL_POLICY: "never" });
38
+ expect(policy.approvalPolicy).toBe("never");
39
+ expect(policy.warnings.join(" ")).toContain("never request approval");
40
+ });
41
+ it("should warn about a full-access sandbox", () => {
42
+ const policy = resolveThreadPolicy({ CODEX_SANDBOX: "danger-full-access" });
43
+ expect(policy.sandbox).toBe("danger-full-access");
44
+ expect(policy.warnings.join(" ")).toContain("removes the sandbox boundary");
45
+ });
46
+ it("should report both warnings when the pair fully bypasses review", () => {
47
+ const policy = resolveThreadPolicy({
48
+ CODEX_APPROVAL_POLICY: "never",
49
+ CODEX_SANDBOX: "danger-full-access",
50
+ });
51
+ expect(policy.warnings).toHaveLength(2);
52
+ });
53
+ });
54
+ describe("describeItem", () => {
55
+ it("should describe a command execution with its cwd", () => {
56
+ const d = describeItem({
57
+ id: "i1",
58
+ type: "commandExecution",
59
+ command: "npm test",
60
+ cwd: "/repo",
61
+ });
62
+ expect(d).toEqual({
63
+ title: "npm test",
64
+ inputPreview: "npm test\n(cwd: /repo)",
65
+ });
66
+ });
67
+ it("should describe a command execution without a cwd", () => {
68
+ const d = describeItem({ id: "i1", type: "commandExecution", command: "ls" });
69
+ expect(d?.inputPreview).toBe("ls");
70
+ });
71
+ it("should describe an MCP tool call as server.tool and expose the server", () => {
72
+ const d = describeItem({
73
+ id: "i2",
74
+ type: "mcpToolCall",
75
+ server: "agentrq-0cHdAEOUJvN",
76
+ tool: "reply",
77
+ arguments: { chatId: "c1" },
78
+ });
79
+ expect(d?.title).toBe("agentrq-0cHdAEOUJvN.reply");
80
+ expect(d?.server).toBe("agentrq-0cHdAEOUJvN");
81
+ expect(d?.inputPreview).toBe('{"chatId":"c1"}');
82
+ });
83
+ it("should describe a file change by path count and list the paths", () => {
84
+ const d = describeItem({
85
+ id: "i3",
86
+ type: "fileChange",
87
+ changes: [{ path: "/a.ts" }, { path: "/b.ts" }],
88
+ });
89
+ expect(d?.title).toBe("Edit 2 files");
90
+ expect(d?.inputPreview).toBe("/a.ts\n/b.ts");
91
+ });
92
+ it("should singularize a one-file change", () => {
93
+ const d = describeItem({ id: "i4", type: "fileChange", changes: [{ path: "/a.ts" }] });
94
+ expect(d?.title).toBe("Edit 1 file");
95
+ });
96
+ it("should still describe a file change with no readable paths", () => {
97
+ const d = describeItem({ id: "i5", type: "fileChange", changes: [] });
98
+ expect(d?.title).toBe("File change");
99
+ });
100
+ it("should ignore item types that are never approved", () => {
101
+ expect(describeItem({ id: "i6", type: "agentMessage", text: "hi" })).toBeUndefined();
102
+ expect(describeItem({ id: "i7", type: "reasoning" })).toBeUndefined();
103
+ });
104
+ it("should ignore a command execution with no command", () => {
105
+ expect(describeItem({ id: "i8", type: "commandExecution" })).toBeUndefined();
106
+ });
107
+ it("should handle malformed input", () => {
108
+ expect(describeItem(undefined)).toBeUndefined();
109
+ expect(describeItem(null)).toBeUndefined();
110
+ expect(describeItem("nope")).toBeUndefined();
111
+ });
112
+ });
113
+ describe("ThreadItemRegistry", () => {
114
+ it("should record and return a describable item", () => {
115
+ const r = new ThreadItemRegistry();
116
+ r.record({ id: "a", type: "commandExecution", command: "ls" });
117
+ expect(r.get("a")?.title).toBe("ls");
118
+ expect(r.size).toBe(1);
119
+ });
120
+ it("should not record items that cannot be described", () => {
121
+ const r = new ThreadItemRegistry();
122
+ r.record({ id: "a", type: "agentMessage", text: "hi" });
123
+ expect(r.size).toBe(0);
124
+ });
125
+ it("should ignore items without a usable id", () => {
126
+ const r = new ThreadItemRegistry();
127
+ r.record({ type: "commandExecution", command: "ls" });
128
+ r.record({ id: 42, type: "commandExecution", command: "ls" });
129
+ expect(r.size).toBe(0);
130
+ });
131
+ it("should return undefined for an unknown or non-string id", () => {
132
+ const r = new ThreadItemRegistry();
133
+ expect(r.get("missing")).toBeUndefined();
134
+ expect(r.get(undefined)).toBeUndefined();
135
+ expect(r.get(7)).toBeUndefined();
136
+ });
137
+ it("should forget an item so the map stays bounded", () => {
138
+ const r = new ThreadItemRegistry();
139
+ r.record({ id: "a", type: "commandExecution", command: "ls" });
140
+ r.forget("a");
141
+ expect(r.get("a")).toBeUndefined();
142
+ expect(r.size).toBe(0);
143
+ });
144
+ it("should clear every entry", () => {
145
+ const r = new ThreadItemRegistry();
146
+ r.record({ id: "a", type: "commandExecution", command: "ls" });
147
+ r.record({ id: "b", type: "commandExecution", command: "pwd" });
148
+ r.clear();
149
+ expect(r.size).toBe(0);
150
+ });
151
+ });
152
+ //# sourceMappingURL=approvals.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approvals.test.js","sourceRoot":"","sources":["../../src/__tests__/approvals.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,136 @@
1
+ import { describe, it, expect, vi, beforeEach } from "vitest";
2
+ import { resolveElicitation } from "../elicitation.js";
3
+ function textResult(text, isError = false) {
4
+ return { isError, content: [{ type: "text", text }] };
5
+ }
6
+ describe("resolveElicitation", () => {
7
+ let callTool;
8
+ let deps;
9
+ beforeEach(() => {
10
+ vi.spyOn(console, "error").mockImplementation(() => { });
11
+ callTool = vi.fn();
12
+ deps = { mcpBridge: { callTool }, resolveTaskId: () => "task-1" };
13
+ });
14
+ it("should delegate a form elicitation to the elicit tool with the thread's task", async () => {
15
+ callTool.mockResolvedValue(textResult(JSON.stringify({ action: "accept", content: { name: "mt" } })));
16
+ const result = await resolveElicitation({
17
+ serverName: "some-server",
18
+ threadId: "thr_1",
19
+ mode: "form",
20
+ message: "What is your name?",
21
+ requestedSchema: { type: "object", properties: {} },
22
+ }, deps);
23
+ expect(callTool).toHaveBeenCalledWith("elicit", {
24
+ taskId: "task-1",
25
+ message: "What is your name?",
26
+ mode: "form",
27
+ requestedSchema: { type: "object", properties: {} },
28
+ });
29
+ expect(result).toEqual({ action: "accept", content: { name: "mt" } });
30
+ });
31
+ it("should pass the url through for url-mode elicitations", async () => {
32
+ callTool.mockResolvedValue(textResult(JSON.stringify({ action: "accept" })));
33
+ await resolveElicitation({
34
+ serverName: "s",
35
+ threadId: "thr_1",
36
+ mode: "url",
37
+ message: "Authorize access",
38
+ url: "https://example.test/auth",
39
+ elicitationId: "e1",
40
+ }, deps);
41
+ expect(callTool).toHaveBeenCalledWith("elicit", {
42
+ taskId: "task-1",
43
+ message: "Authorize access",
44
+ mode: "url",
45
+ url: "https://example.test/auth",
46
+ });
47
+ });
48
+ it("should map a declined answer", async () => {
49
+ callTool.mockResolvedValue(textResult(JSON.stringify({ action: "decline" })));
50
+ const r = await resolveElicitation({ threadId: "t", mode: "form", message: "m" }, deps);
51
+ expect(r).toEqual({ action: "decline" });
52
+ });
53
+ it("should map an unrecognized action to cancel", async () => {
54
+ callTool.mockResolvedValue(textResult(JSON.stringify({ action: "whatever" })));
55
+ const r = await resolveElicitation({ threadId: "t", mode: "form", message: "m" }, deps);
56
+ expect(r).toEqual({ action: "cancel" });
57
+ });
58
+ it("should cancel an unsupported mode without calling the tool", async () => {
59
+ const r = await resolveElicitation({ threadId: "t", mode: "telepathy", message: "m" }, deps);
60
+ expect(r).toEqual({ action: "cancel" });
61
+ expect(callTool).not.toHaveBeenCalled();
62
+ });
63
+ it("should cancel when the elicit tool reports an error", async () => {
64
+ callTool.mockResolvedValue(textResult("boom", true));
65
+ const r = await resolveElicitation({ threadId: "t", mode: "form", message: "m" }, deps);
66
+ expect(r).toEqual({ action: "cancel" });
67
+ });
68
+ it("should cancel when the elicit tool returns no content", async () => {
69
+ callTool.mockResolvedValue({ isError: false, content: [] });
70
+ const r = await resolveElicitation({ threadId: "t", mode: "form", message: "m" }, deps);
71
+ expect(r).toEqual({ action: "cancel" });
72
+ });
73
+ it("should cancel when the elicit tool returns unparseable content", async () => {
74
+ callTool.mockResolvedValue(textResult("not json"));
75
+ const r = await resolveElicitation({ threadId: "t", mode: "form", message: "m" }, deps);
76
+ expect(r).toEqual({ action: "cancel" });
77
+ });
78
+ it("should cancel when the tool call throws", async () => {
79
+ callTool.mockRejectedValue(new Error("offline"));
80
+ const r = await resolveElicitation({ threadId: "t", mode: "form", message: "m" }, deps);
81
+ expect(r).toEqual({ action: "cancel" });
82
+ });
83
+ describe("when the thread has no task", () => {
84
+ beforeEach(() => {
85
+ deps.resolveTaskId = () => undefined;
86
+ });
87
+ it("should create an ongoing task and use it", async () => {
88
+ callTool.mockImplementation(async (name) => {
89
+ if (name === "createTask")
90
+ return textResult("Created task id=task-new");
91
+ if (name === "updateTaskStatus")
92
+ return textResult("ok");
93
+ return textResult(JSON.stringify({ action: "accept", content: { a: 1 } }));
94
+ });
95
+ const r = await resolveElicitation({ threadId: "unknown", mode: "form", message: "Pick one", requestedSchema: {} }, deps);
96
+ expect(callTool).toHaveBeenCalledWith("createTask", {
97
+ title: "Pick one",
98
+ body: "Pick one",
99
+ assignee: "human",
100
+ });
101
+ expect(callTool).toHaveBeenCalledWith("updateTaskStatus", {
102
+ taskId: "task-new",
103
+ status: "ongoing",
104
+ });
105
+ expect(callTool).toHaveBeenCalledWith("elicit", expect.objectContaining({ taskId: "task-new" }));
106
+ expect(r).toEqual({ action: "accept", content: { a: 1 } });
107
+ });
108
+ it("should truncate a long message into the task title", async () => {
109
+ const long = "x".repeat(200);
110
+ callTool.mockImplementation(async (name) => {
111
+ if (name === "createTask")
112
+ return textResult("id=t2");
113
+ if (name === "updateTaskStatus")
114
+ return textResult("ok");
115
+ return textResult(JSON.stringify({ action: "decline" }));
116
+ });
117
+ await resolveElicitation({ threadId: "u", mode: "form", message: long }, deps);
118
+ const call = callTool.mock.calls.find((c) => c[0] === "createTask");
119
+ expect(call?.[1].title).toHaveLength(80);
120
+ expect(call?.[1].title.endsWith("...")).toBe(true);
121
+ expect(call?.[1].body).toBe(long);
122
+ });
123
+ it("should cancel when the created task id cannot be parsed", async () => {
124
+ callTool.mockResolvedValue(textResult("something unexpected"));
125
+ const r = await resolveElicitation({ threadId: "u", mode: "form", message: "m" }, deps);
126
+ expect(r).toEqual({ action: "cancel" });
127
+ expect(callTool).not.toHaveBeenCalledWith("elicit", expect.anything());
128
+ });
129
+ it("should cancel when task creation throws", async () => {
130
+ callTool.mockRejectedValue(new Error("nope"));
131
+ const r = await resolveElicitation({ threadId: "u", mode: "form", message: "m" }, deps);
132
+ expect(r).toEqual({ action: "cancel" });
133
+ });
134
+ });
135
+ });
136
+ //# sourceMappingURL=elicitation.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"elicitation.test.js","sourceRoot":"","sources":["../../src/__tests__/elicitation.test.ts"],"names":[],"mappings":"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"}