@pablopunk/tau 0.0.0-stage → 0.1.1

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 (69) hide show
  1. package/dist/auth-storage-Dk3CUY3q.js +1814 -0
  2. package/dist/bin.js +23 -0
  3. package/dist/cli-entry-DcDpQ30L.js +13 -0
  4. package/dist/client-C91-b2CL.js +1 -0
  5. package/dist/client-y2WkNuZj.js +7977 -0
  6. package/dist/dist-BFP19NOO.js +432 -0
  7. package/dist/dist-Bh1bQHZA.js +38890 -0
  8. package/dist/dist-Cq73_r65.js +3 -0
  9. package/dist/esm-CMGh_WhC.js +9446 -0
  10. package/dist/execute-BeGXhU1O.js +1757 -0
  11. package/dist/fake-claude-connectors-DSP9UC8d.js +1 -0
  12. package/dist/fake-claude-connectors-sDLeP10T.js +107 -0
  13. package/dist/fake-claude-sdk-CvqW_1iQ.js +571 -0
  14. package/dist/fake-claude-thread-script-2iHHwUZM.js +48 -0
  15. package/dist/last-exit-write-ksHeHGrC.js +9 -0
  16. package/dist/latest-version-di9hD7cY.js +106 -0
  17. package/dist/lib-DIX7q_HJ.js +1460 -0
  18. package/dist/machines-behind-BjGgmSs_.js +257 -0
  19. package/dist/main-D-Tg9b5Y.js +1610 -0
  20. package/dist/manager-B_WHbb1U.js +589 -0
  21. package/dist/names-cTrEXB6w.js +35 -0
  22. package/dist/node-BpwblPFP.js +56269 -0
  23. package/dist/pdfjs-nTcHjDPT.js +69856 -0
  24. package/dist/photon_rs-DBr7W_rK.js +4252 -0
  25. package/dist/promise.try-CAAOYvMP.js +1426 -0
  26. package/dist/readability-DsDNO63a.js +1670 -0
  27. package/dist/real-deps-f96UmLBz.js +89 -0
  28. package/dist/rolldown-runtime-1p2KPIdQ.js +44 -0
  29. package/dist/runtime-i-oEtgAl.js +2721 -0
  30. package/dist/sdk-missing-CHbVbY1G.js +10 -0
  31. package/dist/sdk-port-BGw9ORUR.js +215 -0
  32. package/dist/serve-Cmy0rUWr.js +2932 -0
  33. package/dist/serve-Dmzn5V0l.js +1 -0
  34. package/dist/service-command-C74K0saj.js +34 -0
  35. package/dist/service-command-DqcstJ8e.js +1 -0
  36. package/dist/shell-CQa4e7rx.js +643 -0
  37. package/dist/skills/builtin/tau/SKILL.md +51 -0
  38. package/dist/src-DO9LUlhi.js +44088 -0
  39. package/dist/streamableHttp-BBaRYV9h.js +1 -0
  40. package/dist/streamableHttp-DPAoMlJd.js +1931 -0
  41. package/dist/tool-DBZK2lci.js +14335 -0
  42. package/dist/tool-server-BjP37EJg.js +40 -0
  43. package/dist/turndown.cjs-Bo1xLg2S.js +15620 -0
  44. package/dist/turndown.cjs-jpUF50AR.js +3 -0
  45. package/dist/types-C4M3CRp2.js +7592 -0
  46. package/dist/undici-8cI97lnP.js +27110 -0
  47. package/dist/wait-for-lock-B1Qx8GWg.js +1 -0
  48. package/dist/wait-for-lock-CrSl2mi1.js +25 -0
  49. package/dist/watchdog.js +47 -0
  50. package/dist/web/dist/assets/addon-fit-DIOBYJe3.js +1 -0
  51. package/dist/web/dist/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
  52. package/dist/web/dist/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
  53. package/dist/web/dist/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
  54. package/dist/web/dist/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
  55. package/dist/web/dist/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
  56. package/dist/web/dist/assets/index-BktLKZHR.js +108 -0
  57. package/dist/web/dist/assets/index-D_Aa3Oou.css +2 -0
  58. package/dist/web/dist/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
  59. package/dist/web/dist/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
  60. package/dist/web/dist/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
  61. package/dist/web/dist/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
  62. package/dist/web/dist/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
  63. package/dist/web/dist/assets/wght-DMLdVLkb.css +1 -0
  64. package/dist/web/dist/assets/xterm-BrP-ENHg.css +1 -0
  65. package/dist/web/dist/assets/xterm-CerOhKYV.js +16 -0
  66. package/dist/web/dist/favicon.svg +14 -0
  67. package/dist/web/dist/index.html +25 -0
  68. package/package.json +53 -4
  69. package/README.md +0 -3
