@xdevops/issue-auto-finish 1.0.87 → 1.0.89

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 (134) hide show
  1. package/dist/{AIRunnerRegistry-II3WWSFN.js → AIRunnerRegistry-CFDNWSXC.js} +6 -3
  2. package/dist/{LockNote-Z2CLDZNN.js → LockNote-W2JNVMW7.js} +3 -3
  3. package/dist/PtyRunner-NYASBTRP.js +33 -0
  4. package/dist/SdkRunner-U2OTOMZU.js +9 -0
  5. package/dist/ai-runner/AIRunner.d.ts +19 -1
  6. package/dist/ai-runner/AIRunner.d.ts.map +1 -1
  7. package/dist/ai-runner/AIRunnerRegistry.d.ts +8 -0
  8. package/dist/ai-runner/AIRunnerRegistry.d.ts.map +1 -1
  9. package/dist/ai-runner/PlanFileResolver.d.ts +53 -0
  10. package/dist/ai-runner/PlanFileResolver.d.ts.map +1 -0
  11. package/dist/ai-runner/PtyRunner.d.ts +45 -4
  12. package/dist/ai-runner/PtyRunner.d.ts.map +1 -1
  13. package/dist/ai-runner/SdkRunner.d.ts +22 -0
  14. package/dist/ai-runner/SdkRunner.d.ts.map +1 -0
  15. package/dist/ai-runner/index.d.ts +5 -2
  16. package/dist/ai-runner/index.d.ts.map +1 -1
  17. package/dist/ai-runner/sdk/ClaudeCodeSDK.d.ts +37 -0
  18. package/dist/ai-runner/sdk/ClaudeCodeSDK.d.ts.map +1 -0
  19. package/dist/ai-runner/sdk/Stream.d.ts +22 -0
  20. package/dist/ai-runner/sdk/Stream.d.ts.map +1 -0
  21. package/dist/ai-runner/sdk/types.d.ts +146 -0
  22. package/dist/ai-runner/sdk/types.d.ts.map +1 -0
  23. package/dist/{ai-runner-HLA44WI6.js → ai-runner-TOHVJJ76.js} +14 -5
  24. package/dist/{analyze-ZIXNC5GN.js → analyze-DBH4K3J7.js} +8 -6
  25. package/dist/{analyze-ZIXNC5GN.js.map → analyze-DBH4K3J7.js.map} +1 -1
  26. package/dist/{braindump-56WAY2RD.js → braindump-RYI4BGMG.js} +11 -9
  27. package/dist/{braindump-56WAY2RD.js.map → braindump-RYI4BGMG.js.map} +1 -1
  28. package/dist/{chunk-AVGZH64A.js → chunk-2RWGZPNF.js} +4 -1
  29. package/dist/chunk-2RWGZPNF.js.map +1 -0
  30. package/dist/chunk-4XMYOXGZ.js +1153 -0
  31. package/dist/chunk-4XMYOXGZ.js.map +1 -0
  32. package/dist/{chunk-UBQLXQ7I.js → chunk-5JBADEKR.js} +7 -7
  33. package/dist/{chunk-M5C2WILQ.js → chunk-5M5SB6ZA.js} +7 -5
  34. package/dist/{chunk-M5C2WILQ.js.map → chunk-5M5SB6ZA.js.map} +1 -1
  35. package/dist/{chunk-HDFNMVRQ.js → chunk-DVNAH2GV.js} +2 -2
  36. package/dist/{chunk-GXFG4JU6.js → chunk-EU4XFZ2T.js} +2 -2
  37. package/dist/{chunk-NZHKAPU6.js → chunk-FJTZKAJA.js} +9 -3
  38. package/dist/chunk-FJTZKAJA.js.map +1 -0
  39. package/dist/chunk-G7QI5WDI.js +14 -0
  40. package/dist/chunk-G7QI5WDI.js.map +1 -0
  41. package/dist/{chunk-2YQHKXLL.js → chunk-GPZX4DSY.js} +22 -6
  42. package/dist/chunk-GPZX4DSY.js.map +1 -0
  43. package/dist/{chunk-IP3QTP5A.js → chunk-IWSMQXBL.js} +189 -48
  44. package/dist/chunk-IWSMQXBL.js.map +1 -0
  45. package/dist/{chunk-O3WEV5W3.js → chunk-JMACM7AJ.js} +47 -9
  46. package/dist/chunk-JMACM7AJ.js.map +1 -0
  47. package/dist/chunk-MSL7ROVK.js +1 -0
  48. package/dist/{chunk-YCYVNRLF.js → chunk-OBGEEGQ3.js} +61 -19
  49. package/dist/chunk-OBGEEGQ3.js.map +1 -0
  50. package/dist/chunk-R32Q3RGK.js +666 -0
  51. package/dist/chunk-R32Q3RGK.js.map +1 -0
  52. package/dist/{chunk-SAMTXC4A.js → chunk-TFEPHOVE.js} +12 -17
  53. package/dist/chunk-TFEPHOVE.js.map +1 -0
  54. package/dist/{chunk-QZZGIZWC.js → chunk-XSX3PGQW.js} +63 -20
  55. package/dist/chunk-XSX3PGQW.js.map +1 -0
  56. package/dist/{chunk-2MESXJEZ.js → chunk-YNRKPQLS.js} +3 -3
  57. package/dist/cli/setup/PreflightChecker.d.ts +1 -0
  58. package/dist/cli/setup/PreflightChecker.d.ts.map +1 -1
  59. package/dist/cli/setup/env-metadata.d.ts.map +1 -1
  60. package/dist/cli.js +10 -9
  61. package/dist/cli.js.map +1 -1
  62. package/dist/{config-WTRSZLOC.js → config-23TBYFP5.js} +5 -4
  63. package/dist/config-schema.d.ts +6 -0
  64. package/dist/config-schema.d.ts.map +1 -1
  65. package/dist/config.d.ts +6 -0
  66. package/dist/config.d.ts.map +1 -1
  67. package/dist/{doctor-37JNBGDN.js → doctor-ZG3DO7J5.js} +3 -3
  68. package/dist/errors/AIExecutionError.d.ts +3 -0
  69. package/dist/errors/AIExecutionError.d.ts.map +1 -1
  70. package/dist/{errors-S3BWYA4I.js → errors-J3ZRP66W.js} +2 -2
  71. package/dist/events/EventBus.d.ts +1 -1
  72. package/dist/events/EventBus.d.ts.map +1 -1
  73. package/dist/i18n/locales/en.d.ts.map +1 -1
  74. package/dist/i18n/locales/zh-CN.d.ts.map +1 -1
  75. package/dist/index.d.ts.map +1 -1
  76. package/dist/index.js +16 -14
  77. package/dist/{init-QQDXGTPB.js → init-37DLQ5AJ.js} +9 -8
  78. package/dist/{init-QQDXGTPB.js.map → init-37DLQ5AJ.js.map} +1 -1
  79. package/dist/lib.js +10 -8
  80. package/dist/lib.js.map +1 -1
  81. package/dist/orchestrator/PendingDialogStore.d.ts +12 -0
  82. package/dist/orchestrator/PendingDialogStore.d.ts.map +1 -0
  83. package/dist/orchestrator/steps/FailureHandler.d.ts.map +1 -1
  84. package/dist/orchestrator/steps/PhaseLoopStep.d.ts.map +1 -1
  85. package/dist/persistence/PlanPersistence.d.ts +5 -0
  86. package/dist/persistence/PlanPersistence.d.ts.map +1 -1
  87. package/dist/persistence/TodolistExtractor.d.ts +31 -0
  88. package/dist/persistence/TodolistExtractor.d.ts.map +1 -0
  89. package/dist/phases/BasePhase.d.ts.map +1 -1
  90. package/dist/phases/PhaseOutcome.d.ts +2 -0
  91. package/dist/phases/PhaseOutcome.d.ts.map +1 -1
  92. package/dist/phases/PlanPhase.d.ts.map +1 -1
  93. package/dist/prompts/templates.d.ts +2 -2
  94. package/dist/prompts/templates.d.ts.map +1 -1
  95. package/dist/{restart-BMILTP5X.js → restart-C7QBXT44.js} +9 -8
  96. package/dist/{restart-BMILTP5X.js.map → restart-C7QBXT44.js.map} +1 -1
  97. package/dist/run.js +16 -14
  98. package/dist/run.js.map +1 -1
  99. package/dist/start-66JO56AW.js +16 -0
  100. package/dist/start-66JO56AW.js.map +1 -0
  101. package/dist/tracker/IssueTracker.d.ts +6 -0
  102. package/dist/tracker/IssueTracker.d.ts.map +1 -1
  103. package/dist/web/routes/api.d.ts.map +1 -1
  104. package/package.json +5 -1
  105. package/src/web/frontend/dist/assets/index-DJzC2saL.css +1 -0
  106. package/src/web/frontend/dist/assets/{index-D_oTMuJU.js → index-Mnu8M3ww.js} +57 -57
  107. package/src/web/frontend/dist/index.html +2 -2
  108. package/dist/PtyRunner-6UGI5STW.js +0 -22
  109. package/dist/chunk-2YQHKXLL.js.map +0 -1
  110. package/dist/chunk-AVGZH64A.js.map +0 -1
  111. package/dist/chunk-IP3QTP5A.js.map +0 -1
  112. package/dist/chunk-NZHKAPU6.js.map +0 -1
  113. package/dist/chunk-O3WEV5W3.js.map +0 -1
  114. package/dist/chunk-QZZGIZWC.js.map +0 -1
  115. package/dist/chunk-SAMTXC4A.js.map +0 -1
  116. package/dist/chunk-U237JSLB.js +0 -1
  117. package/dist/chunk-U6GWFTKA.js +0 -657
  118. package/dist/chunk-U6GWFTKA.js.map +0 -1
  119. package/dist/chunk-YCYVNRLF.js.map +0 -1
  120. package/dist/start-6QRW6IJI.js +0 -15
  121. package/src/web/frontend/dist/assets/index-COYziOhv.css +0 -1
  122. /package/dist/{AIRunnerRegistry-II3WWSFN.js.map → AIRunnerRegistry-CFDNWSXC.js.map} +0 -0
  123. /package/dist/{LockNote-Z2CLDZNN.js.map → LockNote-W2JNVMW7.js.map} +0 -0
  124. /package/dist/{PtyRunner-6UGI5STW.js.map → PtyRunner-NYASBTRP.js.map} +0 -0
  125. /package/dist/{ai-runner-HLA44WI6.js.map → SdkRunner-U2OTOMZU.js.map} +0 -0
  126. /package/dist/{chunk-U237JSLB.js.map → ai-runner-TOHVJJ76.js.map} +0 -0
  127. /package/dist/{chunk-UBQLXQ7I.js.map → chunk-5JBADEKR.js.map} +0 -0
  128. /package/dist/{chunk-HDFNMVRQ.js.map → chunk-DVNAH2GV.js.map} +0 -0
  129. /package/dist/{chunk-GXFG4JU6.js.map → chunk-EU4XFZ2T.js.map} +0 -0
  130. /package/dist/{config-WTRSZLOC.js.map → chunk-MSL7ROVK.js.map} +0 -0
  131. /package/dist/{chunk-2MESXJEZ.js.map → chunk-YNRKPQLS.js.map} +0 -0
  132. /package/dist/{errors-S3BWYA4I.js.map → config-23TBYFP5.js.map} +0 -0
  133. /package/dist/{doctor-37JNBGDN.js.map → doctor-ZG3DO7J5.js.map} +0 -0
  134. /package/dist/{start-6QRW6IJI.js.map → errors-J3ZRP66W.js.map} +0 -0
