@polpo-ai/react 0.2.2

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 (119) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +556 -0
  3. package/dist/hooks/use-active-delays.d.ts +19 -0
  4. package/dist/hooks/use-active-delays.d.ts.map +1 -0
  5. package/dist/hooks/use-active-delays.js +35 -0
  6. package/dist/hooks/use-active-delays.js.map +1 -0
  7. package/dist/hooks/use-agent.d.ts +12 -0
  8. package/dist/hooks/use-agent.d.ts.map +1 -0
  9. package/dist/hooks/use-agent.js +28 -0
  10. package/dist/hooks/use-agent.js.map +1 -0
  11. package/dist/hooks/use-agents.d.ts +16 -0
  12. package/dist/hooks/use-agents.d.ts.map +1 -0
  13. package/dist/hooks/use-agents.js +51 -0
  14. package/dist/hooks/use-agents.js.map +1 -0
  15. package/dist/hooks/use-approvals.d.ts +19 -0
  16. package/dist/hooks/use-approvals.d.ts.map +1 -0
  17. package/dist/hooks/use-approvals.js +51 -0
  18. package/dist/hooks/use-approvals.js.map +1 -0
  19. package/dist/hooks/use-assessment-progress.d.ts +11 -0
  20. package/dist/hooks/use-assessment-progress.d.ts.map +1 -0
  21. package/dist/hooks/use-assessment-progress.js +10 -0
  22. package/dist/hooks/use-assessment-progress.js.map +1 -0
  23. package/dist/hooks/use-auth-status.d.ts +13 -0
  24. package/dist/hooks/use-auth-status.d.ts.map +1 -0
  25. package/dist/hooks/use-auth-status.js +28 -0
  26. package/dist/hooks/use-auth-status.js.map +1 -0
  27. package/dist/hooks/use-events.d.ts +6 -0
  28. package/dist/hooks/use-events.d.ts.map +1 -0
  29. package/dist/hooks/use-events.js +24 -0
  30. package/dist/hooks/use-events.js.map +1 -0
  31. package/dist/hooks/use-logs.d.ts +10 -0
  32. package/dist/hooks/use-logs.d.ts.map +1 -0
  33. package/dist/hooks/use-logs.js +24 -0
  34. package/dist/hooks/use-logs.js.map +1 -0
  35. package/dist/hooks/use-memory.d.ts +30 -0
  36. package/dist/hooks/use-memory.d.ts.map +1 -0
  37. package/dist/hooks/use-memory.js +66 -0
  38. package/dist/hooks/use-memory.js.map +1 -0
  39. package/dist/hooks/use-mission.d.ts +33 -0
  40. package/dist/hooks/use-mission.d.ts.map +1 -0
  41. package/dist/hooks/use-mission.js +78 -0
  42. package/dist/hooks/use-mission.js.map +1 -0
  43. package/dist/hooks/use-missions.d.ts +19 -0
  44. package/dist/hooks/use-missions.d.ts.map +1 -0
  45. package/dist/hooks/use-missions.js +52 -0
  46. package/dist/hooks/use-missions.js.map +1 -0
  47. package/dist/hooks/use-notifications.d.ts +21 -0
  48. package/dist/hooks/use-notifications.d.ts.map +1 -0
  49. package/dist/hooks/use-notifications.js +43 -0
  50. package/dist/hooks/use-notifications.js.map +1 -0
  51. package/dist/hooks/use-orchestrator-skills.d.ts +13 -0
  52. package/dist/hooks/use-orchestrator-skills.d.ts.map +1 -0
  53. package/dist/hooks/use-orchestrator-skills.js +28 -0
  54. package/dist/hooks/use-orchestrator-skills.js.map +1 -0
  55. package/dist/hooks/use-playbooks.d.ts +29 -0
  56. package/dist/hooks/use-playbooks.d.ts.map +1 -0
  57. package/dist/hooks/use-playbooks.js +49 -0
  58. package/dist/hooks/use-playbooks.js.map +1 -0
  59. package/dist/hooks/use-polpo.d.ts +8 -0
  60. package/dist/hooks/use-polpo.d.ts.map +1 -0
  61. package/dist/hooks/use-polpo.js +8 -0
  62. package/dist/hooks/use-polpo.js.map +1 -0
  63. package/dist/hooks/use-processes.d.ts +9 -0
  64. package/dist/hooks/use-processes.d.ts.map +1 -0
  65. package/dist/hooks/use-processes.js +24 -0
  66. package/dist/hooks/use-processes.js.map +1 -0
  67. package/dist/hooks/use-schedules.d.ts +9 -0
  68. package/dist/hooks/use-schedules.d.ts.map +1 -0
  69. package/dist/hooks/use-schedules.js +35 -0
  70. package/dist/hooks/use-schedules.js.map +1 -0
  71. package/dist/hooks/use-sessions.d.ts +14 -0
  72. package/dist/hooks/use-sessions.d.ts.map +1 -0
  73. package/dist/hooks/use-sessions.js +49 -0
  74. package/dist/hooks/use-sessions.js.map +1 -0
  75. package/dist/hooks/use-skills.d.ts +13 -0
  76. package/dist/hooks/use-skills.d.ts.map +1 -0
  77. package/dist/hooks/use-skills.js +28 -0
  78. package/dist/hooks/use-skills.js.map +1 -0
  79. package/dist/hooks/use-stable-value.d.ts +6 -0
  80. package/dist/hooks/use-stable-value.d.ts.map +1 -0
  81. package/dist/hooks/use-stable-value.js +30 -0
  82. package/dist/hooks/use-stable-value.js.map +1 -0
  83. package/dist/hooks/use-stats.d.ts +3 -0
  84. package/dist/hooks/use-stats.d.ts.map +1 -0
  85. package/dist/hooks/use-stats.js +7 -0
  86. package/dist/hooks/use-stats.js.map +1 -0
  87. package/dist/hooks/use-task-activity.d.ts +21 -0
  88. package/dist/hooks/use-task-activity.d.ts.map +1 -0
  89. package/dist/hooks/use-task-activity.js +72 -0
  90. package/dist/hooks/use-task-activity.js.map +1 -0
  91. package/dist/hooks/use-task.d.ts +14 -0
  92. package/dist/hooks/use-task.d.ts.map +1 -0
  93. package/dist/hooks/use-task.js +58 -0
  94. package/dist/hooks/use-task.js.map +1 -0
  95. package/dist/hooks/use-tasks.d.ts +13 -0
  96. package/dist/hooks/use-tasks.d.ts.map +1 -0
  97. package/dist/hooks/use-tasks.js +50 -0
  98. package/dist/hooks/use-tasks.js.map +1 -0
  99. package/dist/hooks/use-templates.d.ts +21 -0
  100. package/dist/hooks/use-templates.d.ts.map +1 -0
  101. package/dist/hooks/use-templates.js +41 -0
  102. package/dist/hooks/use-templates.js.map +1 -0
  103. package/dist/hooks/use-vault-entries.d.ts +13 -0
  104. package/dist/hooks/use-vault-entries.d.ts.map +1 -0
  105. package/dist/hooks/use-vault-entries.js +32 -0
  106. package/dist/hooks/use-vault-entries.js.map +1 -0
  107. package/dist/index.d.ts +29 -0
  108. package/dist/index.d.ts.map +1 -0
  109. package/dist/index.js +30 -0
  110. package/dist/index.js.map +1 -0
  111. package/dist/provider/polpo-context.d.ts +9 -0
  112. package/dist/provider/polpo-context.d.ts.map +1 -0
  113. package/dist/provider/polpo-context.js +10 -0
  114. package/dist/provider/polpo-context.js.map +1 -0
  115. package/dist/provider/polpo-provider.d.ts +12 -0
  116. package/dist/provider/polpo-provider.d.ts.map +1 -0
  117. package/dist/provider/polpo-provider.js +62 -0
  118. package/dist/provider/polpo-provider.js.map +1 -0
  119. package/package.json +64 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 OpenPolpo Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,556 @@
