@getpaseo/server 0.9.2 → 0.10.0-beta.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.
Files changed (145) hide show
  1. package/dist/scripts/supervisor.js +51 -21
  2. package/dist/server/server/agent/agent-manager.js +22 -2
  3. package/dist/server/server/agent/agent-prompt.js +12 -0
  4. package/dist/server/server/agent/agent-sdk-types.d.ts +3 -0
  5. package/dist/server/server/agent/mcp-shared.d.ts +5 -1
  6. package/dist/server/server/agent/mcp-shared.js +2 -1
  7. package/dist/server/server/agent/provider-registry.js +2 -2
  8. package/dist/server/server/agent/providers/acp-agent.js +20 -11
  9. package/dist/server/server/agent/providers/claude/agent.d.ts +1 -2
  10. package/dist/server/server/agent/providers/claude/agent.js +10 -9
  11. package/dist/server/server/agent/providers/claude/models.d.ts +1 -1
  12. package/dist/server/server/agent/providers/claude/models.js +1 -5
  13. package/dist/server/server/agent/providers/claude/project-dir.d.ts +1 -0
  14. package/dist/server/server/agent/providers/claude/project-dir.js +5 -1
  15. package/dist/server/server/agent/providers/codex-app-server-agent.d.ts +6 -1
  16. package/dist/server/server/agent/providers/codex-app-server-agent.js +10 -1
  17. package/dist/server/server/agent/providers/generic-acp-agent.js +3 -1
  18. package/dist/server/server/agent/providers/omp/agent.js +23 -6
  19. package/dist/server/server/agent/providers/omp/rpc-types.d.ts +1 -0
  20. package/dist/server/server/agent/providers/omp/rpc-types.js +1 -0
  21. package/dist/server/server/agent/providers/opencode/bridge.d.ts +5 -1
  22. package/dist/server/server/agent/providers/opencode/bridge.js +56 -5
  23. package/dist/server/server/agent/providers/opencode/http-error.d.ts +8 -0
  24. package/dist/server/server/agent/providers/opencode/http-error.js +13 -0
  25. package/dist/server/server/agent/providers/opencode/runtime-client.d.ts +38 -0
  26. package/dist/server/server/agent/providers/opencode/runtime-client.js +131 -0
  27. package/dist/server/server/agent/providers/opencode/runtime-notice.d.ts +3 -0
  28. package/dist/server/server/agent/providers/opencode/runtime-notice.js +47 -0
  29. package/dist/server/server/agent/providers/opencode/server-manager.js +19 -8
  30. package/dist/server/server/agent/providers/opencode/v2/agent.d.ts +36 -0
  31. package/dist/server/server/agent/providers/opencode/v2/agent.js +208 -0
  32. package/dist/server/server/agent/providers/opencode/v2/api.d.ts +18 -0
  33. package/dist/server/server/agent/providers/opencode/v2/api.js +2 -0
  34. package/dist/server/server/agent/providers/opencode/v2/bridge-plugin.bundle.mjs +6693 -0
  35. package/dist/server/server/agent/providers/opencode/v2/capabilities.d.ts +3 -0
  36. package/dist/server/server/agent/providers/opencode/v2/capabilities.js +13 -0
  37. package/dist/server/server/agent/providers/opencode/v2/children.d.ts +20 -0
  38. package/dist/server/server/agent/providers/opencode/v2/children.js +75 -0
  39. package/dist/server/server/agent/providers/opencode/v2/commands.d.ts +4 -0
  40. package/dist/server/server/agent/providers/opencode/v2/commands.js +36 -0
  41. package/dist/server/server/agent/providers/opencode/v2/configuration.d.ts +8 -0
  42. package/dist/server/server/agent/providers/opencode/v2/configuration.js +64 -0
  43. package/dist/server/server/agent/providers/opencode/v2/history.d.ts +4 -0
  44. package/dist/server/server/agent/providers/opencode/v2/history.js +15 -0
  45. package/dist/server/server/agent/providers/opencode/v2/mapping.d.ts +7 -0
  46. package/dist/server/server/agent/providers/opencode/v2/mapping.js +42 -0
  47. package/dist/server/server/agent/providers/opencode/v2/permissions.d.ts +18 -0
  48. package/dist/server/server/agent/providers/opencode/v2/permissions.js +157 -0
  49. package/dist/server/server/agent/providers/opencode/v2/readiness.d.ts +18 -0
  50. package/dist/server/server/agent/providers/opencode/v2/readiness.js +51 -0
  51. package/dist/server/server/agent/providers/opencode/v2/runtime.d.ts +36 -0
  52. package/dist/server/server/agent/providers/opencode/v2/runtime.js +230 -0
  53. package/dist/server/server/agent/providers/opencode/v2/session.d.ts +84 -0
  54. package/dist/server/server/agent/providers/opencode/v2/session.js +465 -0
  55. package/dist/server/server/agent/providers/opencode/v2/structured-output.d.ts +8 -0
  56. package/dist/server/server/agent/providers/opencode/v2/structured-output.js +32 -0
  57. package/dist/server/server/agent/providers/opencode/v2/timeline.d.ts +28 -0
  58. package/dist/server/server/agent/providers/opencode/v2/timeline.js +154 -0
  59. package/dist/server/server/agent/providers/opencode/v2/turns.d.ts +40 -0
  60. package/dist/server/server/agent/providers/opencode/v2/turns.js +226 -0
  61. package/dist/server/server/agent/providers/opencode-agent.d.ts +26 -7
  62. package/dist/server/server/agent/providers/opencode-agent.js +100 -40
  63. package/dist/server/server/agent/providers/pi/agent.d.ts +6 -6
  64. package/dist/server/server/agent/providers/pi/agent.js +114 -165
  65. package/dist/server/server/agent/providers/pi/extensions/child-session.d.ts +4 -0
  66. package/dist/server/server/agent/providers/pi/extensions/child-session.js +59 -0
  67. package/dist/server/server/agent/providers/pi/extensions/contract.d.ts +68 -0
  68. package/dist/server/server/agent/providers/pi/extensions/contract.js +2 -0
  69. package/dist/server/server/agent/providers/pi/extensions/gotgenes-pi-subagents/index.d.ts +3 -0
  70. package/dist/server/server/agent/providers/pi/extensions/gotgenes-pi-subagents/index.js +159 -0
  71. package/dist/server/server/agent/providers/pi/extensions/host.d.ts +28 -0
  72. package/dist/server/server/agent/providers/pi/extensions/host.js +94 -0
  73. package/dist/server/server/agent/providers/pi/extensions/index.d.ts +7 -0
  74. package/dist/server/server/agent/providers/pi/extensions/index.js +6 -0
  75. package/dist/server/server/agent/providers/pi/extensions/pi-ask-user/index.d.ts +3 -0
  76. package/dist/server/server/agent/providers/pi/extensions/pi-ask-user/index.js +138 -0
  77. package/dist/server/server/agent/providers/pi/extensions/pi-example-todo/index.d.ts +3 -0
  78. package/dist/server/server/agent/providers/pi/extensions/pi-example-todo/index.js +38 -0
  79. package/dist/server/server/agent/providers/pi/extensions/pi-goal-x/index.d.ts +3 -0
  80. package/dist/server/server/agent/providers/pi/extensions/pi-goal-x/index.js +63 -0
  81. package/dist/server/server/agent/providers/pi/extensions/pi-mcp-adapter/index.d.ts +3 -0
  82. package/dist/server/server/agent/providers/pi/extensions/pi-mcp-adapter/index.js +48 -0
  83. package/dist/server/server/agent/providers/pi/extensions/pi-subagents/index.d.ts +3 -0
  84. package/dist/server/server/agent/providers/pi/extensions/pi-subagents/index.js +131 -0
  85. package/dist/server/server/agent/providers/pi/extensions/registry.d.ts +2 -0
  86. package/dist/server/server/agent/providers/pi/extensions/registry.js +21 -0
  87. package/dist/server/server/agent/providers/pi/extensions/rpiv-ask-user-question/index.d.ts +3 -0
  88. package/dist/server/server/agent/providers/pi/extensions/rpiv-ask-user-question/index.js +180 -0
  89. package/dist/server/server/agent/providers/pi/extensions/rpiv-todo/index.d.ts +3 -0
  90. package/dist/server/server/agent/providers/pi/extensions/rpiv-todo/index.js +51 -0
  91. package/dist/server/server/agent/providers/pi/extensions/subagent-fixture-test.d.ts +22 -0
  92. package/dist/server/server/agent/providers/pi/extensions/subagent-fixture-test.js +66 -0
  93. package/dist/server/server/agent/providers/pi/extensions/task-fixture-test.d.ts +4 -0
  94. package/dist/server/server/agent/providers/pi/extensions/task-fixture-test.js +79 -0
  95. package/dist/server/server/agent/providers/pi/extensions/tintinweb-pi-subagents/index.d.ts +3 -0
  96. package/dist/server/server/agent/providers/pi/extensions/tintinweb-pi-subagents/index.js +149 -0
  97. package/dist/server/server/agent/providers/pi/history-mapper.d.ts +7 -2
  98. package/dist/server/server/agent/providers/pi/history-mapper.js +78 -35
  99. package/dist/server/server/agent/providers/pi/rpc-types.d.ts +3 -0
  100. package/dist/server/server/agent/providers/pi/test-utils/fake-pi.d.ts +170 -0
  101. package/dist/server/server/agent/providers/pi/test-utils/fake-pi.js +355 -0
  102. package/dist/server/server/agent/providers/pi/tool-call-mapper.d.ts +1 -6
  103. package/dist/server/server/agent/providers/pi/tool-call-mapper.js +1 -97
  104. package/dist/server/server/agent/tools/paseo-tools.js +22 -15
  105. package/dist/server/server/auth.d.ts +1 -2
  106. package/dist/server/server/auth.js +8 -14
  107. package/dist/server/server/bootstrap.js +10 -2
  108. package/dist/server/server/daemon-instance.d.ts +1 -0
  109. package/dist/server/server/daemon-instance.js +1 -0
  110. package/dist/server/server/exports.d.ts +1 -1
  111. package/dist/server/server/exports.js +1 -1
  112. package/dist/server/server/local-credential.d.ts +6 -0
  113. package/dist/server/server/local-credential.js +82 -0
  114. package/dist/server/server/session-admission-auth.d.ts +16 -0
  115. package/dist/server/server/session-admission-auth.js +26 -0
  116. package/dist/server/server/websocket-server.d.ts +6 -1
  117. package/dist/server/server/websocket-server.js +132 -55
  118. package/dist/server/web-ui/_expo/static/js/web/{desktop-attachment-bridge-f41bce08c3c4ac2de0652d20234d19e9.js → desktop-attachment-bridge-9da07adb97f5e0eb726f7762afee43f5.js} +1 -1
  119. package/dist/server/web-ui/_expo/static/js/web/{desktop-attachment-bridge-f41bce08c3c4ac2de0652d20234d19e9.js.br → desktop-attachment-bridge-9da07adb97f5e0eb726f7762afee43f5.js.br} +0 -0
  120. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-9da07adb97f5e0eb726f7762afee43f5.js.gz +0 -0
  121. package/dist/server/web-ui/_expo/static/js/web/{desktop-attachment-store-9e271e161480b0d1dd35e58616a37341.js → desktop-attachment-store-d5d3402a752965d3037191484127123b.js} +1 -1
  122. package/dist/server/web-ui/_expo/static/js/web/{desktop-attachment-store-9e271e161480b0d1dd35e58616a37341.js.br → desktop-attachment-store-d5d3402a752965d3037191484127123b.js.br} +0 -0
  123. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-d5d3402a752965d3037191484127123b.js.gz +0 -0
  124. package/dist/server/web-ui/_expo/static/js/web/{index-8868523fc6d311c5da524c067d1cd426.js → index-69ce3c243032c3bedfc6f2ad379a4cdd.js} +1579 -1575
  125. package/dist/server/web-ui/_expo/static/js/web/index-69ce3c243032c3bedfc6f2ad379a4cdd.js.br +0 -0
  126. package/dist/server/web-ui/_expo/static/js/web/index-69ce3c243032c3bedfc6f2ad379a4cdd.js.gz +0 -0
  127. package/dist/server/web-ui/_expo/static/js/web/{indexeddb-attachment-store-369cdb67f5856fd2c72d640df0b7b79e.js → indexeddb-attachment-store-3afc19e43c8152bd3c6d71b3ea8776dc.js} +1 -1
  128. package/dist/server/web-ui/_expo/static/js/web/{indexeddb-attachment-store-369cdb67f5856fd2c72d640df0b7b79e.js.br → indexeddb-attachment-store-3afc19e43c8152bd3c6d71b3ea8776dc.js.br} +0 -0
  129. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-3afc19e43c8152bd3c6d71b3ea8776dc.js.gz +0 -0
  130. package/dist/server/web-ui/_expo/static/js/web/{native-file-attachment-store-bcd89f6ce714279a8f4fa0e024f3a610.js → native-file-attachment-store-187a9d5c32188f357dbbf037a0f89073.js} +3 -3
  131. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-187a9d5c32188f357dbbf037a0f89073.js.br +0 -0
  132. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-187a9d5c32188f357dbbf037a0f89073.js.gz +0 -0
  133. package/dist/server/web-ui/index.html +1 -1
  134. package/dist/server/web-ui/index.html.br +0 -0
  135. package/dist/server/web-ui/index.html.gz +0 -0
  136. package/dist/src/server/daemon-instance.js +1 -0
  137. package/dist/src/server/local-credential.js +82 -0
  138. package/package.json +8 -7
  139. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-f41bce08c3c4ac2de0652d20234d19e9.js.gz +0 -0
  140. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-9e271e161480b0d1dd35e58616a37341.js.gz +0 -0
  141. package/dist/server/web-ui/_expo/static/js/web/index-8868523fc6d311c5da524c067d1cd426.js.br +0 -0
  142. package/dist/server/web-ui/_expo/static/js/web/index-8868523fc6d311c5da524c067d1cd426.js.gz +0 -0
  143. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-369cdb67f5856fd2c72d640df0b7b79e.js.gz +0 -0
  144. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-bcd89f6ce714279a8f4fa0e024f3a610.js.br +0 -0
  145. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-bcd89f6ce714279a8f4fa0e024f3a610.js.gz +0 -0
