@vaclav-synacek/pi-coding-agent-termux 0.50.7-1 → 0.51.1-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.
- package/CHANGELOG.md +94 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +2 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/session-picker.d.ts.map +1 -1
- package/dist/cli/session-picker.js +3 -1
- package/dist/cli/session-picker.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +9 -0
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts +5 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +76 -15
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/extensions/index.d.ts +3 -3
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +19 -1
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +42 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +88 -6
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js +4 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/extensions/wrapper.d.ts.map +1 -1
- package/dist/core/extensions/wrapper.js +1 -1
- package/dist/core/extensions/wrapper.js.map +1 -1
- package/dist/core/keybindings.d.ts +1 -1
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +8 -0
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +27 -18
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +11 -9
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/resource-loader.d.ts +24 -0
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +88 -19
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +1 -0
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts +2 -0
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +2 -0
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +5 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +16 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +1 -0
- package/dist/core/skills.js.map +1 -1
- package/dist/core/tools/bash.d.ts +11 -0
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +18 -3
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/edit.d.ts +2 -0
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/find.d.ts +2 -0
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.d.ts +2 -0
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/index.d.ts +7 -7
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +5 -5
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/ls.d.ts +2 -0
- package/dist/core/tools/ls.d.ts.map +1 -1
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/read.d.ts +2 -0
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/write.d.ts +2 -0
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-message.js +0 -7
- package/dist/modes/interactive/components/custom-message.js.map +1 -1
- package/dist/modes/interactive/components/daxnuts.d.ts.map +1 -1
- package/dist/modes/interactive/components/daxnuts.js +1 -1
- package/dist/modes/interactive/components/daxnuts.js.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.js +4 -1
- package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/dist/modes/interactive/components/session-selector-search.d.ts +4 -2
- package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector-search.js +13 -4
- package/dist/modes/interactive/components/session-selector-search.js.map +1 -1
- package/dist/modes/interactive/components/session-selector.d.ts +12 -2
- package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector.js +188 -57
- package/dist/modes/interactive/components/session-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +2 -0
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +12 -0
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector.d.ts +6 -0
- package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector.js +43 -16
- package/dist/modes/interactive/components/tree-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +24 -15
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +4 -0
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +4 -0
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/utils/clipboard-image.d.ts.map +1 -1
- package/dist/utils/clipboard-image.js +52 -10
- package/dist/utils/clipboard-image.js.map +1 -1
- package/dist/utils/clipboard-native.d.ts +7 -0
- package/dist/utils/clipboard-native.d.ts.map +1 -0
- package/dist/utils/clipboard-native.js +14 -0
- package/dist/utils/clipboard-native.js.map +1 -0
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +14 -0
- package/dist/utils/tools-manager.js.map +1 -1
- package/docs/custom-provider.md +2 -1
- package/docs/extensions.md +57 -9
- package/docs/keybindings.md +9 -0
- package/docs/models.md +43 -14
- package/docs/rpc.md +188 -1
- package/docs/settings.md +5 -1
- package/docs/termux.md +127 -0
- package/examples/extensions/README.md +9 -0
- package/examples/extensions/antigravity-image-gen.ts +1 -1
- package/examples/extensions/bash-spawn-hook.ts +30 -0
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/custom-provider-qwen-cli/index.ts +345 -0
- package/examples/extensions/custom-provider-qwen-cli/package.json +16 -0
- package/examples/extensions/dynamic-resources/SKILL.md +8 -0
- package/examples/extensions/dynamic-resources/dynamic.json +79 -0
- package/examples/extensions/dynamic-resources/dynamic.md +5 -0
- package/examples/extensions/dynamic-resources/index.ts +15 -0
- package/examples/extensions/hello.ts +1 -1
- package/examples/extensions/question.ts +1 -1
- package/examples/extensions/questionnaire.ts +1 -1
- package/examples/extensions/rpc-demo.ts +124 -0
- package/examples/extensions/sandbox/index.ts +1 -1
- package/examples/extensions/shutdown-command.ts +2 -2
- package/examples/extensions/ssh.ts +4 -4
- package/examples/extensions/subagent/index.ts +1 -1
- package/examples/extensions/titlebar-spinner.ts +58 -0
- package/examples/extensions/todo.ts +1 -1
- package/examples/extensions/tool-override.ts +1 -1
- package/examples/extensions/truncated-tool.ts +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/rpc-extension-ui.ts +632 -0
- package/examples/sdk/06-extensions.ts +1 -1
- package/examples/sdk/12-full-control.ts +1 -0
- package/package.json +6 -5
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { dirname, join } from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
4
|
+
|
|
5
|
+
const baseDir = dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
|
|
7
|
+
export default function (pi: ExtensionAPI) {
|
|
8
|
+
pi.on("resources_discover", () => {
|
|
9
|
+
return {
|
|
10
|
+
skillPaths: [join(baseDir, "SKILL.md")],
|
|
11
|
+
promptPaths: [join(baseDir, "dynamic.md")],
|
|
12
|
+
themePaths: [join(baseDir, "dynamic.json")],
|
|
13
|
+
};
|
|
14
|
+
});
|
|
15
|
+
}
|
|
@@ -14,7 +14,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
14
14
|
name: Type.String({ description: "Name to greet" }),
|
|
15
15
|
}),
|
|
16
16
|
|
|
17
|
-
async execute(_toolCallId, params, _onUpdate, _ctx
|
|
17
|
+
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
18
18
|
const { name } = params as { name: string };
|
|
19
19
|
return {
|
|
20
20
|
content: [{ type: "text", text: `Hello, ${name}!` }],
|
|
@@ -40,7 +40,7 @@ export default function question(pi: ExtensionAPI) {
|
|
|
40
40
|
description: "Ask the user a question and let them pick from options. Use when you need user input to proceed.",
|
|
41
41
|
parameters: QuestionParams,
|
|
42
42
|
|
|
43
|
-
async execute(_toolCallId, params, _onUpdate, ctx
|
|
43
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
44
44
|
if (!ctx.hasUI) {
|
|
45
45
|
return {
|
|
46
46
|
content: [{ type: "text", text: "Error: UI not available (running in non-interactive mode)" }],
|
|
@@ -81,7 +81,7 @@ export default function questionnaire(pi: ExtensionAPI) {
|
|
|
81
81
|
"Ask the user one or more questions. Use for clarifying requirements, getting preferences, or confirming decisions. For single questions, shows a simple option list. For multiple questions, shows a tab-based interface.",
|
|
82
82
|
parameters: QuestionnaireParams,
|
|
83
83
|
|
|
84
|
-
async execute(_toolCallId, params, _onUpdate, ctx
|
|
84
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
85
85
|
if (!ctx.hasUI) {
|
|
86
86
|
return errorResult("Error: UI not available (running in non-interactive mode)");
|
|
87
87
|
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RPC Extension UI Demo
|
|
3
|
+
*
|
|
4
|
+
* Purpose-built extension that exercises all RPC-supported extension UI methods.
|
|
5
|
+
* Designed to be loaded alongside the rpc-extension-ui-example.ts script to
|
|
6
|
+
* demonstrate the full extension UI protocol.
|
|
7
|
+
*
|
|
8
|
+
* UI methods exercised:
|
|
9
|
+
* - select() - on tool_call for dangerous bash commands
|
|
10
|
+
* - confirm() - on session_before_switch
|
|
11
|
+
* - input() - via /rpc-input command
|
|
12
|
+
* - editor() - via /rpc-editor command
|
|
13
|
+
* - notify() - after each dialog completes
|
|
14
|
+
* - setStatus() - on turn_start/turn_end
|
|
15
|
+
* - setWidget() - on session_start
|
|
16
|
+
* - setTitle() - on session_start and session_switch
|
|
17
|
+
* - setEditorText() - via /rpc-prefill command
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
21
|
+
|
|
22
|
+
export default function (pi: ExtensionAPI) {
|
|
23
|
+
let turnCount = 0;
|
|
24
|
+
|
|
25
|
+
// -- setTitle, setWidget, setStatus on session lifecycle --
|
|
26
|
+
|
|
27
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
28
|
+
ctx.ui.setTitle("pi RPC Demo");
|
|
29
|
+
ctx.ui.setWidget("rpc-demo", ["--- RPC Extension UI Demo ---", "Loaded and ready."]);
|
|
30
|
+
ctx.ui.setStatus("rpc-demo", `Turns: ${turnCount}`);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
pi.on("session_switch", async (_event, ctx) => {
|
|
34
|
+
turnCount = 0;
|
|
35
|
+
ctx.ui.setTitle("pi RPC Demo (new session)");
|
|
36
|
+
ctx.ui.setStatus("rpc-demo", `Turns: ${turnCount}`);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// -- setStatus on turn lifecycle --
|
|
40
|
+
|
|
41
|
+
pi.on("turn_start", async (_event, ctx) => {
|
|
42
|
+
turnCount++;
|
|
43
|
+
ctx.ui.setStatus("rpc-demo", `Turn ${turnCount} running...`);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
pi.on("turn_end", async (_event, ctx) => {
|
|
47
|
+
ctx.ui.setStatus("rpc-demo", `Turn ${turnCount} done`);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// -- select on dangerous tool calls --
|
|
51
|
+
|
|
52
|
+
pi.on("tool_call", async (event, ctx) => {
|
|
53
|
+
if (event.toolName !== "bash") return undefined;
|
|
54
|
+
|
|
55
|
+
const command = event.input.command as string;
|
|
56
|
+
const isDangerous = /\brm\s+(-rf?|--recursive)/i.test(command) || /\bsudo\b/i.test(command);
|
|
57
|
+
|
|
58
|
+
if (isDangerous) {
|
|
59
|
+
if (!ctx.hasUI) {
|
|
60
|
+
return { block: true, reason: "Dangerous command blocked (no UI)" };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const choice = await ctx.ui.select(`Dangerous command: ${command}`, ["Allow", "Block"]);
|
|
64
|
+
if (choice !== "Allow") {
|
|
65
|
+
ctx.ui.notify("Command blocked by user", "warning");
|
|
66
|
+
return { block: true, reason: "Blocked by user" };
|
|
67
|
+
}
|
|
68
|
+
ctx.ui.notify("Command allowed", "info");
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return undefined;
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// -- confirm on session clear --
|
|
75
|
+
|
|
76
|
+
pi.on("session_before_switch", async (event, ctx) => {
|
|
77
|
+
if (event.reason !== "new") return;
|
|
78
|
+
if (!ctx.hasUI) return;
|
|
79
|
+
|
|
80
|
+
const confirmed = await ctx.ui.confirm("Clear session?", "All messages will be lost.");
|
|
81
|
+
if (!confirmed) {
|
|
82
|
+
ctx.ui.notify("Clear cancelled", "info");
|
|
83
|
+
return { cancel: true };
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// -- input via command --
|
|
88
|
+
|
|
89
|
+
pi.registerCommand("rpc-input", {
|
|
90
|
+
description: "Prompt for text input (demonstrates ctx.ui.input in RPC)",
|
|
91
|
+
handler: async (_args, ctx) => {
|
|
92
|
+
const value = await ctx.ui.input("Enter a value", "type something...");
|
|
93
|
+
if (value) {
|
|
94
|
+
ctx.ui.notify(`You entered: ${value}`, "info");
|
|
95
|
+
} else {
|
|
96
|
+
ctx.ui.notify("Input cancelled", "info");
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// -- editor via command --
|
|
102
|
+
|
|
103
|
+
pi.registerCommand("rpc-editor", {
|
|
104
|
+
description: "Open multi-line editor (demonstrates ctx.ui.editor in RPC)",
|
|
105
|
+
handler: async (_args, ctx) => {
|
|
106
|
+
const text = await ctx.ui.editor("Edit some text", "Line 1\nLine 2\nLine 3");
|
|
107
|
+
if (text) {
|
|
108
|
+
ctx.ui.notify(`Editor submitted (${text.split("\n").length} lines)`, "info");
|
|
109
|
+
} else {
|
|
110
|
+
ctx.ui.notify("Editor cancelled", "info");
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// -- setEditorText via command --
|
|
116
|
+
|
|
117
|
+
pi.registerCommand("rpc-prefill", {
|
|
118
|
+
description: "Prefill the input editor (demonstrates ctx.ui.setEditorText in RPC)",
|
|
119
|
+
handler: async (_args, ctx) => {
|
|
120
|
+
ctx.ui.setEditorText("This text was set by the rpc-demo extension.");
|
|
121
|
+
ctx.ui.notify("Editor prefilled", "info");
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
}
|
|
@@ -211,7 +211,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
211
211
|
pi.registerTool({
|
|
212
212
|
...localBash,
|
|
213
213
|
label: "bash (sandboxed)",
|
|
214
|
-
async execute(id, params, onUpdate, _ctx
|
|
214
|
+
async execute(id, params, signal, onUpdate, _ctx) {
|
|
215
215
|
if (!sandboxEnabled || !sandboxInitialized) {
|
|
216
216
|
return localBash.execute(id, params, signal, onUpdate);
|
|
217
217
|
}
|
|
@@ -23,7 +23,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
23
23
|
label: "Finish and Exit",
|
|
24
24
|
description: "Complete a task and exit pi",
|
|
25
25
|
parameters: Type.Object({}),
|
|
26
|
-
async execute(_toolCallId, _params, _onUpdate, ctx
|
|
26
|
+
async execute(_toolCallId, _params, _signal, _onUpdate, ctx) {
|
|
27
27
|
// Do any final work here...
|
|
28
28
|
// Request graceful shutdown (deferred until agent is idle)
|
|
29
29
|
ctx.shutdown();
|
|
@@ -44,7 +44,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
44
44
|
parameters: Type.Object({
|
|
45
45
|
environment: Type.String({ description: "Target environment (e.g., production, staging)" }),
|
|
46
46
|
}),
|
|
47
|
-
async execute(_toolCallId, params, onUpdate, ctx
|
|
47
|
+
async execute(_toolCallId, params, _signal, onUpdate, ctx) {
|
|
48
48
|
onUpdate?.({ content: [{ type: "text", text: `Deploying to ${params.environment}...` }], details: {} });
|
|
49
49
|
|
|
50
50
|
// Example deployment logic
|
|
@@ -127,7 +127,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
127
127
|
|
|
128
128
|
pi.registerTool({
|
|
129
129
|
...localRead,
|
|
130
|
-
async execute(id, params, onUpdate, _ctx
|
|
130
|
+
async execute(id, params, signal, onUpdate, _ctx) {
|
|
131
131
|
const ssh = getSsh();
|
|
132
132
|
if (ssh) {
|
|
133
133
|
const tool = createReadTool(localCwd, {
|
|
@@ -141,7 +141,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
141
141
|
|
|
142
142
|
pi.registerTool({
|
|
143
143
|
...localWrite,
|
|
144
|
-
async execute(id, params, onUpdate, _ctx
|
|
144
|
+
async execute(id, params, signal, onUpdate, _ctx) {
|
|
145
145
|
const ssh = getSsh();
|
|
146
146
|
if (ssh) {
|
|
147
147
|
const tool = createWriteTool(localCwd, {
|
|
@@ -155,7 +155,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
155
155
|
|
|
156
156
|
pi.registerTool({
|
|
157
157
|
...localEdit,
|
|
158
|
-
async execute(id, params, onUpdate, _ctx
|
|
158
|
+
async execute(id, params, signal, onUpdate, _ctx) {
|
|
159
159
|
const ssh = getSsh();
|
|
160
160
|
if (ssh) {
|
|
161
161
|
const tool = createEditTool(localCwd, {
|
|
@@ -169,7 +169,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
169
169
|
|
|
170
170
|
pi.registerTool({
|
|
171
171
|
...localBash,
|
|
172
|
-
async execute(id, params, onUpdate, _ctx
|
|
172
|
+
async execute(id, params, signal, onUpdate, _ctx) {
|
|
173
173
|
const ssh = getSsh();
|
|
174
174
|
if (ssh) {
|
|
175
175
|
const tool = createBashTool(localCwd, {
|
|
@@ -416,7 +416,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
416
416
|
].join(" "),
|
|
417
417
|
parameters: SubagentParams,
|
|
418
418
|
|
|
419
|
-
async execute(_toolCallId, params, onUpdate, ctx
|
|
419
|
+
async execute(_toolCallId, params, signal, onUpdate, ctx) {
|
|
420
420
|
const agentScope: AgentScope = params.agentScope ?? "user";
|
|
421
421
|
const discovery = discoverAgents(ctx.cwd, agentScope);
|
|
422
422
|
const agents = discovery.agents;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Titlebar Spinner Extension
|
|
3
|
+
*
|
|
4
|
+
* Shows a braille spinner animation in the terminal title while the agent is working.
|
|
5
|
+
* Uses `ctx.ui.setTitle()` to update the terminal title via the extension API.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* pi --extension examples/extensions/titlebar-spinner.ts
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import path from "node:path";
|
|
12
|
+
import type { ExtensionAPI, ExtensionContext } from "@mariozechner/pi-coding-agent";
|
|
13
|
+
|
|
14
|
+
const BRAILLE_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
15
|
+
|
|
16
|
+
function getBaseTitle(pi: ExtensionAPI): string {
|
|
17
|
+
const cwd = path.basename(process.cwd());
|
|
18
|
+
const session = pi.getSessionName();
|
|
19
|
+
return session ? `π - ${session} - ${cwd}` : `π - ${cwd}`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export default function (pi: ExtensionAPI) {
|
|
23
|
+
let timer: ReturnType<typeof setInterval> | null = null;
|
|
24
|
+
let frameIndex = 0;
|
|
25
|
+
|
|
26
|
+
function stopAnimation(ctx: ExtensionContext) {
|
|
27
|
+
if (timer) {
|
|
28
|
+
clearInterval(timer);
|
|
29
|
+
timer = null;
|
|
30
|
+
}
|
|
31
|
+
frameIndex = 0;
|
|
32
|
+
ctx.ui.setTitle(getBaseTitle(pi));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function startAnimation(ctx: ExtensionContext) {
|
|
36
|
+
stopAnimation(ctx);
|
|
37
|
+
timer = setInterval(() => {
|
|
38
|
+
const frame = BRAILLE_FRAMES[frameIndex % BRAILLE_FRAMES.length];
|
|
39
|
+
const cwd = path.basename(process.cwd());
|
|
40
|
+
const session = pi.getSessionName();
|
|
41
|
+
const title = session ? `${frame} π - ${session} - ${cwd}` : `${frame} π - ${cwd}`;
|
|
42
|
+
ctx.ui.setTitle(title);
|
|
43
|
+
frameIndex++;
|
|
44
|
+
}, 80);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
pi.on("agent_start", async (_event, ctx) => {
|
|
48
|
+
startAnimation(ctx);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
pi.on("agent_end", async (_event, ctx) => {
|
|
52
|
+
stopAnimation(ctx);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
pi.on("session_shutdown", async (_event, ctx) => {
|
|
56
|
+
stopAnimation(ctx);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
@@ -141,7 +141,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
141
141
|
description: "Manage a todo list. Actions: list, add (text), toggle (id), clear",
|
|
142
142
|
parameters: TodoParams,
|
|
143
143
|
|
|
144
|
-
async execute(_toolCallId, params, _onUpdate, _ctx
|
|
144
|
+
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
145
145
|
switch (params.action) {
|
|
146
146
|
case "list":
|
|
147
147
|
return {
|
|
@@ -72,7 +72,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
72
72
|
"Read the contents of a file with access logging. Some sensitive paths (.env, secrets, credentials) are blocked.",
|
|
73
73
|
parameters: readSchema,
|
|
74
74
|
|
|
75
|
-
async execute(_toolCallId, params, _onUpdate, ctx) {
|
|
75
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
76
76
|
const { path, offset, limit } = params;
|
|
77
77
|
const absolutePath = resolve(ctx.cwd, path);
|
|
78
78
|
|
|
@@ -52,7 +52,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
52
52
|
description: `Search file contents using ripgrep. Output is truncated to ${DEFAULT_MAX_LINES} lines or ${formatSize(DEFAULT_MAX_BYTES)} (whichever is hit first). If truncated, full output is saved to a temp file.`,
|
|
53
53
|
parameters: RgParams,
|
|
54
54
|
|
|
55
|
-
async execute(_toolCallId, params, _onUpdate, ctx) {
|
|
55
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
56
56
|
const { pattern, path: searchPath, glob } = params;
|
|
57
57
|
|
|
58
58
|
// Build the ripgrep command
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-extension-with-deps",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.15.1",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "pi-extension-with-deps",
|
|
9
|
-
"version": "1.
|
|
9
|
+
"version": "1.15.1",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"ms": "^2.1.3"
|
|
12
12
|
},
|