@agentuity/coder 1.0.39 → 1.0.41

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 (49) hide show
  1. package/dist/client.d.ts +2 -2
  2. package/dist/client.d.ts.map +1 -1
  3. package/dist/client.js +2 -0
  4. package/dist/client.js.map +1 -1
  5. package/dist/hub-overlay-state.d.ts +30 -0
  6. package/dist/hub-overlay-state.d.ts.map +1 -0
  7. package/dist/hub-overlay-state.js +68 -0
  8. package/dist/hub-overlay-state.js.map +1 -0
  9. package/dist/hub-overlay.d.ts +41 -2
  10. package/dist/hub-overlay.d.ts.map +1 -1
  11. package/dist/hub-overlay.js +667 -115
  12. package/dist/hub-overlay.js.map +1 -1
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +19 -34
  15. package/dist/index.js.map +1 -1
  16. package/dist/native-remote-ui-context.d.ts +5 -0
  17. package/dist/native-remote-ui-context.d.ts.map +1 -0
  18. package/dist/native-remote-ui-context.js +30 -0
  19. package/dist/native-remote-ui-context.js.map +1 -0
  20. package/dist/protocol.d.ts +210 -38
  21. package/dist/protocol.d.ts.map +1 -1
  22. package/dist/protocol.js +2 -1
  23. package/dist/protocol.js.map +1 -1
  24. package/dist/remote-lifecycle.d.ts +61 -0
  25. package/dist/remote-lifecycle.d.ts.map +1 -0
  26. package/dist/remote-lifecycle.js +190 -0
  27. package/dist/remote-lifecycle.js.map +1 -0
  28. package/dist/remote-session.d.ts +15 -0
  29. package/dist/remote-session.d.ts.map +1 -1
  30. package/dist/remote-session.js +240 -35
  31. package/dist/remote-session.js.map +1 -1
  32. package/dist/remote-tui.d.ts.map +1 -1
  33. package/dist/remote-tui.js +95 -12
  34. package/dist/remote-tui.js.map +1 -1
  35. package/dist/remote-ui-handler.d.ts +5 -0
  36. package/dist/remote-ui-handler.d.ts.map +1 -0
  37. package/dist/remote-ui-handler.js +53 -0
  38. package/dist/remote-ui-handler.js.map +1 -0
  39. package/package.json +5 -5
  40. package/src/client.ts +5 -3
  41. package/src/hub-overlay-state.ts +117 -0
  42. package/src/hub-overlay.ts +974 -138
  43. package/src/index.ts +19 -50
  44. package/src/native-remote-ui-context.ts +41 -0
  45. package/src/protocol.ts +270 -56
  46. package/src/remote-lifecycle.ts +270 -0
  47. package/src/remote-session.ts +293 -38
  48. package/src/remote-tui.ts +129 -13
  49. package/src/remote-ui-handler.ts +86 -0
package/src/index.ts CHANGED
@@ -18,6 +18,8 @@ import { AgentManagerOverlay } from './overlay.ts';
18
18
  import { ChainEditorOverlay, type ChainResult } from './chain-preview.ts';
19
19
  import { HubOverlay } from './hub-overlay.ts';
20
20
  import { OutputViewerOverlay, type StoredResult } from './output-viewer.ts';