@@ -0,0 +1,355 @@
1
+ import { buildPiLaunch } from "../runtime.js";
2
+ export class FakePi {
3
+ constructor(command = ["pi"]) {
4
+ this.recordedLaunches = [];
5
+ this.sessions = [];
6
+ this.queuedCommands = [];
7
+ this.queuedSessionSetups = [];
8
+ this.command = command;
9
+ }
10
+ async startSession(input) {
11
+ const launch = buildPiLaunch({
12
+ command: this.command,
13
+ session: input,
14
+ });
15
+ this.recordedLaunches.push(launch);
16
+ const session = new FakePiSession(launch);
17
+ session.commands = this.queuedCommands.shift() ?? [];
18
+ this.queuedSessionSetups.shift()?.(session);
19
+ this.sessions.push(session);
20
+ return session;
21
+ }
22
+ queueCommands(commands) {
23
+ this.queuedCommands.push(commands);
24
+ }
25
+ queueSessionSetup(setup) {
26
+ this.queuedSessionSetups.push(setup);
27
+ }
28
+ latestSession() {
29
+ const session = this.sessions.at(-1);
30
+ if (!session) {
31
+ throw new Error("FakePi has no sessions");
32
+ }
33
+ return session;
34
+ }
35
+ }
36
+ export class FakePiSession {
37
+ constructor(launch) {
38
+ this.prompts = [];
39
+ this.steerCalls = [];
40
+ this.steerError = null;
41
+ this.controlRequests = [];
42
+ this.clearQueueError = null;
43
+ this.compactRequests = [];
44
+ this.setAutoCompactionRequests = [];
45
+ this.subagentSubscriptionRequests = [];
46
+ this.subagentMessageRequests = [];
47
+ this.setModelRequests = [];
48
+ this.setThinkingLevelRequests = [];
49
+ this.treeNavigationRequests = [];
50
+ this.handoffRequests = [];
51
+ this.sessionNameRequests = [];
52
+ this.rawFrames = [];
53
+ // Every user entry in the session file, including rewound and compacted ones.
54
+ this.treeUserEntries = [];
55
+ // The user entries on the current branch that getMessages() replays.
56
+ this.contextUserEntries = [];
57
+ this.abortRequested = false;
58
+ this.canceledExtensionUiRequests = [];
59
+ this.extensionUiResponses = [];
60
+ this.setModelResult = null;
61
+ this.models = [];
62
+ this.messages = [];
63
+ this.stats = {
64
+ tokens: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
65
+ cost: 0,
66
+ };
67
+ this.commands = [];
68
+ this.subagents = [];
69
+ this.subagentSubscriptionError = null;
70
+ this.setSessionNameError = null;
71
+ this.compactError = null;
72
+ this.emitCompactEnd = true;
73
+ this.getStateError = null;
74
+ this.getSessionStatsError = null;
75
+ this.promptAck = {};
76
+ this.branchResponse = { text: "" };
77
+ this.branchRequests = [];
78
+ this.subscribers = new Set();
79
+ this.subagentMessageResults = new Map();
80
+ this.nextHeldPrompt = null;
81
+ this.activeHeldPrompt = null;
82
+ this.state = {
83
+ model: null,
84
+ thinkingLevel: "medium",
85
+ isStreaming: false,
86
+ isCompacting: false,
87
+ autoCompactionEnabled: true,
88
+ sessionFile: launch.session ?? "/tmp/pi-session",
89
+ sessionId: "pi-session-1",
90
+ messageCount: 0,
91
+ pendingMessageCount: 0,
92
+ };
93
+ }
94
+ onEvent(callback) {
95
+ this.subscribers.add(callback);
96
+ return () => {
97
+ this.subscribers.delete(callback);
98
+ };
99
+ }
100
+ async prompt(message, images) {
101
+ this.prompts.push({ message, imageCount: images?.length ?? 0 });
102
+ const heldPrompt = this.nextHeldPrompt;
103
+ if (heldPrompt) {
104
+ this.nextHeldPrompt = null;
105
+ this.activeHeldPrompt = heldPrompt;
106
+ try {
107
+ await heldPrompt.promise;
108
+ }
109
+ finally {
110
+ if (this.activeHeldPrompt === heldPrompt) {
111
+ this.activeHeldPrompt = null;
112
+ }
113
+ }
114
+ }
115
+ this.handleTreeNavigationCommand(message);
116
+ this.handleEntryCaptureCommand(message);
117
+ return this.promptAck;
118
+ }
119
+ holdNextPrompt() {
120
+ if (this.nextHeldPrompt || this.activeHeldPrompt) {
121
+ throw new Error("FakePi already has a held prompt");
122
+ }
123
+ let reject;
124
+ const promise = new Promise((_resolve, rejectPromise) => {
125
+ reject = rejectPromise;
126
+ });
127
+ this.nextHeldPrompt = { promise, reject };
128
+ }
129
+ async failHeldPrompt(error) {
130
+ const heldPrompt = this.activeHeldPrompt ?? this.nextHeldPrompt;
131
+ if (!heldPrompt) {
132
+ throw new Error("FakePi has no held prompt");
133
+ }
134
+ heldPrompt.reject(error);
135
+ await new Promise((resolve) => setImmediate(resolve));
136
+ }
137
+ async steer(message, images) {
138
+ this.steerCalls.push({ message, imageCount: images?.length ?? 0 });
139
+ if (this.steerError) {
140
+ throw this.steerError;
141
+ }
142
+ }
143
+ async clearQueue() {
144
+ this.controlRequests.push("clear_queue");
145
+ if (this.clearQueueError) {
146
+ throw this.clearQueueError;
147
+ }
148
+ }
149
+ async compact(customInstructions) {
150
+ this.compactRequests.push(customInstructions === undefined ? {} : { customInstructions });
151
+ this.emit({ type: "compaction_start", reason: "manual" });
152
+ if (this.emitCompactEnd) {
153
+ this.emit({ type: "compaction_end", reason: "manual" });
154
+ }
155
+ if (this.compactError) {
156
+ throw this.compactError;
157
+ }
158
+ }
159
+ async setAutoCompaction(enabled) {
160
+ this.setAutoCompactionRequests.push(enabled);
161
+ this.state = {
162
+ ...this.state,
163
+ autoCompactionEnabled: enabled,
164
+ };
165
+ }
166
+ async abort() {
167
+ this.controlRequests.push("abort");
168
+ this.abortRequested = true;
169
+ }
170
+ async getState() {
171
+ if (this.getStateError) {
172
+ throw this.getStateError;
173
+ }
174
+ return this.state;
175
+ }
176
+ async getMessages() {
177
+ return this.messages;
178
+ }
179
+ async getAvailableModels(_timeoutMs) {
180
+ return this.models;
181
+ }
182
+ async setModel(provider, modelId) {
183
+ this.setModelRequests.push({ provider, modelId });
184
+ if (!this.setModelResult) {
185
+ throw new Error("FakePi setModel requires setModelResult to be scripted");
186
+ }
187
+ this.state = { ...this.state, model: this.setModelResult };
188
+ return this.setModelResult;
189
+ }
190
+ async setThinkingLevel(level) {
191
+ this.setThinkingLevelRequests.push(level);
192
+ }
193
+ async getSessionStats() {
194
+ if (this.getSessionStatsError) {
195
+ throw this.getSessionStatsError;
196
+ }
197
+ return this.stats;
198
+ }
199
+ async setSubagentSubscription(level) {
200
+ this.subagentSubscriptionRequests.push(level);
201
+ if (this.subagentSubscriptionError) {
202
+ throw this.subagentSubscriptionError;
203
+ }
204
+ }
205
+ async getSubagents() {
206
+ return this.subagents;
207
+ }
208
+ async getSubagentMessages(selector) {
209
+ this.subagentMessageRequests.push(selector);
210
+ const key = selector.sessionFile ?? selector.subagentId;
211
+ if (!key) {
212
+ throw new Error("FakePi getSubagentMessages requires a selector");
213
+ }
214
+ const results = this.subagentMessageResults.get(key);
215
+ const result = results?.shift();
216
+ if (!result) {
217
+ throw new Error(`FakePi has no subagent messages queued for ${key}`);
218
+ }
219
+ return result;
220
+ }
221
+ queueSubagentMessages(result) {
222
+ const results = this.subagentMessageResults.get(result.sessionFile) ?? [];
223
+ results.push(result);
224
+ this.subagentMessageResults.set(result.sessionFile, results);
225
+ }
226
+ async getCommands() {
227
+ return this.commands;
228
+ }
229
+ sendRawFrame(frame) {
230
+ this.rawFrames.push(frame);
231
+ }
232
+ async request(command) {
233
+ switch (command.type) {
234
+ case "set_subagent_subscription":
235
+ await this.setSubagentSubscription(command.level);
236
+ return {};
237
+ case "get_subagents":
238
+ return { subagents: await this.getSubagents() };
239
+ case "get_subagent_messages":
240
+ return await this.getSubagentMessages({
241
+ ...(typeof command.subagentId === "string" ? { subagentId: command.subagentId } : {}),
242
+ ...(typeof command.sessionFile === "string" ? { sessionFile: command.sessionFile } : {}),
243
+ ...(typeof command.fromByte === "number" ? { fromByte: command.fromByte } : {}),
244
+ });
245
+ case "branch": {
246
+ const entryId = typeof command.entryId === "string" ? command.entryId : "";
247
+ this.branchRequests.push(entryId);
248
+ return this.branchResponse;
249
+ }
250
+ case "handoff":
251
+ this.handoffRequests.push(typeof command.customInstructions === "string"
252
+ ? { customInstructions: command.customInstructions }
253
+ : {});
254
+ return {};
255
+ case "set_session_name":
256
+ this.sessionNameRequests.push(typeof command.name === "string" ? command.name : "");
257
+ if (this.setSessionNameError) {
258
+ throw this.setSessionNameError;
259
+ }
260
+ return {};
261
+ default:
262
+ throw new Error(`FakePi request does not implement ${command.type}`);
263
+ }
264
+ }
265
+ respondToExtensionUiRequest(id, response) {
266
+ this.extensionUiResponses.push({ id, response });
267
+ }
268
+ cancelExtensionUiRequest(id) {
269
+ this.canceledExtensionUiRequests.push(id);
270
+ this.respondToExtensionUiRequest(id, { cancelled: true });
271
+ }
272
+ async close() { }
273
+ emit(event) {
274
+ for (const subscriber of this.subscribers) {
275
+ subscriber(event);
276
+ }
277
+ }
278
+ finishAgentRun({ message, willRetry }) {
279
+ this.messages = [...this.messages, message];
280
+ this.emit({
281
+ type: "agent_end",
282
+ messages: this.messages,
283
+ willRetry,
284
+ });
285
+ }
286
+ settleTurn() {
287
+ this.emit({ type: "agent_settled" });
288
+ }
289
+ finishTurn(message = { role: "assistant", content: [] }) {
290
+ this.finishAgentRun({ message, willRetry: false });
291
+ this.settleTurn();
292
+ }
293
+ finishLegacyTurn(message = { role: "assistant", content: [] }) {
294
+ this.messages = [...this.messages, message];
295
+ this.emit({ type: "agent_end", messages: this.messages });
296
+ }
297
+ finishSubmittedUserMessage(entry) {
298
+ this.emit({
299
+ type: "message_end",
300
+ message: { role: "user", content: entry.text },
301
+ });
302
+ this.emit({
303
+ type: "extension_ui_request",
304
+ id: `submitted-user-${entry.id}`,
305
+ method: "notify",
306
+ message: `PASEO_SUBMITTED_USER_ENTRY ${JSON.stringify({ entry })}`,
307
+ });
308
+ }
309
+ handleTreeNavigationCommand(message) {
310
+ const prefix = "/paseo_tree ";
311
+ if (!message.startsWith(prefix)) {
312
+ return;
313
+ }
314
+ const payload = JSON.parse(Buffer.from(message.slice(prefix.length), "base64url").toString("utf8"));
315
+ if (typeof payload.targetId !== "string" || typeof payload.requestId !== "string") {
316
+ return;
317
+ }
318
+ this.treeNavigationRequests.push(payload.targetId);
319
+ this.emitEntryCapture(undefined, "tree_navigation");
320
+ this.emitExtensionCommandResult(payload.requestId, { ok: true, result: {} });
321
+ }
322
+ handleEntryCaptureCommand(message) {
323
+ const prefix = "/paseo_capture_entries ";
324
+ if (!message.startsWith(prefix)) {
325
+ return;
326
+ }
327
+ const payload = JSON.parse(Buffer.from(message.slice(prefix.length), "base64url").toString("utf8"));
328
+ if (typeof payload.requestId !== "string") {
329
+ return;
330
+ }
331
+ this.emitEntryCapture(payload.requestId, typeof payload.reason === "string" ? payload.reason : "command");
332
+ }
333
+ emitEntryCapture(requestId, reason = "test") {
334
+ this.emit({
335
+ type: "extension_ui_request",
336
+ id: `capture-${requestId ?? reason}`,
337
+ method: "notify",
338
+ message: `PASEO_ENTRY_CAPTURE ${JSON.stringify({
339
+ reason,
340
+ requestId,
341
+ treeEntries: this.treeUserEntries,
342
+ contextEntries: this.contextUserEntries,
343
+ })}`,
344
+ });
345
+ }
346
+ emitExtensionCommandResult(requestId, result) {
347
+ this.emit({
348
+ type: "extension_ui_request",
349
+ id: `command-${requestId}`,
350
+ method: "notify",
351
+ message: `PASEO_COMMAND_RESULT ${JSON.stringify({ requestId, ...result })}`,
352
+ });
353
+ }
354
+ }
355
+ //# sourceMappingURL=fake-pi.js.map
@@ -48,11 +48,7 @@ interface PiToolResultObject {
48
48
  }