1
+ # @polpo-ai/react
2
+
3
+ Type-safe React hooks for OpenPolpo with real-time Server-Sent Events (SSE) updates.
4
+
5
+ ## Features
6
+
7
+ - 🎣 **Modern React Hooks**: Built with `useSyncExternalStore` for optimal performance
8
+ - 📡 **Real-time Updates**: Push-based SSE, not polling
9
+ - 🔄 **Auto-reconnect**: Exponential backoff with event ID resumption
10
+ - 📦 **Zero Runtime Dependencies**: Only peer dependency is React
11
+ - 🎯 **Type-safe**: Full TypeScript support with inferred types
12
+ - ⚡ **Optimized**: Memoized selectors with WeakMap caching
13
+ - 🔌 **Request Deduplication**: Automatic concurrent request coalescing
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ npm install @polpo-ai/react
19
+ ```
20
+
21
+ **Peer Dependencies**:
22
+ - `react`: ^18.0.0 || ^19.0.0
23
+
24
+ ## Quick Start
25
+
26
+ ```tsx
27
+ import { PolpoProvider, useTasks, useAgents, useStats } from '@polpo-ai/react';
28
+
29
+ function App() {
30
+ return (
31
+ <PolpoProvider
32
+ baseUrl="http://localhost:3890"
33
+ apiKey="optional-api-key"
34
+ >
35
+ <Dashboard />
36
+ </PolpoProvider>
37
+ );
38
+ }
39
+
40
+ function Dashboard() {
41
+ const { tasks } = useTasks();
42
+ const agents = useAgents();
43
+ const stats = useStats();
44
+
45
+ return (
46
+ <div>
47
+ <h1>Polpo Dashboard</h1>
48
+ <p>Tasks: {tasks.length}</p>
49
+ <p>Pending: {stats?.pending ?? 0}</p>
50
+ <ul>
51
+ {tasks.map(task => (
52
+ <li key={task.id}>
53
+ {task.title} - {task.status}
54
+ </li>
55
+ ))}
56
+ </ul>
57
+ </div>
58
+ );
59
+ }
60
+ ```
61
+
62
+ ## API Reference
63
+
64
+ ### PolpoProvider
65
+
66
+ Root provider component that manages connection and state.
67
+
68
+ ```tsx
69
+ <PolpoProvider
70
+ baseUrl="http://localhost:3890"
71
+ apiKey="optional-key"
72
+ autoConnect={true}
73
+ >
74
+ {children}
75
+ </PolpoProvider>
76
+ ```
77
+
78
+ **Props**:
79
+ - `baseUrl`: OpenPolpo server URL
80
+ - `apiKey?`: Optional API key for authentication
81
+ - `autoConnect?`: Auto-connect on mount (default: true)
82
+ - `eventFilter?`: Array of SSE event type patterns to subscribe to
83
+
84
+ ### Hooks
85
+
86
+ #### usePolpo()
87
+
88
+ Access full Polpo state and methods.
89
+
90
+ ```tsx
91
+ const { client, connectionStatus } = usePolpo();
92
+
93
+ // connectionStatus: 'connecting' | 'connected' | 'reconnecting' | 'disconnected' | 'error'
94
+
95
+ // Use the client to call API methods:
96
+ await client.createTask({ title: '...', description: '...', assignTo: 'backend-dev' });
97
+ await client.createMission({ data: '...', name: 'my-mission' });
98
+ ```
99
+
100
+ #### useTasks(filter?)
101
+
102
+ Get all tasks with optional filtering.
103
+
104
+ ```tsx
105
+ // All tasks
106
+ const { tasks } = useTasks();
107
+
108
+ // Filtered tasks
109
+ const { tasks: pendingTasks } = useTasks({ status: 'pending' });
110
+ const { tasks: agentTasks } = useTasks({ assignTo: 'backend-dev' });
111
+ ```
112
+
113
+ **Returns**: `UseTasksReturn` (includes `tasks: Task[]`, `isLoading`, `error`, `createTask`, `deleteTask`, `retryTask`, `refetch`)
114
+
115
+ ```typescript
116
+ interface Task {
117
+ id: string;
118
+ title: string;
119
+ description: string;
120
+ assignTo: string;
121
+ status: 'draft' | 'pending' | 'awaiting_approval' | 'assigned' | 'in_progress' | 'review' | 'done' | 'failed';
122
+ dependsOn: string[];
123
+ group?: string;
124
+ result?: TaskResult;
125
+ createdAt: string;
126
+ updatedAt: string;
127
+ expectations: TaskExpectation[];
128
+ retries: number;
129
+ maxRetries: number;
130
+ missionGroup?: string;
131
+ }
132
+ ```
133
+
134
+ #### useTask(taskId)
135
+
136
+ Get a single task by ID.
137
+
138
+ ```tsx
139
+ const task = useTask('task-123');
140
+
141
+ if (!task) {
142
+ return <div>Task not found</div>;
143
+ }
144
+
145
+ return <div>{task.title}: {task.status}</div>;
146
+ ```
147
+
148
+ **Returns**: `Task | undefined`
149
+
150
+ #### useMissions()
151
+
152
+ Get all missions with CRUD and execution methods.
153
+
154
+ ```tsx
155
+ const {
156
+ missions,
157
+ isLoading,
158
+ error,
159
+ createMission,
160
+ updateMission,
161
+ deleteMission,
162
+ executeMission,
163
+ resumeMission,
164
+ abortMission,
165
+ refetch,
166
+ } = useMissions();
167
+ ```
168
+
169
+ **Returns**: `UseMissionsReturn`
170
+
171
+ ```typescript
172
+ interface Mission {
173
+ id: string;
174
+ name: string;
175
+ data: string;
176
+ prompt?: string;
177
+ status: 'draft' | 'active' | 'paused' | 'completed' | 'failed' | 'cancelled';
178
+ deadline?: string;
179
+ schedule?: string;
180
+ recurring?: boolean;
181
+ qualityThreshold?: number;
182
+ createdAt: string;
183
+ updatedAt: string;
184
+ }
185
+ ```
186
+
187
+ #### useMission(missionId)
188
+
189
+ Get a single mission by ID.
190
+
191
+ ```tsx
192
+ const { mission, report, isLoading, executeMission, abortMission } = useMission('mission-123');
193
+ ```
194
+
195
+ **Returns**: `UseMissionReturn` (includes `mission`, `report: MissionReport | undefined`, and action methods)
196
+
197
+ #### useAgents(filter?)
198
+
199
+ Get all agents.
200
+
201
+ ```tsx
202
+ const agents = useAgents();
203
+ const availableAgents = useAgents({ available: true });
204
+ ```
205
+
206
+ **Returns**: `AgentConfig[]`
207
+
208
+ ```typescript
209
+ interface AgentConfig {
210
+ name: string;
211
+ role?: string;
212
+ model?: string;
213
+ allowedTools?: string[];
214
+ systemPrompt?: string;
215
+ skills?: string[];
216
+ maxTurns?: number;
217
+ maxConcurrency?: number;
218
+ volatile?: boolean;
219
+ missionGroup?: string;
220
+ }
221
+ ```
222
+
223
+ #### useProcesses()
224
+
225
+ Get running agent processes.
226
+
227
+ ```tsx
228
+ const processes = useProcesses();
229
+
230
+ return (
231
+ <ul>
232
+ {processes.map(proc => (
233
+ <li key={proc.agentName}>
234
+ {proc.agentName} - PID: {proc.pid} - {proc.alive ? 'Running' : 'Dead'}
235
+ </li>
236
+ ))}
237
+ </ul>
238
+ );
239
+ ```
240
+
241
+ **Returns**: `AgentProcess[]`
242
+
243
+ ```typescript
244
+ interface AgentProcess {
245
+ agentName: string;
246
+ pid: number;
247
+ taskId: string;
248
+ startedAt: string;
249
+ alive: boolean;
250
+ activity: AgentActivity;
251
+ }
252
+
253
+ interface AgentActivity {
254
+ lastTool?: string;
255
+ lastFile?: string;
256
+ filesCreated: string[];
257
+ filesEdited: string[];
258
+ toolCalls: number;
259
+ totalTokens: number;
260
+ lastUpdate: string;
261
+ summary?: string;
262
+ sessionId?: string;
263
+ }
264
+ ```
265
+
266
+ #### useEvents(limit?)
267
+
268
+ Get recent events from the event stream.
269
+
270
+ ```tsx
271
+ const events = useEvents(50); // Last 50 events
272
+
273
+ return (
274
+ <ul>
275
+ {events.map(event => (
276
+ <li key={event.id}>
277
+ {event.event}: {event.timestamp}
278
+ </li>
279
+ ))}
280
+ </ul>
281
+ );
282
+ ```
283
+
284
+ **Returns**: `SSEEvent[]`
285
+
286
+ #### useStats()
287
+
288
+ Get aggregate statistics.
289
+
290
+ ```tsx
291
+ const stats = useStats();
292
+
293
+ if (!stats) return null;
294
+
295
+ return (
296
+ <div>
297
+ <p>Pending: {stats.pending}</p>
298
+ <p>Running: {stats.running}</p>
299
+ <p>Queued: {stats.queued}</p>
300
+ <p>Done: {stats.done}</p>
301
+ <p>Failed: {stats.failed}</p>
302
+ </div>
303
+ );
304
+ ```
305
+
306
+ **Returns**: `PolpoStats | null`
307
+
308
+ ```typescript
309
+ interface PolpoStats {
310
+ pending: number;
311
+ running: number;
312
+ done: number;
313
+ failed: number;
314
+ queued: number;
315
+ }
316
+ ```
317
+
318
+ #### useMemory()
319
+
320
+ Get Polpo memory entries.
321
+
322
+ ```tsx
323
+ const memory = useMemory();
324
+ ```
325
+
326
+ **Returns**: `MemoryEntry[]`
327
+
328
+ #### useLogs(limit?)
329
+
330
+ Get recent log entries.
331
+
332
+ ```tsx
333
+ const logs = useLogs(100);
334
+ ```
335
+
336
+ **Returns**: `LogEntry[]`
337
+
338
+ ### Methods
339
+
340
+ #### createTask(task)
341
+
342
+ Create a new task via the `useTasks` hook or directly via the client.
343
+
344
+ ```tsx
345
+ const { createTask } = useTasks();
346
+
347
+ await createTask({
348
+ title: 'Implement feature X',
349
+ description: 'Add authentication to the API',
350
+ assignTo: 'backend-dev',
351
+ });
352
+ ```
353
+
354
+ #### retryTask(taskId)
355
+
356
+ Retry a failed task.
357
+
358
+ ```tsx
359
+ const { retryTask } = useTasks();
360
+
361
+ await retryTask('task-123');
362
+ ```
363
+
364
+ #### createMission(req)
365
+
366
+ Create a new mission.
367
+
368
+ ```tsx
369
+ const { createMission } = useMissions();
370
+
371
+ await createMission({
372
+ data: 'tasks:\n - title: Task 1\n assignTo: backend-dev\n description: Do something',
373
+ name: 'new-feature',
374
+ });
375
+ ```
376
+
377
+ #### executeMission(missionId)
378
+
379
+ Execute a mission (create tasks and start agents).
380
+
381
+ ```tsx
382
+ const { executeMission } = useMissions();
383
+
384
+ await executeMission('mission-123');
385
+ ```
386
+
387
+ ## Real-time Updates
388
+
389
+ The SDK uses Server-Sent Events (SSE) for push-based real-time updates. All hooks automatically update when the server emits events.
390
+
391
+ **Event Types**:
392
+ - `task:created`, `task:transition`, `task:updated`, `task:removed`, `task:retry`, `task:fix`, `task:timeout`
393
+ - `mission:saved`, `mission:executed`, `mission:completed`, `mission:resumed`, `mission:deleted`
394
+ - `agent:spawned`, `agent:finished`, `agent:activity`, `agent:stale`
395
+ - `assessment:started`, `assessment:progress`, `assessment:complete`, `assessment:corrected`
396
+ - `orchestrator:started`, `orchestrator:tick`, `orchestrator:shutdown`
397
+
398
+ **Auto-reconnect**:
399
+ - Exponential backoff (`reconnectDelay` → `maxReconnectDelay`, defaults 1s → 30s)
400
+ - Resumes from last event ID
401
+
402
+ ## Authentication
403
+
404
+ The SDK supports two authentication methods:
405
+
406
+ **Header-based** (preferred):
407
+ ```tsx
408
+ <PolpoProvider
409
+ baseUrl="http://localhost:3890"
410
+ apiKey="your-api-key"
411
+ >
412
+ ```
413
+
414
+ **Query parameter** (for EventSource):
415
+ The SDK automatically appends `?apiKey=` to SSE requests when an API key is provided, since EventSource doesn't support custom headers.
416
+
417
+ ## TypeScript
418
+
419
+ Full TypeScript support with exported types:
420
+
421
+ ```typescript
422
+ import type {
423
+ Task,
424
+ Mission,
425
+ MissionReport,
426
+ AgentConfig,
427
+ AgentProcess,
428
+ SSEEvent,
429
+ PolpoStats,
430
+ CreateTaskRequest,
431
+ UpdateTaskRequest,
432
+ CreateMissionRequest,
433
+ UpdateMissionRequest,
434
+ } from '@polpo-ai/react';
435
+ ```
436
+
437
+ ## Examples
438
+
439
+ ### Task List with Retry
440
+
441
+ ```tsx
442
+ import { useTasks } from '@polpo-ai/react';
443
+
444
+ function TaskList() {
445
+ const { tasks, retryTask } = useTasks();
446
+
447
+ return (
448
+ <ul>
449
+ {tasks.map(task => (
450
+ <li key={task.id}>
451
+ <span>{task.title} - {task.status}</span>
452
+ {task.status === 'failed' && (
453
+ <button onClick={() => retryTask(task.id)}>
454
+ Retry
455
+ </button>
456
+ )}
457
+ </li>
458
+ ))}
459
+ </ul>
460
+ );
461
+ }
462
+ ```
463
+
464
+ ### Live Agent Activity
465
+
466
+ ```tsx
467
+ import { useProcesses } from '@polpo-ai/react';
468
+
469
+ function AgentActivity() {
470
+ const processes = useProcesses();
471
+
472
+ return (
473
+ <div>
474
+ {processes.filter(p => p.alive).map(proc => (
475
+ <div key={proc.agentName}>
476
+ <h3>{proc.agentName}</h3>
477
+ <p>Task: {proc.taskId}</p>
478
+ {proc.activity && (
479
+ <>
480
+ <p>Tool: {proc.activity.lastTool}</p>
481
+ <p>File: {proc.activity.lastFile}</p>
482
+ </>
483
+ )}
484
+ </div>
485
+ ))}
486
+ </div>
487
+ );
488
+ }
489
+ ```
490
+
491
+ ### Mission Progress
492
+
493
+ ```tsx
494
+ import { useMission, useTasks } from '@polpo-ai/react';
495
+
496
+ function MissionProgress({ missionId }: { missionId: string }) {
497
+ const { mission, report } = useMission(missionId);
498
+ const { tasks } = useTasks({ group: missionId });
499
+
500
+ if (!mission) return null;
501
+
502
+ const completed = tasks.filter(t => t.status === 'done').length;
503
+ const total = tasks.length;
504
+ const progress = total > 0 ? (completed / total) * 100 : 0;
505
+
506
+ return (
507
+ <div>
508
+ <h2>{mission.name} ({mission.status})</h2>
509
+ <progress value={completed} max={total} />
510
+ <p>{progress.toFixed(0)}% complete ({completed}/{total})</p>
511
+ {report && <p>Score: {report.avgScore?.toFixed(1) ?? 'N/A'}</p>}
512
+ </div>
513
+ );
514
+ }
515
+ ```
516
+
517
+ ### Event Stream
518
+
519
+ ```tsx
520
+ import { useEvents } from '@polpo-ai/react';
521
+
522
+ function EventFeed() {
523
+ const events = useEvents(20);
524
+
525
+ return (
526
+ <ul>
527
+ {events.map(event => (
528
+ <li key={event.id}>
529
+ <strong>{event.event}</strong>
530
+ {' - '}
531
+ {new Date(event.timestamp).toLocaleTimeString()}
532
+ </li>
533
+ ))}
534
+ </ul>
535
+ );
536
+ }
537
+ ```
538
+
539
+ ## Performance
540
+
541
+ The SDK is optimized for performance:
542
+
543
+ - **Memoized Selectors**: WeakMap caching prevents unnecessary re-renders
544
+ - **Batched Updates**: `queueMicrotask` batching for event processing
545
+ - **Request Deduplication**: Concurrent identical requests are coalesced
546
+ - **Efficient Filtering**: Hooks support filtering without re-computation
547
+
548
+ ## Bundle Size
549
+
550
+ - **Zero runtime dependencies** (only React peer)
551
+ - Tree-shakeable ESM exports
552
+ - `sideEffects: false` for optimal bundling
553
+
554
+ ## License
555
+
556
+ MIT
@@ -0,0 +1,19 @@
1
+ import type { ActiveDelay } from "@polpo-ai/client";
2
+ export interface UseActiveDelaysReturn {
3
+ /** Active delays from SSE events (live, updated by delay:started/delay:expired). */
4
+ activeDelays: ActiveDelay[];
5
+ /** Active delays fetched from the server (initial load). */
6
+ fetchedDelays: ActiveDelay[];
7
+ /** Refetch from server. */
8
+ refetch: () => void;
9
+ loading: boolean;
10
+ }
11
+ /**
12
+ * Hook for accessing active delay timers.
13
+ *
14
+ * Combines two sources:
15
+ * 1. SSE events (delay:started / delay:expired) → store.activeDelays (real-time)
16
+ * 2. Initial fetch from GET /missions/delays (catches delays that started before SSE connected)
17
+ */
18
+ export declare function useActiveDelays(): UseActiveDelaysReturn;
19
+ //# sourceMappingURL=use-active-delays.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-active-delays.d.ts","sourceRoot":"","sources":["../../src/hooks/use-active-delays.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,MAAM,WAAW,qBAAqB;IACpC,oFAAoF;IACpF,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,4DAA4D;IAC5D,aAAa,EAAE,WAAW,EAAE,CAAC;IAC7B,2BAA2B;IAC3B,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,IAAI,qBAAqB,CAkCvD"}
@@ -0,0 +1,35 @@
1
+ import { useSyncExternalStore, useState, useEffect, useCallback } from "react";
2
+ import { usePolpoContext } from "../provider/polpo-context.js";
3
+ /**
4
+ * Hook for accessing active delay timers.
5
+ *
6
+ * Combines two sources:
7
+ * 1. SSE events (delay:started / delay:expired) → store.activeDelays (real-time)
8
+ * 2. Initial fetch from GET /missions/delays (catches delays that started before SSE connected)
9
+ */
10
+ export function useActiveDelays() {
11
+ const { client, store } = usePolpoContext();
12
+ // Real-time from store (fed by SSE events via event-reducer)
13
+ const storeDelays = useSyncExternalStore(store.subscribe, () => store.getSnapshot().activeDelays, () => store.getServerSnapshot().activeDelays);
14
+ const [fetchedDelays, setFetchedDelays] = useState([]);
15
+ const [loading, setLoading] = useState(true);
16
+ const [fetchCount, setFetchCount] = useState(0);
17
+ const refetch = useCallback(() => setFetchCount(c => c + 1), []);
18
+ useEffect(() => {
19
+ setLoading(true);
20
+ client.listDelays()
21
+ .then((delays) => {
22
+ setFetchedDelays(delays);
23
+ // Also seed the store so SSE events can update from here
24
+ for (const d of delays) {
25
+ store.getSnapshot().activeDelays.set(`${d.group}:${d.delayName}`, d);
26
+ }
27
+ })
28
+ .catch(() => { })
29
+ .finally(() => setLoading(false));
30
+ }, [client, store, fetchCount]);
31
+ // Merge: store has real-time data, fetched fills in pre-existing delays
32
+ const activeDelays = Array.from(storeDelays.values());
33
+ return { activeDelays, fetchedDelays, refetch, loading };
34
+ }
35
+ //# sourceMappingURL=use-active-delays.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-active-delays.js","sourceRoot":"","sources":["../../src/hooks/use-active-delays.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAC/E,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAa/D;;;;;;GAMG;AACH,MAAM,UAAU,eAAe;IAC7B,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,eAAe,EAAE,CAAC;IAE5C,6DAA6D;IAC7D,MAAM,WAAW,GAAG,oBAAoB,CACtC,KAAK,CAAC,SAAS,EACf,GAAG,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,YAAY,EACtC,GAAG,EAAE,CAAC,KAAK,CAAC,iBAAiB,EAAE,CAAC,YAAY,CAC7C,CAAC;IAEF,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAgB,EAAE,CAAC,CAAC;IACtE,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC7C,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAEhD,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEjE,SAAS,CAAC,GAAG,EAAE;QACb,UAAU,CAAC,IAAI,CAAC,CAAC;QACjB,MAAM,CAAC,UAAU,EAAE;aAChB,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;YACf,gBAAgB,CAAC,MAAM,CAAC,CAAC;YACzB,yDAAyD;YACzD,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;gBACvB,KAAK,CAAC,WAAW,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC;YACvE,CAAC;QACH,CAAC,CAAC;aACD,KAAK,CAAC,GAAG,EAAE,GAAqB,CAAC,CAAC;aAClC,OAAO,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;IACtC,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC;IAEhC,wEAAwE;IACxE,MAAM,YAAY,GAAG,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC;IAEtD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AAC3D,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { AgentConfig } from "@polpo-ai/client";
2
+ export interface UseAgentReturn {
3
+ agent: AgentConfig | null;
4
+ isLoading: boolean;
5
+ error: Error | null;
6
+ refetch: () => Promise<void>;
7
+ }
8
+ /**
9
+ * Fetch a single agent by name from the `/agents/:name` endpoint.
10
+ */
11
+ export declare function useAgent(name: string): UseAgentReturn;
12
+ //# sourceMappingURL=use-agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-agent.d.ts","sourceRoot":"","sources":["../../src/hooks/use-agent.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAuBrD"}
@@ -0,0 +1,28 @@
1
+ import { useCallback, useEffect, useState } from "react";
2
+ import { usePolpoContext } from "../provider/polpo-context.js";
3
+ /**
4
+ * Fetch a single agent by name from the `/agents/:name` endpoint.
5
+ */
6
+ export function useAgent(name) {
7
+ const { client } = usePolpoContext();
8
+ const [agent, setAgent] = useState(null);
9
+ const [isLoading, setIsLoading] = useState(true);
10
+ const [error, setError] = useState(null);
11
+ const fetchAgent = useCallback(async () => {
12
+ try {
13
+ setError(null);
14
+ const data = await client.getAgent(name);
15
+ setAgent(data);
16
+ }
17
+ catch (err) {
18
+ setError(err);
19
+ setAgent(null);
20
+ }
21
+ }, [client, name]);
22
+ useEffect(() => {
23
+ setIsLoading(true);
24
+ fetchAgent().finally(() => setIsLoading(false));
25
+ }, [fetchAgent]);
26
+ return { agent, isLoading, error, refetch: fetchAgent };
27
+ }
28
+ //# sourceMappingURL=use-agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-agent.js","sourceRoot":"","sources":["../../src/hooks/use-agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAU/D;;GAEG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,MAAM,EAAE,MAAM,EAAE,GAAG,eAAe,EAAE,CAAC;IACrC,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAqB,IAAI,CAAC,CAAC;IAC7D,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IACjD,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAe,IAAI,CAAC,CAAC;IAEvD,MAAM,UAAU,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE;QACxC,IAAI,CAAC;YACH,QAAQ,CAAC,IAAI,CAAC,CAAC;YACf,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YACzC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACjB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,QAAQ,CAAC,GAAY,CAAC,CAAC;YACvB,QAAQ,CAAC,IAAI,CAAC,CAAC;QACjB,CAAC;IACH,CAAC,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;IAEnB,SAAS,CAAC,GAAG,EAAE;QACb,YAAY,CAAC,IAAI,CAAC,CAAC;QACnB,UAAU,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;IAClD,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;IAEjB,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;AAC1D,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { AgentConfig, Team, AddAgentRequest, UpdateAgentRequest, AddTeamRequest } from "@polpo-ai/client";
2
+ export interface UseAgentsReturn {
3
+ agents: AgentConfig[];
4
+ teams: Team[];
5
+ isLoading: boolean;
6
+ error: Error | null;
7
+ addAgent: (req: AddAgentRequest, teamName?: string) => Promise<void>;
8
+ updateAgent: (name: string, req: UpdateAgentRequest) => Promise<AgentConfig>;
9
+ removeAgent: (name: string) => Promise<void>;
10
+ addTeam: (req: AddTeamRequest) => Promise<void>;
11
+ removeTeam: (name: string) => Promise<void>;
12
+ renameTeam: (oldName: string, newName: string) => Promise<Team>;
13
+ refetch: () => Promise<void>;
14
+ }
15
+ export declare function useAgents(): UseAgentsReturn;
16
+ //# sourceMappingURL=use-agents.d.ts.map