@nmzpy/pi-ember-stack 0.1.4 → 0.1.6
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/README.md +6 -6
- package/package.json +1 -1
- package/plugins/index.ts +5 -13
- package/plugins/pi-compact-tools/index.ts +244 -51
- package/plugins/pi-custom-agents/index.ts +10 -19
- package/plugins/{pi-compact-tools → pi-custom-agents}/questionnaire-tool.ts +1 -0
- package/plugins/pi-custom-agents/subagent/extensions/index.ts +4 -1
package/README.md
CHANGED
|
@@ -30,8 +30,8 @@ plugins under `plugins/`. Ember projects enable them in `.pi/ember-stack.json`:
|
|
|
30
30
|
Remove a plugin ID to disable it, or use `/stack-plugins` to toggle one from
|
|
31
31
|
the TUI. Restart pi after changing the list. The available plugins are:
|
|
32
32
|
|
|
33
|
-
- `pi-compact-tools`: collapsed native edit rendering
|
|
34
|
-
- `pi-custom-agents`: primary modes, plans, subagent tool, and bundled agent definitions.
|
|
33
|
+
- `pi-compact-tools`: collapsed native edit rendering.
|
|
34
|
+
- `pi-custom-agents`: questionnaire UI, primary modes, plans, subagent tool, and bundled agent definitions.
|
|
35
35
|
- `devin-auth`: Devin provider, OAuth, catalog refresh, and streaming.
|
|
36
36
|
|
|
37
37
|
## Project setup
|
|
@@ -39,7 +39,7 @@ the TUI. Restart pi after changing the list. The available plugins are:
|
|
|
39
39
|
The Ember repository contains a project-local `.pi/settings.json` entry for:
|
|
40
40
|
|
|
41
41
|
```json
|
|
42
|
-
"npm:@nmzpy/pi-ember-stack@0.1.
|
|
42
|
+
"npm:@nmzpy/pi-ember-stack@0.1.6"
|
|
43
43
|
```
|
|
44
44
|
|
|
45
45
|
On a new clone, start pi from the project directory. Pi will ask for a
|
|
@@ -69,9 +69,9 @@ of this repository.
|
|
|
69
69
|
## Development
|
|
70
70
|
|
|
71
71
|
The package entrypoint is `plugins/index.ts`. Compact tools are under
|
|
72
|
-
`plugins/pi-compact-tools/`, while primary modes, plans,
|
|
73
|
-
agents are under `plugins/pi-custom-agents/`. Devin auth
|
|
74
|
-
`plugins/devin-auth/`.
|
|
72
|
+
`plugins/pi-compact-tools/`, while questionnaire, primary modes, plans,
|
|
73
|
+
subagents, and bundled agents are under `plugins/pi-custom-agents/`. Devin auth
|
|
74
|
+
is under `plugins/devin-auth/`.
|
|
75
75
|
|
|
76
76
|
Run the package typecheck with:
|
|
77
77
|
|
package/package.json
CHANGED
package/plugins/index.ts
CHANGED
|
@@ -4,18 +4,13 @@ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
|
4
4
|
|
|
5
5
|
import devinAuthPlugin from "./devin-auth/extensions/index.ts";
|
|
6
6
|
import piCompactToolsPlugin from "./pi-compact-tools/index.ts";
|
|
7
|
-
import piCustomAgentsPlugin
|
|
8
|
-
type PiCustomAgentsOptions,
|
|
9
|
-
} from "./pi-custom-agents/index.ts";
|
|
7
|
+
import piCustomAgentsPlugin from "./pi-custom-agents/index.ts";
|
|
10
8
|
|
|
11
9
|
type PluginId = "pi-compact-tools" | "pi-custom-agents" | "devin-auth";
|
|
12
10
|
type StackPlugin = {
|
|
13
11
|
id: PluginId;
|
|
14
12
|
description: string;
|
|
15
|
-
extension: (
|
|
16
|
-
pi: ExtensionAPI,
|
|
17
|
-
options?: PiCustomAgentsOptions,
|
|
18
|
-
) => void | Promise<void>;
|
|
13
|
+
extension: (pi: ExtensionAPI) => void | Promise<void>;
|
|
19
14
|
};
|
|
20
15
|
|
|
21
16
|
type StackPluginConfig = {
|
|
@@ -32,12 +27,12 @@ const DEFAULT_PLUGIN_IDS: readonly PluginId[] = [
|
|
|
32
27
|
const PLUGINS: readonly StackPlugin[] = [
|
|
33
28
|
{
|
|
34
29
|
id: "pi-compact-tools",
|
|
35
|
-
description: "Collapsed native edit rendering
|
|
30
|
+
description: "Collapsed native edit rendering",
|
|
36
31
|
extension: piCompactToolsPlugin,
|
|
37
32
|
},
|
|
38
33
|
{
|
|
39
34
|
id: "pi-custom-agents",
|
|
40
|
-
description: "
|
|
35
|
+
description: "Questionnaire, primary modes, plans, subagents, and bundled agent definitions",
|
|
41
36
|
extension: piCustomAgentsPlugin,
|
|
42
37
|
},
|
|
43
38
|
{
|
|
@@ -135,12 +130,9 @@ function registerPluginCommand(
|
|
|
135
130
|
export default async function piEmberStackPlugin(pi: ExtensionAPI): Promise<void> {
|
|
136
131
|
const cwd = process.cwd();
|
|
137
132
|
const enabledPlugins = readEnabledPlugins(cwd);
|
|
138
|
-
const pluginOptions: PiCustomAgentsOptions = {
|
|
139
|
-
compactToolsEnabled: enabledPlugins.has("pi-compact-tools"),
|
|
140
|
-
};
|
|
141
133
|
for (const plugin of PLUGINS) {
|
|
142
134
|
if (!enabledPlugins.has(plugin.id)) continue;
|
|
143
|
-
await plugin.extension(pi
|
|
135
|
+
await plugin.extension(pi);
|
|
144
136
|
}
|
|
145
137
|
registerPluginCommand(pi, cwd, enabledPlugins);
|
|
146
138
|
}
|
|
@@ -1,62 +1,195 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
import {
|
|
4
|
+
createBashTool,
|
|
5
|
+
createEditTool,
|
|
6
|
+
createFindTool,
|
|
7
|
+
createGrepTool,
|
|
8
|
+
createLsTool,
|
|
9
|
+
createReadTool,
|
|
10
|
+
createWriteTool,
|
|
11
|
+
type ExtensionAPI,
|
|
12
|
+
} from "@earendil-works/pi-coding-agent";
|
|
13
|
+
import { Text, type Component } from "@earendil-works/pi-tui";
|
|
7
14
|
|
|
8
15
|
const SOURCE_ROOT = path.dirname(fileURLToPath(import.meta.url));
|
|
16
|
+
const BULLET = "• ";
|
|
17
|
+
const DISCOVERY_TOOLS = new Set(["read", "grep", "find", "ls"]);
|
|
9
18
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
19
|
+
type ToolFactory = (cwd: string) => any;
|
|
20
|
+
type ToolRenderContext = {
|
|
21
|
+
args: any;
|
|
22
|
+
toolCallId: string;
|
|
23
|
+
invalidate: () => void;
|
|
24
|
+
};
|
|
25
|
+
type ToolRenderResultOptions = {
|
|
26
|
+
isPartial: boolean;
|
|
27
|
+
};
|
|
28
|
+
type CompactCall = {
|
|
29
|
+
id: string;
|
|
30
|
+
name: string;
|
|
31
|
+
args: any;
|
|
32
|
+
group?: DiscoveryGroup;
|
|
33
|
+
invalidate?: () => void;
|
|
34
|
+
isError: boolean;
|
|
35
|
+
};
|
|
36
|
+
type DiscoveryGroup = {
|
|
37
|
+
records: CompactCall[];
|
|
38
|
+
};
|
|
18
39
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
onUpdate: any,
|
|
24
|
-
ctx: any,
|
|
25
|
-
) {
|
|
26
|
-
return createEditTool(ctx.cwd).execute(
|
|
27
|
-
toolCallId,
|
|
28
|
-
params,
|
|
29
|
-
signal,
|
|
30
|
-
onUpdate,
|
|
31
|
-
);
|
|
32
|
-
},
|
|
40
|
+
function textValue(value: unknown, fallback = ""): string {
|
|
41
|
+
if (value === undefined || value === null) return fallback;
|
|
42
|
+
return String(value).replace(/[\r\n]+/g, " ");
|
|
43
|
+
}
|
|
33
44
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
45
|
+
function toolPath(args: any): string {
|
|
46
|
+
return textValue(args?.file_path ?? args?.path, ".");
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function errorText(result: any, isError: boolean): string | undefined {
|
|
50
|
+
const content = result?.content?.find((item: any) => item.type === "text");
|
|
51
|
+
if (!isError && !content?.text?.startsWith("Error")) return undefined;
|
|
52
|
+
return textValue(content?.text, "Tool failed").split("\n")[0];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function diffStats(result: any): { additions: number; removals: number } {
|
|
56
|
+
const diff = typeof result?.details?.diff === "string" ? result.details.diff : "";
|
|
57
|
+
let additions = 0;
|
|
58
|
+
let removals = 0;
|
|
59
|
+
for (const line of diff.split("\n")) {
|
|
60
|
+
if (line.startsWith("+") && !line.startsWith("+++")) additions++;
|
|
61
|
+
if (line.startsWith("-") && !line.startsWith("---")) removals++;
|
|
62
|
+
}
|
|
63
|
+
return { additions, removals };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function formatCallBody(name: string, args: any, theme: any): string {
|
|
67
|
+
const pathName = toolPath(args);
|
|
68
|
+
switch (name) {
|
|
69
|
+
case "read":
|
|
70
|
+
return theme.fg("toolTitle", theme.bold("Read")) +
|
|
71
|
+
theme.fg("accent", ` ${pathName}`);
|
|
72
|
+
case "grep":
|
|
73
|
+
return theme.fg("toolTitle", theme.bold("Search")) +
|
|
74
|
+
theme.fg("accent", ` ${textValue(args?.pattern)}`) +
|
|
75
|
+
theme.fg("toolOutput", ` in ${pathName}`);
|
|
76
|
+
case "find":
|
|
77
|
+
return theme.fg("toolTitle", theme.bold("Find")) +
|
|
78
|
+
theme.fg("accent", ` ${textValue(args?.pattern)}`) +
|
|
79
|
+
theme.fg("toolOutput", ` in ${pathName}`);
|
|
80
|
+
case "ls":
|
|
81
|
+
return theme.fg("toolTitle", theme.bold("List")) +
|
|
82
|
+
theme.fg("accent", ` ${pathName}`);
|
|
83
|
+
case "bash":
|
|
84
|
+
return theme.fg("toolTitle", theme.bold("Run")) +
|
|
85
|
+
theme.fg("accent", ` $ ${textValue(args?.command)}`);
|
|
86
|
+
case "edit":
|
|
87
|
+
return theme.fg("toolTitle", theme.bold("edit")) +
|
|
88
|
+
theme.fg("accent", ` ${pathName}`);
|
|
89
|
+
case "write":
|
|
90
|
+
return theme.fg("toolTitle", theme.bold("write")) +
|
|
91
|
+
theme.fg("accent", ` ${pathName}`);
|
|
92
|
+
default:
|
|
93
|
+
return theme.fg("toolTitle", theme.bold(name));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
43
96
|
|
|
44
|
-
|
|
45
|
-
|
|
97
|
+
function formatGroup(group: DiscoveryGroup, theme: any): string {
|
|
98
|
+
const lines = [
|
|
99
|
+
theme.fg("muted", BULLET) + theme.fg("toolTitle", theme.bold("Explored")),
|
|
100
|
+
];
|
|
101
|
+
for (const [index, record] of group.records.entries()) {
|
|
102
|
+
const prefix = index === 0 ? " └ " : " ";
|
|
103
|
+
lines.push(theme.fg("dim", prefix) + formatCallBody(record.name, record.args, theme));
|
|
104
|
+
}
|
|
105
|
+
return lines.join("\n");
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
class CompactRenderer {
|
|
109
|
+
private readonly calls = new Map<string, CompactCall>();
|
|
110
|
+
private lastCall: CompactCall | undefined;
|
|
111
|
+
|
|
112
|
+
beginTurn(): void {
|
|
113
|
+
this.lastCall = undefined;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
observeCall(name: string, id: string, args: any): CompactCall {
|
|
117
|
+
return this.registerCall(name, id, args);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
registerCall(
|
|
121
|
+
name: string,
|
|
122
|
+
id: string,
|
|
123
|
+
args: any,
|
|
124
|
+
invalidate?: () => void,
|
|
125
|
+
): CompactCall {
|
|
126
|
+
const existing = this.calls.get(id);
|
|
127
|
+
if (existing) {
|
|
128
|
+
existing.args = args;
|
|
129
|
+
existing.invalidate = invalidate ?? existing.invalidate;
|
|
130
|
+
return existing;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const record: CompactCall = { id, name, args, isError: false };
|
|
134
|
+
this.calls.set(id, record);
|
|
135
|
+
if (DISCOVERY_TOOLS.has(name) && this.lastCall && DISCOVERY_TOOLS.has(this.lastCall.name)) {
|
|
136
|
+
const group = this.lastCall.group ?? { records: [this.lastCall] };
|
|
137
|
+
this.lastCall.group = group;
|
|
138
|
+
group.records.push(record);
|
|
139
|
+
record.group = group;
|
|
140
|
+
for (const groupedCall of group.records) groupedCall.invalidate?.();
|
|
141
|
+
}
|
|
142
|
+
this.lastCall = record;
|
|
143
|
+
record.invalidate = invalidate;
|
|
144
|
+
return record;
|
|
145
|
+
}
|
|
46
146
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
147
|
+
setResult(record: CompactCall, result: any, isError: boolean): void {
|
|
148
|
+
record.isError = isError;
|
|
149
|
+
if (record.group) {
|
|
150
|
+
record.group.records[0]?.invalidate?.();
|
|
151
|
+
}
|
|
152
|
+
}
|
|
51
153
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
154
|
+
renderCall(
|
|
155
|
+
name: string,
|
|
156
|
+
args: any,
|
|
157
|
+
theme: any,
|
|
158
|
+
context: ToolRenderContext,
|
|
159
|
+
): Component {
|
|
160
|
+
const record = this.registerCall(name, context.toolCallId, args, context.invalidate);
|
|
161
|
+
if (record.group && record.group.records.length > 1) {
|
|
162
|
+
if (record.group.records[0] !== record) return new Text("", 0, 0);
|
|
163
|
+
return new Text(formatGroup(record.group, theme), 0, 0);
|
|
164
|
+
}
|
|
165
|
+
return new Text(
|
|
166
|
+
theme.fg("muted", BULLET) + formatCallBody(name, args, theme),
|
|
167
|
+
0,
|
|
168
|
+
0,
|
|
169
|
+
);
|
|
170
|
+
}
|
|
59
171
|
|
|
172
|
+
renderResult(
|
|
173
|
+
name: string,
|
|
174
|
+
args: any,
|
|
175
|
+
result: any,
|
|
176
|
+
options: ToolRenderResultOptions,
|
|
177
|
+
theme: any,
|
|
178
|
+
context: ToolRenderContext & { isError: boolean },
|
|
179
|
+
): Component {
|
|
180
|
+
const record = this.registerCall(name, context.toolCallId, args, context.invalidate);
|
|
181
|
+
this.setResult(record, result, context.isError);
|
|
182
|
+
if (record.group && record.group.records.length > 1) {
|
|
183
|
+
if (record.group.records[0] !== record) return new Text("", 0, 0);
|
|
184
|
+
const error = errorText(result, context.isError);
|
|
185
|
+
return error ? new Text(theme.fg("error", error), 0, 0) : new Text("", 0, 0);
|
|
186
|
+
}
|
|
187
|
+
if (options.isPartial) return new Text("", 0, 0);
|
|
188
|
+
|
|
189
|
+
const error = errorText(result, context.isError);
|
|
190
|
+
if (error) return new Text(theme.fg("error", error), 0, 0);
|
|
191
|
+
if (name === "edit") {
|
|
192
|
+
const { additions, removals } = diffStats(result);
|
|
60
193
|
return new Text(
|
|
61
194
|
theme.fg("success", `+${additions}`) +
|
|
62
195
|
theme.fg("dim", " / ") +
|
|
@@ -64,11 +197,71 @@ function registerCollapsedEditTool(extensionApi: any): void {
|
|
|
64
197
|
0,
|
|
65
198
|
0,
|
|
66
199
|
);
|
|
200
|
+
}
|
|
201
|
+
if (name === "bash") return new Text(theme.fg("success", "Done"), 0, 0);
|
|
202
|
+
if (name === "write") return new Text(theme.fg("success", "Written"), 0, 0);
|
|
203
|
+
return new Text("", 0, 0);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const TOOL_FACTORIES: Record<string, ToolFactory> = {
|
|
208
|
+
bash: createBashTool,
|
|
209
|
+
edit: createEditTool,
|
|
210
|
+
find: createFindTool,
|
|
211
|
+
grep: createGrepTool,
|
|
212
|
+
ls: createLsTool,
|
|
213
|
+
read: createReadTool,
|
|
214
|
+
write: createWriteTool,
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
function registerCompactTool(
|
|
218
|
+
pi: ExtensionAPI,
|
|
219
|
+
name: string,
|
|
220
|
+
factory: ToolFactory,
|
|
221
|
+
renderer: CompactRenderer,
|
|
222
|
+
): void {
|
|
223
|
+
const definition = factory(SOURCE_ROOT);
|
|
224
|
+
pi.registerTool({
|
|
225
|
+
name,
|
|
226
|
+
label: name,
|
|
227
|
+
description: definition.description,
|
|
228
|
+
parameters: definition.parameters,
|
|
229
|
+
renderShell: "self",
|
|
230
|
+
|
|
231
|
+
async execute(
|
|
232
|
+
toolCallId: string,
|
|
233
|
+
params: any,
|
|
234
|
+
signal: AbortSignal,
|
|
235
|
+
onUpdate: any,
|
|
236
|
+
ctx: any,
|
|
237
|
+
) {
|
|
238
|
+
return factory(ctx.cwd).execute(toolCallId, params, signal, onUpdate);
|
|
239
|
+
},
|
|
240
|
+
|
|
241
|
+
renderCall(args: any, theme: any, context: ToolRenderContext): Component {
|
|
242
|
+
return renderer.renderCall(name, args, theme, context);
|
|
243
|
+
},
|
|
244
|
+
|
|
245
|
+
renderResult(
|
|
246
|
+
result: any,
|
|
247
|
+
options: ToolRenderResultOptions,
|
|
248
|
+
theme: any,
|
|
249
|
+
context: ToolRenderContext & { isError: boolean },
|
|
250
|
+
): Component {
|
|
251
|
+
return renderer.renderResult(name, context.args, result, options, theme, context);
|
|
67
252
|
},
|
|
68
253
|
});
|
|
69
254
|
}
|
|
70
255
|
|
|
71
|
-
export default function piCompactToolsPlugin(pi:
|
|
72
|
-
|
|
73
|
-
|
|
256
|
+
export default function piCompactToolsPlugin(pi: ExtensionAPI): void {
|
|
257
|
+
const renderer = new CompactRenderer();
|
|
258
|
+
pi.on("turn_start", () => renderer.beginTurn());
|
|
259
|
+
pi.on("tool_call", (event: any) => {
|
|
260
|
+
if (TOOL_FACTORIES[event.toolName]) {
|
|
261
|
+
renderer.observeCall(event.toolName, event.toolCallId, event.input);
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
for (const [name, factory] of Object.entries(TOOL_FACTORIES)) {
|
|
265
|
+
registerCompactTool(pi, name, factory, renderer);
|
|
266
|
+
}
|
|
74
267
|
}
|
|
@@ -24,7 +24,8 @@ import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
|
24
24
|
import {
|
|
25
25
|
askQuestionnaire,
|
|
26
26
|
type QuestionnaireQuestion,
|
|
27
|
-
|
|
27
|
+
registerQuestionnaireTool,
|
|
28
|
+
} from "./questionnaire-tool.ts";
|
|
28
29
|
import subagentPlugin from "./subagent/extensions/index.ts";
|
|
29
30
|
|
|
30
31
|
function formatTokens(count: number): string {
|
|
@@ -558,21 +559,11 @@ function getLastModeFromSession(ctx: any): string | null {
|
|
|
558
559
|
return null;
|
|
559
560
|
}
|
|
560
561
|
|
|
561
|
-
export
|
|
562
|
-
compactToolsEnabled: boolean;
|
|
563
|
-
};
|
|
564
|
-
|
|
565
|
-
export default async function piCustomAgentsPlugin(
|
|
566
|
-
pi: any,
|
|
567
|
-
options: PiCustomAgentsOptions = { compactToolsEnabled: true },
|
|
568
|
-
) {
|
|
562
|
+
export default async function piCustomAgentsPlugin(pi: any): Promise<void> {
|
|
569
563
|
let currentMode: string = DEFAULT_MODE;
|
|
570
564
|
let lastMessagedMode: string | null = null;
|
|
571
565
|
let waitingForPlan = false;
|
|
572
|
-
|
|
573
|
-
const toolsForMode = (tools: string[]): string[] => compactToolsEnabled
|
|
574
|
-
? tools
|
|
575
|
-
: tools.filter((toolName) => toolName !== "questionnaire");
|
|
566
|
+
registerQuestionnaireTool(pi);
|
|
576
567
|
|
|
577
568
|
for (const modeId of MODE_IDS) {
|
|
578
569
|
const mode = MODES[modeId];
|
|
@@ -602,11 +593,11 @@ export default async function piCustomAgentsPlugin(
|
|
|
602
593
|
const mode = MODES[modeId];
|
|
603
594
|
if (!mode) return;
|
|
604
595
|
currentMode = modeId;
|
|
605
|
-
pi.setActiveTools(
|
|
596
|
+
pi.setActiveTools(mode.tools);
|
|
606
597
|
if (modeId === DEFAULT_MODE) {
|
|
607
598
|
ctx.ui.notify("Coder mode. Full access restored.");
|
|
608
599
|
} else {
|
|
609
|
-
ctx.ui.notify(`${mode.label} mode enabled. Tools: ${
|
|
600
|
+
ctx.ui.notify(`${mode.label} mode enabled. Tools: ${mode.tools.join(", ")}`);
|
|
610
601
|
}
|
|
611
602
|
updateStatus(ctx);
|
|
612
603
|
}
|
|
@@ -903,11 +894,11 @@ export default async function piCustomAgentsPlugin(
|
|
|
903
894
|
if (restored && restored !== DEFAULT_MODE) {
|
|
904
895
|
currentMode = restored;
|
|
905
896
|
lastMessagedMode = restored;
|
|
906
|
-
pi.setActiveTools(
|
|
897
|
+
pi.setActiveTools(MODES[restored].tools);
|
|
907
898
|
} else {
|
|
908
899
|
currentMode = DEFAULT_MODE;
|
|
909
900
|
lastMessagedMode = null;
|
|
910
|
-
pi.setActiveTools(
|
|
901
|
+
pi.setActiveTools(FULL_TOOLS);
|
|
911
902
|
}
|
|
912
903
|
installCustomFooter(ctx);
|
|
913
904
|
updateStatus(ctx);
|
|
@@ -918,11 +909,11 @@ export default async function piCustomAgentsPlugin(
|
|
|
918
909
|
if (restored && restored !== DEFAULT_MODE) {
|
|
919
910
|
currentMode = restored;
|
|
920
911
|
lastMessagedMode = restored;
|
|
921
|
-
pi.setActiveTools(
|
|
912
|
+
pi.setActiveTools(MODES[restored].tools);
|
|
922
913
|
} else {
|
|
923
914
|
currentMode = DEFAULT_MODE;
|
|
924
915
|
lastMessagedMode = null;
|
|
925
|
-
pi.setActiveTools(
|
|
916
|
+
pi.setActiveTools(FULL_TOOLS);
|
|
926
917
|
}
|
|
927
918
|
updateStatus(ctx);
|
|
928
919
|
installCustomFooter(ctx);
|
|
@@ -259,6 +259,7 @@ export function registerQuestionnaireTool(pi: any): void {
|
|
|
259
259
|
renderCall(args: { questions?: QuestionnaireQuestion[] }, theme: any): any {
|
|
260
260
|
const count = args.questions?.length ?? 0;
|
|
261
261
|
return new Text(
|
|
262
|
+
theme.fg("muted", "• ") +
|
|
262
263
|
theme.fg("toolTitle", theme.bold("questionnaire ")) +
|
|
263
264
|
theme.fg("muted", `${count} question${count === 1 ? "" : "s"}`),
|
|
264
265
|
0,
|
|
@@ -756,6 +756,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
756
756
|
// Chain
|
|
757
757
|
if (args.chain && args.chain.length > 0) {
|
|
758
758
|
let text =
|
|
759
|
+
fg("muted", "• ") +
|
|
759
760
|
fg("toolTitle", theme.bold("subagent ")) +
|
|
760
761
|
fg("accent", `chain (${args.chain.length} steps)`) +
|
|
761
762
|
fg("muted", ` [${scope}]`);
|
|
@@ -778,6 +779,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
778
779
|
// Parallel
|
|
779
780
|
if (args.tasks && args.tasks.length > 0) {
|
|
780
781
|
let text =
|
|
782
|
+
fg("muted", "• ") +
|
|
781
783
|
fg("toolTitle", theme.bold("subagent ")) +
|
|
782
784
|
fg("accent", `parallel (${args.tasks.length} tasks)`) +
|
|
783
785
|
fg("muted", ` [${scope}]`);
|
|
@@ -798,6 +800,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
798
800
|
: args.task
|
|
799
801
|
: "...";
|
|
800
802
|
let text =
|
|
803
|
+
fg("muted", "• ") +
|
|
801
804
|
fg("toolTitle", theme.bold("subagent ")) +
|
|
802
805
|
fg("accent", agentName) +
|
|
803
806
|
fg("muted", ` [${scope}]`);
|
|
@@ -1215,4 +1218,4 @@ export default function (pi: ExtensionAPI) {
|
|
|
1215
1218
|
}
|
|
1216
1219
|
}, { overlay: true, overlayOptions: { maxHeight: "70%" } }); // Overlay: editor stays visible below
|
|
1217
1220
|
}
|
|
1218
|
-
}
|
|
1221
|
+
}
|