chatccc 0.2.188 → 0.2.190

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 (67) hide show
  1. package/agent-prompts/claude_specific.md +45 -45
  2. package/agent-prompts/codex_specific.md +2 -2
  3. package/agent-prompts/cursor_specific.md +13 -13
  4. package/config.sample.json +14 -14
  5. package/im-skills/feishu-skill/receive-send-file.md +63 -63
  6. package/im-skills/feishu-skill/receive-send-image.md +24 -24
  7. package/im-skills/feishu-skill/skill.md +3 -3
  8. package/im-skills/wechat-file-skill/receive-send-file.md +38 -38
  9. package/im-skills/wechat-file-skill/send-file.mjs +83 -83
  10. package/im-skills/wechat-file-skill/skill.md +10 -10
  11. package/im-skills/wechat-image-skill/skill.md +10 -10
  12. package/im-skills/wechat-video-skill/receive-send-video.md +38 -38
  13. package/im-skills/wechat-video-skill/send-video.mjs +79 -79
  14. package/im-skills/wechat-video-skill/skill.md +10 -10
  15. package/package.json +1 -1
  16. package/scripts/postinstall-sharp-check.mjs +58 -58
  17. package/src/__tests__/agent-delegate-task-rpc.test.ts +165 -165
  18. package/src/__tests__/builtin-config.test.ts +33 -33
  19. package/src/__tests__/card-plain-text.test.ts +5 -5
  20. package/src/__tests__/cardkit.test.ts +60 -60
  21. package/src/__tests__/cards.test.ts +77 -77
  22. package/src/__tests__/chatgpt-subscription-rpc.test.ts +89 -89
  23. package/src/__tests__/chatgpt-subscription.test.ts +135 -135
  24. package/src/__tests__/chrome-devtools-guard.test.ts +165 -165
  25. package/src/__tests__/claude-adapter.test.ts +592 -592
  26. package/src/__tests__/codex-reset-actions.test.ts +146 -146
  27. package/src/__tests__/config-reload.test.ts +4 -4
  28. package/src/__tests__/config-sample.test.ts +17 -17
  29. package/src/__tests__/feishu-api.test.ts +60 -60
  30. package/src/__tests__/feishu-platform.test.ts +22 -22
  31. package/src/__tests__/format-message.test.ts +47 -47
  32. package/src/__tests__/orchestrator.test.ts +116 -112
  33. package/src/__tests__/privacy.test.ts +198 -198
  34. package/src/__tests__/raw-stream-log.test.ts +106 -106
  35. package/src/__tests__/session.test.ts +17 -17
  36. package/src/__tests__/shared-prefix.test.ts +36 -36
  37. package/src/__tests__/stream-state.test.ts +42 -42
  38. package/src/__tests__/web-ui.test.ts +209 -130
  39. package/src/adapters/claude-adapter.ts +566 -566
  40. package/src/adapters/claude-session-meta-store.ts +120 -120
  41. package/src/adapters/codex-adapter.ts +27 -28
  42. package/src/adapters/cursor-adapter.ts +46 -46
  43. package/src/adapters/raw-stream-log.ts +124 -124
  44. package/src/adapters/resource-monitor.ts +140 -140
  45. package/src/agent-delegate-task-rpc.ts +153 -153
  46. package/src/agent-delegate-task.ts +81 -81
  47. package/src/agent-stop-stuck.ts +129 -129
  48. package/src/builtin/cli.ts +189 -189
  49. package/src/builtin/index.ts +170 -168
  50. package/src/cards.ts +137 -137
  51. package/src/chatgpt-subscription-rpc.ts +27 -27
  52. package/src/chatgpt-subscription.ts +299 -299
  53. package/src/chrome-devtools-guard.ts +318 -318
  54. package/src/codex-reset-actions.ts +184 -184
  55. package/src/config.ts +86 -86
  56. package/src/feishu-platform.ts +20 -20
  57. package/src/format-message.ts +293 -293
  58. package/src/litellm-proxy.ts +374 -374
  59. package/src/orchestrator.ts +143 -143
  60. package/src/privacy.ts +118 -118
  61. package/src/session-chat-binding.ts +6 -6
  62. package/src/session-name.ts +8 -8
  63. package/src/session.ts +98 -98
  64. package/src/shared-prefix.ts +29 -29
  65. package/src/sim-platform.ts +20 -20
  66. package/src/turn-cards.ts +117 -117
  67. package/src/web-ui.ts +142 -24
