@av-pi-studio/client 0.0.92 → 0.0.94

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.
@@ -0,0 +1,235 @@
1
+ import { DaemonClient } from "../daemon-client.js";
2
+ import { PiStudioClient } from "../pistudio-client.js";
3
+ export function makeScriptedDaemon(opts) {
4
+ const sent = [];
5
+ let agentSeq = 0;
6
+ const features = opts?.features ?? { providersSnapshot: true, providerAuth: true };
7
+ const transport = {
8
+ onMessage: null,
9
+ onClose: null,
10
+ onError: null,
11
+ isOpen: true,
12
+ connect: () => Promise.resolve(),
13
+ sendBinary: () => { },
14
+ close: () => { },
15
+ sendText: (data) => {
16
+ const frame = JSON.parse(data);
17
+ if (frame.type === "hello") {
18
+ queueMicrotask(() => transport.onMessage?.(JSON.stringify({
19
+ type: "status",
20
+ payload: {
21
+ status: "server_info",
22
+ serverId: "srv-mock",
23
+ capabilities: {},
24
+ features,
25
+ },
26
+ })));
27
+ return;
28
+ }
29
+ if (frame.type === "session") {
30
+ const msg = frame.message;
31
+ sent.push(msg);
32
+ respond(msg);
33
+ }
34
+ },
35
+ };
36
+ function reply(message) {
37
+ queueMicrotask(() => transport.onMessage?.(JSON.stringify({ type: "session", message })));
38
+ }
39
+ function respond(msg) {
40
+ const requestId = msg.requestId;
41
+ // The `provider_auth_*` family is driven manually by each test via `fake.push()` — real
42
+ // flows are ordering-sensitive (buffering-before-response, prompt races), so an automatic
43
+ // reply here would hide exactly the bugs those tests exist to catch.
44
+ if (typeof msg.type === "string" && msg.type.startsWith("provider_auth_")) {
45
+ return;
46
+ }
47
+ switch (msg.type) {
48
+ case "agent_ui_respond_request":
49
+ case "agent_ui_list_request":
50
+ // Driven manually by each test via `fake.push()` — the ok/error mix (and, for
51
+ // agent_ui_list_request, the exact moment the reply lands relative to other pushed
52
+ // events) is exactly what the acceptance criteria differentiate on; an automatic reply
53
+ // would hide it.
54
+ return;
55
+ case "create_agent_request": {
56
+ const agentId = `agent-${++agentSeq}`;
57
+ reply({ type: "create_agent_response", requestId, payload: { agentId } });
58
+ // Simulate a streamed turn for the new agent.
59
+ if (msg.initialPrompt) {
60
+ reply({
61
+ type: "agent_stream",
62
+ agentId,
63
+ event: { kind: "turn_started" },
64
+ });
65
+ reply({
66
+ type: "agent_stream",
67
+ agentId,
68
+ event: { kind: "assistant_message", text: "hello from mock" },
69
+ });
70
+ reply({ type: "agent_stream", agentId, event: { kind: "turn_completed" } });
71
+ reply({ type: "agent_update", agentId, status: "idle" });
72
+ }
73
+ return;
74
+ }
75
+ case "fetch_agent_timeline_request": {
76
+ reply({
77
+ type: "fetch_agent_timeline_response",
78
+ requestId,
79
+ payload: {
80
+ agentId: msg.agentId,
81
+ items: [{ kind: "assistant_message", text: "hello from mock" }],
82
+ startCursor: "c0",
83
+ endCursor: "c1",
84
+ hasOlder: false,
85
+ hasNewer: false,
86
+ seqStart: 1,
87
+ seqEnd: 1,
88
+ },
89
+ });
90
+ return;
91
+ }
92
+ case "update_agent": {
93
+ reply({ type: "update_agent_response", requestId, payload: { ok: true } });
94
+ reply({
95
+ type: "agent_update",
96
+ agentId: msg.agentId,
97
+ title: msg.title,
98
+ });
99
+ return;
100
+ }
101
+ case "agent_session_stats_request": {
102
+ reply({
103
+ type: "agent_session_stats_response",
104
+ requestId,
105
+ payload: { sessionId: "s1", totalMessages: 3 },
106
+ });
107
+ return;
108
+ }
109
+ case "agent_compact_request": {
110
+ reply({
111
+ type: "agent_compact_response",
112
+ requestId,
113
+ payload: { summary: "compacted", tokensBefore: 1000 },
114
+ });
115
+ return;
116
+ }
117
+ case "agent_list_commands_request": {
118
+ reply({
119
+ type: "agent_list_commands_response",
120
+ requestId,
121
+ payload: {
122
+ commands: [
123
+ {
124
+ name: "fix-tests",
125
+ description: "Fix failing tests",
126
+ source: "prompt",
127
+ scope: "project",
128
+ path: "/w/.pi/agent/prompts/fix-tests.md",
129
+ },
130
+ { name: "skill:brave-search", source: "skill", scope: "user" },
131
+ ],
132
+ },
133
+ });
134
+ return;
135
+ }
136
+ case "list_provider_models": {
137
+ reply({
138
+ type: "list_provider_models_response",
139
+ requestId,
140
+ payload: { models: [{ id: "m1" }, { id: "m2" }] },
141
+ });
142
+ return;
143
+ }
144
+ case "list_provider_modes": {
145
+ reply({
146
+ type: "list_provider_modes_response",
147
+ requestId,
148
+ payload: { modes: [{ id: "plan" }, { id: "default" }] },
149
+ });
150
+ return;
151
+ }
152
+ case "providers.snapshot.refresh.request": {
153
+ reply({
154
+ type: "providers.snapshot.refresh.response",
155
+ requestId,
156
+ payload: { refreshed: true },
157
+ });
158
+ return;
159
+ }
160
+ case "resolve_default_model": {
161
+ reply({
162
+ type: "resolve_default_model_response",
163
+ requestId,
164
+ provider: msg.provider,
165
+ model: "claude-sonnet-5",
166
+ modelProvider: "anthropic",
167
+ });
168
+ return;
169
+ }
170
+ case "extension_packs_list_request": {
171
+ // Flat fields on the message — the real wire schema (packages/protocol/src/messages.ts)
172
+ // has no `payload` wrapper for this pair, unlike several older RPCs above.
173
+ reply({
174
+ type: "extension_packs_list_response",
175
+ requestId,
176
+ autoSync: true,
177
+ selected: ["swe"],
178
+ packs: [
179
+ { id: "core", title: "Core", description: "Always-on core pack", packages: [] },
180
+ { id: "swe", title: "Software Engineering", description: "SWE tools", packages: [] },
181
+ ],
182
+ });
183
+ return;
184
+ }
185
+ case "extension_packs_set_request": {
186
+ const packs = msg.packs;
187
+ if (packs?.includes("unknown")) {
188
+ reply({
189
+ type: "extension_packs_set_response",
190
+ requestId,
191
+ autoSync: true,
192
+ selected: ["swe"],
193
+ packs: [],
194
+ ok: false,
195
+ error: "unknown pack: unknown",
196
+ });
197
+ return;
198
+ }
199
+ reply({
200
+ type: "extension_packs_set_response",
201
+ requestId,
202
+ autoSync: true,
203
+ selected: packs ?? ["swe"],
204
+ packs: [],
205
+ ok: true,
206
+ report: { at: new Date().toISOString(), outcome: "ok", installed: [], failures: [] },
207
+ });
208
+ return;
209
+ }
210
+ default:
211
+ reply({ type: `${String(msg.type)}_response`, requestId, payload: { ok: true } });
212
+ }
213
+ }
214
+ return {
215
+ transport,
216
+ sent,
217
+ features,
218
+ push: (sessionMessage) => reply(sessionMessage),
219
+ drop: (reason = "test drop") => transport.onClose?.(1006, reason),
220
+ };
221
+ }
222
+ /** Builds a connected `PiStudioClient` over `makeScriptedDaemon`. */
223
+ export async function makeFacade(opts) {
224
+ const fake = makeScriptedDaemon(opts);
225
+ const daemon = new DaemonClient({
226
+ url: "ws://mock/ws",
227
+ clientId: "c1",
228
+ clientType: "cli",
229
+ transport: fake.transport,
230
+ rpcTimeoutMs: 1000,
231
+ });
232
+ await daemon.connect();
233
+ return { client: new PiStudioClient(daemon), daemon, fake };
234
+ }
235
+ //# sourceMappingURL=scripted-daemon.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@av-pi-studio/client",
3
- "version": "0.0.92",
3
+ "version": "0.0.94",
4
4
  "files": [
5
5
  "dist",
6
6
  "!dist/**/*.map",
@@ -20,7 +20,7 @@
20
20
  "clean": "rm -rf dist *.tsbuildinfo"
21
21
  },
22
22
  "dependencies": {
23
- "@av-pi-studio/protocol": "^0.0.92",
24
- "@av-pi-studio/relay": "^0.0.92"
23
+ "@av-pi-studio/protocol": "^0.0.94",
24
+ "@av-pi-studio/relay": "^0.0.94"
25
25
  }
26
26
  }