@aliou/pi-dev-kit 0.5.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/package.json +8 -4
- package/src/skills/pi-extension/SKILL.md +51 -37
- package/src/skills/pi-extension/references/additional-apis.md +41 -1
- package/src/skills/pi-extension/references/hooks.md +12 -9
- package/src/skills/pi-extension/references/state.md +38 -27
- package/src/skills/pi-extension/references/structure.md +116 -2
- package/src/skills/pi-extension/references/testing.md +129 -0
- package/src/skills/pi-extension/references/tools.md +674 -156
- package/src/tools/changelog-tool.ts +172 -284
- package/src/tools/docs-tool.ts +87 -146
- package/src/tools/package-manager-tool.ts +98 -127
- package/src/tools/utils.ts +0 -24
- package/src/tools/version-tool.ts +13 -20
|
@@ -42,6 +42,135 @@ Test event hooks by triggering the relevant actions:
|
|
|
42
42
|
- `input`: Type a message that matches your transform pattern.
|
|
43
43
|
- `before_agent_start`: Start any agent turn and verify system prompt modifications.
|
|
44
44
|
|
|
45
|
+
## Unit Testing Core Logic
|
|
46
|
+
|
|
47
|
+
The core/lib pattern makes domain logic testable without the Pi framework. Extract business logic into modules that don't import from `@mariozechner/pi-coding-agent` and test them directly.
|
|
48
|
+
|
|
49
|
+
### Testable core modules
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
// src/manager.ts — no Pi imports
|
|
53
|
+
export class ProcessManager {
|
|
54
|
+
start(name: string, command: string, cwd: string): ProcessInfo { ... }
|
|
55
|
+
get(id: string): ProcessInfo | undefined { ... }
|
|
56
|
+
kill(id: string): Promise<KillResult> { ... }
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
// src/manager.test.ts
|
|
62
|
+
import { describe, it, expect, afterEach } from "vitest";
|
|
63
|
+
import { ProcessManager } from "./manager";
|
|
64
|
+
|
|
65
|
+
describe("ProcessManager", () => {
|
|
66
|
+
let manager: ProcessManager;
|
|
67
|
+
afterEach(() => manager.cleanup());
|
|
68
|
+
|
|
69
|
+
it("starts a process and returns info", () => {
|
|
70
|
+
manager = new ProcessManager();
|
|
71
|
+
const info = manager.start("test", "echo hello", "/tmp");
|
|
72
|
+
expect(info.id).toMatch(/^proc_/);
|
|
73
|
+
expect(info.name).toBe("test");
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Testable execute functions
|
|
79
|
+
|
|
80
|
+
Export the execute logic as a pure function with injected dependencies:
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
// src/tools/read-url.ts
|
|
84
|
+
export async function executeReadUrlRequest(
|
|
85
|
+
input: string,
|
|
86
|
+
signal: AbortSignal | undefined,
|
|
87
|
+
handlers: ReadUrlHandler[],
|
|
88
|
+
fetchImpl: FetchLike = fetch,
|
|
89
|
+
): Promise<ExecuteResult> {
|
|
90
|
+
// all logic here, no Pi imports
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// In the tool registration:
|
|
94
|
+
async execute(_toolCallId, params, signal, _onUpdate, _ctx) {
|
|
95
|
+
return executeReadUrlRequest(params.url, signal, handlers, fetch);
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
// src/tools/read-url.test.ts
|
|
101
|
+
import { describe, it, expect } from "vitest";
|
|
102
|
+
import { executeReadUrlRequest } from "./read-url";
|
|
103
|
+
|
|
104
|
+
const mockHandler = {
|
|
105
|
+
name: "mock",
|
|
106
|
+
matches: (url: URL) => url.hostname === "example.com",
|
|
107
|
+
fetchData: async () => ({ markdown: "# Hello", sourceUrl: "..." }),
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
describe("executeReadUrlRequest", () => {
|
|
111
|
+
it("routes to matching handler", async () => {
|
|
112
|
+
const result = await executeReadUrlRequest(
|
|
113
|
+
"https://example.com/page",
|
|
114
|
+
undefined,
|
|
115
|
+
[mockHandler],
|
|
116
|
+
);
|
|
117
|
+
expect(result.details.handler).toBe("mock");
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Handler pattern
|
|
123
|
+
|
|
124
|
+
For tools that route to different backends based on input, use an interface:
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
export interface ReadUrlHandler {
|
|
128
|
+
name: string;
|
|
129
|
+
matches(url: URL): boolean;
|
|
130
|
+
fetchData(url: URL, signal?: AbortSignal): Promise<HandlerResult>;
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Multiple handlers are tried in order. Each handler is independently testable.
|
|
135
|
+
|
|
136
|
+
### Pi stub for hook testing
|
|
137
|
+
|
|
138
|
+
When testing hooks or tool registration, create a minimal Pi stub:
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
function createPiStub() {
|
|
142
|
+
const toolCallHandlers: Array<Parameters<ExtensionAPI["on"]>[1]> = [];
|
|
143
|
+
const registeredTools: unknown[] = [];
|
|
144
|
+
|
|
145
|
+
const pi = {
|
|
146
|
+
on(eventName: string, handler: Parameters<ExtensionAPI["on"]>[1]) {
|
|
147
|
+
if (eventName === "tool_call") toolCallHandlers.push(handler);
|
|
148
|
+
},
|
|
149
|
+
registerTool(tool: unknown) {
|
|
150
|
+
registeredTools.push(tool);
|
|
151
|
+
},
|
|
152
|
+
} as unknown as ExtensionAPI;
|
|
153
|
+
|
|
154
|
+
return { pi, toolCallHandlers, registeredTools };
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Test setup
|
|
159
|
+
|
|
160
|
+
Extensions use vitest. Add to `package.json`:
|
|
161
|
+
|
|
162
|
+
```json
|
|
163
|
+
{
|
|
164
|
+
"devDependencies": {
|
|
165
|
+
"vitest": "^3.2.0"
|
|
166
|
+
},
|
|
167
|
+
"scripts": {
|
|
168
|
+
"test": "vitest run",
|
|
169
|
+
"test:watch": "vitest"
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
45
174
|
## Debugging
|
|
46
175
|
|
|
47
176
|
Extension errors are logged to the pi log file. Check the output for stack traces:
|