@selesai/code 0.10.1 → 0.11.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 +23 -0
- package/dist/config.d.ts +5 -3
- package/dist/config.js +6 -4
- package/dist/core/skills.d.ts +2 -0
- package/dist/core/skills.js +1 -0
- package/dist/defaults/settings.json +0 -3
- package/dist/extensions/auto-session-name.test.ts +157 -0
- package/dist/extensions/auto-session-name.ts +96 -0
- package/dist/extensions/cost-reconcile.test.ts +76 -0
- package/dist/extensions/cost-reconcile.ts +278 -0
- package/dist/extensions/enable-readonly-tools.test.ts +11 -0
- package/dist/extensions/enable-readonly-tools.ts +7 -3
- package/dist/extensions/package.json +3 -0
- package/dist/extensions/pi-tool-display/CHANGELOG.md +329 -0
- package/dist/extensions/pi-tool-display/LICENSE +21 -0
- package/dist/extensions/pi-tool-display/README.md +417 -0
- package/dist/extensions/pi-tool-display/config/config.example.json +40 -0
- package/dist/extensions/pi-tool-display/index.ts +3 -0
- package/dist/extensions/pi-tool-display/package-lock.json +2555 -0
- package/dist/extensions/pi-tool-display/package.json +86 -0
- package/dist/extensions/pi-tool-display/src/agent-dir.ts +35 -0
- package/dist/extensions/pi-tool-display/src/ansi-utils.ts +116 -0
- package/dist/extensions/pi-tool-display/src/bash-display.ts +213 -0
- package/dist/extensions/pi-tool-display/src/capabilities.ts +88 -0
- package/dist/extensions/pi-tool-display/src/config-modal.ts +541 -0
- package/dist/extensions/pi-tool-display/src/config-store.ts +304 -0
- package/dist/extensions/pi-tool-display/src/debug-logger.ts +150 -0
- package/dist/extensions/pi-tool-display/src/diff-presentation.ts +72 -0
- package/dist/extensions/pi-tool-display/src/diff-renderer.ts +2517 -0
- package/dist/extensions/pi-tool-display/src/disposable.ts +34 -0
- package/dist/extensions/pi-tool-display/src/extension-lifecycle.ts +14 -0
- package/dist/extensions/pi-tool-display/src/index.ts +109 -0
- package/dist/extensions/pi-tool-display/src/line-width-safety.ts +93 -0
- package/dist/extensions/pi-tool-display/src/modal-icons.ts +57 -0
- package/dist/extensions/pi-tool-display/src/pending-diff-preview.ts +370 -0
- package/dist/extensions/pi-tool-display/src/presets.ts +117 -0
- package/dist/extensions/pi-tool-display/src/render-utils.ts +186 -0
- package/dist/extensions/pi-tool-display/src/settings-inspector-modal.ts +475 -0
- package/dist/extensions/pi-tool-display/src/thinking-label.ts +343 -0
- package/dist/extensions/pi-tool-display/src/tool-call-box.ts +181 -0
- package/dist/extensions/pi-tool-display/src/tool-metadata.ts +139 -0
- package/dist/extensions/pi-tool-display/src/tool-overrides.ts +2168 -0
- package/dist/extensions/pi-tool-display/src/types.ts +109 -0
- package/dist/extensions/pi-tool-display/src/user-message-box-markdown.ts +64 -0
- package/dist/extensions/pi-tool-display/src/user-message-box-native.ts +66 -0
- package/dist/extensions/pi-tool-display/src/user-message-box-patch.ts +72 -0
- package/dist/extensions/pi-tool-display/src/user-message-box-renderer.ts +419 -0
- package/dist/extensions/pi-tool-display/src/user-message-box-utils.ts +106 -0
- package/dist/extensions/pi-tool-display/src/write-display-utils.ts +31 -0
- package/dist/extensions/pi-tool-display/src/zellij-modal.ts +1027 -0
- package/dist/extensions/pi-tool-display/tests/active-backlog-red.test.ts +65 -0
- package/dist/extensions/pi-tool-display/tests/ansi-utils.test.ts +345 -0
- package/dist/extensions/pi-tool-display/tests/bash-display.test.ts +442 -0
- package/dist/extensions/pi-tool-display/tests/capabilities-edge.test.ts +360 -0
- package/dist/extensions/pi-tool-display/tests/capabilities.test.ts +54 -0
- package/dist/extensions/pi-tool-display/tests/config-modal.test.ts +360 -0
- package/dist/extensions/pi-tool-display/tests/config-store.test.ts +87 -0
- package/dist/extensions/pi-tool-display/tests/custom-tool-overrides.test.ts +415 -0
- package/dist/extensions/pi-tool-display/tests/debug-logger-edge.test.ts +630 -0
- package/dist/extensions/pi-tool-display/tests/debug-logger.test.ts +62 -0
- package/dist/extensions/pi-tool-display/tests/diff-renderer-ansi.test.ts +55 -0
- package/dist/extensions/pi-tool-display/tests/diff-renderer-edge.test.ts +886 -0
- package/dist/extensions/pi-tool-display/tests/diff-renderer-numbering.test.ts +135 -0
- package/dist/extensions/pi-tool-display/tests/diff-renderer-width.test.ts +454 -0
- package/dist/extensions/pi-tool-display/tests/diff-renderer-wrap.test.ts +169 -0
- package/dist/extensions/pi-tool-display/tests/index-integration.test.ts +354 -0
- package/dist/extensions/pi-tool-display/tests/pending-diff-preview.test.ts +79 -0
- package/dist/extensions/pi-tool-display/tests/presets-edge.test.ts +229 -0
- package/dist/extensions/pi-tool-display/tests/presets.test.ts +26 -0
- package/dist/extensions/pi-tool-display/tests/reload-behavior.test.ts +1241 -0
- package/dist/extensions/pi-tool-display/tests/render-utils.test.ts +710 -0
- package/dist/extensions/pi-tool-display/tests/settings-inspector.test.ts +450 -0
- package/dist/extensions/pi-tool-display/tests/thinking-label-edge.test.ts +904 -0
- package/dist/extensions/pi-tool-display/tests/thinking-label.test.ts +72 -0
- package/dist/extensions/pi-tool-display/tests/tool-call-box.test.ts +105 -0
- package/dist/extensions/pi-tool-display/tests/tool-overrides-config.test.ts +613 -0
- package/dist/extensions/pi-tool-display/tests/tool-overrides-mcp.test.ts +499 -0
- package/dist/extensions/pi-tool-display/tests/tool-overrides-registration.test.ts +315 -0
- package/dist/extensions/pi-tool-display/tests/tool-overrides-write-meta.test.ts +68 -0
- package/dist/extensions/pi-tool-display/tests/tool-ui-utils.test.ts +413 -0
- package/dist/extensions/pi-tool-display/tests/user-message-box-performance-red.test.ts +176 -0
- package/dist/extensions/pi-tool-display/tests/user-message-box.test.ts +908 -0
- package/dist/extensions/pi-tool-display/tests/zellij-modal.test.ts +848 -0
- package/dist/extensions/pi-tool-display/tool-display-api-consumer.d.ts +30 -0
- package/dist/extensions/pi-tool-display/tool-display-api-consumer.js +40 -0
- package/dist/extensions/pi-zentui/extensions/zentui/format.ts +46 -1
- package/dist/extensions/pi-zentui/extensions/zentui/index.ts +10 -0
- package/dist/extensions/pi-zentui/extensions/zentui/user-message-styles.ts +1 -1
- package/dist/extensions/pi-zentui/test/extension-compliance.test.ts +3 -3
- package/dist/extensions/pi-zentui/test/format.test.ts +50 -2
- package/dist/modes/interactive/components/startup-box.d.ts +38 -0
- package/dist/modes/interactive/components/startup-box.js +90 -0
- package/dist/modes/interactive/interactive-mode.d.ts +3 -0
- package/dist/modes/interactive/interactive-mode.js +85 -122
- package/dist/skills/agent-browser/SKILL.md +1 -0
- package/dist/skills/batch-grill-me/SKILL.md +1 -0
- package/dist/skills/brandkit/SKILL.md +1 -0
- package/dist/skills/design-references/SKILL.md +1 -0
- package/dist/skills/design-taste-frontend/SKILL.md +1 -0
- package/dist/skills/design-taste-frontend-v1/SKILL.md +1 -0
- package/dist/skills/full-output-enforcement/SKILL.md +1 -0
- package/dist/skills/gpt-taste/SKILL.md +1 -0
- package/dist/skills/grill-me/SKILL.md +1 -0
- package/dist/skills/handoff/SKILL.md +1 -0
- package/dist/skills/handoff-text/SKILL.md +1 -0
- package/dist/skills/high-end-visual-design/SKILL.md +1 -0
- package/dist/skills/image-to-code/SKILL.md +1 -0
- package/dist/skills/imagegen-frontend-mobile/SKILL.md +1 -0
- package/dist/skills/imagegen-frontend-web/SKILL.md +1 -0
- package/dist/skills/implanger/SKILL.md +1 -0
- package/dist/skills/improve-codebase/SKILL.md +1 -0
- package/dist/skills/industrial-brutalist-ui/SKILL.md +1 -0
- package/dist/skills/minimalist-ui/SKILL.md +1 -0
- package/dist/skills/pi-subagents/SKILL.md +1 -0
- package/dist/skills/planger/SKILL.md +1 -0
- package/dist/skills/ponytail/SKILL.md +1 -0
- package/dist/skills/ponytail-audit/SKILL.md +1 -0
- package/dist/skills/ponytail-debt/SKILL.md +1 -0
- package/dist/skills/ponytail-gain/SKILL.md +1 -0
- package/dist/skills/ponytail-help/SKILL.md +1 -0
- package/dist/skills/ponytail-review/SKILL.md +1 -0
- package/dist/skills/redesign-existing-projects/SKILL.md +1 -0
- package/dist/skills/selesai-handoff/SKILL.md +1 -0
- package/dist/skills/stitch-design-taste/SKILL.md +1 -0
- package/dist/skills/unlazy/SKILL.md +1 -0
- package/dist/skills/web-design-guidelines/SKILL.md +1 -0
- package/dist/skills/workflow/SKILL.md +1 -0
- package/package.json +3 -3
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { existsSync, mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import test from "node:test";
|
|
6
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
7
|
+
import { CONFIG_DIR_NAME } from "@earendil-works/pi-coding-agent";
|
|
8
|
+
import {
|
|
9
|
+
applyCapabilityConfigGuards,
|
|
10
|
+
detectToolDisplayCapabilities,
|
|
11
|
+
} from "../src/capabilities.ts";
|
|
12
|
+
import { DEFAULT_TOOL_DISPLAY_CONFIG } from "../src/types.ts";
|
|
13
|
+
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
// Helpers
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
|
|
18
|
+
function createApiStub(
|
|
19
|
+
allTools: unknown[],
|
|
20
|
+
commands: Array<{ name: string }> = [],
|
|
21
|
+
getAllToolsThrows = false,
|
|
22
|
+
getCommandsThrows = false,
|
|
23
|
+
): ExtensionAPI {
|
|
24
|
+
return {
|
|
25
|
+
getAllTools: () => {
|
|
26
|
+
if (getAllToolsThrows) {
|
|
27
|
+
throw new Error("getAllTools failed");
|
|
28
|
+
}
|
|
29
|
+
return allTools;
|
|
30
|
+
},
|
|
31
|
+
getCommands: () => {
|
|
32
|
+
if (getCommandsThrows) {
|
|
33
|
+
throw new Error("getCommands failed");
|
|
34
|
+
}
|
|
35
|
+
return commands;
|
|
36
|
+
},
|
|
37
|
+
} as unknown as ExtensionAPI;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function makeMcpTool(name: string, description?: string): unknown {
|
|
41
|
+
return {
|
|
42
|
+
name,
|
|
43
|
+
description: description ?? `MCP wrapper for ${name}`,
|
|
44
|
+
parameters: {},
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function makeNonMcpTool(name: string): unknown {
|
|
49
|
+
return {
|
|
50
|
+
name,
|
|
51
|
+
description: `Built-in ${name} tool`,
|
|
52
|
+
parameters: {},
|
|
53
|
+
execute: () => {},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function withTempDir(name: string, fn: (dir: string) => void): void {
|
|
58
|
+
const dir = mkdtempSync(join(tmpdir(), name));
|
|
59
|
+
try {
|
|
60
|
+
fn(dir);
|
|
61
|
+
} finally {
|
|
62
|
+
rmSync(dir, { recursive: true, force: true });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
// Tests
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
|
|
70
|
+
test("returns no capabilities when API is empty", () => {
|
|
71
|
+
withTempDir("pi-cap-empty-", (dir) => {
|
|
72
|
+
const oldEnv = process.env.PI_CODING_AGENT_DIR;
|
|
73
|
+
process.env.PI_CODING_AGENT_DIR = dir;
|
|
74
|
+
try {
|
|
75
|
+
const api = createApiStub([], []);
|
|
76
|
+
const caps = detectToolDisplayCapabilities(api, dir);
|
|
77
|
+
assert.equal(caps.hasMcpTooling, false);
|
|
78
|
+
assert.equal(caps.hasRtkOptimizer, false);
|
|
79
|
+
} finally {
|
|
80
|
+
if (oldEnv === undefined) {
|
|
81
|
+
delete process.env.PI_CODING_AGENT_DIR;
|
|
82
|
+
} else {
|
|
83
|
+
process.env.PI_CODING_AGENT_DIR = oldEnv;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test("detects MCP capability via isMcpToolCandidate with 'MCP' in description", () => {
|
|
90
|
+
const api = createApiStub([
|
|
91
|
+
makeMcpTool("exa_web_search_exa", "Search the web. Direct MCP wrapper for 'exa:web_search_exa'."),
|
|
92
|
+
]);
|
|
93
|
+
const caps = detectToolDisplayCapabilities(api, "/tmp");
|
|
94
|
+
|
|
95
|
+
assert.equal(caps.hasMcpTooling, true);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
test("detects MCP capability via tool named 'mcp'", () => {
|
|
99
|
+
const api = createApiStub([
|
|
100
|
+
makeNonMcpTool("read"),
|
|
101
|
+
{ name: "mcp", description: "MCP proxy", parameters: {} },
|
|
102
|
+
]);
|
|
103
|
+
const caps = detectToolDisplayCapabilities(api, "/tmp");
|
|
104
|
+
|
|
105
|
+
assert.equal(caps.hasMcpTooling, true);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test("non-MCP tools do not set hasMcpTooling", () => {
|
|
109
|
+
const api = createApiStub([
|
|
110
|
+
makeNonMcpTool("read"),
|
|
111
|
+
makeNonMcpTool("edit"),
|
|
112
|
+
makeNonMcpTool("bash"),
|
|
113
|
+
]);
|
|
114
|
+
const caps = detectToolDisplayCapabilities(api, "/tmp");
|
|
115
|
+
|
|
116
|
+
assert.equal(caps.hasMcpTooling, false);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
test("handles getAllTools throwing gracefully", () => {
|
|
120
|
+
const api = createApiStub([], [], true);
|
|
121
|
+
const caps = detectToolDisplayCapabilities(api, "/tmp");
|
|
122
|
+
|
|
123
|
+
assert.equal(caps.hasMcpTooling, false);
|
|
124
|
+
// Should still attempt RTK detection
|
|
125
|
+
assert.equal(typeof caps.hasRtkOptimizer, "boolean");
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test("recognises RTK capability via registered command", () => {
|
|
129
|
+
const api = createApiStub([], [{ name: "rtk" }]);
|
|
130
|
+
const caps = detectToolDisplayCapabilities(api, "/tmp");
|
|
131
|
+
|
|
132
|
+
assert.equal(caps.hasRtkOptimizer, true);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test("recognises RTK capability via rtk- prefix command", () => {
|
|
136
|
+
const api = createApiStub([], [{ name: "rtk-compact" }]);
|
|
137
|
+
const caps = detectToolDisplayCapabilities(api, "/tmp");
|
|
138
|
+
|
|
139
|
+
assert.equal(caps.hasRtkOptimizer, true);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
test("handles getCommands throwing gracefully and falls back to path probe", () => {
|
|
143
|
+
withTempDir("pi-cap-cmd-throw-", (dir) => {
|
|
144
|
+
const oldEnv = process.env.PI_CODING_AGENT_DIR;
|
|
145
|
+
process.env.PI_CODING_AGENT_DIR = dir;
|
|
146
|
+
try {
|
|
147
|
+
const api = createApiStub([], [], false, true);
|
|
148
|
+
const caps = detectToolDisplayCapabilities(api, dir);
|
|
149
|
+
assert.equal(caps.hasRtkOptimizer, false);
|
|
150
|
+
} finally {
|
|
151
|
+
if (oldEnv === undefined) {
|
|
152
|
+
delete process.env.PI_CODING_AGENT_DIR;
|
|
153
|
+
} else {
|
|
154
|
+
process.env.PI_CODING_AGENT_DIR = oldEnv;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
test("detects RTK extension path when pi-rtk-optimizer exists in agent dir", () => {
|
|
161
|
+
withTempDir("pi-rtk-test-", (dir) => {
|
|
162
|
+
const extDir = join(dir, "extensions", "pi-rtk-optimizer");
|
|
163
|
+
mkdirSync(extDir, { recursive: true });
|
|
164
|
+
|
|
165
|
+
const oldEnv = process.env.PI_CODING_AGENT_DIR;
|
|
166
|
+
process.env.PI_CODING_AGENT_DIR = dir;
|
|
167
|
+
|
|
168
|
+
try {
|
|
169
|
+
const api = createApiStub([], []);
|
|
170
|
+
const caps = detectToolDisplayCapabilities(api, dir);
|
|
171
|
+
assert.equal(caps.hasRtkOptimizer, true);
|
|
172
|
+
} finally {
|
|
173
|
+
if (oldEnv === undefined) {
|
|
174
|
+
delete process.env.PI_CODING_AGENT_DIR;
|
|
175
|
+
} else {
|
|
176
|
+
process.env.PI_CODING_AGENT_DIR = oldEnv;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
test("detects RTK extension via cwd config-dir path", () => {
|
|
183
|
+
withTempDir("pi-rtk-cwd-", (dir) => {
|
|
184
|
+
const extDir = join(dir, CONFIG_DIR_NAME, "extensions", "pi-rtk-optimizer");
|
|
185
|
+
mkdirSync(extDir, { recursive: true });
|
|
186
|
+
|
|
187
|
+
const api = createApiStub([], []);
|
|
188
|
+
const caps = detectToolDisplayCapabilities(api, dir);
|
|
189
|
+
|
|
190
|
+
assert.equal(caps.hasRtkOptimizer, true);
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
test("no false positive when both commands and path are absent", () => {
|
|
195
|
+
withTempDir("pi-cap-no-fp-", (dir) => {
|
|
196
|
+
const oldEnv = process.env.PI_CODING_AGENT_DIR;
|
|
197
|
+
process.env.PI_CODING_AGENT_DIR = dir;
|
|
198
|
+
try {
|
|
199
|
+
const api = createApiStub([], []);
|
|
200
|
+
const caps = detectToolDisplayCapabilities(api, dir);
|
|
201
|
+
assert.equal(caps.hasRtkOptimizer, false);
|
|
202
|
+
} finally {
|
|
203
|
+
if (oldEnv === undefined) {
|
|
204
|
+
delete process.env.PI_CODING_AGENT_DIR;
|
|
205
|
+
} else {
|
|
206
|
+
process.env.PI_CODING_AGENT_DIR = oldEnv;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
test("applyCapabilityConfigGuards preserves MCP output when MCP may appear dynamically", () => {
|
|
213
|
+
const guarded = applyCapabilityConfigGuards(
|
|
214
|
+
{ ...DEFAULT_TOOL_DISPLAY_CONFIG, mcpOutputMode: "preview" },
|
|
215
|
+
{ hasMcpTooling: false, hasRtkOptimizer: true },
|
|
216
|
+
);
|
|
217
|
+
|
|
218
|
+
assert.equal(guarded.mcpOutputMode, "preview");
|
|
219
|
+
assert.equal(guarded.showRtkCompactionHints, DEFAULT_TOOL_DISPLAY_CONFIG.showRtkCompactionHints);
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
test("applyCapabilityConfigGuards disables RTK hints when RTK unavailable", () => {
|
|
223
|
+
const guarded = applyCapabilityConfigGuards(
|
|
224
|
+
{ ...DEFAULT_TOOL_DISPLAY_CONFIG, showRtkCompactionHints: true },
|
|
225
|
+
{ hasMcpTooling: true, hasRtkOptimizer: false },
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
assert.equal(guarded.mcpOutputMode, DEFAULT_TOOL_DISPLAY_CONFIG.mcpOutputMode);
|
|
229
|
+
assert.equal(guarded.showRtkCompactionHints, false);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
test("applyCapabilityConfigGuards preserves values when both capabilities present", () => {
|
|
233
|
+
const input = {
|
|
234
|
+
...DEFAULT_TOOL_DISPLAY_CONFIG,
|
|
235
|
+
mcpOutputMode: "preview" as const,
|
|
236
|
+
showRtkCompactionHints: true,
|
|
237
|
+
};
|
|
238
|
+
const guarded = applyCapabilityConfigGuards(input, {
|
|
239
|
+
hasMcpTooling: true,
|
|
240
|
+
hasRtkOptimizer: true,
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
assert.equal(guarded.mcpOutputMode, "preview");
|
|
244
|
+
assert.equal(guarded.showRtkCompactionHints, true);
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
test("applyCapabilityConfigGuards clones registerToolOverrides", () => {
|
|
248
|
+
const input = { ...DEFAULT_TOOL_DISPLAY_CONFIG };
|
|
249
|
+
const guarded = applyCapabilityConfigGuards(input, {
|
|
250
|
+
hasMcpTooling: false,
|
|
251
|
+
hasRtkOptimizer: false,
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
// Modifying the source should not affect the guarded copy
|
|
255
|
+
const originalOverrides = input.registerToolOverrides;
|
|
256
|
+
const guardedOverrides = guarded.registerToolOverrides;
|
|
257
|
+
assert.notEqual(originalOverrides, guardedOverrides, "should be a different object");
|
|
258
|
+
assert.deepEqual(originalOverrides, guardedOverrides);
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
// #6: PI_CODING_AGENT_DIR support — env var changes affect RTK path probe
|
|
262
|
+
test("PI_CODING_AGENT_DIR influences RTK extension path detection", () => {
|
|
263
|
+
withTempDir("pi-coding-agent-dir-", (dir) => {
|
|
264
|
+
// Create the expected rtk-optimizer path inside a custom agent dir
|
|
265
|
+
const extDir = join(dir, "extensions", "pi-rtk-optimizer");
|
|
266
|
+
mkdirSync(extDir, { recursive: true });
|
|
267
|
+
|
|
268
|
+
const previousEnv = process.env.PI_CODING_AGENT_DIR;
|
|
269
|
+
process.env.PI_CODING_AGENT_DIR = dir;
|
|
270
|
+
|
|
271
|
+
try {
|
|
272
|
+
const api = createApiStub([], []);
|
|
273
|
+
const caps = detectToolDisplayCapabilities(api, dir);
|
|
274
|
+
assert.equal(caps.hasRtkOptimizer, true, "PI_CODING_AGENT_DIR should point to dir with rtk-optimizer");
|
|
275
|
+
} finally {
|
|
276
|
+
if (previousEnv === undefined) {
|
|
277
|
+
delete process.env.PI_CODING_AGENT_DIR;
|
|
278
|
+
} else {
|
|
279
|
+
process.env.PI_CODING_AGENT_DIR = previousEnv;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
test("PI_CODING_AGENT_DIR set to dir without rtk-optimizer yields no RTK capability", () => {
|
|
286
|
+
withTempDir("pi-cap-no-rtk-", (dir) => {
|
|
287
|
+
const oldEnv = process.env.PI_CODING_AGENT_DIR;
|
|
288
|
+
process.env.PI_CODING_AGENT_DIR = dir;
|
|
289
|
+
try {
|
|
290
|
+
const api = createApiStub([], []);
|
|
291
|
+
const caps = detectToolDisplayCapabilities(api, dir);
|
|
292
|
+
assert.equal(caps.hasRtkOptimizer, false, "dir without rtk-optimizer should yield false");
|
|
293
|
+
} finally {
|
|
294
|
+
if (oldEnv === undefined) {
|
|
295
|
+
delete process.env.PI_CODING_AGENT_DIR;
|
|
296
|
+
} else {
|
|
297
|
+
process.env.PI_CODING_AGENT_DIR = oldEnv;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
// #20: peer dependency compatibility — missing/renamed APIs
|
|
304
|
+
test("tools without description do not trigger false MCP detection", () => {
|
|
305
|
+
const api = createApiStub([
|
|
306
|
+
{ name: "custom-tool", parameters: {} },
|
|
307
|
+
]);
|
|
308
|
+
const caps = detectToolDisplayCapabilities(api, "/tmp");
|
|
309
|
+
|
|
310
|
+
assert.equal(caps.hasMcpTooling, false);
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
test("tools with 'MCP' in the description but no MCP-like name are detected", () => {
|
|
314
|
+
const api = createApiStub([
|
|
315
|
+
{
|
|
316
|
+
name: "random_tool",
|
|
317
|
+
description: "This uses the MCP protocol for communication with external servers.",
|
|
318
|
+
parameters: {},
|
|
319
|
+
},
|
|
320
|
+
]);
|
|
321
|
+
const caps = detectToolDisplayCapabilities(api, "/tmp");
|
|
322
|
+
|
|
323
|
+
assert.equal(caps.hasMcpTooling, true);
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
test("tool with empty name string is handled safely", () => {
|
|
327
|
+
const api = createApiStub([
|
|
328
|
+
{ name: "", description: "empty name tool", parameters: {} },
|
|
329
|
+
]);
|
|
330
|
+
const caps = detectToolDisplayCapabilities(api, "/tmp");
|
|
331
|
+
|
|
332
|
+
assert.equal(caps.hasMcpTooling, false);
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
test("tool with undefined name is handled safely", () => {
|
|
336
|
+
const api = createApiStub([
|
|
337
|
+
{ description: "no name field", parameters: {} },
|
|
338
|
+
]);
|
|
339
|
+
const caps = detectToolDisplayCapabilities(api, "/tmp");
|
|
340
|
+
|
|
341
|
+
assert.equal(caps.hasMcpTooling, false);
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
test("commands list can contain non-string name entries", () => {
|
|
345
|
+
const api = createApiStub(
|
|
346
|
+
[],
|
|
347
|
+
// @ts-expect-error testing edge case
|
|
348
|
+
[{ name: 123 }, { name: "rtk" }],
|
|
349
|
+
);
|
|
350
|
+
const caps = detectToolDisplayCapabilities(api, "/tmp");
|
|
351
|
+
|
|
352
|
+
assert.equal(caps.hasRtkOptimizer, true);
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
test("empty allTools array does not throw", () => {
|
|
356
|
+
const api = createApiStub([]);
|
|
357
|
+
const caps = detectToolDisplayCapabilities(api, "/tmp");
|
|
358
|
+
|
|
359
|
+
assert.equal(caps.hasMcpTooling, false);
|
|
360
|
+
});
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
4
|
+
import { CONFIG_DIR_NAME } from "@earendil-works/pi-coding-agent";
|
|
5
|
+
import {
|
|
6
|
+
applyCapabilityConfigGuards,
|
|
7
|
+
detectToolDisplayCapabilities,
|
|
8
|
+
} from "../src/capabilities.ts";
|
|
9
|
+
import { DEFAULT_TOOL_DISPLAY_CONFIG } from "../src/types.ts";
|
|
10
|
+
|
|
11
|
+
function createExtensionApiStub(allTools: unknown[]): ExtensionAPI {
|
|
12
|
+
return {
|
|
13
|
+
getAllTools(): unknown[] {
|
|
14
|
+
return allTools;
|
|
15
|
+
},
|
|
16
|
+
getCommands(): Array<{ name: string }> {
|
|
17
|
+
return [];
|
|
18
|
+
},
|
|
19
|
+
} as unknown as ExtensionAPI;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
test("detectToolDisplayCapabilities recognises MCP tools from v0.62.0 tool info without label or execute", () => {
|
|
23
|
+
const api = createExtensionApiStub([
|
|
24
|
+
{
|
|
25
|
+
name: "exa_web_search_exa",
|
|
26
|
+
description:
|
|
27
|
+
"Search the web with Exa. Direct MCP wrapper for 'exa:web_search_exa'. Common args: query*.",
|
|
28
|
+
parameters: {},
|
|
29
|
+
sourceInfo: {
|
|
30
|
+
path: "C:/Users/Administrator/.pi/agent/extensions/pi-mcp-adapter/index.ts",
|
|
31
|
+
source: "local",
|
|
32
|
+
scope: "user",
|
|
33
|
+
origin: "top-level",
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
]);
|
|
37
|
+
|
|
38
|
+
const capabilities = detectToolDisplayCapabilities(api, `C:/Users/Administrator/${CONFIG_DIR_NAME}`);
|
|
39
|
+
|
|
40
|
+
assert.equal(capabilities.hasMcpTooling, true);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test("applyCapabilityConfigGuards preserves MCP output when MCP tooling is not detected yet", () => {
|
|
44
|
+
const guarded = applyCapabilityConfigGuards(
|
|
45
|
+
{ ...DEFAULT_TOOL_DISPLAY_CONFIG, mcpOutputMode: "preview" },
|
|
46
|
+
{
|
|
47
|
+
hasMcpTooling: false,
|
|
48
|
+
hasRtkOptimizer: true,
|
|
49
|
+
},
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
assert.equal(guarded.mcpOutputMode, "preview");
|
|
53
|
+
assert.equal(guarded.showRtkCompactionHints, DEFAULT_TOOL_DISPLAY_CONFIG.showRtkCompactionHints);
|
|
54
|
+
});
|