49
49
  interface PiToolResultDetails {
50
50
  diff?: string;
51
- mode?: string;
52
- server?: string;
53
- tool?: string;
54
- mcpResult?: unknown;
55
- xdev?: unknown;
51
+ [key: string]: unknown;
56
52
  }
57
53
  interface PiToolResultTextContent {
58
54
  type: "text";
@@ -107,7 +103,6 @@ export type PiTrackedToolCall = PiBashToolCall | PiReadToolCall | PiEditToolCall
107
103
  export declare function parseToolResult(rawResult: unknown): PiToolResult;
108
104
  export declare function extractTextFromToolResult(result: PiToolResult): string | undefined;
109
105
  export declare function parseToolArgs(toolName: string, rawArgs: unknown): PiTrackedToolCall;
110
- export declare function resolveToolCallName(toolCall: PiTrackedToolCall, result?: PiToolResult): string;
111
106
  export declare function mapToolDetail(toolCall: PiTrackedToolCall, result?: PiToolResult): ToolCallDetail;
112
107
  export {};
113
108
  //# sourceMappingURL=tool-call-mapper.d.ts.map
@@ -17,12 +17,6 @@ const PiToolResultDetailsSchema = z
17
17
  diff: z.string().optional(),
18
18
  })
19
19
  .passthrough();