21
+ import { setNativeRemoteExtensionContext } from './native-remote-ui-context.ts';
22
+ import { handleRemoteUiRequest } from './remote-ui-handler.ts';
21
23
  import type {
22
24
  HubAction,
23
25
  HubResponse,
@@ -280,6 +282,7 @@ export function agentuityCoderHub(pi: ExtensionAPI) {
280
282
  // to an existing sandbox session. The full UI is set up (tools, commands, /hub)
281
283
  // but user input is relayed to the remote sandbox instead of the local Pi agent.
282
284
  const remoteSessionId = process.env[REMOTE_SESSION_ENV] || null;
285
+ const isNativeRemote = !!process.env[NATIVE_REMOTE_ENV];
283
286
  if (remoteSessionId) {
284
287
  log(`Remote mode: will connect as controller to session ${remoteSessionId}`);
285
288
  }
@@ -573,7 +576,13 @@ export function agentuityCoderHub(pi: ExtensionAPI) {
573
576
  // Server sends JSON Schema; TypeBox schemas are JSON Schema at runtime
574
577
  parameters: toolDef.parameters as TSchema,
575
578
  ...(toolDef.promptSnippet ? { promptSnippet: toolDef.promptSnippet } : {}),
576
- ...(toolDef.promptGuidelines ? { promptGuidelines: toolDef.promptGuidelines } : {}),
579
+ ...(toolDef.promptGuidelines
580
+ ? {
581
+ promptGuidelines: Array.isArray(toolDef.promptGuidelines)
582
+ ? toolDef.promptGuidelines
583
+ : [toolDef.promptGuidelines],
584
+ }
585
+ : {}),
577
586
  async execute(
578
587
  toolCallId: string,
579
588
  params: unknown,
@@ -1347,8 +1356,11 @@ export function agentuityCoderHub(pi: ExtensionAPI) {
1347
1356
 
1348
1357
  // session_start: establish WebSocket connection to Hub + set up footer
1349
1358
  onEvent('session_start', async (event: unknown, ctx: ExtensionContext) => {
1350
- await ensureConnected();
1351
1359
  footerCtx = ctx;
1360
+ if (isNativeRemote && remoteSessionId) {
1361
+ setNativeRemoteExtensionContext(ctx);
1362
+ }
1363
+ await ensureConnected();
1352
1364
  if (ctx.hasUI) {
1353
1365
  ctx.ui.setStatus('hub_connection', getHubUiStatus());
1354
1366
  }
@@ -1424,8 +1436,6 @@ export function agentuityCoderHub(pi: ExtensionAPI) {
1424
1436
  // via Agent.emit(). Extension only provides Hub UI (footer, /hub, commands).
1425
1437
  // No pi.sendMessage() rendering, no setupRemoteMode() event handlers.
1426
1438
  // 2. Legacy remote: Extension handles all rendering via pi.sendMessage({ customType }).
1427
- const isNativeRemote = !!process.env[NATIVE_REMOTE_ENV];
1428
-
1429
1439
  if (remoteSessionId) {
1430
1440
  let remoteSession: RemoteSession | null = null;
1431
1441
 
@@ -1481,52 +1491,8 @@ export function agentuityCoderHub(pi: ExtensionAPI) {
1481
1491
  });
1482
1492
 
1483
1493
  remoteSession.setUiHandler(async (request) => {
1484
- if (!footerCtx?.hasUI) return null;
1485
- const ui = footerCtx.ui;
1486
- switch (request.method) {
1487
- case 'select': {
1488
- const options =
1489
- (request.params.options as Array<{ label: string; value: string }>) ??
1490
- [];
1491
- const title = (request.params.title as string) ?? 'Select';
1492
- const result = await ui.select(
1493
- title,
1494
- options.map((o) => o.label)
1495
- );
1496
- if (result === null || result === undefined) return null;
1497
- const idx = typeof result === 'number' ? result : Number(result);
1498
- return options[idx]?.value ?? null;
1499
- }
1500
- case 'confirm':
1501
- return await ui.confirm(
1502
- (request.params.message as string) ?? 'Confirm?',
1503
- (request.params.message as string) ?? 'Confirm?'
1504
- );
1505
- case 'input':
1506
- return await ui.input(
1507
- (request.params.prompt as string) ?? 'Input:',
1508
- (request.params.placeholder as string) ?? ''
1509
- );
1510
- case 'editor':
1511
- return await ui.editor(
1512
- (request.params.content as string) ?? '',
1513
- (request.params.language as string) ?? 'text'
1514
- );
1515
- case 'notify':
1516
- ui.notify((request.params.message as string) ?? '');
1517
- return undefined;
1518
- case 'setStatus':
1519
- ui.setStatus(
1520
- (request.params.key as string) ?? 'remote',
1521
- (request.params.text as string) ?? ''
1522
- );
1523
- return undefined;
1524
- case 'setTitle':
1525
- ui.setTitle((request.params.title as string) ?? '');
1526
- return undefined;
1527
- default:
1528
- return null;
1529
- }
1494
+ if (!footerCtx) return null;
1495
+ return await handleRemoteUiRequest(footerCtx, request);
1530
1496
  });
1531
1497
  } catch (err) {
1532
1498
  const msg = err instanceof Error ? err.message : String(err);
@@ -1549,6 +1515,9 @@ export function agentuityCoderHub(pi: ExtensionAPI) {
1549
1515
  'session_shutdown',
1550
1516
  async (_event: unknown, _ctx: ExtensionContext) => {
1551
1517
  log('Shutting down — closing Hub connection');
1518
+ if (isNativeRemote && remoteSessionId) {
1519
+ setNativeRemoteExtensionContext(null);
1520
+ }
1552
1521
  try {
1553
1522
  client.close();
1554
1523
  } catch {
@@ -0,0 +1,41 @@
1
+ import type { ExtensionContext } from '@mariozechner/pi-coding-agent';
2
+
3
+ type ContextWaiter = (ctx: ExtensionContext | null) => void;
4
+
5
+ let nativeRemoteExtensionContext: ExtensionContext | null = null;
6
+ const waiters = new Set<ContextWaiter>();
7
+
8
+ export function setNativeRemoteExtensionContext(ctx: ExtensionContext | null): void {
9
+ nativeRemoteExtensionContext = ctx;
10
+ for (const waiter of waiters) {
11
+ waiter(ctx);
12
+ }
13
+ waiters.clear();
14
+ }
15
+
16
+ export function getNativeRemoteExtensionContext(): ExtensionContext | null {
17
+ return nativeRemoteExtensionContext;
18
+ }
19
+
20
+ export function waitForNativeRemoteExtensionContext(
21
+ timeoutMs = 10_000
22
+ ): Promise<ExtensionContext | null> {
23
+ if (nativeRemoteExtensionContext) {
24
+ return Promise.resolve(nativeRemoteExtensionContext);
25
+ }
26
+
27
+ return new Promise((resolve) => {
28
+ const waiter: ContextWaiter = (ctx) => {
29
+ clearTimeout(timer);
30
+ waiters.delete(waiter);
31
+ resolve(ctx);
32
+ };
33
+
34
+ const timer = setTimeout(() => {
35
+ waiters.delete(waiter);
36
+ resolve(nativeRemoteExtensionContext);
37
+ }, timeoutMs);
38
+
39
+ waiters.add(waiter);
40
+ });
41
+ }
package/src/protocol.ts CHANGED
@@ -1,22 +1,80 @@
1
- // ---- Init Message (Server Client on connect) ----
1
+ // Hub protocol types used by the Coder TUI package.
2
+ // Keep the legacy exported names stable while modeling the newer hub envelopes.
2
3
 
3
4
  export interface HubToolDefinition {
4
5
  name: string;
5
6
  label: string;
6
7
  description: string;
7
- parameters: Record<string, unknown>; // JSON Schema object
8
+ parameters: Record<string, unknown>;
8
9
  promptSnippet?: string;
9
- promptGuidelines?: string;
10
+ promptGuidelines?: string | string[];
10
11
  }
11
12
 
12
- /** Command definition sent by Hub for agent routing slash commands. */
13
13
  export interface HubCommandDefinition {
14
14
  name: string;
15
15
  description: string;
16
16
  }
17
17
 
18
+ export interface AckAction {
19
+ action: 'ACK';
20
+ }
21
+
22
+ export interface BlockAction {
23
+ action: 'BLOCK';
24
+ reason: string;
25
+ }
26
+
27
+ export interface ConfirmAction {
28
+ action: 'CONFIRM';
29
+ title: string;
30
+ message: string;
31
+ deny_reason?: string;
32
+ }
33
+
34
+ export interface NotifyAction {
35
+ action: 'NOTIFY';
36
+ message: string;
37
+ level?: 'info' | 'warning' | 'error';
38
+ }
39
+
40
+ export interface ReturnAction {
41
+ action: 'RETURN';
42
+ result: unknown;
43
+ }
44
+
45
+ export interface StatusAction {
46
+ action: 'STATUS';
47
+ key: string;
48
+ text?: string;
49
+ }
50
+
51
+ export interface SystemPromptAction {
52
+ action: 'SYSTEM_PROMPT';
53
+ systemPrompt: string;
54
+ mode?: 'replace' | 'prefix' | 'suffix';
55
+ }
56
+
57
+ export interface InjectMessageAction {
58
+ action: 'INJECT_MESSAGE';
59
+ message: {
60
+ role: 'user' | 'assistant';
61
+ content: string;
62
+ };
63
+ }
64
+
65
+ export type HubAction =
66
+ | AckAction
67
+ | BlockAction
68
+ | ConfirmAction
69
+ | NotifyAction
70
+ | ReturnAction
71
+ | StatusAction
72
+ | SystemPromptAction
73
+ | InjectMessageAction;
74
+
18
75
  export interface AgentDefinition {
19
76
  name: string;
77
+ displayName?: string;
20
78
  description: string;
21
79
  systemPrompt: string;
22
80
  model?: string;
@@ -41,10 +99,14 @@ export interface InitMessage {
41
99
  commands?: HubCommandDefinition[];
42
100
  agents?: AgentDefinition[];
43
101
  config?: HubConfig;
102
+ model?: {
103
+ provider: string;
104
+ id: string;
105
+ };
106
+ thinkingLevel?: string;
107
+ task?: string;
44
108
  }
45
109
 
46
- // ---- Request Messages (Client → Server) ----
47
-
48
110
  export interface EventRequest {
49
111
  id: string;
50
112
  type: 'event';
@@ -60,7 +122,6 @@ export interface ToolRequest {
60
122
  params: Record<string, unknown>;
61
123
  }
62
124
 
63
- /** Command request (Client -> Server) for slash command execution. */
64
125
  export interface CommandRequest {
65
126
  id: string;
66
127
  type: 'command';
@@ -70,68 +131,228 @@ export interface CommandRequest {
70
131
 
71
132
  export type HubRequest = EventRequest | ToolRequest | CommandRequest;
72
133
 
73
- // ---- Actions ----
134
+ export interface SessionEntryMessage {
135
+ type: 'session_entry';
136
+ path: string;
137
+ line: string;
138
+ }
74
139
 
75
- export interface AckAction {
76
- action: 'ACK';
140
+ export interface SessionWriteMessage {
141
+ type: 'session_write';
142
+ path: string;
143
+ content: string;
77
144
  }
78
145
 
79
- export interface BlockAction {
80
- action: 'BLOCK';
81
- reason: string;
146
+ export interface RpcCommandMessage {
147
+ type: 'rpc_command';
148
+ command: Record<string, unknown>;
82
149
  }
83
150
 
84
- export interface ConfirmAction {
85
- action: 'CONFIRM';
86
- title: string;
87
- message: string;
88
- deny_reason?: string;
151
+ export interface RpcUiResponseMessage {
152
+ type: 'rpc_ui_response';
153
+ id: string;
154
+ result: unknown;
89
155
  }
90
156
 
91
- export interface NotifyAction {
92
- action: 'NOTIFY';
157
+ export interface PingMessage {
158
+ type: 'ping';
159
+ timestamp: number;
160
+ }
161
+
162
+ export type HubClientMessage =
163
+ | HubRequest
164
+ | SessionEntryMessage
165
+ | SessionWriteMessage
166
+ | RpcCommandMessage
167
+ | RpcUiResponseMessage
168
+ | PingMessage;
169
+
170
+ export interface HubResponse {
171
+ id: string;
172
+ actions: HubAction[];
173
+ }
174
+
175
+ export interface CoderHubStreamReadyMessage {
176
+ type: 'session_stream_ready';
177
+ streamId: string;
178
+ streamUrl: string;
179
+ }
180
+
181
+ export interface CoderHubSessionResumeMessage {
182
+ type: 'session_resume';
183
+ streamUrl: string;
184
+ streamId: string;
185
+ activePrdKey?: string;
186
+ }
187
+
188
+ export interface ConnectionRejectedMessage {
189
+ type: 'connection_rejected';
190
+ code: string;
93
191
  message: string;
94
- level?: 'info' | 'warning' | 'error';
192
+ sessionId?: string;
193
+ reconnectState?: string;
194
+ expiredAt?: number;
195
+ timestamp: number;
95
196
  }
96
197
 
97
- export interface ReturnAction {
98
- action: 'RETURN';
99
- result: unknown;
198
+ export interface ConversationEntry {
199
+ type:
200
+ | 'message'
201
+ | 'thinking'
202
+ | 'tool_call'
203
+ | 'tool_result'
204
+ | 'task_result'
205
+ | 'turn'
206
+ | 'user_prompt';
207
+ agent?: string;
208
+ content?: string;
209
+ toolName?: string;
210
+ toolArgs?: Record<string, unknown>;
211
+ toolCallId?: string;
212
+ isError?: boolean;
213
+ taskId?: string;
214
+ timestamp: number;
100
215
  }
101
216
 
102
- export interface StatusAction {
103
- action: 'STATUS';
104
- key: string;
105
- text?: string; // undefined = clear status
217
+ export interface HydrationTaskState {
218
+ taskId: string;
219
+ agent: string;
220
+ status: 'running' | 'completed' | 'failed';
221
+ prompt: string;
222
+ duration?: number;
223
+ result?: string;
224
+ error?: string;
106
225
  }
107
226
 
108
- export interface SystemPromptAction {
109
- action: 'SYSTEM_PROMPT';
110
- systemPrompt: string;
111
- mode?: 'replace' | 'prefix' | 'suffix';
227
+ export interface SessionParticipant {
228
+ id: string;
229
+ role: 'lead' | 'observer' | 'controller';
230
+ transport: 'ws' | 'sse';
231
+ subscriptions: string[];
232
+ connectedAt: number;
233
+ lastActivity: number;
112
234
  }
113
235
 
114
- export interface InjectMessageAction {
115
- action: 'INJECT_MESSAGE';
116
- message: {
117
- role: 'user' | 'assistant';
118
- content: string;
236
+ export interface SessionStreamBlock {
237
+ output: string;
238
+ thinking: string;
239
+ }
240
+
241
+ export interface SessionStreamProjection extends SessionStreamBlock {
242
+ tasks: Record<string, SessionStreamBlock>;
243
+ }
244
+
245
+ export interface SessionSnapshot {
246
+ sessionId: string;
247
+ label: string;
248
+ status: 'active' | 'paused' | 'shutdown' | 'archived' | 'error' | 'stopped';
249
+ createdAt: string;
250
+ mode: 'sandbox' | 'tui';
251
+ task?: string;
252
+ error?: string;
253
+ streamId?: string | null;
254
+ streamUrl?: string | null;
255
+ context: {
256
+ branch?: string;
257
+ workingDirectory?: string;
119
258
  };
259
+ participants: SessionParticipant[];
260
+ tasks: Array<{
261
+ taskId: string;
262
+ agent: string;
263
+ status: 'running' | 'completed' | 'failed';
264
+ prompt: string;
265
+ duration?: number;
266
+ startedAt?: string;
267
+ completedAt?: string;
268
+ }>;
269
+ agentActivity: Record<
270
+ string,
271
+ {
272
+ name?: string;
273
+ status: string;
274
+ currentTool?: string;
275
+ currentToolArgs?: string;
276
+ toolCallCount: number;
277
+ lastActivity: number;
278
+ totalElapsed?: number;
279
+ }
280
+ >;
281
+ stream?: SessionStreamProjection;
282
+ tags?: string[];
283
+ defaultAgent?: string;
284
+ bucket?: 'running' | 'paused' | 'provisioning' | 'history';
285
+ runtimeAvailable?: boolean;
286
+ controlAvailable?: boolean;
287
+ historyOnly?: boolean;
120
288
  }
121
289
 
122
- export type HubAction =
123
- | AckAction
124
- | BlockAction
125
- | ConfirmAction
126
- | NotifyAction
127
- | ReturnAction
128
- | StatusAction
129
- | SystemPromptAction
130
- | InjectMessageAction;
290
+ export interface CoderHubHydrationMessage {
291
+ type: 'session_hydration';
292
+ sessionId: string;
293
+ resumedAt: number;
294
+ entries: ConversationEntry[];
295
+ tasks: HydrationTaskState[];
296
+ stream?: SessionStreamProjection;
297
+ task?: string;
298
+ streamingState?: {
299
+ isStreaming?: boolean;
300
+ activeTasks?: Array<{
301
+ taskId: string;
302
+ agent: string;
303
+ }>;
304
+ };
305
+ }
131
306
 
132
- // ---- Progress Tracking (Sub-Agent → Parent) ----
307
+ export interface PresenceEventMessage {
308
+ type: 'presence';
309
+ event: 'session_join' | 'session_leave' | 'presence_update';
310
+ participant?: SessionParticipant;
311
+ participants?: SessionParticipant[];
312
+ sessionId: string;
313
+ timestamp: number;
314
+ }
315
+
316
+ export interface BroadcastEventMessage {
317
+ type: 'broadcast';
318
+ event: string;
319
+ data: Record<string, unknown>;
320
+ category?: string;
321
+ sessionId?: string;
322
+ timestamp?: number;
323
+ }
324
+
325
+ export interface RpcEventMessage {
326
+ type: 'rpc_event';
327
+ event: Record<string, unknown>;
328
+ timestamp: number;
329
+ }
330
+
331
+ export interface RpcResponseMessage {
332
+ type: 'rpc_response';
333
+ response: Record<string, unknown>;
334
+ }
335
+
336
+ export interface RpcUiRequestMessage {
337
+ type: 'rpc_ui_request';
338
+ id: string;
339
+ method: string;
340
+ params: Record<string, unknown>;
341
+ }
342
+
343
+ export type ServerMessage =
344
+ | InitMessage
345
+ | HubResponse
346
+ | CoderHubHydrationMessage
347
+ | CoderHubStreamReadyMessage
348
+ | CoderHubSessionResumeMessage
349
+ | ConnectionRejectedMessage
350
+ | PresenceEventMessage
351
+ | BroadcastEventMessage
352
+ | RpcEventMessage
353
+ | RpcResponseMessage
354
+ | RpcUiRequestMessage;
133
355
 
134
- /** Progress update from a running sub-agent */
135
356
  export interface AgentProgressUpdate {
136
357
  agentName: string;
137
358
  status:
@@ -146,12 +367,5 @@ export interface AgentProgressUpdate {
146
367
  currentToolArgs?: string;
147
368
  elapsed: number;
148
369
  tokens?: { input: number; output: number; cost: number };
149
- delta?: string; // Streaming token delta for thinking_delta / text_delta
150
- }
151
-
152
- // ---- Response Message (Server → Client) ----
153
-
154
- export interface HubResponse {
155
- id: string;
156
- actions: HubAction[];
370
+ delta?: string;
157
371
  }