@ganglion/xacpx 0.20.1 → 0.20.3-beta.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.
@@ -3260,6 +3260,7 @@ function createStreamingPromptState(formatToolCalls = false, options) {
3260
3260
  emittedToolCallIds: new Set,
3261
3261
  positionedToolCallIds: new Set,
3262
3262
  toolCalls: new Map,
3263
+ cursorPlanEntries: new Map,
3263
3264
  toolEventMode,
3264
3265
  driver,
3265
3266
  rawStream,
@@ -3318,13 +3319,17 @@ function parseStreamingChunks(state, line) {
3318
3319
  }
3319
3320
  const wantsStructured = state.toolEventMode === "structured" || state.toolEventMode === "both";
3320
3321
  const wantsText = (state.toolEventMode === "text" || state.toolEventMode === "both") && state.formatToolCalls;
3321
- if (wantsStructured && state.onToolEvent) {
3322
- const merged = update.toolCallId ? mergeToolCallUpdate(state, update.toolCallId, update) : update;
3322
+ const merged = update.toolCallId && (state.onToolEvent || state.onPlan) ? mergeToolCallUpdate(state, update.toolCallId, update) : update;
3323
+ const cursorPlan = normalizeCursorPlanUpdate(state, merged);
3324
+ const consumedAsPlan = cursorPlan !== undefined && state.onPlan !== undefined;
3325
+ if (consumedAsPlan) {
3326
+ state.onPlan?.(cursorPlan);
3327
+ } else if (wantsStructured && state.onToolEvent) {
3323
3328
  const toolEvent = buildToolUseEvent(merged, state.driver);
3324
3329
  if (toolEvent)
3325
3330
  state.onToolEvent(toolEvent);
3326
3331
  }
3327
- if (wantsText) {
3332
+ if (wantsText && !consumedAsPlan) {
3328
3333
  const formatted = formatToolCallEvent(update, update.sessionUpdate);
3329
3334
  if (formatted) {
3330
3335
  const toolCallId = update.toolCallId;
@@ -3340,7 +3345,7 @@ function parseStreamingChunks(state, line) {
3340
3345
  }
3341
3346
  if (update.sessionUpdate === "plan") {
3342
3347
  const entries = Array.isArray(update.entries) ? update.entries.filter((x) => !!x && typeof x === "object" && typeof x.content === "string" && typeof x.status === "string") : [];
3343
- if (entries.length > 0)
3348
+ if (Array.isArray(update.entries))
3344
3349
  state.onPlan?.(entries);
3345
3350
  return;
3346
3351
  }
@@ -3452,7 +3457,7 @@ function isEmptyToolField(v) {
3452
3457
  function mergeToolCallUpdate(state, toolCallId, update) {
3453
3458
  const prev = state.toolCalls.get(toolCallId) ?? { toolCallId };
3454
3459
  const merged = { ...prev };
3455
- for (const key of ["kind", "title", "rawInput", "content", "rawOutput", "locations", "status"]) {
3460
+ for (const key of ["kind", "title", "toolCallId", "parentToolCallId", "rawInput", "content", "rawOutput", "locations", "status"]) {
3456
3461
  const next = update[key];
3457
3462
  if (!isEmptyToolField(next))
3458
3463
  merged[key] = next;
@@ -3484,19 +3489,7 @@ function buildToolUseEvent(update, driver) {
3484
3489
  const toolCallId = update.toolCallId;
3485
3490
  if (!toolCallId)
3486
3491
  return null;
3487
- const kindRaw = update.kind ?? "";
3488
- const kind = (() => {
3489
- switch (kindRaw) {
3490
- case "read":
3491
- case "search":
3492
- case "execute":
3493
- case "edit":
3494
- case "think":
3495
- return kindRaw;
3496
- default:
3497
- return "other";
3498
- }
3499
- })();
3492
+ const kind = normalizeToolKind(update, driver);
3500
3493
  const title = (update.title ?? "").trim();
3501
3494
  const toolName = title || "Tool";
3502
3495
  const summaryRaw = summarizeToolInput(update.rawInput, title) || summarizeToolInput(update.rawOutput, title);
@@ -3512,8 +3505,8 @@ function buildToolUseEvent(update, driver) {
3512
3505
  const content = update.content;
3513
3506
  const rawOutput = update.rawOutput ?? claudeToolResponse;
3514
3507
  const locations = update.locations;
3515
- const parentToolCallId = claudeMeta?.parentToolUseId?.trim();
3516
- const isSubagent = claudeMeta?.toolName === "Agent" || driver === "qoder" && update._meta?.qoder?.toolName === "Agent" || driver === "kimi" && isKimiSubagentInput(rawInput) || driver === "codex" && isCodexSubagentMeta(update._meta?.codex?.subagent);
3508
+ const parentToolCallId = claudeMeta?.parentToolUseId?.trim() || update.parentToolCallId?.trim();
3509
+ const isSubagent = claudeMeta?.toolName === "Agent" || driver === "qoder" && update._meta?.qoder?.toolName === "Agent" || driver === "kimi" && isKimiSubagentInput(rawInput) || driver === "codex" && isCodexSubagentMeta(update._meta?.codex?.subagent) || driver === "cursor" && isCursorSubagentInput(rawInput, title);
3517
3510
  return {
3518
3511
  toolCallId,
3519
3512
  ...parentToolCallId ? { parentToolCallId } : {},
@@ -3528,6 +3521,165 @@ function buildToolUseEvent(update, driver) {
3528
3521
  status
3529
3522
  };
3530
3523
  }
3524
+ function normalizeCursorPlanUpdate(state, update) {
3525
+ if (state.driver !== "cursor")
3526
+ return;
3527
+ if (!CURSOR_PLAN_TOOL_NAMES.has(cursorToolIdentity(update)))
3528
+ return;
3529
+ const input = cursorToolInput(update.rawInput);
3530
+ const output = cursorToolInput(update.rawOutput);
3531
+ const todos = readCursorTodoList(input) ?? readCursorTodoList(output);
3532
+ if (todos === undefined)
3533
+ return;
3534
+ const merge = input?.merge === true || output?.merge === true;
3535
+ if (todos.length === 0) {
3536
+ state.cursorPlanEntries.clear();
3537
+ return [];
3538
+ }
3539
+ const patches = todos.map((todo, index) => parseCursorPlanTodo(todo, index)).filter((todo) => todo !== undefined);
3540
+ if (patches.length === 0)
3541
+ return;
3542
+ if (!merge)
3543
+ state.cursorPlanEntries.clear();
3544
+ for (const patch of patches) {
3545
+ const previous = state.cursorPlanEntries.get(patch.key);
3546
+ const content = patch.content ?? previous?.content;
3547
+ if (!content)
3548
+ continue;
3549
+ const status = patch.status ?? previous?.status ?? "pending";
3550
+ const priority = patch.priority ?? previous?.priority;
3551
+ state.cursorPlanEntries.set(patch.key, {
3552
+ content,
3553
+ status,
3554
+ ...priority ? { priority } : {}
3555
+ });
3556
+ }
3557
+ return [...state.cursorPlanEntries.values()];
3558
+ }
3559
+ function readCursorTodoList(input) {
3560
+ if (!input)
3561
+ return;
3562
+ for (const key of ["todos", "todoList"]) {
3563
+ if (Array.isArray(input[key]))
3564
+ return input[key];
3565
+ }
3566
+ return;
3567
+ }
3568
+ function parseCursorPlanTodo(value, index) {
3569
+ if (!isRecord2(value))
3570
+ return;
3571
+ const id = readFirstString(value, ["id", "todoId", "taskId"]);
3572
+ const content = readFirstString(value, ["content", "task", "description", "title", "text"]);
3573
+ const key = id ? `id:${id}` : content ? `content:${content}` : `index:${index}`;
3574
+ const status = normalizeCursorPlanStatus(value.status ?? value.state);
3575
+ const priority = normalizePlanPriority(value.priority);
3576
+ if (!content && !status && !priority && !id)
3577
+ return;
3578
+ return {
3579
+ key,
3580
+ ...content ? { content } : {},
3581
+ ...status ? { status } : {},
3582
+ ...priority ? { priority } : {}
3583
+ };
3584
+ }
3585
+ function normalizeCursorPlanStatus(value) {
3586
+ if (typeof value !== "string")
3587
+ return;
3588
+ const normalized = value.trim().toLowerCase().replace(/[\s-]+/g, "_").replace(/^todo_status_/, "");
3589
+ switch (normalized) {
3590
+ case "pending":
3591
+ case "todo":
3592
+ case "not_started":
3593
+ case "notstarted":
3594
+ case "incomplete":
3595
+ return "pending";
3596
+ case "in_progress":
3597
+ case "inprogress":
3598
+ case "active":
3599
+ case "working":
3600
+ return "in_progress";
3601
+ case "completed":
3602
+ case "complete":
3603
+ case "done":
3604
+ case "finished":
3605
+ return "completed";
3606
+ default:
3607
+ return;
3608
+ }
3609
+ }
3610
+ function normalizePlanPriority(value) {
3611
+ if (value !== "high" && value !== "medium" && value !== "low")
3612
+ return;
3613
+ return value;
3614
+ }
3615
+ function cursorToolInput(rawInput) {
3616
+ if (!isRecord2(rawInput))
3617
+ return;
3618
+ if (isRecord2(rawInput.args))
3619
+ return rawInput.args;
3620
+ return rawInput;
3621
+ }
3622
+ function normalizeCursorToolName(title) {
3623
+ return (title ?? "").trim().toLowerCase().replace(/[\s_-]+/g, "");
3624
+ }
3625
+ function cursorToolIdentity(update) {
3626
+ const input = cursorToolInput(update.rawInput);
3627
+ const declared = typeof input?.[CURSOR_TOOL_NAME_KEY] === "string" ? input[CURSOR_TOOL_NAME_KEY] : undefined;
3628
+ return normalizeCursorToolName(declared ?? update.title);
3629
+ }
3630
+ function normalizeToolKind(update, driver) {
3631
+ const kindRaw = update?.kind?.trim().toLowerCase() ?? "";
3632
+ switch (kindRaw) {
3633
+ case "read":
3634
+ case "search":
3635
+ case "execute":
3636
+ case "edit":
3637
+ case "think":
3638
+ return kindRaw;
3639
+ }
3640
+ if (driver !== "cursor")
3641
+ return "other";
3642
+ switch (cursorToolIdentity(update ?? {})) {
3643
+ case "read":
3644
+ case "readfile":
3645
+ return "read";
3646
+ case "grep":
3647
+ case "glob":
3648
+ case "find":
3649
+ case "codebasesearch":
3650
+ case "search":
3651
+ return "search";
3652
+ case "shell":
3653
+ case "bash":
3654
+ case "terminal":
3655
+ return "execute";
3656
+ case "strreplace":
3657
+ case "replace":
3658
+ case "edit":
3659
+ case "write":
3660
+ case "delete":
3661
+ return "edit";
3662
+ case "task":
3663
+ case "delegate":
3664
+ case "runsubagent":
3665
+ case "switchmode":
3666
+ case "todowrite":
3667
+ case "updatetodos":
3668
+ case "todoread":
3669
+ case "createplan":
3670
+ case "updateplan":
3671
+ case "plan":
3672
+ return "think";
3673
+ default:
3674
+ return "other";
3675
+ }
3676
+ }
3677
+ function isCursorSubagentInput(rawInput, title) {
3678
+ if (!CURSOR_SUBAGENT_TOOL_NAMES.has(cursorToolIdentity({ title, rawInput })))
3679
+ return false;
3680
+ const input = cursorToolInput(rawInput);
3681
+ return input !== undefined && readFirstString(input, ["subagent_type", "subagentType", "agent", "agentType", "prompt", "instructions"]) !== undefined;
3682
+ }
3531
3683
  function isKimiSubagentInput(rawInput) {
3532
3684
  return isRecord2(rawInput) && readFirstString(rawInput, ["prompt"]) !== undefined && readFirstString(rawInput, ["subagent_type", "subagentType"]) !== undefined;
3533
3685
  }
@@ -3542,6 +3694,12 @@ function summarizeToolInput(rawInput, title = "") {
3542
3694
  }
3543
3695
  if (!isRecord2(rawInput))
3544
3696
  return;
3697
+ const nestedInput = cursorToolInput(rawInput);
3698
+ if (nestedInput !== rawInput) {
3699
+ const nestedSummary = summarizeToolInput(nestedInput, title);
3700
+ if (nestedSummary)
3701
+ return nestedSummary;
3702
+ }
3545
3703
  const taskSummary = summarizeTaskInput(rawInput, title);
3546
3704
  if (taskSummary)
3547
3705
  return taskSummary;
@@ -3562,6 +3720,16 @@ function summarizeToolInput(rawInput, title = "") {
3562
3720
  return parts.join(" ");
3563
3721
  }
3564
3722
  }
3723
+ const globPattern = readFirstString(rawInput, ["glob_pattern"]);
3724
+ if (globPattern) {
3725
+ const targetDirectory = readFirstString(rawInput, ["target_directory"]);
3726
+ return targetDirectory ? `${globPattern} in ${targetDirectory}` : globPattern;
3727
+ }
3728
+ const mode = readFirstString(rawInput, ["target_mode_id", "mode_id"]);
3729
+ const explanation = readFirstString(rawInput, ["explanation"]);
3730
+ if (mode || explanation) {
3731
+ return mode && explanation ? `${mode}: ${explanation}` : mode ?? explanation;
3732
+ }
3565
3733
  return readFirstString(rawInput, [
3566
3734
  "path",
3567
3735
  "file",
@@ -3575,6 +3743,7 @@ function summarizeToolInput(rawInput, title = "") {
3575
3743
  "pattern",
3576
3744
  "text",
3577
3745
  "search",
3746
+ "working_directory",
3578
3747
  "name",
3579
3748
  "description"
3580
3749
  ]);
@@ -3681,7 +3850,7 @@ function isGenericToolTitle(kind, title) {
3681
3850
  }
3682
3851
  return false;
3683
3852
  }
3684
- var SENTENCE_TERMINAL_AT_END, PARAGRAPH_BOUNDARY_AT_END, PARAGRAPH_BOUNDARY_AT_START, LINE_BREAK_AT_END, LINE_BREAK_AT_START, PARTIAL_CRLF_PARAGRAPH_BOUNDARY_AT_END, USAGE_BREAKDOWN_FIELDS;
3853
+ var SENTENCE_TERMINAL_AT_END, PARAGRAPH_BOUNDARY_AT_END, PARAGRAPH_BOUNDARY_AT_START, LINE_BREAK_AT_END, LINE_BREAK_AT_START, PARTIAL_CRLF_PARAGRAPH_BOUNDARY_AT_END, CURSOR_TOOL_NAME_KEY = "_toolName", CURSOR_PLAN_TOOL_NAMES, CURSOR_SUBAGENT_TOOL_NAMES, USAGE_BREAKDOWN_FIELDS;
3685
3854
  var init_streaming_prompt = __esm(() => {
3686
3855
  init_background_followup();
3687
3856
  init_tool_kind_emoji();
@@ -3691,6 +3860,15 @@ var init_streaming_prompt = __esm(() => {
3691
3860
  LINE_BREAK_AT_END = /\r?\n[\t ]*$/;
3692
3861
  LINE_BREAK_AT_START = /^[\t ]*\r?\n/;
3693
3862
  PARTIAL_CRLF_PARAGRAPH_BOUNDARY_AT_END = /\r?\n[\t ]*\r$/;
3863
+ CURSOR_PLAN_TOOL_NAMES = new Set([
3864
+ "todowrite",
3865
+ "createplan",
3866
+ "updateplan",
3867
+ "plan",
3868
+ "updatetodos",
3869
+ "todoread"
3870
+ ]);
3871
+ CURSOR_SUBAGENT_TOOL_NAMES = new Set(["task", "delegate", "runsubagent", "subagent"]);
3694
3872
  USAGE_BREAKDOWN_FIELDS = [
3695
3873
  ["inputTokens", ["inputTokens", "input_tokens"]],
3696
3874
  ["outputTokens", ["outputTokens", "output_tokens"]],
package/dist/cli.js CHANGED
@@ -52653,6 +52653,7 @@ function createStreamingPromptState(formatToolCalls = false, options) {
52653
52653
  emittedToolCallIds: new Set,
52654
52654
  positionedToolCallIds: new Set,
52655
52655
  toolCalls: new Map,
52656
+ cursorPlanEntries: new Map,
52656
52657
  toolEventMode,
52657
52658
  driver,
52658
52659
  rawStream,
@@ -52711,13 +52712,17 @@ function parseStreamingChunks(state, line) {
52711
52712
  }
52712
52713
  const wantsStructured = state.toolEventMode === "structured" || state.toolEventMode === "both";
52713
52714
  const wantsText = (state.toolEventMode === "text" || state.toolEventMode === "both") && state.formatToolCalls;
52714
- if (wantsStructured && state.onToolEvent) {
52715
- const merged = update.toolCallId ? mergeToolCallUpdate(state, update.toolCallId, update) : update;
52715
+ const merged = update.toolCallId && (state.onToolEvent || state.onPlan) ? mergeToolCallUpdate(state, update.toolCallId, update) : update;
52716
+ const cursorPlan = normalizeCursorPlanUpdate(state, merged);
52717
+ const consumedAsPlan = cursorPlan !== undefined && state.onPlan !== undefined;
52718
+ if (consumedAsPlan) {
52719
+ state.onPlan?.(cursorPlan);
52720
+ } else if (wantsStructured && state.onToolEvent) {
52716
52721
  const toolEvent = buildToolUseEvent(merged, state.driver);
52717
52722
  if (toolEvent)
52718
52723
  state.onToolEvent(toolEvent);
52719
52724
  }
52720
- if (wantsText) {
52725
+ if (wantsText && !consumedAsPlan) {
52721
52726
  const formatted = formatToolCallEvent(update, update.sessionUpdate);
52722
52727
  if (formatted) {
52723
52728
  const toolCallId = update.toolCallId;
@@ -52733,7 +52738,7 @@ function parseStreamingChunks(state, line) {
52733
52738
  }
52734
52739
  if (update.sessionUpdate === "plan") {
52735
52740
  const entries = Array.isArray(update.entries) ? update.entries.filter((x) => !!x && typeof x === "object" && typeof x.content === "string" && typeof x.status === "string") : [];
52736
- if (entries.length > 0)
52741
+ if (Array.isArray(update.entries))
52737
52742
  state.onPlan?.(entries);
52738
52743
  return;
52739
52744
  }
@@ -52845,7 +52850,7 @@ function isEmptyToolField(v) {
52845
52850
  function mergeToolCallUpdate(state, toolCallId, update) {
52846
52851
  const prev = state.toolCalls.get(toolCallId) ?? { toolCallId };
52847
52852
  const merged = { ...prev };
52848
- for (const key of ["kind", "title", "rawInput", "content", "rawOutput", "locations", "status"]) {
52853
+ for (const key of ["kind", "title", "toolCallId", "parentToolCallId", "rawInput", "content", "rawOutput", "locations", "status"]) {
52849
52854
  const next = update[key];
52850
52855
  if (!isEmptyToolField(next))
52851
52856
  merged[key] = next;
@@ -52877,19 +52882,7 @@ function buildToolUseEvent(update, driver) {
52877
52882
  const toolCallId = update.toolCallId;
52878
52883
  if (!toolCallId)
52879
52884
  return null;
52880
- const kindRaw = update.kind ?? "";
52881
- const kind = (() => {
52882
- switch (kindRaw) {
52883
- case "read":
52884
- case "search":
52885
- case "execute":
52886
- case "edit":
52887
- case "think":
52888
- return kindRaw;
52889
- default:
52890
- return "other";
52891
- }
52892
- })();
52885
+ const kind = normalizeToolKind(update, driver);
52893
52886
  const title = (update.title ?? "").trim();
52894
52887
  const toolName = title || "Tool";
52895
52888
  const summaryRaw = summarizeToolInput(update.rawInput, title) || summarizeToolInput(update.rawOutput, title);
@@ -52905,8 +52898,8 @@ function buildToolUseEvent(update, driver) {
52905
52898
  const content = update.content;
52906
52899
  const rawOutput = update.rawOutput ?? claudeToolResponse;
52907
52900
  const locations = update.locations;
52908
- const parentToolCallId = claudeMeta?.parentToolUseId?.trim();
52909
- const isSubagent = claudeMeta?.toolName === "Agent" || driver === "qoder" && update._meta?.qoder?.toolName === "Agent" || driver === "kimi" && isKimiSubagentInput(rawInput) || driver === "codex" && isCodexSubagentMeta(update._meta?.codex?.subagent);
52901
+ const parentToolCallId = claudeMeta?.parentToolUseId?.trim() || update.parentToolCallId?.trim();
52902
+ const isSubagent = claudeMeta?.toolName === "Agent" || driver === "qoder" && update._meta?.qoder?.toolName === "Agent" || driver === "kimi" && isKimiSubagentInput(rawInput) || driver === "codex" && isCodexSubagentMeta(update._meta?.codex?.subagent) || driver === "cursor" && isCursorSubagentInput(rawInput, title);
52910
52903
  return {
52911
52904
  toolCallId,
52912
52905
  ...parentToolCallId ? { parentToolCallId } : {},
@@ -52921,6 +52914,165 @@ function buildToolUseEvent(update, driver) {
52921
52914
  status
52922
52915
  };
52923
52916
  }
52917
+ function normalizeCursorPlanUpdate(state, update) {
52918
+ if (state.driver !== "cursor")
52919
+ return;
52920
+ if (!CURSOR_PLAN_TOOL_NAMES.has(cursorToolIdentity(update)))
52921
+ return;
52922
+ const input = cursorToolInput(update.rawInput);
52923
+ const output = cursorToolInput(update.rawOutput);
52924
+ const todos = readCursorTodoList(input) ?? readCursorTodoList(output);
52925
+ if (todos === undefined)
52926
+ return;
52927
+ const merge2 = input?.merge === true || output?.merge === true;
52928
+ if (todos.length === 0) {
52929
+ state.cursorPlanEntries.clear();
52930
+ return [];
52931
+ }
52932
+ const patches = todos.map((todo, index) => parseCursorPlanTodo(todo, index)).filter((todo) => todo !== undefined);
52933
+ if (patches.length === 0)
52934
+ return;
52935
+ if (!merge2)
52936
+ state.cursorPlanEntries.clear();
52937
+ for (const patch of patches) {
52938
+ const previous = state.cursorPlanEntries.get(patch.key);
52939
+ const content = patch.content ?? previous?.content;
52940
+ if (!content)
52941
+ continue;
52942
+ const status = patch.status ?? previous?.status ?? "pending";
52943
+ const priority = patch.priority ?? previous?.priority;
52944
+ state.cursorPlanEntries.set(patch.key, {
52945
+ content,
52946
+ status,
52947
+ ...priority ? { priority } : {}
52948
+ });
52949
+ }
52950
+ return [...state.cursorPlanEntries.values()];
52951
+ }
52952
+ function readCursorTodoList(input) {
52953
+ if (!input)
52954
+ return;
52955
+ for (const key of ["todos", "todoList"]) {
52956
+ if (Array.isArray(input[key]))
52957
+ return input[key];
52958
+ }
52959
+ return;
52960
+ }
52961
+ function parseCursorPlanTodo(value, index) {
52962
+ if (!isRecord4(value))
52963
+ return;
52964
+ const id = readFirstString(value, ["id", "todoId", "taskId"]);
52965
+ const content = readFirstString(value, ["content", "task", "description", "title", "text"]);
52966
+ const key = id ? `id:${id}` : content ? `content:${content}` : `index:${index}`;
52967
+ const status = normalizeCursorPlanStatus(value.status ?? value.state);
52968
+ const priority = normalizePlanPriority(value.priority);
52969
+ if (!content && !status && !priority && !id)
52970
+ return;
52971
+ return {
52972
+ key,
52973
+ ...content ? { content } : {},
52974
+ ...status ? { status } : {},
52975
+ ...priority ? { priority } : {}
52976
+ };
52977
+ }
52978
+ function normalizeCursorPlanStatus(value) {
52979
+ if (typeof value !== "string")
52980
+ return;
52981
+ const normalized = value.trim().toLowerCase().replace(/[\s-]+/g, "_").replace(/^todo_status_/, "");
52982
+ switch (normalized) {
52983
+ case "pending":
52984
+ case "todo":
52985
+ case "not_started":
52986
+ case "notstarted":
52987
+ case "incomplete":
52988
+ return "pending";
52989
+ case "in_progress":
52990
+ case "inprogress":
52991
+ case "active":
52992
+ case "working":
52993
+ return "in_progress";
52994
+ case "completed":
52995
+ case "complete":
52996
+ case "done":
52997
+ case "finished":
52998
+ return "completed";
52999
+ default:
53000
+ return;
53001
+ }
53002
+ }
53003
+ function normalizePlanPriority(value) {
53004
+ if (value !== "high" && value !== "medium" && value !== "low")
53005
+ return;
53006
+ return value;
53007
+ }
53008
+ function cursorToolInput(rawInput) {
53009
+ if (!isRecord4(rawInput))
53010
+ return;
53011
+ if (isRecord4(rawInput.args))
53012
+ return rawInput.args;
53013
+ return rawInput;
53014
+ }
53015
+ function normalizeCursorToolName(title) {
53016
+ return (title ?? "").trim().toLowerCase().replace(/[\s_-]+/g, "");
53017
+ }
53018
+ function cursorToolIdentity(update) {
53019
+ const input = cursorToolInput(update.rawInput);
53020
+ const declared = typeof input?.[CURSOR_TOOL_NAME_KEY] === "string" ? input[CURSOR_TOOL_NAME_KEY] : undefined;
53021
+ return normalizeCursorToolName(declared ?? update.title);
53022
+ }
53023
+ function normalizeToolKind(update, driver) {
53024
+ const kindRaw = update?.kind?.trim().toLowerCase() ?? "";
53025
+ switch (kindRaw) {
53026
+ case "read":
53027
+ case "search":
53028
+ case "execute":
53029
+ case "edit":
53030
+ case "think":
53031
+ return kindRaw;
53032
+ }
53033
+ if (driver !== "cursor")
53034
+ return "other";
53035
+ switch (cursorToolIdentity(update ?? {})) {
53036
+ case "read":
53037
+ case "readfile":
53038
+ return "read";
53039
+ case "grep":
53040
+ case "glob":
53041
+ case "find":
53042
+ case "codebasesearch":
53043
+ case "search":
53044
+ return "search";
53045
+ case "shell":
53046
+ case "bash":
53047
+ case "terminal":
53048
+ return "execute";
53049
+ case "strreplace":
53050
+ case "replace":
53051
+ case "edit":
53052
+ case "write":
53053
+ case "delete":
53054
+ return "edit";
53055
+ case "task":
53056
+ case "delegate":
53057
+ case "runsubagent":
53058
+ case "switchmode":
53059
+ case "todowrite":
53060
+ case "updatetodos":
53061
+ case "todoread":
53062
+ case "createplan":
53063
+ case "updateplan":
53064
+ case "plan":
53065
+ return "think";
53066
+ default:
53067
+ return "other";
53068
+ }
53069
+ }
53070
+ function isCursorSubagentInput(rawInput, title) {
53071
+ if (!CURSOR_SUBAGENT_TOOL_NAMES.has(cursorToolIdentity({ title, rawInput })))
53072
+ return false;
53073
+ const input = cursorToolInput(rawInput);
53074
+ return input !== undefined && readFirstString(input, ["subagent_type", "subagentType", "agent", "agentType", "prompt", "instructions"]) !== undefined;
53075
+ }
52924
53076
  function isKimiSubagentInput(rawInput) {
52925
53077
  return isRecord4(rawInput) && readFirstString(rawInput, ["prompt"]) !== undefined && readFirstString(rawInput, ["subagent_type", "subagentType"]) !== undefined;
52926
53078
  }
@@ -52935,6 +53087,12 @@ function summarizeToolInput(rawInput, title = "") {
52935
53087
  }
52936
53088
  if (!isRecord4(rawInput))
52937
53089
  return;
53090
+ const nestedInput = cursorToolInput(rawInput);
53091
+ if (nestedInput !== rawInput) {
53092
+ const nestedSummary = summarizeToolInput(nestedInput, title);
53093
+ if (nestedSummary)
53094
+ return nestedSummary;
53095
+ }
52938
53096
  const taskSummary = summarizeTaskInput(rawInput, title);
52939
53097
  if (taskSummary)
52940
53098
  return taskSummary;
@@ -52955,6 +53113,16 @@ function summarizeToolInput(rawInput, title = "") {
52955
53113
  return parts.join(" ");
52956
53114
  }
52957
53115
  }
53116
+ const globPattern = readFirstString(rawInput, ["glob_pattern"]);
53117
+ if (globPattern) {
53118
+ const targetDirectory = readFirstString(rawInput, ["target_directory"]);
53119
+ return targetDirectory ? `${globPattern} in ${targetDirectory}` : globPattern;
53120
+ }
53121
+ const mode = readFirstString(rawInput, ["target_mode_id", "mode_id"]);
53122
+ const explanation = readFirstString(rawInput, ["explanation"]);
53123
+ if (mode || explanation) {
53124
+ return mode && explanation ? `${mode}: ${explanation}` : mode ?? explanation;
53125
+ }
52958
53126
  return readFirstString(rawInput, [
52959
53127
  "path",
52960
53128
  "file",
@@ -52968,6 +53136,7 @@ function summarizeToolInput(rawInput, title = "") {
52968
53136
  "pattern",
52969
53137
  "text",
52970
53138
  "search",
53139
+ "working_directory",
52971
53140
  "name",
52972
53141
  "description"
52973
53142
  ]);
@@ -53074,7 +53243,7 @@ function isGenericToolTitle(kind, title) {
53074
53243
  }
53075
53244
  return false;
53076
53245
  }
53077
- var SENTENCE_TERMINAL_AT_END, PARAGRAPH_BOUNDARY_AT_END, PARAGRAPH_BOUNDARY_AT_START, LINE_BREAK_AT_END, LINE_BREAK_AT_START, PARTIAL_CRLF_PARAGRAPH_BOUNDARY_AT_END, USAGE_BREAKDOWN_FIELDS;
53246
+ var SENTENCE_TERMINAL_AT_END, PARAGRAPH_BOUNDARY_AT_END, PARAGRAPH_BOUNDARY_AT_START, LINE_BREAK_AT_END, LINE_BREAK_AT_START, PARTIAL_CRLF_PARAGRAPH_BOUNDARY_AT_END, CURSOR_TOOL_NAME_KEY = "_toolName", CURSOR_PLAN_TOOL_NAMES, CURSOR_SUBAGENT_TOOL_NAMES, USAGE_BREAKDOWN_FIELDS;
53078
53247
  var init_streaming_prompt = __esm(() => {
53079
53248
  init_background_followup();
53080
53249
  init_tool_kind_emoji();
@@ -53084,6 +53253,15 @@ var init_streaming_prompt = __esm(() => {
53084
53253
  LINE_BREAK_AT_END = /\r?\n[\t ]*$/;
53085
53254
  LINE_BREAK_AT_START = /^[\t ]*\r?\n/;
53086
53255
  PARTIAL_CRLF_PARAGRAPH_BOUNDARY_AT_END = /\r?\n[\t ]*\r$/;
53256
+ CURSOR_PLAN_TOOL_NAMES = new Set([
53257
+ "todowrite",
53258
+ "createplan",
53259
+ "updateplan",
53260
+ "plan",
53261
+ "updatetodos",
53262
+ "todoread"
53263
+ ]);
53264
+ CURSOR_SUBAGENT_TOOL_NAMES = new Set(["task", "delegate", "runsubagent", "subagent"]);
53087
53265
  USAGE_BREAKDOWN_FIELDS = [
53088
53266
  ["inputTokens", ["inputTokens", "input_tokens"]],
53089
53267
  ["outputTokens", ["outputTokens", "output_tokens"]],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ganglion/xacpx",
3
- "version": "0.20.1",
3
+ "version": "0.20.3-beta.0",
4
4
  "description": "随时随地通过聊天频道(微信 / 飞书 / 元宝等)远程控制 `acpx` 上的 Claude Code、Codex 等 Agents。",
5
5
  "keywords": [
6
6
  "acpx",