@@ -1,120 +1,120 @@
1
- // =============================================================================
2
- // claude-session-meta-store.ts — Claude 会话 sessionId → meta 持久化映射
3
- // =============================================================================
4
- // 背景:Claude Agent SDK 的 getSessionInfo 可能因 cwd / 本地记录缺失而查不到。
5
- // ChatCCC 额外维护 sessionId → { cwd, model } 映射作为展示与恢复兜底。
6
- //
7
- // 存储:
8
- // 文件 state/claude-session-meta.json,结构:
9
- // { "<sessionId>": { "cwd": "...", "model": "..." } }
10
- //
11
- // API 设计:
12
- // set(sid, partial) → 部分合并写入;只更新非空字段,不会清空其他字段
13
- // =============================================================================
14
-
15
- import { mkdir, readFile, writeFile } from "node:fs/promises";
16
- import { dirname, join } from "node:path";
17
-
18
- import { USER_DATA_DIR } from "../config.ts";
19
-
20
- export const CLAUDE_SESSION_META_FILE = join(
21
- USER_DATA_DIR,
22
- "state",
23
- "claude-session-meta.json",
24
- );
25
-
26
- export interface ClaudeSessionMeta {
27
- cwd: string;
28
- model?: string;
29
- }
30
-
31
- export interface ClaudeSessionMetaStore {
32
- get(sessionId: string): Promise<ClaudeSessionMeta | undefined>;
33
- set(sessionId: string, partial: Partial<ClaudeSessionMeta>): Promise<void>;
34
- }
35
-
36
- interface RawEntry {
37
- cwd?: string;
38
- model?: string;
39
- }
40
-
41
- function isNonEmptyString(v: unknown): v is string {
42
- return typeof v === "string" && v.length > 0;
43
- }
44
-
45
- function parseEntry(raw: unknown): RawEntry | null {
46
- if (typeof raw === "string" && raw.length > 0) {
47
- return { cwd: raw };
48
- }
49
- if (raw && typeof raw === "object" && !Array.isArray(raw)) {
50
- const obj = raw as Record<string, unknown>;
51
- const out: RawEntry = {};
52
- if (isNonEmptyString(obj.cwd)) out.cwd = obj.cwd;
53
- if (isNonEmptyString(obj.model)) out.model = obj.model;
54
- return out;
55
- }
56
- return null;
57
- }
58
-
59
- export function createClaudeSessionMetaStore(
60
- filePath: string = CLAUDE_SESSION_META_FILE,
61
- ): ClaudeSessionMetaStore {
62
- let cache: Record<string, RawEntry> | null = null;
63
-
64
- async function load(): Promise<Record<string, RawEntry>> {
65
- if (cache) return cache;
66
- try {
67
- const raw = await readFile(filePath, "utf-8");
68
- const parsed = JSON.parse(raw);
69
- if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
70
- const out: Record<string, RawEntry> = {};
71
- for (const [k, v] of Object.entries(parsed as Record<string, unknown>)) {
72
- const entry = parseEntry(v);
73
- if (entry) out[k] = entry;
74
- }
75
- cache = out;
76
- return out;
77
- }
78
- } catch {
79
- // 文件不存在 / JSON 损坏 → 视为空映射
80
- }
81
- cache = {};
82
- return cache;
83
- }
84
-
85
- return {
86
- async get(sessionId: string): Promise<ClaudeSessionMeta | undefined> {
87
- const map = await load();
88
- const entry = map[sessionId];
89
- if (!entry || !isNonEmptyString(entry.cwd)) return undefined;
90
- return entry.model
91
- ? { cwd: entry.cwd, model: entry.model }
92
- : { cwd: entry.cwd };
93
- },
94
-
95
- async set(
96
- sessionId: string,
97
- partial: Partial<ClaudeSessionMeta>,
98
- ): Promise<void> {
99
- const map = await load();
100
- const existing = map[sessionId] ?? {};
101
- const merged: RawEntry = { ...existing };
102
- if (isNonEmptyString(partial.cwd)) merged.cwd = partial.cwd;
103
- if (isNonEmptyString(partial.model)) merged.model = partial.model;
104
-
105
- if (existing.cwd === merged.cwd && existing.model === merged.model) return;
106
-
107
- map[sessionId] = merged;
108
- try {
109
- await mkdir(dirname(filePath), { recursive: true });
110
- await writeFile(filePath, JSON.stringify(map, null, 2), "utf-8");
111
- } catch (err) {
112
- console.error(
113
- `[claude-session-meta] failed to persist ${filePath}: ${(err as Error).message}`,
114
- );
115
- }
116
- },
117
- };
118
- }
119
-
120
- export const defaultClaudeSessionMetaStore = createClaudeSessionMetaStore();
1
+ // =============================================================================
2
+ // claude-session-meta-store.ts — Claude 会话 sessionId → meta 持久化映射
3
+ // =============================================================================
4
+ // 背景:Claude Agent SDK 的 getSessionInfo 可能因 cwd / 本地记录缺失而查不到。
5
+ // ChatCCC 额外维护 sessionId → { cwd, model } 映射作为展示与恢复兜底。
6
+ //
7
+ // 存储:
8
+ // 文件 state/claude-session-meta.json,结构:
9
+ // { "<sessionId>": { "cwd": "...", "model": "..." } }
10
+ //
11
+ // API 设计:
12
+ // set(sid, partial) → 部分合并写入;只更新非空字段,不会清空其他字段
13
+ // =============================================================================
14
+
15
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
16
+ import { dirname, join } from "node:path";
17
+
18
+ import { USER_DATA_DIR } from "../config.ts";
19
+
20
+ export const CLAUDE_SESSION_META_FILE = join(
21
+ USER_DATA_DIR,
22
+ "state",
23
+ "claude-session-meta.json",
24
+ );
25
+
26
+ export interface ClaudeSessionMeta {
27
+ cwd: string;
28
+ model?: string;
29
+ }
30
+
31
+ export interface ClaudeSessionMetaStore {
32
+ get(sessionId: string): Promise<ClaudeSessionMeta | undefined>;
33
+ set(sessionId: string, partial: Partial<ClaudeSessionMeta>): Promise<void>;
34
+ }
35
+
36
+ interface RawEntry {
37
+ cwd?: string;
38
+ model?: string;
39
+ }
40
+
41
+ function isNonEmptyString(v: unknown): v is string {
42
+ return typeof v === "string" && v.length > 0;
43
+ }
44
+
45
+ function parseEntry(raw: unknown): RawEntry | null {
46
+ if (typeof raw === "string" && raw.length > 0) {
47
+ return { cwd: raw };
48
+ }
49
+ if (raw && typeof raw === "object" && !Array.isArray(raw)) {
50
+ const obj = raw as Record<string, unknown>;
51
+ const out: RawEntry = {};
52
+ if (isNonEmptyString(obj.cwd)) out.cwd = obj.cwd;
53
+ if (isNonEmptyString(obj.model)) out.model = obj.model;
54
+ return out;
55
+ }
56
+ return null;
57
+ }
58
+
59
+ export function createClaudeSessionMetaStore(
60
+ filePath: string = CLAUDE_SESSION_META_FILE,
61
+ ): ClaudeSessionMetaStore {
62
+ let cache: Record<string, RawEntry> | null = null;
63
+
64
+ async function load(): Promise<Record<string, RawEntry>> {
65
+ if (cache) return cache;
66
+ try {
67
+ const raw = await readFile(filePath, "utf-8");
68
+ const parsed = JSON.parse(raw);
69
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
70
+ const out: Record<string, RawEntry> = {};
71
+ for (const [k, v] of Object.entries(parsed as Record<string, unknown>)) {
72
+ const entry = parseEntry(v);
73
+ if (entry) out[k] = entry;
74
+ }
75
+ cache = out;
76
+ return out;
77
+ }
78
+ } catch {
79
+ // 文件不存在 / JSON 损坏 → 视为空映射
80
+ }
81
+ cache = {};
82
+ return cache;
83
+ }
84
+
85
+ return {
86
+ async get(sessionId: string): Promise<ClaudeSessionMeta | undefined> {
87
+ const map = await load();
88
+ const entry = map[sessionId];
89
+ if (!entry || !isNonEmptyString(entry.cwd)) return undefined;
90
+ return entry.model
91
+ ? { cwd: entry.cwd, model: entry.model }
92
+ : { cwd: entry.cwd };
93
+ },
94
+
95
+ async set(
96
+ sessionId: string,
97
+ partial: Partial<ClaudeSessionMeta>,
98
+ ): Promise<void> {
99
+ const map = await load();
100
+ const existing = map[sessionId] ?? {};
101
+ const merged: RawEntry = { ...existing };
102
+ if (isNonEmptyString(partial.cwd)) merged.cwd = partial.cwd;
103
+ if (isNonEmptyString(partial.model)) merged.model = partial.model;
104
+
105
+ if (existing.cwd === merged.cwd && existing.model === merged.model) return;
106
+
107
+ map[sessionId] = merged;
108
+ try {
109
+ await mkdir(dirname(filePath), { recursive: true });
110
+ await writeFile(filePath, JSON.stringify(map, null, 2), "utf-8");
111
+ } catch (err) {
112
+ console.error(
113
+ `[claude-session-meta] failed to persist ${filePath}: ${(err as Error).message}`,
114
+ );
115
+ }
116
+ },
117
+ };
118
+ }
119
+
120
+ export const defaultClaudeSessionMetaStore = createClaudeSessionMetaStore();
@@ -72,7 +72,6 @@ function buildCodexPromptText(userText: string): string {
72
72
  function detectCodexCommand(): string {
73
73
  return config.codex.path || "codex";
74
74
  }
75
- const CODEX_COMMAND = detectCodexCommand();
76
75
 
77
76
  /** exec 模式共用参数:JSONL 输出、绕过沙盒和确认、跳过 git 仓库检查 */
78
77
  const CODEX_BASE_ARGS = [
@@ -184,13 +183,13 @@ export function normalizeCodexMessage(
184
183
  // 子进程辅助函数
185
184
  // ---------------------------------------------------------------------------
186
185
 
187
- function spawnCodex(
188
- args: string[],
189
- cwd?: string,
190
- stdinText?: string,
191
- modelOverride?: string,
192
- effortOverride?: string,
193
- ): ChildProcess {
186
+ function spawnCodex(
187
+ args: string[],
188
+ cwd?: string,
189
+ stdinText?: string,
190
+ modelOverride?: string,
191
+ effortOverride?: string,
192
+ ): ChildProcess {
194
193
  const allArgs = [...args];
195
194
  const model = modelOverride ?? resolveCodexModel();
196
195
  if (model) {
@@ -198,12 +197,12 @@ function spawnCodex(
198
197
  const execIdx = allArgs.indexOf("exec");
199
198
  allArgs.splice(execIdx + 1, 0, "-m", model);
200
199
  }
201
- const effort = effortOverride ?? resolveCodexEffort();
200
+ const effort = effortOverride ?? resolveCodexEffort();
202
201
  if (effort) {
203
202
  allArgs.push("-c", `model_reasoning_effort="${effort}"`);
204
203
  }
205
204
 
206
- const proc = spawn(CODEX_COMMAND, allArgs, {
205
+ const proc = spawn(detectCodexCommand(), allArgs, {
207
206
  cwd,
208
207
  stdio: [stdinText !== undefined ? "pipe" : "ignore", "pipe", "pipe"],
209
208
  windowsHide: true,
@@ -259,17 +258,17 @@ async function* readJsonLines(
259
258
  // ---------------------------------------------------------------------------
260
259
 
261
260
  class CodexAdapter implements ToolAdapter {
262
- readonly displayName = "Codex";
263
- readonly sessionDescPrefix = "Codex Session:";
264
- private metaStore: CodexSessionMetaStore;
265
- private modelOverride: string | undefined;
266
- private effortOverride: string | undefined;
267
-
268
- constructor(metaStore: CodexSessionMetaStore, modelOverride?: string, effortOverride?: string) {
269
- this.metaStore = metaStore;
270
- this.modelOverride = modelOverride;
271
- this.effortOverride = effortOverride;
272
- }
261
+ readonly displayName = "Codex";
262
+ readonly sessionDescPrefix = "Codex Session:";
263
+ private metaStore: CodexSessionMetaStore;
264
+ private modelOverride: string | undefined;
265
+ private effortOverride: string | undefined;
266
+
267
+ constructor(metaStore: CodexSessionMetaStore, modelOverride?: string, effortOverride?: string) {
268
+ this.metaStore = metaStore;
269
+ this.modelOverride = modelOverride;
270
+ this.effortOverride = effortOverride;
271
+ }
273
272
 
274
273
  // createSession: 生成 sessionId,记录 cwd,不创建 Codex 线程(延迟到首次 prompt)
275
274
  async createSession(cwd: string): Promise<CreateSessionResult> {
@@ -299,7 +298,7 @@ class CodexAdapter implements ToolAdapter {
299
298
  ? [...baseArgs, "-C", cwd, "-"]
300
299
  : [...baseArgs, "resume", threadId, "-"];
301
300
 
302
- const proc = spawnCodex(args, cwd, buildCodexPromptText(userText), this.modelOverride, this.effortOverride);
301
+ const proc = spawnCodex(args, cwd, buildCodexPromptText(userText), this.modelOverride, this.effortOverride);
303
302
  if (proc.pid !== undefined) options?.onProcessStart?.({ pid: proc.pid });
304
303
 
305
304
  // 关键:spawn 用了 shell:true,proc.pid 指向的是壳进程(cmd.exe / sh)。
@@ -353,8 +352,8 @@ class CodexAdapter implements ToolAdapter {
353
352
  export interface CreateCodexAdapterOptions {
354
353
  metaStore?: CodexSessionMetaStore;
355
354
  /** per-session 模型覆盖(/model 命令);传了就用,不传走全局 codex.model */
356
- model?: string;
357
- effort?: string;
355
+ model?: string;
356
+ effort?: string;
358
357
  }
359
358
 
360
359
  export function createCodexAdapter(
@@ -362,7 +361,7 @@ export function createCodexAdapter(
362
361
  ): ToolAdapter {
363
362
  return new CodexAdapter(
364
363
  options.metaStore ?? defaultCodexSessionMetaStore,
365
- options.model,
366
- options.effort,
367
- );
368
- }
364
+ options.model,
365
+ options.effort,
366
+ );
367
+ }
@@ -20,16 +20,16 @@ import type {
20
20
  SessionInfo,
21
21
  } from "./adapter-interface.ts";
22
22
  import { parseUserCommand } from "./adapter-interface.ts";
23
- import { config, CURSOR_AGENT_COMMAND, CURSOR_AGENT_ARGS, RAW_STREAM_LOGS_DIR } from "../config.ts";
23
+ import { config, CURSOR_AGENT_COMMAND, CURSOR_AGENT_ARGS, RAW_STREAM_LOGS_DIR } from "../config.ts";
24
24
  import {
25
25
  defaultCursorSessionMetaStore,
26
26
  type CursorSessionMetaStore,
27
27
  } from "./cursor-session-meta-store.ts";
28
- import { killProcessTree } from "./proc-tree-kill.ts";
29
- import {
30
- createRawStreamLog,
31
- type RawStreamLogHandle,
32
- } from "./raw-stream-log.ts";
28
+ import { killProcessTree } from "./proc-tree-kill.ts";
29
+ import {
30
+ createRawStreamLog,
31
+ type RawStreamLogHandle,
32
+ } from "./raw-stream-log.ts";
33
33
 
34
34
  // ---------------------------------------------------------------------------
35
35
  // 特殊注入提示
@@ -348,12 +348,12 @@ function spawnAgent(
348
348
  return proc;
349
349
  }
350
350
 
351
- async function* readJsonLines(
352
- proc: ChildProcess,
353
- signal?: AbortSignal,
354
- debugTag?: string,
355
- rawLog?: RawStreamLogHandle | null,
356
- ): AsyncGenerator<CursorMessageLine> {
351
+ async function* readJsonLines(
352
+ proc: ChildProcess,
353
+ signal?: AbortSignal,
354
+ debugTag?: string,
355
+ rawLog?: RawStreamLogHandle | null,
356
+ ): AsyncGenerator<CursorMessageLine> {
357
357
  const tag = debugTag ?? "cursor";
358
358
  const rl = createInterface({ input: proc.stdout!, crlfDelay: Infinity });
359
359
  // abort 时主动 close readline,避免等待 Windows 管道自然关闭(可能延迟数分钟)
@@ -364,10 +364,10 @@ async function* readJsonLines(
364
364
  for await (const line of rl) {
365
365
  if (signal?.aborted) break;
366
366
  lineCount++;
367
- const trimmed = line.trim();
368
- if (!trimmed) continue;
369
- rawLog?.writeLine(trimmed);
370
- try {
367
+ const trimmed = line.trim();
368
+ if (!trimmed) continue;
369
+ rawLog?.writeLine(trimmed);
370
+ try {
371
371
  yield JSON.parse(trimmed) as CursorMessageLine;
372
372
  } catch { /* 非 JSON 行静默跳过 */ }
373
373
  }
@@ -432,32 +432,32 @@ class CursorAdapter implements ToolAdapter {
432
432
  cmd.mode ?? undefined,
433
433
  );
434
434
  this.activeProcs.add(proc);
435
- if (proc.pid !== undefined) options?.onProcessStart?.({ pid: proc.pid });
436
-
437
- const rawLogConfig = config.rawStreamLogs.cursor;
438
- let rawLog: RawStreamLogHandle | null = null;
439
- try {
440
- rawLog = await createRawStreamLog({
441
- enabled: rawLogConfig.enabled,
442
- rootDir: RAW_STREAM_LOGS_DIR,
443
- tool: "cursor",
444
- sessionId,
445
- label: "prompt",
446
- maxBytesPerTurn: rawLogConfig.maxBytesPerTurn,
447
- retentionDays: rawLogConfig.retentionDays,
448
- });
449
- } catch (err) {
450
- console.error(`[Cursor raw stream log] create failed: ${(err as Error).message}`);
451
- }
435
+ if (proc.pid !== undefined) options?.onProcessStart?.({ pid: proc.pid });
436
+
437
+ const rawLogConfig = config.rawStreamLogs.cursor;
438
+ let rawLog: RawStreamLogHandle | null = null;
439
+ try {
440
+ rawLog = await createRawStreamLog({
441
+ enabled: rawLogConfig.enabled,
442
+ rootDir: RAW_STREAM_LOGS_DIR,
443
+ tool: "cursor",
444
+ sessionId,
445
+ label: "prompt",
446
+ maxBytesPerTurn: rawLogConfig.maxBytesPerTurn,
447
+ retentionDays: rawLogConfig.retentionDays,
448
+ });
449
+ } catch (err) {
450
+ console.error(`[Cursor raw stream log] create failed: ${(err as Error).message}`);
451
+ }
452
452
 
453
453
  // 见 codex-adapter.ts 同位置注释:spawn 用了 shell:true,必须杀整棵树,
454
454
  // 否则 abort 后真正在跑的孙进程 cursor-agent 还会继续输出 & 占用资源。
455
- const onAbort = () => { void killProcessTree(proc.pid); };
456
- signal?.addEventListener("abort", onAbort, { once: true });
457
- let sawResult = false;
458
-
459
- try {
460
- for await (const raw of readJsonLines(proc, signal, sessionId, rawLog)) {
455
+ const onAbort = () => { void killProcessTree(proc.pid); };
456
+ signal?.addEventListener("abort", onAbort, { once: true });
457
+ let sawResult = false;
458
+
459
+ try {
460
+ for await (const raw of readJsonLines(proc, signal, sessionId, rawLog)) {
461
461
  if (signal?.aborted) break;
462
462
  if (
463
463
  raw.type === "system" &&
@@ -473,17 +473,17 @@ class CursorAdapter implements ToolAdapter {
473
473
  if (normalized) yield normalized;
474
474
 
475
475
  // result 是流末事件,收到后立即结束进程,防止 CLI 僵死导致 readline 挂起。
476
- if (raw.type === "result") {
477
- sawResult = true;
478
- void killProcessTree(proc.pid);
476
+ if (raw.type === "result") {
477
+ sawResult = true;
478
+ void killProcessTree(proc.pid);
479
479
  break;
480
480
  }
481
481
  }
482
482
  } finally {
483
483
  signal?.removeEventListener("abort", onAbort);
484
- await killProcessTree(proc.pid);
485
- await rawLog?.close({ keep: rawLogConfig.keepCompleted || signal?.aborted === true || !sawResult });
486
- this.activeProcs.delete(proc);
484
+ await killProcessTree(proc.pid);
485
+ await rawLog?.close({ keep: rawLogConfig.keepCompleted || signal?.aborted === true || !sawResult });
486
+ this.activeProcs.delete(proc);
487
487
  if (proc.pid !== undefined) options?.onProcessExit?.({ pid: proc.pid });
488
488
  console.log(`[Cursor debug] prompt end: sessionId=${sessionId}, signalAborted=${signal?.aborted ?? false}`);
489
489
  }
@@ -519,4 +519,4 @@ export function createCursorAdapter(
519
519
  options: CreateCursorAdapterOptions = {},
520
520
  ): ToolAdapter {
521
521
  return new CursorAdapter(options.metaStore ?? defaultCursorSessionMetaStore, options.model);
522
- }
522
+ }