@@ -0,0 +1 @@
1
+ export { t as FAKE_LINEAR, n as FAKE_NEEDS_AUTH, r as FAKE_SLACK } from "./fake-claude-connectors-sDLeP10T.js";
@@ -0,0 +1,107 @@
1
+ import { i as connectorServerOf, n as cliToolNameOf } from "./names-cTrEXB6w.js";
2
+ //#region ../core/src/claude-cli/testing/fake-claude-connectors.ts
3
+ const FAKE_LINEAR = {
4
+ name: "claude.ai Linear",
5
+ status: "connected",
6
+ tools: [
7
+ {
8
+ name: "list_teams",
9
+ readOnly: true
10
+ },
11
+ {
12
+ name: "get_issue",
13
+ readOnly: true
14
+ },
15
+ {
16
+ name: "save_comment",
17
+ readOnly: false
18
+ }
19
+ ]
20
+ };
21
+ const FAKE_SLACK = {
22
+ name: "claude.ai Slack",
23
+ status: "connected",
24
+ tools: [{
25
+ name: "slack_search_public",
26
+ readOnly: true
27
+ }, {
28
+ name: "slack_send_message",
29
+ readOnly: false
30
+ }]
31
+ };
32
+ const FAKE_NEEDS_AUTH = {
33
+ name: "claude.ai Notion",
34
+ status: "needs-auth",
35
+ tools: []
36
+ };
37
+ const connectorCliName = (server, tool) => cliToolNameOf({
38
+ server: connectorServerOf(server),
39
+ tool
40
+ });
41
+ const connectorsAreOpen = (options) => !options.strictMcpConfig && !options.settings.disableClaudeAiConnectors;
42
+ const matchesAllowed = (allowed, toolName) => allowed.endsWith("*") ? toolName.startsWith(allowed.slice(0, -1)) : allowed === toolName;
43
+ const isAllowedByList = (allowedTools, toolName) => allowedTools.some((allowed) => matchesAllowed(allowed, toolName));
44
+ const disabledServer = (server) => ({
45
+ ...server,
46
+ status: "disabled",
47
+ tools: []
48
+ });
49
+ function createFakeMcpState(input) {
50
+ const switchedOff = /* @__PURE__ */ new Set();
51
+ const { toggles } = input;
52
+ let polls = 0;
53
+ const stillPending = () => polls >= 1 && polls <= input.pendingPolls;
54
+ const tauServer = () => ({
55
+ name: "tau",
56
+ status: "connected",
57
+ source: "sdk",
58
+ error: null,
59
+ tools: input.tauTools().map((name) => ({
60
+ name,
61
+ readOnly: false
62
+ }))
63
+ });
64
+ const connectorServer = (server) => {
65
+ const status = {
66
+ name: server.name,
67
+ status: stillPending() ? "pending" : server.status,
68
+ source: server.source ?? "claudeai",
69
+ error: null,
70
+ tools: stillPending() ? [] : server.tools
71
+ };
72
+ return switchedOff.has(server.name) ? disabledServer(status) : status;
73
+ };
74
+ const statuses = () => [tauServer(), ...input.open ? input.connectors.map(connectorServer) : []];
75
+ const loadedConnectorTools = () => statuses().filter((server) => server.source !== "sdk" && server.status === "connected").flatMap((server) => server.tools.map((tool) => ({
76
+ server: server.name,
77
+ tool: tool.name
78
+ })));
79
+ return {
80
+ toggles,
81
+ control: {
82
+ async mcpServerStatus() {
83
+ polls += 1;
84
+ return statuses();
85
+ },
86
+ async toggleMcpServer(name, enabled) {
87
+ toggles.push({
88
+ name,
89
+ enabled
90
+ });
91
+ if (enabled) switchedOff.delete(name);
92
+ else switchedOff.add(name);
93
+ }
94
+ },
95
+ context: () => {
96
+ const loadedMcpToolCounts = {};
97
+ for (const { server } of loadedConnectorTools()) loadedMcpToolCounts[server] = (loadedMcpToolCounts[server] ?? 0) + 1;
98
+ return {
99
+ memoryFileCount: 0,
100
+ loadedMcpToolCounts
101
+ };
102
+ },
103
+ activeToolNames: () => loadedConnectorTools().map(({ server, tool }) => connectorCliName(server, tool))
104
+ };
105
+ }
106
+ //#endregion
107
+ export { connectorsAreOpen as a, connectorCliName as i, FAKE_NEEDS_AUTH as n, createFakeMcpState as o, FAKE_SLACK as r, isAllowedByList as s, FAKE_LINEAR as t };
@@ -0,0 +1,571 @@
1
+ import { t as TOOL_NAME_PREFIX } from "./tool-server-BjP37EJg.js";
2
+ import { a as connectorsAreOpen, i as connectorCliName, o as createFakeMcpState, s as isAllowedByList } from "./fake-claude-connectors-sDLeP10T.js";
3
+ //#region ../core/src/claude-cli/testing/fake-claude-events.ts
4
+ const FAKE_USAGE = {
5
+ input_tokens: 10,
6
+ output_tokens: 5,
7
+ cache_read_input_tokens: 0,
8
+ cache_creation_input_tokens: 0
9
+ };
10
+ const FAKE_CONTEXT_WINDOW = 1e6;
11
+ function createMessageIds() {
12
+ let message = 0;
13
+ let uuid = 0;
14
+ let tool = 0;
15
+ return {
16
+ messageId: () => `msg_fake_${++message}`,
17
+ uuid: () => `uuid-fake-${++uuid}`,
18
+ toolUseId: () => `toolu_fake_${++tool}`
19
+ };
20
+ }
21
+ const streamEvent = (sessionId, event) => ({
22
+ type: "stream_event",
23
+ session_id: sessionId,
24
+ event
25
+ });
26
+ const deltaOf = (block) => {
27
+ if (block.type === "text") return {
28
+ type: "text_delta",
29
+ text: block.text
30
+ };
31
+ if (block.type === "thinking") return {
32
+ type: "thinking_delta",
33
+ thinking: block.thinking
34
+ };
35
+ return {
36
+ type: "input_json_delta",
37
+ partial_json: JSON.stringify(block.input)
38
+ };
39
+ };
40
+ const startOf = (block) => block.type === "tool_use" ? {
41
+ ...block,
42
+ input: {}
43
+ } : {
44
+ ...block,
45
+ text: "",
46
+ thinking: ""
47
+ };
48
+ /** Stream events, then one `assistant` message per content block, as the SDK emits them. */
49
+ function apiMessageEvents(sessionId, message, ids) {
50
+ const events = [streamEvent(sessionId, {
51
+ type: "message_start",
52
+ message: {
53
+ id: message.id,
54
+ model: message.model,
55
+ usage: FAKE_USAGE
56
+ }
57
+ })];
58
+ message.blocks.forEach((block, index) => {
59
+ events.push(streamEvent(sessionId, {
60
+ type: "content_block_start",
61
+ index,
62
+ content_block: startOf(block)
63
+ }));
64
+ events.push(streamEvent(sessionId, {
65
+ type: "content_block_delta",
66
+ index,
67
+ delta: deltaOf(block)
68
+ }));
69
+ events.push(streamEvent(sessionId, {
70
+ type: "content_block_stop",
71
+ index
72
+ }));
73
+ });
74
+ events.push(streamEvent(sessionId, {
75
+ type: "message_delta",
76
+ delta: { stop_reason: message.stopReason },
77
+ usage: FAKE_USAGE
78
+ }), streamEvent(sessionId, { type: "message_stop" }));
79
+ for (const block of message.blocks) events.push({
80
+ type: "assistant",
81
+ uuid: ids.uuid(),
82
+ session_id: sessionId,
83
+ ...message.error && { error: message.error },
84
+ message: {
85
+ id: message.id,
86
+ model: message.model,
87
+ role: "assistant",
88
+ content: [block],
89
+ stop_reason: message.stopReason,
90
+ usage: FAKE_USAGE
91
+ }
92
+ });
93
+ return events;
94
+ }
95
+ const rateLimitEvent = (sessionId, limit, uuid) => ({
96
+ type: "rate_limit_event",
97
+ uuid,
98
+ session_id: sessionId,
99
+ rate_limit_info: {
100
+ status: limit.status,
101
+ rateLimitType: "five_hour",
102
+ utilization: limit.fiveHour,
103
+ resetsAt: limit.resetsAt,
104
+ unifiedWindows: { five_hour: { utilization: limit.fiveHour } }
105
+ }
106
+ });
107
+ const toolResultEvent = (sessionId, toolUseId, text, isError, uuid) => ({
108
+ type: "user",
109
+ uuid,
110
+ session_id: sessionId,
111
+ message: {
112
+ role: "user",
113
+ content: [{
114
+ type: "tool_result",
115
+ tool_use_id: toolUseId,
116
+ content: text,
117
+ is_error: isError
118
+ }]
119
+ }
120
+ });
121
+ const resultEvent = (sessionId, model, outcome, uuid) => ({
122
+ type: "result",
123
+ uuid,
124
+ session_id: sessionId,
125
+ subtype: outcome === "success" ? "success" : "error_during_execution",
126
+ is_error: outcome !== "success",
127
+ ...outcome === "interrupted" && { terminal_reason: "aborted_tools" },
128
+ usage: FAKE_USAGE,
129
+ modelUsage: { [model]: {
130
+ ...FAKE_USAGE,
131
+ contextWindow: FAKE_CONTEXT_WINDOW,
132
+ costUSD: 0
133
+ } }
134
+ });
135
+ const initEvent = (sessionId, model, toolNames, apiKeySource) => ({
136
+ type: "system",
137
+ subtype: "init",
138
+ session_id: sessionId,
139
+ model,
140
+ tools: toolNames,
141
+ mcp_servers: [{
142
+ name: "tau",
143
+ status: "connected"
144
+ }],
145
+ apiKeySource,
146
+ claude_code_version: "0.0.0-fake"
147
+ });
148
+ //#endregion
149
+ //#region ../core/src/claude-cli/testing/fake-claude-models.ts
150
+ const STANDARD_EFFORT = [
151
+ "low",
152
+ "medium",
153
+ "high",
154
+ "xhigh"
155
+ ];
156
+ const NO_EFFORT = [];
157
+ const row = (value, resolvedModel, displayName, supportedEffortLevels = STANDARD_EFFORT) => ({
158
+ value,
159
+ resolvedModel,
160
+ displayName,
161
+ description: `${displayName} (fake)`,
162
+ supportedEffortLevels,
163
+ supportsThinkingOff: supportedEffortLevels.length === 0 || value === "haiku"
164
+ });
165
+ /** The 14 rows the spike saw from `supportedModels()` on CLI 2.1.302. */
166
+ const FAKE_CLAUDE_MODELS = [
167
+ row("default", "claude-opus-5-5", "Default (Opus 5.5)"),
168
+ row("opus", "claude-opus-5-5", "Opus 5.5"),
169
+ row("fable", "claude-fable-5-1", "Fable 5.1"),
170
+ row("sonnet", "claude-sonnet-5-5", "Sonnet 5.5"),
171
+ row("haiku", "claude-haiku-5-5", "Haiku 5.5", NO_EFFORT),
172
+ row("claude-haiku-4-5-20251001", "claude-haiku-4-5-20251001", "Haiku 4.5", NO_EFFORT),
173
+ row("claude-sonnet-5", "claude-sonnet-5", "Sonnet 5"),
174
+ row("claude-opus-5", "claude-opus-5", "Opus 5"),
175
+ row("claude-fable-5", "claude-fable-5", "Fable 5"),
176
+ row("claude-opus-4-8", "claude-opus-4-8", "Opus 4.8"),
177
+ row("claude-opus-4-7", "claude-opus-4-7", "Opus 4.7"),
178
+ row("claude-opus-4-6", "claude-opus-4-6", "Opus 4.6"),
179
+ row("claude-sonnet-4-6", "claude-sonnet-4-6", "Sonnet 4.6"),
180
+ row("claude-mythos-5-1", "claude-mythos-5-1", "Mythos 5.1")
181
+ ];
182
+ //#endregion
183
+ //#region ../core/src/claude-cli/testing/message-channel.ts
184
+ function createMessageChannel() {
185
+ const queue = [];
186
+ let ended = false;
187
+ let wake;
188
+ async function* iterate() {
189
+ while (true) {
190
+ while (queue.length === 0 && !ended) await new Promise((resolve) => wake = resolve);
191
+ const next = queue.shift();
192
+ if (next === void 0) return;
193
+ yield next;
194
+ }
195
+ }
196
+ return {
197
+ [Symbol.asyncIterator]: iterate,
198
+ push(value) {
199
+ if (ended) return;
200
+ queue.push(value);
201
+ wake?.();
202
+ },
203
+ end() {
204
+ ended = true;
205
+ wake?.();
206
+ }
207
+ };
208
+ }
209
+ //#endregion
210
+ //#region ../core/src/claude-cli/testing/fake-claude-query.ts
211
+ const INTERRUPTED_TEXT = "The tool call was interrupted by the user.";
212
+ const textOfInput = (message) => typeof message.message.content === "string" ? message.message.content : message.message.content.map((block) => block.type === "text" ? block.text : "[image]").join("\n");
213
+ const resolvedModel = (model) => FAKE_CLAUDE_MODELS.find((row) => row.value === model)?.resolvedModel ?? model;
214
+ const textOfResult = (result) => result.content.map((block) => block.type === "text" ? block.text : "[image]").join("\n");
215
+ const nextTick = () => new Promise((resolve) => setImmediate(resolve));
216
+ const sleepMs = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
217
+ const deniedText = (toolName) => `Permission to use ${toolName} has been denied.`;
218
+ const unavailableText = (toolName) => `Error: No such tool available: ${toolName}`;
219
+ const cliNameOf = (use) => use.connector ? connectorCliName(use.connector.server, use.name) : `${TOOL_NAME_PREFIX}${use.name}`;
220
+ function createFakeQuery(deps) {
221
+ const { options, record, script, ids } = deps;
222
+ const out = createMessageChannel();
223
+ const pending = [];
224
+ let model = options.model;
225
+ let turnIndex = 0;
226
+ let initSent = false;
227
+ let inputDone = false;
228
+ let wake;
229
+ let interruptTurn;
230
+ let turnInterrupted;
231
+ const mcp = createFakeMcpState({
232
+ open: connectorsAreOpen(options),
233
+ connectors: deps.connectors,
234
+ tauTools: () => (options.toolHost?.listTools() ?? []).map((tool) => `${TOOL_NAME_PREFIX}${tool.name}`),
235
+ pendingPolls: deps.pendingPolls,
236
+ toggles: record.toggles
237
+ });
238
+ const emit = (message) => out.push(message);
239
+ const sessionId = () => record.sessionId;
240
+ async function readInput() {
241
+ if (typeof options.prompt === "string") {
242
+ pending.push(options.prompt);
243
+ record.inputs.push(options.prompt);
244
+ inputDone = true;
245
+ return;
246
+ }
247
+ for await (const message of options.prompt) {
248
+ const text = textOfInput(message);
249
+ record.inputs.push(text);
250
+ pending.push(text);
251
+ wake?.();
252
+ }
253
+ inputDone = true;
254
+ }
255
+ const emitApiMessage = (blocks, stopReason, error) => {
256
+ const message = {
257
+ id: ids.messageId(),
258
+ model: resolvedModel(model),
259
+ blocks,
260
+ stopReason,
261
+ error
262
+ };
263
+ for (const event of apiMessageEvents(sessionId(), message, ids)) emit(event);
264
+ };
265
+ const emitResult = (outcome) => emit(resultEvent(sessionId(), resolvedModel(model), outcome, ids.uuid()));
266
+ function foldPending() {
267
+ if (pending.length === 0) return;
268
+ record.folded.push({
269
+ turnIndex,
270
+ texts: pending.splice(0)
271
+ });
272
+ }
273
+ async function runTool(use, toolUseId) {
274
+ const host = options.toolHost;
275
+ if (!host) throw new Error("The fake SDK got a tool call but no tool host.");
276
+ const args = use.arguments ?? {};
277
+ record.toolCalls.push({
278
+ name: use.name,
279
+ toolUseId,
280
+ arguments: args
281
+ });
282
+ const call = host.callTool({
283
+ name: use.name,
284
+ arguments: args,
285
+ toolUseId
286
+ });
287
+ return turnInterrupted ? Promise.race([call, turnInterrupted]) : call;
288
+ }
289
+ async function askPermission(use, toolName, toolUseId) {
290
+ if (isAllowedByList(options.allowedTools, toolName)) return {
291
+ behavior: "allow",
292
+ updatedInput: use.arguments ?? {}
293
+ };
294
+ if (!options.canUseTool || options.permissionMode === "dontAsk") return {
295
+ behavior: "deny",
296
+ message: deniedText(toolName)
297
+ };
298
+ const controller = new AbortController();
299
+ const asked = options.canUseTool({
300
+ toolName,
301
+ input: use.arguments ?? {},
302
+ toolUseId,
303
+ signal: controller.signal,
304
+ mcpServer: {
305
+ name: use.connector?.server ?? "",
306
+ source: "claudeai"
307
+ }
308
+ });
309
+ const decision = await Promise.race([asked, turnInterrupted ?? asked]);
310
+ const settled = decision === "interrupted" ? "aborted" : decision.behavior;
311
+ record.permissionRequests.push({
312
+ toolName,
313
+ toolUseId,
314
+ decision: settled
315
+ });
316
+ if (decision === "interrupted") controller.abort();
317
+ return decision;
318
+ }
319
+ async function runConnector(use, toolUseId) {
320
+ const run = use.connector;
321
+ if (!run) return "done";
322
+ const toolName = cliNameOf(use);
323
+ const call = {
324
+ toolName,
325
+ toolUseId,
326
+ ran: false
327
+ };
328
+ record.connectorCalls.push(call);
329
+ if (!mcp.activeToolNames().includes(toolName)) {
330
+ emitToolResult(toolUseId, unavailableText(toolName), true);
331
+ return "done";
332
+ }
333
+ const decision = await askPermission(use, toolName, toolUseId);
334
+ if (decision === "interrupted") return "interrupted";
335
+ if (decision.behavior === "deny") {
336
+ emitToolResult(toolUseId, decision.message, true);
337
+ return "done";
338
+ }
339
+ if (await Promise.race([sleepMs(run.delayMs ?? 0), turnInterrupted ?? sleepMs(0)]) === "interrupted") return "interrupted";
340
+ call.ran = true;
341
+ emitToolResult(toolUseId, run.result, run.isError ?? false);
342
+ return "done";
343
+ }
344
+ async function runTauTool(use, toolUseId) {
345
+ const result = await runTool(use, toolUseId);
346
+ if (result === "interrupted") return "interrupted";
347
+ emitToolResult(toolUseId, textOfResult(result), result.isError);
348
+ return "done";
349
+ }
350
+ function emitToolResult(toolUseId, text, isError) {
351
+ record.toolResults.push({
352
+ toolUseId,
353
+ text,
354
+ isError
355
+ });
356
+ emit(toolResultEvent(sessionId(), toolUseId, text, isError, ids.uuid()));
357
+ }
358
+ async function runToolsStep(step) {
359
+ const uses = step.calls.map((call) => ({
360
+ call,
361
+ toolUseId: ids.toolUseId()
362
+ }));
363
+ const blocks = uses.map(({ call, toolUseId }) => ({
364
+ type: "tool_use",
365
+ id: toolUseId,
366
+ name: cliNameOf(call),
367
+ input: call.arguments ?? {}
368
+ }));
369
+ emitApiMessage([...step.text ? [{
370
+ type: "text",
371
+ text: step.text
372
+ }] : [], ...blocks], "tool_use");
373
+ for (const [index, { call, toolUseId }] of uses.entries()) if ((call.connector ? await runConnector(call, toolUseId) : await runTauTool(call, toolUseId)) === "interrupted") {
374
+ for (const open of uses.slice(index)) emitToolResult(open.toolUseId, INTERRUPTED_TEXT, true);
375
+ return "interrupted";
376
+ }
377
+ return "continue";
378
+ }
379
+ async function runStep(step) {
380
+ if (step.kind === "rateLimit") {
381
+ emit(rateLimitEvent(sessionId(), step.limit, ids.uuid()));
382
+ return "continue";
383
+ }
384
+ if (step.kind === "text") {
385
+ const thinking = step.thinking ? [{
386
+ type: "thinking",
387
+ thinking: step.thinking
388
+ }] : [];
389
+ emitApiMessage([...thinking, {
390
+ type: "text",
391
+ text: step.text
392
+ }], "end_turn");
393
+ emitResult("success");
394
+ return "ended";
395
+ }
396
+ if (step.kind === "error") {
397
+ emitApiMessage([{
398
+ type: "text",
399
+ text: step.text ?? step.code
400
+ }], "end_turn", step.code);
401
+ emitResult("error");
402
+ return "ended";
403
+ }
404
+ return runToolsStep(step);
405
+ }
406
+ async function runTurn(firstUserText) {
407
+ turnInterrupted = new Promise((resolve) => {
408
+ interruptTurn = () => resolve("interrupted");
409
+ });
410
+ if (!initSent) {
411
+ initSent = true;
412
+ const names = [...(options.toolHost?.listTools() ?? []).map((tool) => `${TOOL_NAME_PREFIX}${tool.name}`), ...mcp.activeToolNames()];
413
+ emit(initEvent(sessionId(), resolvedModel(model), names, deps.apiKeySource));
414
+ }
415
+ const steps = script(turnIndex, firstUserText, options.toolHost !== void 0);
416
+ for (const step of steps) {
417
+ await nextTick();
418
+ const outcome = await runStep(step);
419
+ if (outcome === "interrupted") return void emitResult("interrupted");
420
+ if (outcome === "ended") return;
421
+ foldPending();
422
+ }
423
+ emitResult("success");
424
+ }
425
+ async function drive() {
426
+ while (!record.closed) {
427
+ while (pending.length === 0 && !record.closed && !inputDone) await new Promise((resolve) => wake = resolve);
428
+ const first = pending.shift();
429
+ if (first === void 0) return;
430
+ await runTurn(first);
431
+ turnIndex += 1;
432
+ interruptTurn = void 0;
433
+ }
434
+ }
435
+ readInput().finally(() => wake?.());
436
+ drive().finally(() => out.end());
437
+ return {
438
+ [Symbol.asyncIterator]: () => out[Symbol.asyncIterator](),
439
+ async interrupt() {
440
+ record.interrupts += 1;
441
+ interruptTurn?.();
442
+ },
443
+ ...mcp.control,
444
+ async setModel(next) {
445
+ record.models.push(next);
446
+ model = next;
447
+ },
448
+ async applyFlagSettings(settings) {
449
+ record.flags.push({ ...settings });
450
+ },
451
+ async isAutoCompactEnabled() {
452
+ return options.settings.autoCompactEnabled !== false;
453
+ },
454
+ close() {
455
+ record.closed = true;
456
+ wake?.();
457
+ interruptTurn?.();
458
+ out.end();
459
+ }
460
+ };
461
+ }
462
+ //#endregion
463
+ //#region ../core/src/claude-cli/testing/fake-claude-script.ts
464
+ const sayOk = () => [{
465
+ kind: "text",
466
+ text: "ok"
467
+ }];
468
+ //#endregion
469
+ //#region ../core/src/claude-cli/testing/fake-claude-sdk.ts
470
+ const FAKE_LOGGED_IN = {
471
+ loggedIn: true,
472
+ authMethod: "claude.ai",
473
+ subscriptionType: "team",
474
+ orgName: "Fake Org"
475
+ };
476
+ function createFakeClaudeSdk(options = {}) {
477
+ const queries = [];
478
+ const deletedSessions = [];
479
+ const ids = createMessageIds();
480
+ let script = options.script ?? sayOk;
481
+ let auth = options.auth ?? FAKE_LOGGED_IN;
482
+ let sessions = 0;
483
+ let loads = 0;
484
+ const probes = [];
485
+ const connectors = options.connectors ?? [];
486
+ const pendingPolls = options.pendingPolls ?? 0;
487
+ const startProbe = (probeOptions = {}) => {
488
+ probes.push({ settingSources: probeOptions.settingSources ?? [] });
489
+ const mcp = createFakeMcpState({
490
+ open: true,
491
+ connectors,
492
+ tauTools: () => [],
493
+ pendingPolls,
494
+ toggles: []
495
+ });
496
+ return {
497
+ ...mcp.control,
498
+ contextSummary: async () => mcp.context(),
499
+ close: () => void 0
500
+ };
501
+ };
502
+ const sessionFor = (query) => query.resume && !query.forkSession ? query.resume : `fake-session-${++sessions}`;
503
+ const port = {
504
+ async authStatus() {
505
+ if (auth instanceof Error) throw auth;
506
+ return auth;
507
+ },
508
+ async accountInfo() {
509
+ return options.account ?? {
510
+ organization: "Fake Org",
511
+ subscriptionType: "Claude Team"
512
+ };
513
+ },
514
+ async supportedModels() {
515
+ return options.models ?? FAKE_CLAUDE_MODELS;
516
+ },
517
+ async bundledCliVersion() {
518
+ return options.bundledCliVersion ?? "0.0.0-fake";
519
+ },
520
+ startProbe,
521
+ startQuery(queryOptions) {
522
+ const record = {
523
+ options: queryOptions,
524
+ sessionId: sessionFor(queryOptions),
525
+ inputs: [],
526
+ folded: [],
527
+ toolCalls: [],
528
+ toolResults: [],
529
+ models: [],
530
+ flags: [],
531
+ interrupts: 0,
532
+ closed: false,
533
+ permissionRequests: [],
534
+ connectorCalls: [],
535
+ toggles: []
536
+ };
537
+ queries.push(record);
538
+ return createFakeQuery({
539
+ options: queryOptions,
540
+ record,
541
+ script: (turn, text, hasTools) => script(turn, text, hasTools),
542
+ ids,
543
+ apiKeySource: options.apiKeySource ?? "none",
544
+ connectors,
545
+ pendingPolls
546
+ });
547
+ },
548
+ async deleteSession(sessionId) {
549
+ deletedSessions.push(sessionId);
550
+ }
551
+ };
552
+ return {
553
+ port,
554
+ queries,
555
+ deletedSessions,
556
+ probes,
557
+ loadCount: () => loads,
558
+ async load() {
559
+ loads += 1;
560
+ return port;
561
+ },
562
+ setScript(next) {
563
+ script = next;
564
+ },
565
+ setAuth(next) {
566
+ auth = next;
567
+ }
568
+ };
569
+ }
570
+ //#endregion
571
+ export { FAKE_LOGGED_IN, createFakeClaudeSdk };