20
- const XdevExecuteDetailsSchema = z.object({
21
- tool: z.string().trim().min(1),
22
- mode: z.literal("execute"),
23
- args: z.unknown().optional(),
24
- inner: z.unknown().optional(),
25
- });
26
20
  const PiToolResultObjectSchema = z
27
21
  .object({
28
22
  output: z.string().optional(),
@@ -35,12 +29,6 @@ const PiToolResultObjectSchema = z
35
29
  })
36
30
  .passthrough();
37
31
  const PiToolResultSchema = z.union([z.string(), PiToolResultObjectSchema, z.null()]);
38
- function isRecord(value) {
39
- return typeof value === "object" && value !== null && !Array.isArray(value);
40
- }
41
- function readNonEmptyString(value) {
42
- return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
43
- }
44
32
  const BashToolInputSchema = z.object({
45
33
  command: z.string(),
46
34
  timeout: z.number().optional(),
@@ -128,47 +116,8 @@ export function parseToolArgs(toolName, rawArgs) {
128
116
  }
129
117
  return { kind: "unknown", toolName, args: rawArgs ?? null };
130
118
  }
131
- function stripMcpProxyPrefix(toolName, serverName) {
132
- const prefix = `${serverName}_`;
133
- return toolName.startsWith(prefix) ? toolName.slice(prefix.length) : toolName;
134
- }
135
- export function resolveToolCallName(toolCall, result) {
136
- if (toolCall.kind === "write" && result && typeof result !== "string") {
137
- const xdev = XdevExecuteDetailsSchema.safeParse(result.details?.xdev);
138
- if (xdev.success) {
139
- return xdev.data.tool;
140
- }
141
- }
142
- if (toolCall.toolName !== "mcp") {
143
- return toolCall.toolName;
144
- }
145
- if (result && typeof result !== "string") {
146
- const serverName = readNonEmptyString(result.details?.server);
147
- const toolName = readNonEmptyString(result.details?.tool);
148
- if (serverName && toolName) {
149
- return `${serverName}.${toolName}`;
150
- }
151
- }
152
- if (isRecord(toolCall.args)) {
153
- const requestedTool = readNonEmptyString(toolCall.args.tool);
154
- const requestedServer = readNonEmptyString(toolCall.args.server);
155
- if (requestedTool && requestedServer) {
156
- return `${requestedServer}.${stripMcpProxyPrefix(requestedTool, requestedServer)}`;
157
- }
158
- if (requestedTool) {
159
- const [serverName, ...toolParts] = requestedTool.split("_");
160
- if (serverName && toolParts.length > 0) {
161
- return `${serverName}.${toolParts.join("_")}`;
162
- }
163
- }
164
- }
165
- return toolCall.toolName;
166
- }
167
119
  export function mapToolDetail(toolCall, result) {
168
120
  const parsedResult = result ?? null;
169
- if (isTaskToolCall(toolCall)) {
170
- return mapTaskToolDetail(toolCall.args, parsedResult);
171
- }
172
121
  switch (toolCall.kind) {
173
122
  case "bash": {
174
123
  const summary = resolveToolCallOutput(parsedResult);
@@ -199,7 +148,7 @@ export function mapToolDetail(toolCall, result) {
199
148
  };
200
149
  }
201
150
  case "write":
202
- return mapWriteToolDetail(toolCall.args, parsedResult);
151
+ return { type: "write", filePath: toolCall.args.path, content: toolCall.args.content };
203
152
  case "find":
204
153
  return mapFindToolDetail(toolCall.args, parsedResult);
205
154
  case "grep":
@@ -214,51 +163,6 @@ export function mapToolDetail(toolCall, result) {
214
163
  };
215
164
  }
216
165
  }
217
- function isTaskToolCall(toolCall) {
218
- if (toolCall.toolName === "task") {
219
- return true;
220
- }
221
- if (toolCall.toolName !== "subagent" || !isRecord(toolCall.args)) {
222
- return false;
223
- }
224
- return (toolCall.args.action === undefined &&
225
- (readNonEmptyString(toolCall.args.agent) !== undefined ||
226
- readNonEmptyString(toolCall.args.task) !== undefined));
227
- }
228
- function mapTaskToolDetail(args, result) {
229
- const argRecord = isRecord(args) ? args : {};
230
- return {
231
- type: "sub_agent",
232
- subAgentType: readNonEmptyString(argRecord.agent),
233
- description: readNonEmptyString(argRecord.task),
234
- log: extractTextFromToolResult(result)?.trim() ?? "",
235
- };
236
- }
237
- function mapWriteToolDetail(args, result) {
238
- if (result && typeof result !== "string" && result.details && "xdev" in result.details) {
239
- const xdev = XdevExecuteDetailsSchema.safeParse(result.details.xdev);
240
- if (xdev.success) {
241
- return {
242
- type: "unknown",
243
- input: xdev.data.args ?? null,
244
- output: {
245
- ...result,
246
- details: xdev.data.inner ?? null,
247
- },
248
- };
249
- }
250
- return {
251
- type: "unknown",
252
- input: args,
253
- output: result,
254
- };
255
- }
256
- return {
257
- type: "write",
258
- filePath: args.path,
259
- content: args.content,
260
- };
261
- }
262
166
  function resolveToolCallOutput(result) {
263
167
  if (typeof result === "string") {
264
168
  return { output: result };
@@ -1394,6 +1394,7 @@ export function createPaseoToolCatalog(options) {
1394
1394
  throw new Error("unreachable");
1395
1395
  }
1396
1396
  }
1397
+ const PROMPTED_AGENT_NOTIFICATION_GUIDANCE = "You will get notified when the prompted agent finishes, errors, or needs permission. Do not poll for status; continue with other work until the notification arrives.";
1397
1398
  registerTool("send_agent_prompt", {
1398
1399
  title: "Send agent prompt",
1399
1400
  description: "Send a task to a running agent. Agent-scoped callers run in background by default; top-level callers wait by default.",
@@ -1406,16 +1407,10 @@ export function createPaseoToolCatalog(options) {
1406
1407
  guidance: z.string().optional(),
1407
1408
  },
1408
1409
  }, async ({ agentId, prompt, sessionMode, background = Boolean(callerAgentId), notifyOnFinish = Boolean(callerAgentId), }) => {
1409
- const shouldNotifyOnFinish = Boolean(callerAgentId && notifyOnFinish && background);
1410
- await sendPromptToAgent({
1411
- agentManager,
1412
- agentStorage,
1413
- agentId,
1414
- prompt,
1415
- sessionMode,
1416
- logger: childLogger,
1417
- });
1418
- if (shouldNotifyOnFinish && callerAgentId) {
1410
+ function armFinishNotification() {
1411
+ if (!callerAgentId || !notifyOnFinish) {
1412
+ return false;
1413
+ }
1419
1414
  setupFinishNotification({
1420
1415
  agentManager,
1421
1416
  agentStorage,
@@ -1423,17 +1418,32 @@ export function createPaseoToolCatalog(options) {
1423
1418
  callerAgentId,
1424
1419
  logger: childLogger,
1425
1420
  });
1421
+ return true;
1426
1422
  }
1423
+ await sendPromptToAgent({
1424
+ agentManager,
1425
+ agentStorage,
1426
+ agentId,
1427
+ prompt,
1428
+ sessionMode,
1429
+ logger: childLogger,
1430
+ });
1427
1431
  // If not running in background, wait for completion
1428
1432
  if (!background) {
1429
1433
  const result = await waitForAgentWithTimeout(agentManager, agentId, {
1430
1434
  waitForActive: true,
1431
1435
  });
1436
+ // The wait ran out while the agent keeps working, so its result arrives as a
1437
+ // finish notification instead of in this response.
1438
+ const notifying = result.timedOut &&
1439
+ agentManager.getAgent(agentId)?.lifecycle === "running" &&
1440
+ armFinishNotification();
1432
1441
  const responseData = {
1433
1442
  success: true,
1434
1443
  status: result.status,
1435
1444
  lastMessage: result.lastMessage,
1436
1445
  permission: sanitizePermissionRequest(result.permission),
1446
+ ...(notifying ? { guidance: PROMPTED_AGENT_NOTIFICATION_GUIDANCE } : {}),
1437
1447
  };
1438
1448
  const validJson = ensureValidJson(responseData);
1439
1449
  const response = {
@@ -1442,6 +1452,7 @@ export function createPaseoToolCatalog(options) {
1442
1452
  };
1443
1453
  return response;
1444
1454
  }
1455
+ const notifying = armFinishNotification();
1445
1456
  // Return immediately if background=true
1446
1457
  // Re-fetch snapshot since the state may have changed
1447
1458
  const currentSnapshot = agentManager.getAgent(agentId);
@@ -1450,11 +1461,7 @@ export function createPaseoToolCatalog(options) {
1450
1461
  status: currentSnapshot?.lifecycle ?? "idle",
1451
1462
  lastMessage: null,
1452
1463
  permission: null,
1453
- ...(shouldNotifyOnFinish
1454
- ? {
1455
- guidance: "You will get notified when the prompted agent finishes, errors, or needs permission. Do not poll for status; continue with other work until the notification arrives.",
1456
- }
1457
- : {}),
1464
+ ...(notifying ? { guidance: PROMPTED_AGENT_NOTIFICATION_GUIDANCE } : {}),
1458
1465
  };
1459
1466
  const validJson = ensureValidJson(responseData);
1460
1467
  const response = {
@@ -2,6 +2,7 @@ import type { RequestHandler } from "express";
2
2
  export declare const DAEMON_PASSWORD_BCRYPT_COST = 12;
3
3
  export interface DaemonAuthConfig {
4
4
  password?: string;
5
+ localCredential?: () => string | null;
5
6
  }
6
7
  export interface BearerAuthRejectContext {
7
8
  path: string;
@@ -12,9 +13,7 @@ interface BearerValidationInput {
12
13
  password: string | undefined;
13
14
  token: string | null;
14
15
  }
15
- export declare function isBearerTokenValid(input: BearerValidationInput): boolean;
16
16
  export declare function isBearerTokenValidAsync(input: BearerValidationInput): Promise<boolean>;
17
- export declare function isBearerTokenValidSync(input: BearerValidationInput): boolean;
18
17
  export declare function hashDaemonPassword(password: string): string;
19
18
  export declare function extractHttpBearerToken(value: string | undefined): string | null;
20
19
  export declare function extractWsBearerProtocol(value: string | undefined): string | null;
@@ -1,9 +1,7 @@
1
- import { compare, compareSync, hashSync } from "bcryptjs";
1
+ import { compare, hashSync } from "bcryptjs";
2
2
  import { timingSafeEqual } from "node:crypto";
3
+ import { matchesLocalCredential } from "./local-credential.js";
3
4
  export const DAEMON_PASSWORD_BCRYPT_COST = 12;
4
- export function isBearerTokenValid(input) {
5
- return isBearerTokenValidSync(input);
6
- }
7
5
  export async function isBearerTokenValidAsync(input) {
8
6
  if (!input.password) {
9
7
  return true;
@@ -13,15 +11,6 @@ export async function isBearerTokenValidAsync(input) {
13
11
  }
14
12
  return compare(input.token, input.password);
15
13
  }
16
- export function isBearerTokenValidSync(input) {
17
- if (!input.password) {
18
- return true;
19
- }
20
- if (input.token === null) {
21
- return false;
22
- }
23
- return compareSync(input.token, input.password);
24
- }
25
14
  export function hashDaemonPassword(password) {
26
15
  return hashSync(password, DAEMON_PASSWORD_BCRYPT_COST);
27
16
  }
@@ -68,7 +57,12 @@ export function createRequireBearerMiddleware(auth, onReject) {
68
57
  void (async () => {
69
58
  try {
70
59
  const token = extractHttpBearerToken(req.header("authorization"));
71
- if (!(await isBearerTokenValidAsync({ password, token }))) {
60
+ const localCredential = req.path === "/api/status" ? auth?.localCredential?.() : null;
61
+ const isLocal = localCredential !== null &&
62
+ localCredential !== undefined &&
63
+ token !== null &&
64
+ matchesLocalCredential(localCredential, token);
65
+ if (!isLocal && !(await isBearerTokenValidAsync({ password, token }))) {
72
66
  onReject?.({
73
67
  path: req.path,
74
68
  method: req.method,