@llblab/pi-actors 0.22.4 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +1 -0
- package/BACKLOG.md +0 -220
- package/CHANGELOG.md +23 -1
- package/README.md +1 -1
- package/dist/index.js +15 -0
- package/dist/lib/actor-inspector-tui.d.ts +4 -0
- package/dist/lib/actor-inspector-tui.js +53 -12
- package/dist/lib/actor-rooms.d.ts +8 -0
- package/dist/lib/actor-rooms.js +61 -10
- package/dist/lib/async-runs.d.ts +34 -2
- package/dist/lib/async-runs.js +215 -22
- package/dist/lib/command-templates.js +5 -5
- package/dist/lib/limits.d.ts +11 -0
- package/dist/lib/limits.js +11 -0
- package/dist/lib/observability.js +6 -4
- package/dist/lib/output.js +4 -5
- package/dist/lib/recipe-discovery.js +1 -0
- package/dist/lib/recipe-references.d.ts +11 -2
- package/dist/lib/recipe-references.js +4 -2
- package/dist/lib/recipe-usage.d.ts +2 -1
- package/dist/lib/recipe-usage.js +15 -3
- package/dist/lib/runtime.js +12 -2
- package/dist/lib/tools.js +197 -38
- package/docs/async-runs.md +2 -1
- package/docs/template-recipes.md +1 -1
- package/docs/tool-registry.md +0 -1
- package/index.ts +18 -0
- package/lib/actor-inspector-tui.ts +131 -29
- package/lib/actor-rooms.ts +155 -44
- package/lib/async-runs.ts +290 -31
- package/lib/command-templates.ts +5 -5
- package/lib/limits.ts +12 -0
- package/lib/observability.ts +10 -4
- package/lib/output.ts +4 -6
- package/lib/recipe-discovery.ts +1 -0
- package/lib/recipe-references.ts +20 -4
- package/lib/recipe-usage.ts +31 -4
- package/lib/runtime.ts +31 -7
- package/lib/tools.ts +296 -57
- package/package.json +2 -1
- package/scripts/async-runner.mjs +6 -0
- package/scripts/conformance.mjs +47 -0
- package/scripts/coordinator.mjs +13 -0
- package/scripts/locker.mjs +13 -0
- package/scripts/music-player.mjs +21 -2
- package/scripts/recipe-utils.mjs +13 -0
- package/scripts/validate-recipe.mjs +13 -0
- package/skills/actors/SKILL.md +3 -3
- package/skills/swarm/SKILL.md +1 -1
package/AGENTS.md
CHANGED
|
@@ -64,6 +64,7 @@
|
|
|
64
64
|
- `npm run check`: Lightweight extension-load sanity check
|
|
65
65
|
- `npm test`: Focused regression tests for extracted pure domains
|
|
66
66
|
- `npm run pack:dry`: Verify package contents and npm metadata
|
|
67
|
+
- `npm run conformance`: Compact protocol conformance runner for actor/recipe behavior
|
|
67
68
|
- `bash ~/.pi/agent/skills/abcd-context/scripts/validate-context.sh`: Validate context split, links, and README/docs reachability
|
|
68
69
|
|
|
69
70
|
## Pre-Task Preparation
|
package/BACKLOG.md
CHANGED
|
@@ -84,20 +84,6 @@ No open hotfix items.
|
|
|
84
84
|
- `inspect` can show id, correlation, and causation.
|
|
85
85
|
- No migration is forced.
|
|
86
86
|
|
|
87
|
-
### M-03 Mailbox Contract v1
|
|
88
|
-
|
|
89
|
-
- Priority: Medium.
|
|
90
|
-
- Goal: Extend `mailbox.accepts` and `mailbox.emits` from string arrays to backward-compatible typed contracts.
|
|
91
|
-
- Direction:
|
|
92
|
-
- Keep string declarations valid.
|
|
93
|
-
- Normalize typed entries for inspection.
|
|
94
|
-
- Support fields such as body schema, ack requirement, idempotency, response requirement, level, and summary.
|
|
95
|
-
- Acceptance:
|
|
96
|
-
- String declarations still work.
|
|
97
|
-
- `inspect view=mailbox` shows normalized contracts.
|
|
98
|
-
- Messages outside accepts produce advisory warnings by default, not hard blocks.
|
|
99
|
-
- Docs clarify advisory versus strict mode.
|
|
100
|
-
|
|
101
87
|
### M-04 Actor Loop Helper SDK
|
|
102
88
|
|
|
103
89
|
- Priority: Medium.
|
|
@@ -119,143 +105,6 @@ No open hotfix items.
|
|
|
119
105
|
- Concurrent wake and poll paths do not double-process messages.
|
|
120
106
|
- Helper supports run inbox and branch inbox.
|
|
121
107
|
|
|
122
|
-
### M-05 Branch Delivery Unification
|
|
123
|
-
|
|
124
|
-
- Priority: Medium.
|
|
125
|
-
- Goal: Route direct branch messages and room multicast branch copies through one internal helper.
|
|
126
|
-
- Target helper:
|
|
127
|
-
- `routeBranchEnvelope(stateDir, runId, message, { source })`.
|
|
128
|
-
- Acceptance:
|
|
129
|
-
- Direct branch messages and room multicast produce the same durable branch inbox shape.
|
|
130
|
-
- Parent run dispatch envelope is consistent.
|
|
131
|
-
- Tests cover both paths.
|
|
132
|
-
|
|
133
|
-
### M-06 Attention Semantics v1
|
|
134
|
-
|
|
135
|
-
- Priority: Medium.
|
|
136
|
-
- Goal: Formalize coordinator attention behavior through semantic metadata rather than transport knobs.
|
|
137
|
-
- Direction:
|
|
138
|
-
- Support attention metadata such as `requires_response=true` and reason.
|
|
139
|
-
- Map response-required messages to follow-up.
|
|
140
|
-
- Keep progress/info messages inspectable or notify-only.
|
|
141
|
-
- Preserve existing internal `delivery` behavior.
|
|
142
|
-
- Acceptance:
|
|
143
|
-
- `requires_response=true` becomes coordinator follow-up.
|
|
144
|
-
- Progress info stays log or notification.
|
|
145
|
-
- Explicit stop and kill controls do not create duplicate terminal follow-up.
|
|
146
|
-
|
|
147
|
-
### M-07 Recipe Doctor
|
|
148
|
-
|
|
149
|
-
- Priority: Medium.
|
|
150
|
-
- Goal: Add intentional recipe health inspection.
|
|
151
|
-
- Surface:
|
|
152
|
-
- `inspect target=recipes view=doctor`.
|
|
153
|
-
- `inspect target=recipes view=doctor verbose=true`.
|
|
154
|
-
- Checks:
|
|
155
|
-
- Import graph health.
|
|
156
|
-
- Shadowing and blockers.
|
|
157
|
-
- Invalid or disabled recipes.
|
|
158
|
-
- Risky command templates.
|
|
159
|
-
- Absolute path portability.
|
|
160
|
-
- OS compatibility.
|
|
161
|
-
- Root permissions.
|
|
162
|
-
- Mailbox completeness.
|
|
163
|
-
- Artifact placeholder resolution.
|
|
164
|
-
- Stale or unused usage.
|
|
165
|
-
- Acceptance:
|
|
166
|
-
- Compact output is grouped by severity.
|
|
167
|
-
- Verbose output is structured.
|
|
168
|
-
- No automatic cleanup happens.
|
|
169
|
-
- Every diagnostic has reason and suggested actions.
|
|
170
|
-
|
|
171
|
-
### M-08 Artifact Manifest v1
|
|
172
|
-
|
|
173
|
-
- Priority: Medium.
|
|
174
|
-
- Goal: Extend recipe artifacts from string paths to backward-compatible artifact metadata.
|
|
175
|
-
- Direction:
|
|
176
|
-
- Keep string artifact paths valid.
|
|
177
|
-
- Add optional object fields such as path, kind, media type, and required.
|
|
178
|
-
- Resolve manifests with existence, size, and optional hash.
|
|
179
|
-
- Acceptance:
|
|
180
|
-
- String artifacts remain valid.
|
|
181
|
-
- Runtime resolves manifest with `exists`, `size`, and optional `sha256`.
|
|
182
|
-
- Terminal follow-ups group named artifacts.
|
|
183
|
-
- Missing required artifacts are visible in result and inspect output.
|
|
184
|
-
|
|
185
|
-
### M-09 Lifecycle Retention Policy
|
|
186
|
-
|
|
187
|
-
- Priority: Medium.
|
|
188
|
-
- Goal: Add explicit archive and prune behavior for terminal run state.
|
|
189
|
-
- Messages:
|
|
190
|
-
- `control.archive`.
|
|
191
|
-
- `control.prune`.
|
|
192
|
-
- Direction:
|
|
193
|
-
- Only terminal runs can be archived or pruned.
|
|
194
|
-
- Active runs fail closed.
|
|
195
|
-
- Archive moves or compresses state with a tombstone.
|
|
196
|
-
- Prune deletes terminal state after ownership checks, optionally preserving artifacts.
|
|
197
|
-
- Acceptance:
|
|
198
|
-
- Terminal cleanup candidates are inspectable.
|
|
199
|
-
- Artifacts can be preserved.
|
|
200
|
-
- Active run deletion is impossible.
|
|
201
|
-
|
|
202
|
-
### M-10 Inspector v2 For Unread Mentions And Needs Response
|
|
203
|
-
|
|
204
|
-
- Priority: Medium.
|
|
205
|
-
- Goal: Strengthen the TUI inspector as the operator membrane for multi-actor sessions.
|
|
206
|
-
- Direction:
|
|
207
|
-
- Add stable event ids in previews.
|
|
208
|
-
- Add unread cursor per session, run, and room.
|
|
209
|
-
- Preserve mention filtering.
|
|
210
|
-
- Add needs-response marker from attention semantics.
|
|
211
|
-
- Distinguish room timeline rows from branch inbox rows.
|
|
212
|
-
- Acceptance:
|
|
213
|
-
- `/actors-inspector-filter unread` works.
|
|
214
|
-
- `/actors-inspector-filter mention <text>` works.
|
|
215
|
-
- `/actors-inspect <number>` marks the item read for the current session.
|
|
216
|
-
- Unread state stays UI/session metadata, not protocol truth.
|
|
217
|
-
|
|
218
|
-
### M-11 Run State Index
|
|
219
|
-
|
|
220
|
-
- Priority: Medium.
|
|
221
|
-
- Goal: Add a rebuildable run-state index to reduce recursive scans and improve observability performance.
|
|
222
|
-
- Target file:
|
|
223
|
-
- `~/.pi/agent/tmp/pi-actors/runs/index.json`.
|
|
224
|
-
- Contents:
|
|
225
|
-
- State dir.
|
|
226
|
-
- Run id.
|
|
227
|
-
- Owner id.
|
|
228
|
-
- Status.
|
|
229
|
-
- Updated time.
|
|
230
|
-
- Recipe or tool.
|
|
231
|
-
- Acceptance:
|
|
232
|
-
- Index accelerates list and summarize.
|
|
233
|
-
- Corruption falls back to scan.
|
|
234
|
-
- Rebuild helper exists.
|
|
235
|
-
- Nested runs are represented without id collision.
|
|
236
|
-
|
|
237
|
-
### M-12 Internal Conformance Runner
|
|
238
|
-
|
|
239
|
-
- Priority: Medium.
|
|
240
|
-
- Goal: Add a CI-ready internal conformance runner for pi-actors protocol behavior.
|
|
241
|
-
- Script:
|
|
242
|
-
- `npm run conformance`.
|
|
243
|
-
- Suites:
|
|
244
|
-
- Recipe discovery.
|
|
245
|
-
- Register, update, and delete.
|
|
246
|
-
- Spawn lifecycle.
|
|
247
|
-
- Message routing.
|
|
248
|
-
- Room roster.
|
|
249
|
-
- Branch inbox.
|
|
250
|
-
- Ownership checks.
|
|
251
|
-
- Artifacts.
|
|
252
|
-
- Attention semantics.
|
|
253
|
-
- Acceptance:
|
|
254
|
-
- Runs without Pi UI where possible.
|
|
255
|
-
- Outputs compact report.
|
|
256
|
-
- Fixtures live in the repository.
|
|
257
|
-
- CI can run it.
|
|
258
|
-
|
|
259
108
|
### M-13 Packaged Actor Worker Recipe Template
|
|
260
109
|
|
|
261
110
|
- Priority: Medium.
|
|
@@ -270,50 +119,6 @@ No open hotfix items.
|
|
|
270
119
|
- Recipe demonstrates correct mailbox loop semantics.
|
|
271
120
|
- It is a recipe-authoring example, not a product feature.
|
|
272
121
|
|
|
273
|
-
### M-14 Recipe Usage Integrity Improvements
|
|
274
|
-
|
|
275
|
-
- Priority: Medium.
|
|
276
|
-
- Goal: Make recipe usage tracking more explainable.
|
|
277
|
-
- Direction:
|
|
278
|
-
- Add fingerprint diff reason.
|
|
279
|
-
- Add reset reason.
|
|
280
|
-
- Consider optional last error.
|
|
281
|
-
- Split launch counts by tool, spawn, and direct recipe.
|
|
282
|
-
- Acceptance:
|
|
283
|
-
- `inspect recipes view=summary verbose=true` shows whether usage refers to current recipe content.
|
|
284
|
-
- Doctor can flag unused current meaning instead of stale old recipe history.
|
|
285
|
-
|
|
286
|
-
### M-15 Safer Command Warning Policy
|
|
287
|
-
|
|
288
|
-
- Priority: Medium.
|
|
289
|
-
- Goal: Unify command-template diagnostics by severity and make warnings actionable without startup spam.
|
|
290
|
-
- Severity:
|
|
291
|
-
- `info`: portability.
|
|
292
|
-
- `warning`: broad mutation, shell, or eval.
|
|
293
|
-
- `error`: impossible, invalid, or unsafe repeat.
|
|
294
|
-
- Direction:
|
|
295
|
-
- Treat legitimate `bash` wrappers as expected trusted boundaries when already packaged or explicitly registered.
|
|
296
|
-
- Keep routine shell wrapper notes out of startup warning blocks.
|
|
297
|
-
- Surface shell/eval/destructive diagnostics through register-time warnings, doctor, and verbose recipe inspection.
|
|
298
|
-
- Acceptance:
|
|
299
|
-
- Command-template warnings include command label, reason, and suggested mitigation.
|
|
300
|
-
- `register_tool` shows relevant warnings.
|
|
301
|
-
- Recipe doctor aggregates warning policy.
|
|
302
|
-
- Startup no longer emits large warning blocks only because recipes wrap `bash`.
|
|
303
|
-
|
|
304
|
-
### M-16 Output And Log Size Governance
|
|
305
|
-
|
|
306
|
-
- Priority: Medium.
|
|
307
|
-
- Goal: Keep stdout, stderr, result, outbox, and actor-message previews bounded in agent context.
|
|
308
|
-
- Direction:
|
|
309
|
-
- Centralize constants for body preview, outbox preview, inspector preview, and tail lines.
|
|
310
|
-
- Keep verbose output opt-in.
|
|
311
|
-
- Prefer files or artifacts for large bodies.
|
|
312
|
-
- Acceptance:
|
|
313
|
-
- Actor messages and previews share consistent caps.
|
|
314
|
-
- Verbose mode is explicit.
|
|
315
|
-
- Large bodies do not flood normal tool output.
|
|
316
|
-
|
|
317
122
|
### M-17 Windows And Nix Portability Pass
|
|
318
123
|
|
|
319
124
|
- Priority: Medium.
|
|
@@ -341,18 +146,6 @@ No open hotfix items.
|
|
|
341
146
|
- Corrupt paths are reported clearly.
|
|
342
147
|
- Canonical state is not silently rewritten without explicit action.
|
|
343
148
|
|
|
344
|
-
### M-19 Recipe Import Graph Inspector
|
|
345
|
-
|
|
346
|
-
- Priority: Medium.
|
|
347
|
-
- Goal: Add focused inspection for recipe import graphs.
|
|
348
|
-
- Surface:
|
|
349
|
-
- `inspect target=recipes view=imports`.
|
|
350
|
-
- `inspect target=recipes view=imports verbose=true`.
|
|
351
|
-
- Acceptance:
|
|
352
|
-
- Shows import graph, aliases, resolved paths, and shadowed imports.
|
|
353
|
-
- Shows cyclic and depth diagnostics.
|
|
354
|
-
- Helps debug packaged and user recipe composition.
|
|
355
|
-
|
|
356
149
|
### M-20 Spawn Preflight Mode
|
|
357
150
|
|
|
358
151
|
- Priority: Medium.
|
|
@@ -393,19 +186,6 @@ No open hotfix items.
|
|
|
393
186
|
- Examples cover branch, room, run, session, and tool addresses.
|
|
394
187
|
- No new public address kinds are added.
|
|
395
188
|
|
|
396
|
-
### M-23 Room Compaction Metadata Improvements
|
|
397
|
-
|
|
398
|
-
- Priority: Medium.
|
|
399
|
-
- Goal: Record richer room compaction metadata.
|
|
400
|
-
- Direction:
|
|
401
|
-
- Track dropped count.
|
|
402
|
-
- Track first and last kept timestamps.
|
|
403
|
-
- Track configured max.
|
|
404
|
-
- Acceptance:
|
|
405
|
-
- `inspect room:<run> view=status verbose=true` shows compaction info.
|
|
406
|
-
- Compaction never corrupts JSONL.
|
|
407
|
-
- Tests cover low `PI_ACTORS_ROOM_MAX_MESSAGES`.
|
|
408
|
-
|
|
409
189
|
### M-24 Coordinator Follow-Up Deduplication
|
|
410
190
|
|
|
411
191
|
- Priority: Medium.
|
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,28 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## 0.23.0: Actor Manifests, Inspection, and Runtime Hygiene
|
|
4
|
+
|
|
5
|
+
- `[Tools]` Unified branch-envelope routing for direct branch messages and selected-recipient room multicast so both paths persist the same branch-local inbox shape before dispatching through the parent run mailbox.
|
|
6
|
+
- `[Async Runs]` Added attention semantics for coordinator-bound actor messages: `metadata.requires_response=true` now produces a follow-up while ordinary coordinator progress messages default to notification-level delivery.
|
|
7
|
+
- `[Registry]` Added `inspect target=recipes view=doctor` as an intentional recipe health surface with compact severity/action counts and structured verbose diagnostics.
|
|
8
|
+
- `[Async Runs]` Added artifact manifest resolution for string and object artifact declarations, including `exists`, `size`, `sha256`, and missing required artifact visibility in artifact inspection.
|
|
9
|
+
- `[Async Runs]` Added explicit terminal run retention controls via `control.archive` and `control.prune`, with active-run fail-closed behavior and optional artifact preservation during prune.
|
|
10
|
+
- `[Inspector]` Added stable event ids, needs-response markers, and session-local read markers to actor inspector previews and selected-item details.
|
|
11
|
+
- `[Registry]` Suppressed routine trusted `bash` wrapper diagnostics from startup warning notifications while keeping them available through recipe diagnostics surfaces.
|
|
12
|
+
- `[Async Runs]` Added a rebuildable run-state index for run listing and observability discovery, with corrupt-index fallback to recursive scan and nested-run-safe state directory entries.
|
|
13
|
+
- `[Testing]` Added `npm run conformance` for a compact CI-ready protocol conformance runner covering recipes, registry, spawn lifecycle, messaging, rooms, branch inboxes, ownership, artifacts, and attention semantics.
|
|
14
|
+
- `[Mailbox]` Added backward-compatible typed mailbox contracts with normalized inspection and advisory warnings for undeclared run message types.
|
|
15
|
+
- `[Output]` Centralized inspect, preview, and tool-output size limits so bounded output governance is shared across tools, room previews, and the actor inspector.
|
|
16
|
+
- `[Registry]` Added explicit mitigation guidance to command-template trust-boundary warnings for shells, eval modes, and broad filesystem mutation.
|
|
17
|
+
- `[Scripts]` Added top-of-file descriptions to packaged helper scripts so their purpose, boundaries, and policy ownership are clear when opened directly.
|
|
18
|
+
- `[Rooms]` Added room compaction metadata with dropped count, configured maximum, and first/last kept timestamps exposed through room status inspection.
|
|
19
|
+
- `[Recipes]` Improved usage telemetry with launch-kind counters (`tool`, `spawn`, `direct`) and explicit reset reasons when recipe content fingerprints change.
|
|
20
|
+
- `[Inspect]` Added `inspect target=recipes view=imports` to summarize recipe import aliases and source references for debugging recipe composition.
|
|
21
|
+
|
|
22
|
+
## 0.22.5: CI Stability Hotfix
|
|
23
|
+
|
|
24
|
+
- `[Tests]` Stabilized the Windows named-pipe control endpoint regression by keeping its synthetic run alive longer under slower full-suite CI scheduling.
|
|
25
|
+
- `[Tests]` Stabilized the coordinator-locker queue/lock smoke by waiting for assignment, renewal, and denial actor messages before stopping the helper, removing a FIFO processing race from main-branch validation.
|
|
4
26
|
|
|
5
27
|
## 0.22.4: Actor Isolation and Registry Diagnostics Hotfix
|
|
6
28
|
|
package/README.md
CHANGED
|
@@ -161,7 +161,7 @@ The terminal actor inspector is hidden by default. When opened without an explic
|
|
|
161
161
|
/actors-inspect 3
|
|
162
162
|
```
|
|
163
163
|
|
|
164
|
-
The table is compact and optimistic by default: bounded route/type/summary/body previews, capped noisy room rows, branch-local inbox previews, and an inline roster summary in the form `name/role` that wraps only when needed. Active roster members use the target color; members that sent `actor.leave` remain visible as inactive/muted participants from the current run. Use `unread` to focus queued branch inbox work and `branch <name>` / `current-branch <name>` to focus one branch's room/direct/inbox traffic. `/actors-inspect <number>` opens the selected row as a full-message view; toggle again to return to the table or close it. Actor display names come from room `actor.join` roster metadata or branch addresses, keeping debugger output plain and name-driven.
|
|
164
|
+
The table is compact and optimistic by default: bounded route/type/summary/body previews, capped noisy room rows, branch-local inbox previews, stable event ids in selected-message details, and an inline roster summary in the form `name/role` that wraps only when needed. Active roster members use the target color; members that sent `actor.leave` remain visible as inactive/muted participants from the current run. Use `unread` to focus queued branch inbox work and `branch <name>` / `current-branch <name>` to focus one branch's room/direct/inbox traffic. Rows with `metadata.requires_response=true` show a `!` attention marker. `/actors-inspect <number>` opens the selected row as a full-message view and marks it read for the current session filter; toggle again to return to the table or close it. Actor display names come from room `actor.join` roster metadata or branch addresses, keeping debugger output plain and name-driven.
|
|
165
165
|
|
|
166
166
|
## Registry Model
|
|
167
167
|
|
package/dist/index.js
CHANGED
|
@@ -49,6 +49,7 @@ export default function toolRegistryExtension(pi) {
|
|
|
49
49
|
let actorInspectorUnreadOnly = false;
|
|
50
50
|
let actorInspectorRoomLimitPerRun = 12;
|
|
51
51
|
let selectedInspectorSequence;
|
|
52
|
+
const actorInspectorReadKeys = new Set();
|
|
52
53
|
let recipeWatcherFailureNotified = false;
|
|
53
54
|
const getRunOwnerId = (ctx) => ctx.sessionManager.getSessionId();
|
|
54
55
|
const retireCandidateRuns = (ctx, summary) => {
|
|
@@ -84,6 +85,7 @@ export default function toolRegistryExtension(pi) {
|
|
|
84
85
|
branch: actorInspectorBranch,
|
|
85
86
|
mention: actorInspectorMention,
|
|
86
87
|
ownerId,
|
|
88
|
+
readKeys: actorInspectorReadKeys,
|
|
87
89
|
roomLimitPerRun: actorInspectorRoomLimitPerRun,
|
|
88
90
|
unreadOnly: actorInspectorUnreadOnly,
|
|
89
91
|
});
|
|
@@ -356,6 +358,19 @@ export default function toolRegistryExtension(pi) {
|
|
|
356
358
|
ctx.ui.notify("Usage: /actors-inspect <number>", "warning");
|
|
357
359
|
return;
|
|
358
360
|
}
|
|
361
|
+
const previews = ActorInspectorTui.readActorInspectorPreviews(RUN_STATE_ROOT, actorInspectorRows, {
|
|
362
|
+
channels: actorInspectorChannels,
|
|
363
|
+
currentRunOnly: true,
|
|
364
|
+
branch: actorInspectorBranch,
|
|
365
|
+
mention: actorInspectorMention,
|
|
366
|
+
ownerId: getRunOwnerId(ctx),
|
|
367
|
+
readKeys: actorInspectorReadKeys,
|
|
368
|
+
roomLimitPerRun: actorInspectorRoomLimitPerRun,
|
|
369
|
+
unreadOnly: actorInspectorUnreadOnly,
|
|
370
|
+
});
|
|
371
|
+
const preview = previews.find((item) => item.sequence === sequence);
|
|
372
|
+
if (preview)
|
|
373
|
+
actorInspectorReadKeys.add(ActorInspectorTui.inspectorPreviewReadKey(preview));
|
|
359
374
|
selectedInspectorSequence = sequence;
|
|
360
375
|
communicationWidgetVisible = true;
|
|
361
376
|
updateRunUi(ctx);
|
|
@@ -6,10 +6,12 @@ export interface ActorInspectorPreview {
|
|
|
6
6
|
body_preview?: string;
|
|
7
7
|
branch?: string;
|
|
8
8
|
channel: "broadcast" | "direct" | "room";
|
|
9
|
+
event_id?: string;
|
|
9
10
|
from?: string;
|
|
10
11
|
from_display?: string;
|
|
11
12
|
inbox_status?: string;
|
|
12
13
|
message_id?: string;
|
|
14
|
+
needs_response?: boolean;
|
|
13
15
|
run: string;
|
|
14
16
|
sequence?: number;
|
|
15
17
|
summary?: string;
|
|
@@ -44,9 +46,11 @@ export interface ActorInspectorPreviewReadOptions {
|
|
|
44
46
|
currentRunOnly?: boolean;
|
|
45
47
|
channels?: ActorInspectorPreview["channel"][];
|
|
46
48
|
mention?: string;
|
|
49
|
+
readKeys?: Iterable<string>;
|
|
47
50
|
roomLimitPerRun?: number;
|
|
48
51
|
unreadOnly?: boolean;
|
|
49
52
|
}
|
|
53
|
+
export declare function inspectorPreviewReadKey(preview: ActorInspectorPreview): string;
|
|
50
54
|
export declare function readActorInspectorPreviews(stateRoot?: string, limit?: number, options?: ActorInspectorPreviewReadOptions): ActorInspectorPreview[];
|
|
51
55
|
export declare function readActorInspectorRoster(stateRoot: string | undefined, run: string, room?: string): ActorInspectorRosterMember[];
|
|
52
56
|
export declare function renderInspectorRosterLine(members: ActorInspectorRosterMember[], width?: number, styles?: ActorInspectorWidgetStyle): string | undefined;
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import * as fs from "node:fs";
|
|
6
6
|
import * as path from "node:path";
|
|
7
7
|
import { visibleWidth } from "@earendil-works/pi-tui";
|
|
8
|
+
import * as Limits from "./limits.js";
|
|
8
9
|
import * as Paths from "./paths.js";
|
|
9
10
|
function asRecord(value) {
|
|
10
11
|
return value && typeof value === "object" && !Array.isArray(value)
|
|
@@ -32,7 +33,7 @@ function readJsonLines(file) {
|
|
|
32
33
|
return [];
|
|
33
34
|
}
|
|
34
35
|
}
|
|
35
|
-
function previewValue(value, maxLength =
|
|
36
|
+
function previewValue(value, maxLength = Limits.INSPECTOR_BODY_PREVIEW_CHARS) {
|
|
36
37
|
if (value === undefined)
|
|
37
38
|
return undefined;
|
|
38
39
|
const text = typeof value === "string" ? value : JSON.stringify(value);
|
|
@@ -58,6 +59,10 @@ function previewFromMessage(run, message, timestamp, displayNames = {}) {
|
|
|
58
59
|
const from = typeof message.from === "string" ? message.from : undefined;
|
|
59
60
|
const summary = typeof message.summary === "string" ? message.summary : undefined;
|
|
60
61
|
const body = asRecord(message.body);
|
|
62
|
+
const metadata = asRecord(message.metadata);
|
|
63
|
+
const eventId = typeof message.id === "string" && message.id.trim()
|
|
64
|
+
? message.id.trim()
|
|
65
|
+
: undefined;
|
|
61
66
|
const display = from
|
|
62
67
|
? typeof body.display === "string" && body.display.trim()
|
|
63
68
|
? body.display.trim()
|
|
@@ -68,8 +73,10 @@ function previewFromMessage(run, message, timestamp, displayNames = {}) {
|
|
|
68
73
|
? { body_preview: previewValue(message.body) }
|
|
69
74
|
: {}),
|
|
70
75
|
channel: channelFor({ to }),
|
|
76
|
+
...(eventId ? { event_id: eventId } : {}),
|
|
71
77
|
...(from ? { from } : {}),
|
|
72
78
|
...(display ? { from_display: display } : {}),
|
|
79
|
+
...(metadata.requires_response === true ? { needs_response: true } : {}),
|
|
73
80
|
run,
|
|
74
81
|
...(summary ? { summary } : {}),
|
|
75
82
|
timestamp,
|
|
@@ -129,14 +136,21 @@ function readBranchInboxPreviews(run, stateDir) {
|
|
|
129
136
|
.filter((entry) => entry.isDirectory())
|
|
130
137
|
.flatMap((entry) => readJsonLines(path.join(branchesDir, entry.name, "inbox.jsonl"))
|
|
131
138
|
.map((message) => {
|
|
132
|
-
const preview = previewFromMessage(run, message, String(message.queued_at ??
|
|
139
|
+
const preview = previewFromMessage(run, message, String(message.queued_at ??
|
|
140
|
+
message.received_at ??
|
|
141
|
+
message.timestamp ??
|
|
142
|
+
""));
|
|
133
143
|
if (!preview)
|
|
134
144
|
return undefined;
|
|
135
145
|
return {
|
|
136
146
|
...preview,
|
|
137
147
|
branch: entry.name,
|
|
138
|
-
...(typeof message.id === "string"
|
|
139
|
-
|
|
148
|
+
...(typeof message.id === "string"
|
|
149
|
+
? { message_id: message.id }
|
|
150
|
+
: {}),
|
|
151
|
+
...(typeof message.status === "string"
|
|
152
|
+
? { inbox_status: message.status }
|
|
153
|
+
: {}),
|
|
140
154
|
};
|
|
141
155
|
})
|
|
142
156
|
.filter((preview) => Boolean(preview)));
|
|
@@ -167,8 +181,22 @@ function getRunOwnerId(stateDir) {
|
|
|
167
181
|
function matchesOwner(stateDir, ownerId) {
|
|
168
182
|
return ownerId === undefined || getRunOwnerId(stateDir) === ownerId;
|
|
169
183
|
}
|
|
170
|
-
function
|
|
171
|
-
return
|
|
184
|
+
export function inspectorPreviewReadKey(preview) {
|
|
185
|
+
return [
|
|
186
|
+
preview.channel,
|
|
187
|
+
preview.run,
|
|
188
|
+
preview.branch ?? "",
|
|
189
|
+
preview.event_id ?? preview.message_id ?? preview.timestamp,
|
|
190
|
+
preview.from ?? "",
|
|
191
|
+
preview.to,
|
|
192
|
+
preview.type,
|
|
193
|
+
].join("|");
|
|
194
|
+
}
|
|
195
|
+
function isUnreadPreview(preview, readKeys) {
|
|
196
|
+
if (readKeys?.has(inspectorPreviewReadKey(preview)))
|
|
197
|
+
return false;
|
|
198
|
+
return (preview.inbox_status === "queued" ||
|
|
199
|
+
(preview.inbox_status === undefined && preview.branch !== undefined));
|
|
172
200
|
}
|
|
173
201
|
function matchesBranchFilter(preview, branch) {
|
|
174
202
|
const name = branch?.trim();
|
|
@@ -183,7 +211,8 @@ function matchesPreviewFilter(preview, options) {
|
|
|
183
211
|
if (options.channels?.length && !options.channels.includes(preview.channel)) {
|
|
184
212
|
return false;
|
|
185
213
|
}
|
|
186
|
-
|
|
214
|
+
const readKeys = options.readKeys ? new Set(options.readKeys) : undefined;
|
|
215
|
+
if (options.unreadOnly && !isUnreadPreview(preview, readKeys))
|
|
187
216
|
return false;
|
|
188
217
|
if (!matchesBranchFilter(preview, options.branch))
|
|
189
218
|
return false;
|
|
@@ -298,6 +327,9 @@ function routeText(preview) {
|
|
|
298
327
|
return `${actor} ⇢ ${preview.to}`;
|
|
299
328
|
return `${actor} → ${actorName(preview.to)}`;
|
|
300
329
|
}
|
|
330
|
+
function attentionMarker(preview) {
|
|
331
|
+
return preview.needs_response ? "! " : "";
|
|
332
|
+
}
|
|
301
333
|
function style(styleFn, text) {
|
|
302
334
|
return styleFn ? styleFn(text) : text;
|
|
303
335
|
}
|
|
@@ -351,7 +383,7 @@ function renderCompactInspectorEntry(preview, width, sequenceWidth, routeWidth,
|
|
|
351
383
|
const contentWidth = Math.max(8, width - prefix.length - suffix.length);
|
|
352
384
|
const sequence = String(preview.sequence ?? 0).padStart(sequenceWidth, " ");
|
|
353
385
|
const sequencePrefix = `${sequence}${separator}`;
|
|
354
|
-
const route = routeText(preview)
|
|
386
|
+
const route = `${attentionMarker(preview)}${routeText(preview)}`;
|
|
355
387
|
const routePadding = " ".repeat(Math.max(0, routeWidth - displayWidth(route)));
|
|
356
388
|
const typePadding = " ".repeat(Math.max(0, typeWidth - displayWidth(preview.type)));
|
|
357
389
|
const headline = previewText(preview);
|
|
@@ -382,7 +414,7 @@ function renderInspectorEntry(preview, width, sequenceWidth, routeWidth, typeWid
|
|
|
382
414
|
const contentWidth = Math.max(8, width - prefix.length - suffix.length);
|
|
383
415
|
const sequence = String(preview.sequence ?? 0).padStart(sequenceWidth, " ");
|
|
384
416
|
const sequencePrefix = `${sequence}${separator}`;
|
|
385
|
-
const route = routeText(preview)
|
|
417
|
+
const route = `${attentionMarker(preview)}${routeText(preview)}`;
|
|
386
418
|
const type = preview.type;
|
|
387
419
|
const summary = preview.summary?.trim() ?? "";
|
|
388
420
|
const body = preview.body_preview?.trim() || (!summary ? previewText(preview) : "-");
|
|
@@ -430,7 +462,10 @@ export function readActorInspectorRoster(stateRoot = Paths.getRunStateRoot(), ru
|
|
|
430
462
|
}
|
|
431
463
|
function rosterRoleText(role) {
|
|
432
464
|
const roleLabel = role?.split(";")[0] ?? "";
|
|
433
|
-
const cleaned = roleLabel
|
|
465
|
+
const cleaned = roleLabel
|
|
466
|
+
.replaceAll(/\s*\([^)]*\)\s*$/g, "")
|
|
467
|
+
.trim()
|
|
468
|
+
.toLowerCase();
|
|
434
469
|
if (!cleaned || cleaned === "actor")
|
|
435
470
|
return undefined;
|
|
436
471
|
return cleaned.replaceAll(/\s+/g, "-");
|
|
@@ -444,7 +479,10 @@ function rosterMemberText(member) {
|
|
|
444
479
|
}
|
|
445
480
|
function isRosterMemberActive(member) {
|
|
446
481
|
const status = member.status?.trim().toLowerCase();
|
|
447
|
-
return !status ||
|
|
482
|
+
return (!status ||
|
|
483
|
+
status === "present" ||
|
|
484
|
+
status === "active" ||
|
|
485
|
+
status === "running");
|
|
448
486
|
}
|
|
449
487
|
export function renderInspectorRosterLine(members, width = 80, styles = {}) {
|
|
450
488
|
return renderInspectorRosterPanel(members, width, styles)?.[0];
|
|
@@ -491,12 +529,15 @@ export function renderInspectorItemView(previews, width = 80, styles = {}, optio
|
|
|
491
529
|
const orderedKeys = [
|
|
492
530
|
"channel",
|
|
493
531
|
"run",
|
|
532
|
+
"event_id",
|
|
494
533
|
"from",
|
|
495
534
|
"from_display",
|
|
496
535
|
"to",
|
|
497
536
|
"type",
|
|
498
537
|
"summary",
|
|
499
538
|
"body_preview",
|
|
539
|
+
"message_id",
|
|
540
|
+
"needs_response",
|
|
500
541
|
"timestamp",
|
|
501
542
|
"stripe",
|
|
502
543
|
];
|
|
@@ -540,7 +581,7 @@ export function renderInspectorWidget(previews, width = 80, styles = {}, options
|
|
|
540
581
|
const sequencePrefixWidth = sequenceWidth + separatorWidth;
|
|
541
582
|
const fixedSeparatorsWidth = separatorWidth * 3;
|
|
542
583
|
const availableForColumns = Math.max(0, safeWidth - 1 - sequencePrefixWidth - fixedSeparatorsWidth);
|
|
543
|
-
const naturalRouteWidth = Math.max(...visible.map(({ preview }) => displayWidth(routeText(preview))));
|
|
584
|
+
const naturalRouteWidth = Math.max(...visible.map(({ preview }) => displayWidth(`${attentionMarker(preview)}${routeText(preview)}`)));
|
|
544
585
|
const naturalTypeWidth = Math.max(...visible.map(({ preview }) => displayWidth(preview.type)));
|
|
545
586
|
const routeWidth = Math.min(naturalRouteWidth, Math.max(4, Math.floor(availableForColumns * 0.35)));
|
|
546
587
|
const typeWidth = Math.min(naturalTypeWidth, Math.max(4, Math.floor(availableForColumns * 0.25)));
|
|
@@ -32,10 +32,18 @@ export interface RoomMessagePreview {
|
|
|
32
32
|
to: string;
|
|
33
33
|
type: string;
|
|
34
34
|
}
|
|
35
|
+
export interface RoomCompactionInfo {
|
|
36
|
+
compacted_at: string;
|
|
37
|
+
dropped_count: number;
|
|
38
|
+
first_kept_at?: string;
|
|
39
|
+
last_kept_at?: string;
|
|
40
|
+
max_messages: number;
|
|
41
|
+
}
|
|
35
42
|
export interface RoomStatus {
|
|
36
43
|
room: string;
|
|
37
44
|
message_count: number;
|
|
38
45
|
roster_count: number;
|
|
46
|
+
compaction?: RoomCompactionInfo;
|
|
39
47
|
last_message_at?: string;
|
|
40
48
|
last_message_from?: string;
|
|
41
49
|
last_message_summary?: string;
|