pi-cc-extensions 0.8.27 → 0.8.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/extensions/claude-code-style.ts +127 -24
- package/extensions/tool-grouping.ts +48 -0
- package/package.json +1 -1
|
@@ -2354,9 +2354,46 @@ function singleToolCallSummary(
|
|
|
2354
2354
|
): { main: string; detail: string } {
|
|
2355
2355
|
const title = label === toolName ? humanizeToolLabel(label) : label;
|
|
2356
2356
|
if (!args || typeof args !== "object") return { main: title, detail: "" };
|
|
2357
|
+
const name = toolName.toLowerCase();
|
|
2358
|
+
const value = (fallback: string, ...keys: string[]) => {
|
|
2359
|
+
const found = keys.map((key) => args[key]).find((item) => typeof item === "string" && item);
|
|
2360
|
+
return `${title} ${oneLine(found || fallback, Infinity)}`;
|
|
2361
|
+
};
|
|
2357
2362
|
if (AGENT_FAMILY_TOOL_NAMES.has(toolName) && args.agent_id) {
|
|
2358
2363
|
return { main: `${title} ${oneLine(args.agent_id, Infinity)}`, detail: "" };
|
|
2359
2364
|
}
|
|
2365
|
+
if (name === "agent" || name === "agents") {
|
|
2366
|
+
return {
|
|
2367
|
+
main: value(name === "agent" ? "launch agent" : "launch agents", "description", "prompt"),
|
|
2368
|
+
detail: "",
|
|
2369
|
+
};
|
|
2370
|
+
}
|
|
2371
|
+
if (name === "skill") return { main: value("run skill", "name"), detail: "" };
|
|
2372
|
+
if (name === "enterplanmode" || name === "enter_plan_mode") {
|
|
2373
|
+
return { main: `${title} enable read-only planning`, detail: "" };
|
|
2374
|
+
}
|
|
2375
|
+
if (name === "exitplanmode" || name === "exit_plan_mode") {
|
|
2376
|
+
return { main: `${title} present plan`, detail: "" };
|
|
2377
|
+
}
|
|
2378
|
+
if (name === "taskcreate") return { main: value("create task", "subject"), detail: "" };
|
|
2379
|
+
if (name === "tasklist") return { main: `${title} task list`, detail: "" };
|
|
2380
|
+
if (name === "taskget" || name === "taskupdate") {
|
|
2381
|
+
return { main: value("task", "taskId", "task_id"), detail: "" };
|
|
2382
|
+
}
|
|
2383
|
+
if (name === "taskoutput" || name === "taskstop") {
|
|
2384
|
+
return { main: value("background task", "task_id", "taskId"), detail: "" };
|
|
2385
|
+
}
|
|
2386
|
+
if (name === "taskexecute") {
|
|
2387
|
+
const ids = Array.isArray(args.task_ids)
|
|
2388
|
+
? args.task_ids
|
|
2389
|
+
: Array.isArray(args.taskIds)
|
|
2390
|
+
? args.taskIds
|
|
2391
|
+
: [];
|
|
2392
|
+
const summary = ids.length
|
|
2393
|
+
? `${ids[0]}${ids.length > 1 ? ` (+${ids.length - 1} tasks)` : ""}`
|
|
2394
|
+
: "start tasks";
|
|
2395
|
+
return { main: `${title} ${summary}`, detail: "" };
|
|
2396
|
+
}
|
|
2360
2397
|
if (toolName === "read") {
|
|
2361
2398
|
const details = [
|
|
2362
2399
|
args.offset !== undefined ? `offset=${args.offset}` : "",
|
|
@@ -2367,7 +2404,7 @@ function singleToolCallSummary(
|
|
|
2367
2404
|
detail: details.length ? ` (${details.join(", ")})` : "",
|
|
2368
2405
|
};
|
|
2369
2406
|
}
|
|
2370
|
-
const
|
|
2407
|
+
const preferred =
|
|
2371
2408
|
args.path ??
|
|
2372
2409
|
args.file_path ??
|
|
2373
2410
|
args.command ??
|
|
@@ -2382,8 +2419,8 @@ function singleToolCallSummary(
|
|
|
2382
2419
|
args.message;
|
|
2383
2420
|
return {
|
|
2384
2421
|
main:
|
|
2385
|
-
|
|
2386
|
-
? `${title} ${oneLine(
|
|
2422
|
+
preferred !== undefined && preferred !== null && typeof preferred !== "object"
|
|
2423
|
+
? `${title} ${oneLine(preferred, Infinity)}`
|
|
2387
2424
|
: title,
|
|
2388
2425
|
detail: "",
|
|
2389
2426
|
};
|
|
@@ -2415,6 +2452,74 @@ export function shouldRenderRichDiff(
|
|
|
2415
2452
|
return mode === "on" && !isError && (toolName === "edit" || toolName === "write");
|
|
2416
2453
|
}
|
|
2417
2454
|
|
|
2455
|
+
type ParsedTask = { id: string; status: string; subject: string };
|
|
2456
|
+
|
|
2457
|
+
function parseTaskList(text: string): ParsedTask[] {
|
|
2458
|
+
return text
|
|
2459
|
+
.split("\n")
|
|
2460
|
+
.map((line) => line.match(/^#(\d+) \[([^\]]+)] (.+)$/))
|
|
2461
|
+
.filter((match): match is RegExpMatchArray => Boolean(match))
|
|
2462
|
+
.map((match) => ({ id: match[1]!, status: match[2]!, subject: match[3]! }));
|
|
2463
|
+
}
|
|
2464
|
+
|
|
2465
|
+
function taskListSummary(tasks: ParsedTask[]): string {
|
|
2466
|
+
const counts = { pending: 0, in_progress: 0, completed: 0 };
|
|
2467
|
+
for (const task of tasks) {
|
|
2468
|
+
if (task.status in counts) counts[task.status as keyof typeof counts]++;
|
|
2469
|
+
}
|
|
2470
|
+
return [
|
|
2471
|
+
`${tasks.length} tasks`,
|
|
2472
|
+
counts.in_progress ? `${counts.in_progress} in progress` : "",
|
|
2473
|
+
counts.pending ? `${counts.pending} pending` : "",
|
|
2474
|
+
counts.completed ? `${counts.completed} completed` : "",
|
|
2475
|
+
]
|
|
2476
|
+
.filter(Boolean)
|
|
2477
|
+
.join(" • ");
|
|
2478
|
+
}
|
|
2479
|
+
|
|
2480
|
+
function renderExpandedTaskResult(
|
|
2481
|
+
toolName: string,
|
|
2482
|
+
text: string,
|
|
2483
|
+
theme: any,
|
|
2484
|
+
isError: boolean,
|
|
2485
|
+
): any | undefined {
|
|
2486
|
+
if (isError) return undefined;
|
|
2487
|
+
if (toolName === "TaskList") {
|
|
2488
|
+
const tasks = parseTaskList(text);
|
|
2489
|
+
if (!tasks.length) return undefined;
|
|
2490
|
+
const limit = Math.max(1, config.expandedPreviewMaxLines);
|
|
2491
|
+
const rows = tasks.slice(0, limit).map((task) => {
|
|
2492
|
+
const color =
|
|
2493
|
+
task.status === "completed"
|
|
2494
|
+
? "success"
|
|
2495
|
+
: task.status === "in_progress"
|
|
2496
|
+
? "warning"
|
|
2497
|
+
: "muted";
|
|
2498
|
+
return ` ${theme.fg("accent", `#${task.id}`)} ${theme.fg(color, task.status)} ${theme.fg("dim", task.subject)}`;
|
|
2499
|
+
});
|
|
2500
|
+
if (tasks.length > rows.length)
|
|
2501
|
+
rows.push(theme.fg("muted", ` … ${tasks.length - rows.length} more tasks`));
|
|
2502
|
+
return new Text(` ↳ ${theme.fg("muted", taskListSummary(tasks))}\n${rows.join("\n")}`, 0, 0);
|
|
2503
|
+
}
|
|
2504
|
+
const line = text.trim();
|
|
2505
|
+
if (!line || line.includes("\n")) return undefined;
|
|
2506
|
+
let formatted: string | undefined;
|
|
2507
|
+
let match: RegExpMatchArray | null;
|
|
2508
|
+
if (
|
|
2509
|
+
toolName === "TaskCreate" &&
|
|
2510
|
+
(match = line.match(/^Task #(\d+) created successfully: (.+)$/))
|
|
2511
|
+
) {
|
|
2512
|
+
formatted = `${theme.fg("success", "Created task")} ${theme.fg("accent", `#${match[1]}`)} ${theme.fg("muted", match[2])}`;
|
|
2513
|
+
} else if (toolName === "TaskUpdate" && (match = line.match(/^Updated task #(\d+) (.+)$/))) {
|
|
2514
|
+
formatted = `${theme.fg("success", "Updated task")} ${theme.fg("accent", `#${match[1]}`)} ${theme.fg("muted", match[2])}`;
|
|
2515
|
+
} else if (toolName === "TaskExecute") {
|
|
2516
|
+
formatted = `${theme.fg("success", "Started")} ${theme.fg("muted", line)}`;
|
|
2517
|
+
} else if (toolName === "TaskStop") {
|
|
2518
|
+
formatted = `${theme.fg("success", "Stopped")} ${theme.fg("muted", line)}`;
|
|
2519
|
+
}
|
|
2520
|
+
return formatted ? new Text(` ↳ ${formatted}`, 0, 0) : undefined;
|
|
2521
|
+
}
|
|
2522
|
+
|
|
2418
2523
|
/** Wrap an arbitrary tool definition with ccstyle call/result rendering. */
|
|
2419
2524
|
function createCcstyleTool(
|
|
2420
2525
|
originalTool: any,
|
|
@@ -2493,17 +2598,24 @@ function createCcstyleTool(
|
|
|
2493
2598
|
|
|
2494
2599
|
const text = textFromResult(result, expanded);
|
|
2495
2600
|
const args = context?.args;
|
|
2601
|
+
if (expanded) {
|
|
2602
|
+
const taskResult = renderExpandedTaskResult(toolName, text, theme, Boolean(isError));
|
|
2603
|
+
if (taskResult) return taskResult;
|
|
2604
|
+
}
|
|
2605
|
+
const tasks = !isError && toolName === "TaskList" ? parseTaskList(text) : [];
|
|
2496
2606
|
const outputLines = outputLineCount(result) || countLines(text);
|
|
2497
2607
|
const lineWord = outputLines === 1 ? "line" : "lines";
|
|
2498
2608
|
const action = toolName === "read" ? "loaded" : "returned";
|
|
2499
|
-
const rendered =
|
|
2500
|
-
?
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
:
|
|
2506
|
-
|
|
2609
|
+
const rendered = tasks.length
|
|
2610
|
+
? taskListSummary(tasks)
|
|
2611
|
+
: isError
|
|
2612
|
+
? text
|
|
2613
|
+
? oneLine(text)
|
|
2614
|
+
: "Failed"
|
|
2615
|
+
: outputLines
|
|
2616
|
+
? `${outputLines} ${lineWord} ${action}`
|
|
2617
|
+
: "Done";
|
|
2618
|
+
const expandable = !expanded && (tasks.length > 0 || hasExpandableDetail(text, args));
|
|
2507
2619
|
const hint = expandable ? theme.fg("muted", " • click to show more") : "";
|
|
2508
2620
|
const hoveredHint = expandable ? theme.fg("text", " • click to show more") : "";
|
|
2509
2621
|
if (expanded) {
|
|
@@ -2546,7 +2658,7 @@ function createCcstyleTool(
|
|
|
2546
2658
|
* Apart from the write override used to capture pre-write content, renderers are
|
|
2547
2659
|
* applied through ToolExecutionComponent. Patch its lookup once so tools use the
|
|
2548
2660
|
* same compact fallback shell by default. Tools named in excludeRenderers keep
|
|
2549
|
-
* their original renderer
|
|
2661
|
+
* their original renderer.
|
|
2550
2662
|
*/
|
|
2551
2663
|
const GLOBAL_TOOL_RENDER_PATCH = Symbol.for("pi.ccstyle.global-tool-render-patch");
|
|
2552
2664
|
const COMPONENT_TOOL_RENDER_MODE = Symbol.for("pi.ccstyle.component-tool-render-mode");
|
|
@@ -2557,7 +2669,6 @@ const AGENT_FAMILY_TOOL_NAMES = new Set([
|
|
|
2557
2669
|
"get_subagent_result",
|
|
2558
2670
|
"steer_subagent",
|
|
2559
2671
|
]);
|
|
2560
|
-
const DEDICATED_SUBAGENT_TOOL_NAMES = new Set(["Agent"]);
|
|
2561
2672
|
|
|
2562
2673
|
type ToolRenderMethods = {
|
|
2563
2674
|
hasRendererDefinition: (...args: any[]) => boolean;
|
|
@@ -2611,7 +2722,6 @@ export function preservesOriginalRenderer(
|
|
|
2611
2722
|
builtInToolDefinition?: any,
|
|
2612
2723
|
excludeRenderers: readonly string[] = config.excludeRenderers,
|
|
2613
2724
|
): boolean {
|
|
2614
|
-
if (DEDICATED_SUBAGENT_TOOL_NAMES.has(toolName)) return true;
|
|
2615
2725
|
if (!excludeRenderers.includes(toolName)) return false;
|
|
2616
2726
|
return [extensionDefinition, builtInToolDefinition].some(
|
|
2617
2727
|
(definition) =>
|
|
@@ -2652,16 +2762,9 @@ function shouldGloballyStyleTool(component: any, patch: GlobalToolRenderPatch):
|
|
|
2652
2762
|
return useCcstyle;
|
|
2653
2763
|
}
|
|
2654
2764
|
|
|
2655
|
-
function shouldUseSelfShell(component: any,
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
const useSelfShell =
|
|
2659
|
-
patch.enabled() &&
|
|
2660
|
-
DEDICATED_SUBAGENT_TOOL_NAMES.has(toolName) &&
|
|
2661
|
-
definition != null &&
|
|
2662
|
-
definition.renderShell === undefined;
|
|
2663
|
-
component[COMPONENT_TOOL_SELF_SHELL_MODE] = useSelfShell;
|
|
2664
|
-
return useSelfShell;
|
|
2765
|
+
function shouldUseSelfShell(component: any, _patch: GlobalToolRenderPatch): boolean {
|
|
2766
|
+
component[COMPONENT_TOOL_SELF_SHELL_MODE] = false;
|
|
2767
|
+
return false;
|
|
2665
2768
|
}
|
|
2666
2769
|
|
|
2667
2770
|
function getGloballyStyledTool(component: any, patch: GlobalToolRenderPatch): any {
|
|
@@ -110,7 +110,55 @@ function humanizeToolName(name: string): string {
|
|
|
110
110
|
|
|
111
111
|
function toolSummary(tool: any): { main: string; detail: string } {
|
|
112
112
|
const name = toolName(tool);
|
|
113
|
+
const lowerName = name.toLowerCase();
|
|
113
114
|
const args = tool?.args ?? {};
|
|
115
|
+
const titled = humanizeToolName(name);
|
|
116
|
+
const value = (fallback: string, ...keys: string[]) => {
|
|
117
|
+
const found = keys.map((key) => args[key]).find((item) => typeof item === "string" && item);
|
|
118
|
+
return `${titled} ${oneLine(found || fallback)}`;
|
|
119
|
+
};
|
|
120
|
+
if (lowerName === "agent" || lowerName === "agents") {
|
|
121
|
+
return {
|
|
122
|
+
main: value(
|
|
123
|
+
lowerName === "agent" ? "launch agent" : "launch agents",
|
|
124
|
+
"description",
|
|
125
|
+
"prompt",
|
|
126
|
+
),
|
|
127
|
+
detail: "",
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
if (lowerName === "get_subagent_result" || lowerName === "steer_subagent") {
|
|
131
|
+
return {
|
|
132
|
+
main: value(lowerName === "get_subagent_result" ? "agent result" : "steer agent", "agent_id"),
|
|
133
|
+
detail: "",
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
if (lowerName === "skill") return { main: value("run skill", "name"), detail: "" };
|
|
137
|
+
if (lowerName === "enterplanmode" || lowerName === "enter_plan_mode") {
|
|
138
|
+
return { main: `${titled} enable read-only planning`, detail: "" };
|
|
139
|
+
}
|
|
140
|
+
if (lowerName === "exitplanmode" || lowerName === "exit_plan_mode") {
|
|
141
|
+
return { main: `${titled} present plan`, detail: "" };
|
|
142
|
+
}
|
|
143
|
+
if (lowerName === "taskcreate") return { main: value("create task", "subject"), detail: "" };
|
|
144
|
+
if (lowerName === "tasklist") return { main: `${titled} task list`, detail: "" };
|
|
145
|
+
if (lowerName === "taskget" || lowerName === "taskupdate") {
|
|
146
|
+
return { main: value("task", "taskId", "task_id"), detail: "" };
|
|
147
|
+
}
|
|
148
|
+
if (lowerName === "taskoutput" || lowerName === "taskstop") {
|
|
149
|
+
return { main: value("background task", "task_id", "taskId"), detail: "" };
|
|
150
|
+
}
|
|
151
|
+
if (lowerName === "taskexecute") {
|
|
152
|
+
const ids = Array.isArray(args.task_ids)
|
|
153
|
+
? args.task_ids
|
|
154
|
+
: Array.isArray(args.taskIds)
|
|
155
|
+
? args.taskIds
|
|
156
|
+
: [];
|
|
157
|
+
return {
|
|
158
|
+
main: `${titled} ${ids.length ? `${ids[0]}${ids.length > 1 ? ` (+${ids.length - 1} tasks)` : ""}` : "start tasks"}`,
|
|
159
|
+
detail: "",
|
|
160
|
+
};
|
|
161
|
+
}
|
|
114
162
|
if (name === "read") {
|
|
115
163
|
const details = [
|
|
116
164
|
args.offset !== undefined ? `offset=${args.offset}` : "",
|
package/package.json
CHANGED