pi-compact-tools 0.6.0 → 0.6.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.
- package/LICENSE +21 -21
- package/README.md +3 -3
- package/extensions/compact-tools-invocation.ts +33 -9
- package/extensions/compact-tools-thinking.ts +56 -29
- package/extensions/compact-tools.ts +5 -1
- package/package.json +64 -64
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 Dong Hyeong Lee
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Dong Hyeong Lee
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -30,7 +30,7 @@ Completed `edit` rows show their full diff initially by default. The per-tool `a
|
|
|
30
30
|
|
|
31
31
|
- Compact rendering for `read`, `write`, `edit`, `bash`, `powershell`, `grep`, `find`, and `ls`
|
|
32
32
|
- Animated configurable spinner in fullscreen TUI mode
|
|
33
|
-
-
|
|
33
|
+
- Four-step `Ctrl+T` thinking cycle: summary, detail, summary, then hidden
|
|
34
34
|
- Millisecond-precision duration with neutral status text
|
|
35
35
|
- Per-tool initial compaction and global-toggle participation with `auto_compact: true` or `false`
|
|
36
36
|
- Tool invocation details are always fully visible
|
|
@@ -140,12 +140,12 @@ Remove `"powershell"` on systems where it is unavailable.
|
|
|
140
140
|
`Ctrl+T` cycles every thinking block through:
|
|
141
141
|
|
|
142
142
|
```text
|
|
143
|
-
one-line summary
|
|
143
|
+
one-line summary → summary + │-indented detail → one-line summary → Thinking...
|
|
144
144
|
```
|
|
145
145
|
|
|
146
146
|
Standalone bold lines and Markdown headings split one provider thinking run into logical sections. Each section gets its own summary, optional `│`-indented detail, and control row; `Ctrl+T` cycles all sections together. While thinking streams, a text-color highlight sweeps across summaries using streaming updates; no spinner glyph or title circle is shown. The transformation is display-only; complete thinking remains unchanged in the session and model context.
|
|
147
147
|
|
|
148
|
-
Relevant invocation details stay visible, including paths, patterns, shell commands, and auxiliary arguments. Read calls omit offset and limit noise, then report the number of lines read after completion. Large payloads represented as results, such as write content and edit diffs, follow the result toggle.
|
|
148
|
+
Relevant invocation details stay visible, including paths, patterns, shell commands, and auxiliary arguments. After `grep`, `find`, or `ls` completes, auxiliary arguments appear in parentheses beside the `Done in …s` status instead of in the invocation line or a JSON block. Read calls omit offset and limit noise, then report the number of lines read after completion. Large payloads represented as results, such as write content and edit diffs, follow the result toggle.
|
|
149
149
|
|
|
150
150
|
A mouse click toggles one row's result:
|
|
151
151
|
|
|
@@ -7,13 +7,7 @@ function pathFrom(args: ToolArgs): string {
|
|
|
7
7
|
return typeof value === "string" ? normalizeLineEndings(value) : "";
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
const path = pathFrom(args) || (name === "grep" || name === "find" || name === "ls" ? "." : "");
|
|
12
|
-
if (name === "read") return path;
|
|
13
|
-
if (name !== "grep" && name !== "find") return path;
|
|
14
|
-
const pattern = typeof args.pattern === "string" ? normalizeLineEndings(args.pattern) : "…";
|
|
15
|
-
return name === "grep" ? `/${pattern}/ in ${path}` : `${pattern} in ${path}`;
|
|
16
|
-
}
|
|
10
|
+
const INLINE_ARGUMENT_TOOLS = new Set(["grep", "find", "ls"]);
|
|
17
11
|
|
|
18
12
|
function omitArgument(name: string, key: string): boolean {
|
|
19
13
|
if (key === "path" || key === "file_path") return true;
|
|
@@ -22,8 +16,7 @@ function omitArgument(name: string, key: string): boolean {
|
|
|
22
16
|
return (name === "grep" || name === "find") && key === "pattern";
|
|
23
17
|
}
|
|
24
18
|
|
|
25
|
-
|
|
26
|
-
if (name === "edit") return {};
|
|
19
|
+
function collectArgumentDetails(name: string, args: ToolArgs): ToolArgs {
|
|
27
20
|
const details: ToolArgs = {};
|
|
28
21
|
for (const [key, value] of Object.entries(args)) {
|
|
29
22
|
if (value !== undefined && !omitArgument(name, key)) details[key] = value;
|
|
@@ -31,6 +24,37 @@ export function getArgumentDetails(name: string, args: ToolArgs): ToolArgs {
|
|
|
31
24
|
return details;
|
|
32
25
|
}
|
|
33
26
|
|
|
27
|
+
function formatInlineValue(value: unknown): string {
|
|
28
|
+
if (typeof value === "string") {
|
|
29
|
+
const compact = normalizeLineEndings(value).replace(/\s+/gu, " ").trim();
|
|
30
|
+
return compact || '""';
|
|
31
|
+
}
|
|
32
|
+
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
|
|
33
|
+
return String(value);
|
|
34
|
+
}
|
|
35
|
+
return JSON.stringify(value) ?? String(value);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function formatArgumentSummary(name: string, args: ToolArgs): string | undefined {
|
|
39
|
+
if (!INLINE_ARGUMENT_TOOLS.has(name)) return undefined;
|
|
40
|
+
const arguments_ = Object.entries(collectArgumentDetails(name, args));
|
|
41
|
+
if (arguments_.length === 0) return undefined;
|
|
42
|
+
return arguments_.map(([key, value]) => `${key} ${formatInlineValue(value)}`).join(" · ");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function getCallDetails(name: string, args: ToolArgs): string {
|
|
46
|
+
const path = pathFrom(args) || (INLINE_ARGUMENT_TOOLS.has(name) ? "." : "");
|
|
47
|
+
if (name === "read") return path;
|
|
48
|
+
if (name !== "grep" && name !== "find") return path;
|
|
49
|
+
const pattern = typeof args.pattern === "string" ? normalizeLineEndings(args.pattern) : "…";
|
|
50
|
+
return name === "grep" ? `/${pattern}/ in ${path}` : `${pattern} in ${path}`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function getArgumentDetails(name: string, args: ToolArgs): ToolArgs {
|
|
54
|
+
if (name === "edit" || INLINE_ARGUMENT_TOOLS.has(name)) return {};
|
|
55
|
+
return collectArgumentDetails(name, args);
|
|
56
|
+
}
|
|
57
|
+
|
|
34
58
|
export function getTextResult(result: AgentToolResult<unknown>): string {
|
|
35
59
|
const parts: string[] = [];
|
|
36
60
|
for (const item of result.content) {
|
|
@@ -3,6 +3,7 @@ import { readFileSync } from "node:fs";
|
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import {
|
|
5
5
|
isKeyRelease,
|
|
6
|
+
isKeyRepeat,
|
|
6
7
|
Key,
|
|
7
8
|
matchesKey,
|
|
8
9
|
stripTerminalSequences,
|
|
@@ -11,6 +12,7 @@ import {
|
|
|
11
12
|
} from "@earendil-works/pi-tui";
|
|
12
13
|
|
|
13
14
|
export type ThinkingView = "summary" | "detail" | "hidden";
|
|
15
|
+
export type ThinkingPhase = "summary" | "detail" | "summary-after-detail" | "hidden";
|
|
14
16
|
|
|
15
17
|
type ThinkingRenderOptions = {
|
|
16
18
|
styleSummary?: (summary: string, sectionIndex: number) => string;
|
|
@@ -19,12 +21,29 @@ type ThinkingRenderOptions = {
|
|
|
19
21
|
styleControlPrefix?: (prefix: string) => string;
|
|
20
22
|
};
|
|
21
23
|
|
|
22
|
-
const
|
|
24
|
+
const NEXT_PHASE: Record<ThinkingPhase, ThinkingPhase> = {
|
|
23
25
|
summary: "detail",
|
|
24
|
-
detail: "
|
|
26
|
+
detail: "summary-after-detail",
|
|
27
|
+
"summary-after-detail": "hidden",
|
|
25
28
|
hidden: "summary",
|
|
26
29
|
};
|
|
27
30
|
|
|
31
|
+
export function thinkingViewForPhase(phase: ThinkingPhase): ThinkingView {
|
|
32
|
+
return phase === "summary-after-detail" ? "summary" : phase;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function nextThinkingPhase(phase: ThinkingPhase): ThinkingPhase {
|
|
36
|
+
return NEXT_PHASE[phase];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export type ThinkingToggleInput = "toggle" | "repeat" | "release";
|
|
40
|
+
|
|
41
|
+
export function classifyThinkingToggleInput(data: string): ThinkingToggleInput | undefined {
|
|
42
|
+
if (!matchesKey(data, Key.ctrl("t"))) return undefined;
|
|
43
|
+
if (isKeyRelease(data)) return "release";
|
|
44
|
+
return isKeyRepeat(data) ? "repeat" : "toggle";
|
|
45
|
+
}
|
|
46
|
+
|
|
28
47
|
function plainSummary(line: string): string {
|
|
29
48
|
return line
|
|
30
49
|
.replace(/^\s{0,3}#{1,6}\s+/u, "")
|
|
@@ -145,7 +164,7 @@ export function renderThinkingView(
|
|
|
145
164
|
.join("\n\n");
|
|
146
165
|
}
|
|
147
166
|
|
|
148
|
-
function
|
|
167
|
+
function getInitialThinkingPhase(): ThinkingPhase {
|
|
149
168
|
try {
|
|
150
169
|
const settings = JSON.parse(readFileSync(join(getAgentDir(), "settings.json"), "utf8")) as {
|
|
151
170
|
hideThinkingBlock?: unknown;
|
|
@@ -160,6 +179,8 @@ export function isThinkingStreamEvent(eventType: string): boolean {
|
|
|
160
179
|
return eventType === "thinking_start" || eventType === "thinking_delta";
|
|
161
180
|
}
|
|
162
181
|
|
|
182
|
+
const SHIMMER_FRAME_INTERVAL_MS = 80;
|
|
183
|
+
|
|
163
184
|
function shimmer(summary: string, theme: Theme, startedAt: number): string {
|
|
164
185
|
const characters = [...summary];
|
|
165
186
|
if (characters.length === 0) return summary;
|
|
@@ -168,7 +189,7 @@ function shimmer(summary: string, theme: Theme, startedAt: number): string {
|
|
|
168
189
|
// enters at its first character instead of inheriting another section's
|
|
169
190
|
// wall-clock phase.
|
|
170
191
|
const elapsed = Math.max(0, Date.now() - startedAt);
|
|
171
|
-
const center = Math.floor(elapsed /
|
|
192
|
+
const center = Math.floor(elapsed / SHIMMER_FRAME_INTERVAL_MS) % (characters.length + sweepTail);
|
|
172
193
|
let currentColor: Parameters<Theme["fg"]>[0] | undefined;
|
|
173
194
|
let chunk = "";
|
|
174
195
|
let output = "";
|
|
@@ -194,17 +215,15 @@ function shimmer(summary: string, theme: Theme, startedAt: number): string {
|
|
|
194
215
|
}
|
|
195
216
|
|
|
196
217
|
export class ThinkingCycleController {
|
|
197
|
-
private
|
|
218
|
+
private phase: ThinkingPhase = "summary";
|
|
198
219
|
private unsubscribe: (() => void) | undefined;
|
|
199
220
|
private theme: Theme | undefined;
|
|
200
221
|
private thinkingStreamActive = false;
|
|
222
|
+
private refreshThinking: (() => void) | undefined;
|
|
201
223
|
private readonly summarySweepStartedAt = new Map<number, number>();
|
|
202
224
|
|
|
203
225
|
constructor(pi: ExtensionAPI) {
|
|
204
|
-
pi.on("message_start", () =>
|
|
205
|
-
this.thinkingStreamActive = false;
|
|
206
|
-
this.summarySweepStartedAt.clear();
|
|
207
|
-
});
|
|
226
|
+
pi.on("message_start", () => this.resetSweep());
|
|
208
227
|
pi.on("message_update", (event) => {
|
|
209
228
|
// `context.isStreaming` describes the whole assistant message. Tool-call
|
|
210
229
|
// argument streaming therefore remains true after thinking has ended.
|
|
@@ -213,20 +232,14 @@ export class ThinkingCycleController {
|
|
|
213
232
|
if (eventType === "thinking_start") this.summarySweepStartedAt.clear();
|
|
214
233
|
this.thinkingStreamActive = isThinkingStreamEvent(eventType);
|
|
215
234
|
});
|
|
216
|
-
pi.on("message_end", () =>
|
|
217
|
-
|
|
218
|
-
this.summarySweepStartedAt.clear();
|
|
219
|
-
});
|
|
220
|
-
pi.on("tool_call", () => {
|
|
221
|
-
this.thinkingStreamActive = false;
|
|
222
|
-
this.summarySweepStartedAt.clear();
|
|
223
|
-
});
|
|
235
|
+
pi.on("message_end", () => this.resetSweep());
|
|
236
|
+
pi.on("tool_call", () => this.resetSweep());
|
|
224
237
|
|
|
225
238
|
pi.registerMarkdownTransformer((markdown, context) => {
|
|
226
239
|
if (context.messageType !== "assistant-thinking") return markdown;
|
|
227
240
|
const theme = this.theme;
|
|
228
241
|
const detailTextPrefix = theme?.getFgAnsi("thinkingText");
|
|
229
|
-
return renderThinkingView(markdown, this.
|
|
242
|
+
return renderThinkingView(markdown, thinkingViewForPhase(this.phase), context.availableWidth, {
|
|
230
243
|
styleSummary: theme
|
|
231
244
|
? context.isStreaming && this.thinkingStreamActive
|
|
232
245
|
? (summary, sectionIndex) => {
|
|
@@ -254,6 +267,11 @@ export class ThinkingCycleController {
|
|
|
254
267
|
});
|
|
255
268
|
}
|
|
256
269
|
|
|
270
|
+
private resetSweep(): void {
|
|
271
|
+
this.thinkingStreamActive = false;
|
|
272
|
+
this.summarySweepStartedAt.clear();
|
|
273
|
+
}
|
|
274
|
+
|
|
257
275
|
bind(ctx: ExtensionContext): void {
|
|
258
276
|
this.unsubscribe?.();
|
|
259
277
|
this.theme = ctx.ui.theme;
|
|
@@ -263,21 +281,29 @@ export class ThinkingCycleController {
|
|
|
263
281
|
// host is hidden, Markdown transformers are not invoked at all. Pi wraps
|
|
264
282
|
// this label in thinkingText, so an inner thinkingMax span is required to
|
|
265
283
|
// keep it consistent with completed summary titles.
|
|
266
|
-
this.
|
|
284
|
+
this.phase = getInitialThinkingPhase();
|
|
267
285
|
const hiddenLabel = this.theme.fg("thinkingMax", this.theme.bold("Thinking..."));
|
|
268
|
-
|
|
286
|
+
// Pi does not currently expose transcript invalidation directly. Updating
|
|
287
|
+
// this label rebuilds assistant Markdown and requests a render without
|
|
288
|
+
// changing the message or its hidden/visible state.
|
|
289
|
+
this.refreshThinking = () => ctx.ui.setHiddenThinkingLabel(hiddenLabel);
|
|
290
|
+
this.refreshThinking();
|
|
269
291
|
this.unsubscribe = ctx.ui.onTerminalInput((data) => {
|
|
270
|
-
|
|
271
|
-
if (
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
292
|
+
const input = classifyThinkingToggleInput(data);
|
|
293
|
+
if (input === undefined) return undefined;
|
|
294
|
+
// Kitty-capable macOS terminals report held keys as repeat events. Treating
|
|
295
|
+
// those as presses can skip detail before the user sees it.
|
|
296
|
+
if (input === "release" || input === "repeat") return { consume: true };
|
|
297
|
+
this.phase = nextThinkingPhase(this.phase);
|
|
298
|
+
if (this.phase === "detail" || this.phase === "summary-after-detail") {
|
|
299
|
+
// Visible-to-visible transitions are owned by this extension. Rebuild the
|
|
300
|
+
// Markdown and prevent Pi's built-in two-state toggle from hiding it.
|
|
301
|
+
this.refreshThinking?.();
|
|
276
302
|
return { consume: true };
|
|
277
303
|
}
|
|
278
|
-
// detail -> hidden and hidden -> summary intentionally reach
|
|
279
|
-
// two-state handler. This keeps
|
|
280
|
-
// clears built-in per-block click overrides
|
|
304
|
+
// summary-after-detail -> hidden and hidden -> summary intentionally reach
|
|
305
|
+
// Pi's existing two-state handler. This keeps visibility/settings in sync
|
|
306
|
+
// and clears built-in per-block click overrides.
|
|
281
307
|
return undefined;
|
|
282
308
|
});
|
|
283
309
|
}
|
|
@@ -285,6 +311,7 @@ export class ThinkingCycleController {
|
|
|
285
311
|
dispose(): void {
|
|
286
312
|
this.unsubscribe?.();
|
|
287
313
|
this.unsubscribe = undefined;
|
|
314
|
+
this.refreshThinking = undefined;
|
|
288
315
|
this.thinkingStreamActive = false;
|
|
289
316
|
this.summarySweepStartedAt.clear();
|
|
290
317
|
this.theme = undefined;
|
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
import { isFullscreenMode, loadConfig } from "./compact-tools-config.ts";
|
|
29
29
|
import { classifyToggleInput } from "./compact-tools-input.ts";
|
|
30
30
|
import {
|
|
31
|
+
formatArgumentSummary,
|
|
31
32
|
formatReadResultSummary,
|
|
32
33
|
getArgumentDetails,
|
|
33
34
|
getCallDetails,
|
|
@@ -100,12 +101,14 @@ function renderControls(
|
|
|
100
101
|
running: boolean,
|
|
101
102
|
isError: boolean,
|
|
102
103
|
summary?: string,
|
|
104
|
+
argumentSummary?: string,
|
|
103
105
|
): Component {
|
|
104
106
|
const duration = running && !runtime.animatesRows ? undefined : formatDuration(state);
|
|
105
107
|
const status = running
|
|
106
108
|
? (duration ?? "Running")
|
|
107
109
|
: `${isError ? "Failed" : "Done"}${duration ? ` in ${duration}` : ""}`;
|
|
108
110
|
let details = theme.fg("borderAccent", status);
|
|
111
|
+
if (argumentSummary && !running) details += theme.fg("borderAccent", ` (${argumentSummary})`);
|
|
109
112
|
if (summary) details += theme.fg("borderAccent", ` • ${summary}`);
|
|
110
113
|
if (state.hasResult) {
|
|
111
114
|
const clickAction = state.expanded ? "to hide" : "for result";
|
|
@@ -192,7 +195,8 @@ function renderFileResult(
|
|
|
192
195
|
const container = new CachedContainer();
|
|
193
196
|
appendFileResult(container, definition, state, output, theme, ctx.isError);
|
|
194
197
|
const summary = name === "read" && !ctx.isError ? formatReadResultSummary(result) : undefined;
|
|
195
|
-
|
|
198
|
+
const argumentSummary = formatArgumentSummary(name, ctx.args);
|
|
199
|
+
container.addChild(renderControls(theme, state, options.isPartial, ctx.isError, summary, argumentSummary));
|
|
196
200
|
return container;
|
|
197
201
|
}
|
|
198
202
|
|
package/package.json
CHANGED
|
@@ -1,64 +1,64 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "pi-compact-tools",
|
|
3
|
-
"version": "0.6.
|
|
4
|
-
"description": "Compact, expandable UI for pi's built-in tools, bundled with a polished GitHub Dark theme.",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"license": "MIT",
|
|
7
|
-
"author": "Dong Hyeong Lee",
|
|
8
|
-
"repository": {
|
|
9
|
-
"type": "git",
|
|
10
|
-
"url": "git+https://github.com/nedleeds/pi-compact-tools.git"
|
|
11
|
-
},
|
|
12
|
-
"homepage": "https://github.com/nedleeds/pi-compact-tools#readme",
|
|
13
|
-
"bugs": {
|
|
14
|
-
"url": "https://github.com/nedleeds/pi-compact-tools/issues"
|
|
15
|
-
},
|
|
16
|
-
"keywords": [
|
|
17
|
-
"pi-package",
|
|
18
|
-
"pi-coding-agent",
|
|
19
|
-
"pi-extension",
|
|
20
|
-
"terminal-ui",
|
|
21
|
-
"theme"
|
|
22
|
-
],
|
|
23
|
-
"files": [
|
|
24
|
-
"extensions",
|
|
25
|
-
"themes",
|
|
26
|
-
"examples",
|
|
27
|
-
"scripts",
|
|
28
|
-
"schemas",
|
|
29
|
-
"README.md",
|
|
30
|
-
"LICENSE"
|
|
31
|
-
],
|
|
32
|
-
"scripts": {
|
|
33
|
-
"test": "tsx --test tests/*.test.ts",
|
|
34
|
-
"check": "tsc --noEmit && npm test && npm run check:resources",
|
|
35
|
-
"check:resources": "node scripts/check-resources.mjs",
|
|
36
|
-
"prepublishOnly": "npm run check"
|
|
37
|
-
},
|
|
38
|
-
"pi": {
|
|
39
|
-
"extensions": [
|
|
40
|
-
"./extensions/compact-tools.ts"
|
|
41
|
-
],
|
|
42
|
-
"themes": [
|
|
43
|
-
"./themes/github-dark-pro.json"
|
|
44
|
-
],
|
|
45
|
-
"image": "https://raw.githubusercontent.com/nedleeds/pi-compact-tools/main/assets/nerd-font-workflow-optimized.gif"
|
|
46
|
-
},
|
|
47
|
-
"peerDependencies": {
|
|
48
|
-
"@earendil-works/pi-coding-agent": "*",
|
|
49
|
-
"@earendil-works/pi-tui": "*"
|
|
50
|
-
},
|
|
51
|
-
"devDependencies": {
|
|
52
|
-
"@earendil-works/pi-coding-agent": "0.85.1",
|
|
53
|
-
"@earendil-works/pi-tui": "0.85.1",
|
|
54
|
-
"@types/node": "^24.0.0",
|
|
55
|
-
"tsx": "^4.23.13",
|
|
56
|
-
"typescript": "^5.9.0"
|
|
57
|
-
},
|
|
58
|
-
"engines": {
|
|
59
|
-
"node": ">=22.19.0"
|
|
60
|
-
},
|
|
61
|
-
"publishConfig": {
|
|
62
|
-
"access": "public"
|
|
63
|
-
}
|
|
64
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "pi-compact-tools",
|
|
3
|
+
"version": "0.6.1",
|
|
4
|
+
"description": "Compact, expandable UI for pi's built-in tools, bundled with a polished GitHub Dark theme.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "Dong Hyeong Lee",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/nedleeds/pi-compact-tools.git"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/nedleeds/pi-compact-tools#readme",
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/nedleeds/pi-compact-tools/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"pi-package",
|
|
18
|
+
"pi-coding-agent",
|
|
19
|
+
"pi-extension",
|
|
20
|
+
"terminal-ui",
|
|
21
|
+
"theme"
|
|
22
|
+
],
|
|
23
|
+
"files": [
|
|
24
|
+
"extensions",
|
|
25
|
+
"themes",
|
|
26
|
+
"examples",
|
|
27
|
+
"scripts",
|
|
28
|
+
"schemas",
|
|
29
|
+
"README.md",
|
|
30
|
+
"LICENSE"
|
|
31
|
+
],
|
|
32
|
+
"scripts": {
|
|
33
|
+
"test": "tsx --test tests/*.test.ts",
|
|
34
|
+
"check": "tsc --noEmit && npm test && npm run check:resources",
|
|
35
|
+
"check:resources": "node scripts/check-resources.mjs",
|
|
36
|
+
"prepublishOnly": "npm run check"
|
|
37
|
+
},
|
|
38
|
+
"pi": {
|
|
39
|
+
"extensions": [
|
|
40
|
+
"./extensions/compact-tools.ts"
|
|
41
|
+
],
|
|
42
|
+
"themes": [
|
|
43
|
+
"./themes/github-dark-pro.json"
|
|
44
|
+
],
|
|
45
|
+
"image": "https://raw.githubusercontent.com/nedleeds/pi-compact-tools/main/assets/nerd-font-workflow-optimized.gif"
|
|
46
|
+
},
|
|
47
|
+
"peerDependencies": {
|
|
48
|
+
"@earendil-works/pi-coding-agent": "*",
|
|
49
|
+
"@earendil-works/pi-tui": "*"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@earendil-works/pi-coding-agent": "0.85.1",
|
|
53
|
+
"@earendil-works/pi-tui": "0.85.1",
|
|
54
|
+
"@types/node": "^24.0.0",
|
|
55
|
+
"tsx": "^4.23.13",
|
|
56
|
+
"typescript": "^5.9.0"
|
|
57
|
+
},
|
|
58
|
+
"engines": {
|
|
59
|
+
"node": ">=22.19.0"
|
|
60
|
+
},
|
|
61
|
+
"publishConfig": {
|
|
62
|
+
"access": "public"
|
|
63
|
+
}
|
|
64
|
+
}
|