@@ -0,0 +1,666 @@
1
+ import {
2
+ isShuttingDown
3
+ } from "./chunk-G7QI5WDI.js";
4
+ import {
5
+ logger
6
+ } from "./chunk-GF2RRYHB.js";
7
+
8
+ // src/ai-runner/SdkRunner.ts
9
+ import fs from "fs";
10
+ import path from "path";
11
+
12
+ // src/ai-runner/sdk/ClaudeCodeSDK.ts
13
+ import { spawn } from "child_process";
14
+ import { createInterface } from "readline";
15
+
16
+ // src/ai-runner/sdk/Stream.ts
17
+ var Stream = class {
18
+ queue = [];
19
+ readResolve;
20
+ readReject;
21
+ isDone = false;
22
+ hasError;
23
+ started = false;
24
+ [Symbol.asyncIterator]() {
25
+ if (this.started) {
26
+ throw new Error("Stream can only be iterated once");
27
+ }
28
+ this.started = true;
29
+ return this;
30
+ }
31
+ async next() {
32
+ if (this.queue.length > 0) {
33
+ return { done: false, value: this.queue.shift() };
34
+ }
35
+ if (this.isDone) {
36
+ return { done: true, value: void 0 };
37
+ }
38
+ if (this.hasError) {
39
+ throw this.hasError;
40
+ }
41
+ return new Promise((resolve, reject) => {
42
+ this.readResolve = resolve;
43
+ this.readReject = reject;
44
+ });
45
+ }
46
+ enqueue(value) {
47
+ if (this.readResolve) {
48
+ const resolve = this.readResolve;
49
+ this.readResolve = void 0;
50
+ this.readReject = void 0;
51
+ resolve({ done: false, value });
52
+ } else {
53
+ this.queue.push(value);
54
+ }
55
+ }
56
+ done() {
57
+ this.isDone = true;
58
+ if (this.readResolve) {
59
+ const resolve = this.readResolve;
60
+ this.readResolve = void 0;
61
+ this.readReject = void 0;
62
+ resolve({ done: true, value: void 0 });
63
+ }
64
+ }
65
+ error(error) {
66
+ this.hasError = error;
67
+ if (this.readReject) {
68
+ const reject = this.readReject;
69
+ this.readResolve = void 0;
70
+ this.readReject = void 0;
71
+ reject(error);
72
+ }
73
+ }
74
+ async return() {
75
+ this.isDone = true;
76
+ return { done: true, value: void 0 };
77
+ }
78
+ };
79
+
80
+ // src/ai-runner/sdk/types.ts
81
+ var AbortError = class extends Error {
82
+ constructor(message) {
83
+ super(message);
84
+ this.name = "AbortError";
85
+ }
86
+ };
87
+
88
+ // src/ai-runner/sdk/ClaudeCodeSDK.ts
89
+ var logger2 = logger.child("ClaudeCodeSDK");
90
+ var Query = class {
91
+ constructor(child, childStdin, processExitPromise, canCallTool) {
92
+ this.childStdin = childStdin;
93
+ this.child = child;
94
+ this.canCallTool = canCallTool;
95
+ this.readMessages(processExitPromise);
96
+ this.sdkMessages = this.readSdkMessages();
97
+ }
98
+ pendingControlResponses = /* @__PURE__ */ new Map();
99
+ cancelControllers = /* @__PURE__ */ new Map();
100
+ sdkMessages;
101
+ inputStream = new Stream();
102
+ canCallTool;
103
+ /** The underlying child process — exposed for kill/abort by SdkRunner. */
104
+ child;
105
+ setError(error) {
106
+ this.inputStream.error(error);
107
+ }
108
+ // -- AsyncIterableIterator -------------------------------------------------
109
+ next() {
110
+ return this.sdkMessages.next();
111
+ }
112
+ return(value) {
113
+ if (this.sdkMessages.return) {
114
+ return this.sdkMessages.return(value);
115
+ }
116
+ return Promise.resolve({ done: true, value: void 0 });
117
+ }
118
+ throw(e) {
119
+ if (this.sdkMessages.throw) {
120
+ return this.sdkMessages.throw(e);
121
+ }
122
+ return Promise.reject(e);
123
+ }
124
+ [Symbol.asyncIterator]() {
125
+ return this.sdkMessages;
126
+ }
127
+ // -- Internal: read stdout JSON lines --------------------------------------
128
+ async readMessages(processExitPromise) {
129
+ const rl = createInterface({ input: this.child.stdout });
130
+ try {
131
+ for await (const line of rl) {
132
+ if (!line.trim()) continue;
133
+ try {
134
+ const message = JSON.parse(line);
135
+ if (message.type === "control_response") {
136
+ const controlResponse = message;
137
+ const handler = this.pendingControlResponses.get(
138
+ controlResponse.response.request_id
139
+ );
140
+ if (handler) {
141
+ handler(controlResponse.response);
142
+ }
143
+ continue;
144
+ }
145
+ if (message.type === "control_request") {
146
+ await this.handleControlRequest(
147
+ message
148
+ );
149
+ continue;
150
+ }
151
+ if (message.type === "control_cancel_request") {
152
+ this.handleControlCancelRequest(
153
+ message
154
+ );
155
+ continue;
156
+ }
157
+ this.inputStream.enqueue(message);
158
+ } catch {
159
+ logger2.debug("Non-JSON line from Claude stdout: " + line.slice(0, 200));
160
+ }
161
+ }
162
+ await processExitPromise;
163
+ } catch (error) {
164
+ this.inputStream.error(error);
165
+ } finally {
166
+ this.inputStream.done();
167
+ this.cleanupControllers();
168
+ rl.close();
169
+ }
170
+ }
171
+ async *readSdkMessages() {
172
+ for await (const message of this.inputStream) {
173
+ yield message;
174
+ }
175
+ }
176
+ // -- Control request handling (tool permissions) ---------------------------
177
+ async handleControlRequest(request) {
178
+ if (!this.childStdin) {
179
+ logger2.debug("Cannot handle control request \u2014 no stdin available");
180
+ return;
181
+ }
182
+ const controller = new AbortController();
183
+ this.cancelControllers.set(request.request_id, controller);
184
+ try {
185
+ const response = await this.processControlRequest(
186
+ request,
187
+ controller.signal
188
+ );
189
+ const controlResponse = {
190
+ type: "control_response",
191
+ response: {
192
+ subtype: "success",
193
+ request_id: request.request_id,
194
+ response
195
+ }
196
+ };
197
+ this.childStdin.write(JSON.stringify(controlResponse) + "\n");
198
+ } catch (error) {
199
+ const controlErrorResponse = {
200
+ type: "control_response",
201
+ response: {
202
+ subtype: "error",
203
+ request_id: request.request_id,
204
+ error: error instanceof Error ? error.message : String(error)
205
+ }
206
+ };
207
+ this.childStdin.write(JSON.stringify(controlErrorResponse) + "\n");
208
+ } finally {
209
+ this.cancelControllers.delete(request.request_id);
210
+ }
211
+ }
212
+ handleControlCancelRequest(request) {
213
+ const controller = this.cancelControllers.get(request.request_id);
214
+ if (controller) {
215
+ controller.abort();
216
+ this.cancelControllers.delete(request.request_id);
217
+ }
218
+ }
219
+ async processControlRequest(request, signal) {
220
+ if (request.request.subtype === "can_use_tool") {
221
+ if (!this.canCallTool) {
222
+ throw new Error("canCallTool callback is not provided.");
223
+ }
224
+ return this.canCallTool(
225
+ request.request.tool_name,
226
+ request.request.input,
227
+ { signal }
228
+ );
229
+ }
230
+ throw new Error(
231
+ "Unsupported control request subtype: " + request.request.subtype
232
+ );
233
+ }
234
+ cleanupControllers() {
235
+ for (const [, controller] of this.cancelControllers) {
236
+ controller.abort();
237
+ }
238
+ this.cancelControllers.clear();
239
+ }
240
+ };
241
+ function query(config) {
242
+ const {
243
+ prompt,
244
+ binary,
245
+ options: {
246
+ allowedTools = [],
247
+ disallowedTools = [],
248
+ cwd,
249
+ model,
250
+ permissionMode = "default",
251
+ canCallTool,
252
+ resume,
253
+ continueConversation,
254
+ appendSystemPrompt,
255
+ maxTurns,
256
+ abort
257
+ } = {}
258
+ } = config;
259
+ const args = ["--output-format", "stream-json", "--verbose"];
260
+ if (appendSystemPrompt) args.push("--append-system-prompt", appendSystemPrompt);
261
+ if (maxTurns) args.push("--max-turns", maxTurns.toString());
262
+ if (model) args.push("--model", model);
263
+ if (continueConversation) args.push("--continue");
264
+ if (resume) args.push("--resume", resume);
265
+ if (allowedTools.length > 0) args.push("--allowedTools", allowedTools.join(","));
266
+ if (disallowedTools.length > 0) args.push("--disallowedTools", disallowedTools.join(","));
267
+ if (permissionMode) args.push("--permission-mode", permissionMode);
268
+ if (canCallTool) {
269
+ args.push("--permission-prompt-tool", "stdio");
270
+ args.push("--input-format", "stream-json");
271
+ }
272
+ if (!canCallTool) {
273
+ args.push("--print", prompt.trim());
274
+ }
275
+ const { CLAUDECODE: _, ...cleanEnv } = process.env;
276
+ logger2.info("Spawning Claude Code process", {
277
+ binary,
278
+ argCount: args.length,
279
+ cwd,
280
+ hasCanCallTool: !!canCallTool
281
+ });
282
+ logger2.debug("Claude Code args", { args });
283
+ const child = spawn(binary, args, {
284
+ cwd,
285
+ stdio: ["pipe", "pipe", "pipe"],
286
+ signal: abort,
287
+ env: cleanEnv,
288
+ windowsHide: true
289
+ });
290
+ let childStdin = null;
291
+ if (!canCallTool) {
292
+ child.stdin.end();
293
+ } else {
294
+ childStdin = child.stdin;
295
+ const userMessage = {
296
+ type: "user",
297
+ message: {
298
+ role: "user",
299
+ content: prompt.trim()
300
+ }
301
+ };
302
+ childStdin.write(JSON.stringify(userMessage) + "\n");
303
+ }
304
+ child.stderr.on("data", (data) => {
305
+ logger2.debug("Claude Code stderr: " + data.toString().trimEnd());
306
+ });
307
+ const cleanup = () => {
308
+ if (!child.killed) {
309
+ child.kill("SIGTERM");
310
+ }
311
+ };
312
+ abort?.addEventListener("abort", cleanup);
313
+ process.on("exit", cleanup);
314
+ const processExitPromise = new Promise((resolve, reject) => {
315
+ child.on("close", (code) => {
316
+ if (abort?.aborted) {
317
+ reject(new AbortError("Claude Code process aborted"));
318
+ } else if (code !== 0) {
319
+ reject(new Error(`Claude Code process exited with code ${code}`));
320
+ } else {
321
+ resolve();
322
+ }
323
+ });
324
+ });
325
+ const q = new Query(child, childStdin, processExitPromise, canCallTool);
326
+ child.on("error", (error) => {
327
+ if (abort?.aborted) {
328
+ q.setError(new AbortError("Claude Code process aborted"));
329
+ } else {
330
+ q.setError(
331
+ new Error(`Failed to spawn Claude Code process: ${error.message}`)
332
+ );
333
+ }
334
+ });
335
+ processExitPromise.catch(() => {
336
+ }).finally(() => {
337
+ cleanup();
338
+ abort?.removeEventListener("abort", cleanup);
339
+ });
340
+ return q;
341
+ }
342
+
343
+ // src/ai-runner/SdkRunner.ts
344
+ var logger3 = logger.child("SdkRunner");
345
+ var SIGKILL_GRACE_MS = 1e4;
346
+ var IDLE_CHECK_INTERVAL_MS = 5e3;
347
+ var SdkRunner = class {
348
+ constructor(binary, nvmNodeVersion, model) {
349
+ this.binary = binary;
350
+ this.nvmNodeVersion = nvmNodeVersion;
351
+ this.model = model;
352
+ }
353
+ activeProcesses = /* @__PURE__ */ new Map();
354
+ // -- AIRunner interface ----------------------------------------------------
355
+ async run(options) {
356
+ if (isShuttingDown()) {
357
+ logger3.warn("SdkRunner skipped \u2014 service is shutting down");
358
+ return { success: false, output: "Service shutting down", exitCode: null };
359
+ }
360
+ const {
361
+ prompt,
362
+ workDir,
363
+ timeoutMs,
364
+ idleTimeoutMs,
365
+ onStreamEvent,
366
+ mode,
367
+ artifactPaths
368
+ } = options;
369
+ logger3.info("SdkRunner.run()", {
370
+ workDir,
371
+ timeoutMs,
372
+ mode,
373
+ phaseName: options.phaseName
374
+ });
375
+ const abortController = new AbortController();
376
+ const isPlanMode = mode === "plan";
377
+ let planContent;
378
+ const queryOptions = {
379
+ cwd: workDir,
380
+ model: this.model,
381
+ abort: abortController.signal
382
+ };
383
+ if (isPlanMode) {
384
+ queryOptions.permissionMode = "plan";
385
+ queryOptions.allowedTools = ["Read", "Grep", "Glob", "WebSearch"];
386
+ queryOptions.canCallTool = async (toolName, input, _opts) => {
387
+ if (toolName === "ExitPlanMode" || toolName === "exit_plan_mode") {
388
+ const planInput = input;
389
+ planContent = typeof planInput?.plan === "string" ? planInput.plan : void 0;
390
+ logger3.info("ExitPlanMode intercepted", {
391
+ hasPlan: !!planContent,
392
+ planLength: planContent?.length
393
+ });
394
+ if (planContent && artifactPaths && artifactPaths.length > 0) {
395
+ for (const targetPath of artifactPaths) {
396
+ const targetDir = path.dirname(targetPath);
397
+ if (!fs.existsSync(targetDir)) {
398
+ fs.mkdirSync(targetDir, { recursive: true });
399
+ }
400
+ fs.writeFileSync(targetPath, planContent, "utf-8");
401
+ logger3.info("Plan written to artifact path", { target: targetPath });
402
+ }
403
+ }
404
+ return { behavior: "deny", message: "Plan captured by SdkRunner" };
405
+ }
406
+ return {
407
+ behavior: "allow",
408
+ updatedInput: input && typeof input === "object" ? input : {}
409
+ };
410
+ };
411
+ } else {
412
+ queryOptions.permissionMode = "bypassPermissions";
413
+ }
414
+ if (options.continueSession && options.sessionId) {
415
+ queryOptions.resume = options.sessionId;
416
+ }
417
+ const q = query({
418
+ prompt,
419
+ binary: this.binary,
420
+ options: queryOptions
421
+ });
422
+ const entry = {
423
+ child: q.child,
424
+ workDir,
425
+ abort: abortController
426
+ };
427
+ this.activeProcesses.set(q.child, entry);
428
+ const outputParts = [];
429
+ const stderrParts = [];
430
+ let sessionId;
431
+ let resultMessage;
432
+ let caughtError;
433
+ let lastActivityTime = Date.now();
434
+ let timedOut = false;
435
+ let timeoutType;
436
+ let wasActiveAtTimeout = false;
437
+ q.child.stderr.on("data", (data) => {
438
+ stderrParts.push(data.toString());
439
+ });
440
+ const graceWindowMs = options.timeoutGraceMs ?? 6e4;
441
+ const extensionMs = options.timeoutExtensionMs ?? 6e5;
442
+ const maxExtensions = options.timeoutMaxExtensions ?? 3;
443
+ let extensions = 0;
444
+ const scheduleWallTimer = (delayMs) => {
445
+ return setTimeout(() => {
446
+ const recentMs = Date.now() - lastActivityTime;
447
+ const isActive = recentMs < graceWindowMs;
448
+ if (isActive && extensions < maxExtensions) {
449
+ extensions++;
450
+ logger3.info("Wall-clock timeout extended (agent still active)", {
451
+ extensions,
452
+ maxExtensions,
453
+ lastOutputAgoMs: recentMs
454
+ });
455
+ wallTimer = scheduleWallTimer(extensionMs);
456
+ return;
457
+ }
458
+ timedOut = true;
459
+ timeoutType = "wall-clock";
460
+ wasActiveAtTimeout = isActive;
461
+ abortController.abort();
462
+ }, delayMs);
463
+ };
464
+ let wallTimer = scheduleWallTimer(timeoutMs);
465
+ const effectiveIdleMs = idleTimeoutMs ?? 6e5;
466
+ const idleCheck = setInterval(() => {
467
+ const idleMs = Date.now() - lastActivityTime;
468
+ if (idleMs >= effectiveIdleMs) {
469
+ timedOut = true;
470
+ timeoutType = "idle";
471
+ wasActiveAtTimeout = false;
472
+ abortController.abort();
473
+ }
474
+ }, IDLE_CHECK_INTERVAL_MS);
475
+ try {
476
+ for await (const message of q) {
477
+ lastActivityTime = Date.now();
478
+ this.processMessage(
479
+ message,
480
+ outputParts,
481
+ onStreamEvent,
482
+ (sid) => {
483
+ sessionId = sid;
484
+ },
485
+ (result) => {
486
+ resultMessage = result;
487
+ }
488
+ );
489
+ }
490
+ } catch (error) {
491
+ caughtError = error;
492
+ if (error instanceof AbortError) {
493
+ logger3.info("Claude Code process aborted", { timedOut, timeoutType });
494
+ } else {
495
+ logger3.error("Unexpected error during SDK message iteration", {
496
+ error: error.message
497
+ });
498
+ }
499
+ } finally {
500
+ clearTimeout(wallTimer);
501
+ clearInterval(idleCheck);
502
+ this.activeProcesses.delete(q.child);
503
+ }
504
+ const output = outputParts.join("");
505
+ const success = !timedOut && resultMessage != null && !resultMessage.is_error;
506
+ let errorMessage;
507
+ if (!success) {
508
+ const parts = [];
509
+ if (timedOut) {
510
+ parts.push(
511
+ timeoutType === "idle" ? "AI \u957F\u65F6\u95F4\u65E0\u54CD\u5E94\uFF0C\u5DF2\u8D85\u65F6\u7EC8\u6B62" : "\u6267\u884C\u8D85\u65F6"
512
+ );
513
+ }
514
+ if (resultMessage?.is_error && resultMessage.result) {
515
+ parts.push(resultMessage.result);
516
+ }
517
+ if (!resultMessage && caughtError && !(caughtError instanceof AbortError)) {
518
+ parts.push(caughtError.message);
519
+ }
520
+ const stderr = stderrParts.join("").trim();
521
+ if (stderr && parts.length === 0) {
522
+ parts.push(stderr.slice(0, 500));
523
+ }
524
+ errorMessage = parts.join(" | ") || "Claude Code \u8FDB\u7A0B\u5F02\u5E38\u9000\u51FA\uFF08\u65E0\u8F93\u51FA\uFF09";
525
+ }
526
+ logger3.info("SdkRunner completed", {
527
+ workDir,
528
+ success,
529
+ timedOut,
530
+ timeoutType,
531
+ outputLength: output.length,
532
+ sessionId,
533
+ resultSubtype: resultMessage?.subtype
534
+ });
535
+ return {
536
+ success,
537
+ output: resultMessage?.result ?? output,
538
+ errorMessage,
539
+ sessionId: sessionId ?? resultMessage?.session_id,
540
+ exitCode: success ? 0 : timedOut ? null : 1,
541
+ timeoutType,
542
+ wasActiveAtTimeout
543
+ };
544
+ }
545
+ killAll() {
546
+ for (const [child, entry] of this.activeProcesses) {
547
+ entry.abort.abort();
548
+ this.forceKill(child);
549
+ }
550
+ logger3.info("SdkRunner: all active processes killed", {
551
+ count: this.activeProcesses.size
552
+ });
553
+ this.activeProcesses.clear();
554
+ }
555
+ killByWorkDir(targetWorkDir) {
556
+ let killed = 0;
557
+ for (const [child, entry] of this.activeProcesses) {
558
+ if (entry.workDir === targetWorkDir) {
559
+ entry.abort.abort();
560
+ this.forceKill(child);
561
+ this.activeProcesses.delete(child);
562
+ killed++;
563
+ }
564
+ }
565
+ if (killed > 0) {
566
+ logger3.info("SdkRunner: killed processes by workDir", {
567
+ workDir: targetWorkDir,
568
+ killed
569
+ });
570
+ }
571
+ return killed;
572
+ }
573
+ // -- Internal helpers ------------------------------------------------------
574
+ processMessage(message, outputParts, onStreamEvent, onSessionId, onResult) {
575
+ switch (message.type) {
576
+ case "system": {
577
+ const sys = message;
578
+ if (sys.session_id) onSessionId(sys.session_id);
579
+ if (onStreamEvent) {
580
+ onStreamEvent({
581
+ type: "system",
582
+ content: message,
583
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
584
+ });
585
+ }
586
+ break;
587
+ }
588
+ case "assistant": {
589
+ const assistant = message;
590
+ if (assistant.message?.content) {
591
+ for (const block of assistant.message.content) {
592
+ if (block.type === "text" && block.text) {
593
+ outputParts.push(block.text);
594
+ }
595
+ }
596
+ }
597
+ if (onStreamEvent) {
598
+ onStreamEvent({
599
+ type: "assistant",
600
+ content: message,
601
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
602
+ });
603
+ }
604
+ break;
605
+ }
606
+ case "result": {
607
+ const result = message;
608
+ onResult(result);
609
+ if (result.session_id) onSessionId(result.session_id);
610
+ if (onStreamEvent) {
611
+ onStreamEvent({
612
+ type: "result",
613
+ content: message,
614
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
615
+ });
616
+ }
617
+ break;
618
+ }
619
+ case "user": {
620
+ if (onStreamEvent) {
621
+ onStreamEvent({
622
+ type: "user",
623
+ content: message,
624
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
625
+ });
626
+ }
627
+ break;
628
+ }
629
+ case "log": {
630
+ const log = message;
631
+ if (log.log) {
632
+ logger3.debug(`Claude log [${log.log.level}]: ${log.log.message}`);
633
+ }
634
+ break;
635
+ }
636
+ default: {
637
+ if (onStreamEvent) {
638
+ onStreamEvent({
639
+ type: message.type || "raw",
640
+ content: message,
641
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
642
+ });
643
+ }
644
+ break;
645
+ }
646
+ }
647
+ }
648
+ forceKill(child) {
649
+ try {
650
+ if (child.exitCode === null) {
651
+ child.kill("SIGTERM");
652
+ setTimeout(() => {
653
+ if (child.exitCode === null) {
654
+ child.kill("SIGKILL");
655
+ }
656
+ }, SIGKILL_GRACE_MS);
657
+ }
658
+ } catch {
659
+ }
660
+ }
661
+ };
662
+
663
+ export {
664
+ SdkRunner
665
+ };
666
+ //# sourceMappingURL=chunk-R32Q3RGK.js.map