@llblab/pi-actors 0.22.5 → 0.24.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 +125 -59
- package/BACKLOG.md +88 -403
- package/CHANGELOG.md +39 -0
- package/README.md +14 -1
- package/dist/fixtures/protocol/actor-message-branch.json +13 -0
- package/dist/fixtures/protocol/artifact-manifest.json +9 -0
- package/dist/fixtures/protocol/mailbox-contract.json +15 -0
- package/dist/fixtures/protocol/recipe-summary.json +16 -0
- package/dist/fixtures/protocol/room-message.json +11 -0
- package/dist/fixtures/protocol/room-roster.json +11 -0
- package/dist/fixtures/protocol/run-inbox-message.json +9 -0
- package/dist/fixtures/protocol/run-outbox-event.json +9 -0
- package/dist/fixtures/protocol/run-state.json +10 -0
- package/dist/index.js +18 -2
- package/dist/lib/actor-inspector-tui.d.ts +4 -0
- package/dist/lib/actor-inspector-tui.js +58 -44
- package/dist/lib/actor-rooms.d.ts +16 -0
- package/dist/lib/actor-rooms.js +123 -28
- package/dist/lib/actor-worker.d.ts +13 -0
- package/dist/lib/actor-worker.js +86 -0
- package/dist/lib/async-runner.d.ts +5 -0
- package/dist/lib/async-runner.js +134 -0
- package/dist/lib/async-runs.d.ts +34 -2
- package/dist/lib/async-runs.js +224 -50
- package/dist/lib/build-dist.d.ts +5 -0
- package/dist/lib/build-dist.js +24 -0
- package/dist/lib/command-templates.js +5 -5
- package/dist/lib/conformance.d.ts +12 -0
- package/dist/lib/conformance.js +28 -0
- package/dist/lib/coordinator.d.ts +5 -0
- package/dist/lib/coordinator.js +557 -0
- package/dist/lib/limits.d.ts +11 -0
- package/dist/lib/limits.js +11 -0
- package/dist/lib/locker.d.ts +5 -0
- package/dist/lib/locker.js +310 -0
- package/dist/lib/mailbox-loop.d.ts +41 -0
- package/dist/lib/mailbox-loop.js +62 -0
- package/dist/lib/observability.d.ts +2 -2
- package/dist/lib/observability.js +57 -57
- package/dist/lib/output.js +4 -5
- package/dist/lib/prompts.d.ts +1 -1
- package/dist/lib/prompts.js +1 -1
- package/dist/lib/recipe-discovery.js +1 -0
- package/dist/lib/recipe-references.d.ts +11 -2
- package/dist/lib/recipe-references.js +29 -4
- package/dist/lib/recipe-usage.d.ts +2 -1
- package/dist/lib/recipe-usage.js +15 -3
- package/dist/lib/recipe-utils.d.ts +5 -0
- package/dist/lib/recipe-utils.js +385 -0
- package/dist/lib/runtime-notifier.js +3 -7
- package/dist/lib/runtime.js +12 -2
- package/dist/lib/state-readers.d.ts +21 -0
- package/dist/lib/state-readers.js +74 -0
- package/dist/lib/tools.js +198 -39
- package/dist/lib/validate-recipe.d.ts +6 -0
- package/dist/lib/validate-recipe.js +104 -0
- package/dist/recipes/actor-worker.json +35 -0
- package/dist/recipes/coordinator-locker.json +45 -0
- package/dist/recipes/lens-swarm.json +66 -0
- package/dist/recipes/locker.json +45 -0
- package/dist/recipes/music-player.json +38 -0
- package/dist/recipes/pipeline-architect-coordinator.json +95 -0
- package/dist/recipes/pipeline-artifact-bundle.json +100 -0
- package/dist/recipes/pipeline-artifact-report.json +58 -0
- package/dist/recipes/pipeline-artifact-write.json +72 -0
- package/dist/recipes/pipeline-async-run-ops.json +70 -0
- package/dist/recipes/pipeline-checkpoint-continuation.json +67 -0
- package/dist/recipes/pipeline-development-tasking.json +81 -0
- package/dist/recipes/pipeline-docs-maintenance.json +80 -0
- package/dist/recipes/pipeline-media-library.json +59 -0
- package/dist/recipes/pipeline-quorum-review.json +79 -0
- package/dist/recipes/pipeline-release-readiness.json +110 -0
- package/dist/recipes/pipeline-release-summary.json +88 -0
- package/dist/recipes/pipeline-repo-health.json +89 -0
- package/dist/recipes/pipeline-research-synthesis.json +94 -0
- package/dist/recipes/pipeline-review-readiness.json +54 -0
- package/dist/recipes/pipeline-room-swarm.json +50 -0
- package/dist/recipes/subagent-artifact.json +32 -0
- package/dist/recipes/subagent-checkpoint.json +33 -0
- package/dist/recipes/subagent-conflict-report.json +32 -0
- package/dist/recipes/subagent-contradiction-map.json +33 -0
- package/dist/recipes/subagent-critic.json +35 -0
- package/dist/recipes/subagent-evidence-map.json +33 -0
- package/dist/recipes/subagent-followup.json +33 -0
- package/dist/recipes/subagent-judge.json +33 -0
- package/dist/recipes/subagent-merge.json +33 -0
- package/dist/recipes/subagent-message.json +34 -0
- package/dist/recipes/subagent-normalize.json +31 -0
- package/dist/recipes/subagent-plan.json +33 -0
- package/dist/recipes/subagent-prompt.json +28 -0
- package/dist/recipes/subagent-quorum.json +43 -0
- package/dist/recipes/subagent-review-coordinator.json +114 -0
- package/dist/recipes/subagent-review.json +37 -0
- package/dist/recipes/subagent-task-card.json +35 -0
- package/dist/recipes/subagent-tools.json +27 -0
- package/dist/recipes/subagent-verify.json +34 -0
- package/dist/recipes/subagents-prompts.json +51 -0
- package/dist/recipes/utility-actor-message.json +23 -0
- package/dist/recipes/utility-artifact-manifest.json +16 -0
- package/dist/recipes/utility-artifact-write.json +16 -0
- package/dist/recipes/utility-changelog-head.json +11 -0
- package/dist/recipes/utility-changelog-section.json +13 -0
- package/dist/recipes/utility-coordinator-lock-snapshot.json +13 -0
- package/dist/recipes/utility-git-log.json +11 -0
- package/dist/recipes/utility-git-status.json +9 -0
- package/dist/recipes/utility-jsonl-tail.json +10 -0
- package/dist/recipes/utility-markdown-index.json +14 -0
- package/dist/recipes/utility-package-summary.json +11 -0
- package/dist/recipes/utility-playlist-build.json +17 -0
- package/dist/recipes/utility-playlist-scan.json +11 -0
- package/dist/recipes/utility-run-ops-snapshot.json +17 -0
- package/dist/recipes/utility-run-state-files.json +13 -0
- package/dist/recipes/utility-run-summary.json +11 -0
- package/dist/recipes/utility-skill-summary.json +13 -0
- package/dist/recipes/utility-validate-recipe.json +13 -0
- package/dist/recipes/utility-validation-wrapper.json +13 -0
- package/dist/scripts/actor-worker.mjs +31 -0
- package/dist/scripts/async-runner.mjs +31 -0
- package/dist/scripts/build-dist.mjs +25 -0
- package/dist/scripts/conformance.mjs +33 -0
- package/dist/scripts/coordinator.mjs +31 -0
- package/dist/scripts/locker.mjs +33 -0
- package/dist/scripts/music-player.mjs +964 -0
- package/dist/scripts/recipe-utils.mjs +31 -0
- package/dist/scripts/validate-recipe.mjs +34 -0
- package/dist/skills/actors/SKILL.md +375 -0
- package/dist/skills/swarm/SKILL.md +467 -0
- package/dist/skills/swarm/references/development-swarm.md +596 -0
- package/docs/actor-messages.md +2 -2
- package/docs/async-runs.md +13 -1
- package/docs/template-recipes.md +2 -2
- package/docs/tool-registry.md +0 -1
- package/fixtures/protocol/actor-message-branch.json +13 -0
- package/fixtures/protocol/artifact-manifest.json +9 -0
- package/fixtures/protocol/mailbox-contract.json +15 -0
- package/fixtures/protocol/recipe-summary.json +16 -0
- package/fixtures/protocol/room-message.json +11 -0
- package/fixtures/protocol/room-roster.json +11 -0
- package/fixtures/protocol/run-inbox-message.json +9 -0
- package/fixtures/protocol/run-outbox-event.json +9 -0
- package/fixtures/protocol/run-state.json +10 -0
- package/index.ts +21 -0
- package/lib/actor-inspector-tui.ts +138 -59
- package/lib/actor-rooms.ts +241 -60
- package/lib/actor-worker.ts +118 -0
- package/lib/async-runner.ts +173 -0
- package/lib/async-runs.ts +302 -53
- package/lib/build-dist.ts +30 -0
- package/lib/command-templates.ts +5 -5
- package/lib/conformance.ts +46 -0
- package/lib/coordinator.ts +649 -0
- package/lib/limits.ts +12 -0
- package/lib/locker.ts +340 -0
- package/lib/mailbox-loop.ts +148 -0
- package/lib/observability.ts +34 -23
- package/lib/output.ts +4 -6
- package/lib/prompts.ts +1 -1
- package/lib/recipe-discovery.ts +1 -0
- package/lib/recipe-references.ts +57 -6
- package/lib/recipe-usage.ts +31 -4
- package/lib/recipe-utils.ts +486 -0
- package/lib/runtime-notifier.ts +4 -6
- package/lib/runtime.ts +31 -7
- package/lib/state-readers.ts +93 -0
- package/lib/tools.ts +297 -58
- package/lib/validate-recipe.ts +110 -0
- package/package.json +11 -2
- package/recipes/actor-worker.json +35 -0
- package/recipes/pipeline-quorum-review.json +12 -7
- package/scripts/actor-worker.mjs +31 -0
- package/scripts/async-runner.mjs +11 -195
- package/scripts/build-dist.mjs +25 -0
- package/scripts/conformance.mjs +33 -0
- package/scripts/coordinator.mjs +19 -616
- package/scripts/locker.mjs +23 -322
- package/scripts/music-player.mjs +21 -2
- package/scripts/recipe-utils.mjs +20 -467
- package/scripts/validate-recipe.mjs +23 -113
- package/skills/actors/SKILL.md +7 -4
- package/skills/swarm/SKILL.md +3 -1
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "actor-worker",
|
|
3
|
+
"path": "recipes/actor-worker.json",
|
|
4
|
+
"location": "packaged",
|
|
5
|
+
"active": true,
|
|
6
|
+
"args": [
|
|
7
|
+
"run",
|
|
8
|
+
"branch",
|
|
9
|
+
"poll_ms",
|
|
10
|
+
"state_dir"
|
|
11
|
+
],
|
|
12
|
+
"mailbox": {
|
|
13
|
+
"kind": "branch",
|
|
14
|
+
"accepts": ["task.assign", "control.stop"]
|
|
15
|
+
}
|
|
16
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -39,6 +39,7 @@ export default function toolRegistryExtension(pi) {
|
|
|
39
39
|
const runDirWatchers = new Map();
|
|
40
40
|
const observedRuns = new Map();
|
|
41
41
|
const observedRunEventLines = new Map();
|
|
42
|
+
const observedRunOutboxEventIds = new Map();
|
|
42
43
|
const retirementAttempts = new Set();
|
|
43
44
|
let runStatusFrame = 0;
|
|
44
45
|
let communicationWidgetVisible = false;
|
|
@@ -49,6 +50,7 @@ export default function toolRegistryExtension(pi) {
|
|
|
49
50
|
let actorInspectorUnreadOnly = false;
|
|
50
51
|
let actorInspectorRoomLimitPerRun = 12;
|
|
51
52
|
let selectedInspectorSequence;
|
|
53
|
+
const actorInspectorReadKeys = new Set();
|
|
52
54
|
let recipeWatcherFailureNotified = false;
|
|
53
55
|
const getRunOwnerId = (ctx) => ctx.sessionManager.getSessionId();
|
|
54
56
|
const retireCandidateRuns = (ctx, summary) => {
|
|
@@ -84,6 +86,7 @@ export default function toolRegistryExtension(pi) {
|
|
|
84
86
|
branch: actorInspectorBranch,
|
|
85
87
|
mention: actorInspectorMention,
|
|
86
88
|
ownerId,
|
|
89
|
+
readKeys: actorInspectorReadKeys,
|
|
87
90
|
roomLimitPerRun: actorInspectorRoomLimitPerRun,
|
|
88
91
|
unreadOnly: actorInspectorUnreadOnly,
|
|
89
92
|
});
|
|
@@ -100,7 +103,7 @@ export default function toolRegistryExtension(pi) {
|
|
|
100
103
|
}
|
|
101
104
|
: undefined, { placement: "belowEditor" });
|
|
102
105
|
const transitions = Observability.detectRunTransitions(observedRuns, summary);
|
|
103
|
-
const outboxEvents = Observability.detectRunOutboxEvents(observedRunEventLines, summary);
|
|
106
|
+
const outboxEvents = Observability.detectRunOutboxEvents(observedRunEventLines, summary, observedRunOutboxEventIds);
|
|
104
107
|
if (!notify)
|
|
105
108
|
return;
|
|
106
109
|
retireCandidateRuns(ctx, summary);
|
|
@@ -119,7 +122,7 @@ export default function toolRegistryExtension(pi) {
|
|
|
119
122
|
details: transition,
|
|
120
123
|
}, { deliverAs: "followUp", triggerTurn: true });
|
|
121
124
|
}
|
|
122
|
-
Observability.pruneRunObservationState(observedRuns, observedRunEventLines, summary, transitions.map((transition) => transition.stateDir ?? transition.run));
|
|
125
|
+
Observability.pruneRunObservationState(observedRuns, observedRunEventLines, summary, transitions.map((transition) => transition.stateDir ?? transition.run), observedRunOutboxEventIds);
|
|
123
126
|
for (const event of outboxEvents) {
|
|
124
127
|
if (!Observability.shouldNotifyRunOutboxEvent(event))
|
|
125
128
|
continue;
|
|
@@ -356,6 +359,19 @@ export default function toolRegistryExtension(pi) {
|
|
|
356
359
|
ctx.ui.notify("Usage: /actors-inspect <number>", "warning");
|
|
357
360
|
return;
|
|
358
361
|
}
|
|
362
|
+
const previews = ActorInspectorTui.readActorInspectorPreviews(RUN_STATE_ROOT, actorInspectorRows, {
|
|
363
|
+
channels: actorInspectorChannels,
|
|
364
|
+
currentRunOnly: true,
|
|
365
|
+
branch: actorInspectorBranch,
|
|
366
|
+
mention: actorInspectorMention,
|
|
367
|
+
ownerId: getRunOwnerId(ctx),
|
|
368
|
+
readKeys: actorInspectorReadKeys,
|
|
369
|
+
roomLimitPerRun: actorInspectorRoomLimitPerRun,
|
|
370
|
+
unreadOnly: actorInspectorUnreadOnly,
|
|
371
|
+
});
|
|
372
|
+
const preview = previews.find((item) => item.sequence === sequence);
|
|
373
|
+
if (preview)
|
|
374
|
+
actorInspectorReadKeys.add(ActorInspectorTui.inspectorPreviewReadKey(preview));
|
|
359
375
|
selectedInspectorSequence = sequence;
|
|
360
376
|
communicationWidgetVisible = true;
|
|
361
377
|
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,34 +5,18 @@
|
|
|
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";
|
|
10
|
+
import { readJsonFileResilient, readJsonlFileResilient } from "./state-readers.js";
|
|
9
11
|
function asRecord(value) {
|
|
10
12
|
return value && typeof value === "object" && !Array.isArray(value)
|
|
11
13
|
? value
|
|
12
14
|
: {};
|
|
13
15
|
}
|
|
14
16
|
function readJsonLines(file) {
|
|
15
|
-
|
|
16
|
-
return fs
|
|
17
|
-
.readFileSync(file, "utf8")
|
|
18
|
-
.split("\n")
|
|
19
|
-
.filter(Boolean)
|
|
20
|
-
.flatMap((line) => {
|
|
21
|
-
try {
|
|
22
|
-
return [JSON.parse(line)];
|
|
23
|
-
}
|
|
24
|
-
catch {
|
|
25
|
-
return [];
|
|
26
|
-
}
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
catch (error) {
|
|
30
|
-
if (error.code === "ENOENT")
|
|
31
|
-
return [];
|
|
32
|
-
return [];
|
|
33
|
-
}
|
|
17
|
+
return readJsonlFileResilient(file).records;
|
|
34
18
|
}
|
|
35
|
-
function previewValue(value, maxLength =
|
|
19
|
+
function previewValue(value, maxLength = Limits.INSPECTOR_BODY_PREVIEW_CHARS) {
|
|
36
20
|
if (value === undefined)
|
|
37
21
|
return undefined;
|
|
38
22
|
const text = typeof value === "string" ? value : JSON.stringify(value);
|
|
@@ -58,6 +42,10 @@ function previewFromMessage(run, message, timestamp, displayNames = {}) {
|
|
|
58
42
|
const from = typeof message.from === "string" ? message.from : undefined;
|
|
59
43
|
const summary = typeof message.summary === "string" ? message.summary : undefined;
|
|
60
44
|
const body = asRecord(message.body);
|
|
45
|
+
const metadata = asRecord(message.metadata);
|
|
46
|
+
const eventId = typeof message.id === "string" && message.id.trim()
|
|
47
|
+
? message.id.trim()
|
|
48
|
+
: undefined;
|
|
61
49
|
const display = from
|
|
62
50
|
? typeof body.display === "string" && body.display.trim()
|
|
63
51
|
? body.display.trim()
|
|
@@ -68,8 +56,10 @@ function previewFromMessage(run, message, timestamp, displayNames = {}) {
|
|
|
68
56
|
? { body_preview: previewValue(message.body) }
|
|
69
57
|
: {}),
|
|
70
58
|
channel: channelFor({ to }),
|
|
59
|
+
...(eventId ? { event_id: eventId } : {}),
|
|
71
60
|
...(from ? { from } : {}),
|
|
72
61
|
...(display ? { from_display: display } : {}),
|
|
62
|
+
...(metadata.requires_response === true ? { needs_response: true } : {}),
|
|
73
63
|
run,
|
|
74
64
|
...(summary ? { summary } : {}),
|
|
75
65
|
timestamp,
|
|
@@ -78,12 +68,7 @@ function previewFromMessage(run, message, timestamp, displayNames = {}) {
|
|
|
78
68
|
};
|
|
79
69
|
}
|
|
80
70
|
function readRoomRosterRecords(stateDir, room) {
|
|
81
|
-
|
|
82
|
-
return JSON.parse(fs.readFileSync(path.join(stateDir, "rooms", room, "roster.json"), "utf8"));
|
|
83
|
-
}
|
|
84
|
-
catch {
|
|
85
|
-
return {};
|
|
86
|
-
}
|
|
71
|
+
return readJsonFileResilient(path.join(stateDir, "rooms", room, "roster.json"), {}).value;
|
|
87
72
|
}
|
|
88
73
|
function memberDisplay(_address, member) {
|
|
89
74
|
const display = typeof member.display === "string" ? member.display.trim() : "";
|
|
@@ -129,14 +114,21 @@ function readBranchInboxPreviews(run, stateDir) {
|
|
|
129
114
|
.filter((entry) => entry.isDirectory())
|
|
130
115
|
.flatMap((entry) => readJsonLines(path.join(branchesDir, entry.name, "inbox.jsonl"))
|
|
131
116
|
.map((message) => {
|
|
132
|
-
const preview = previewFromMessage(run, message, String(message.queued_at ??
|
|
117
|
+
const preview = previewFromMessage(run, message, String(message.queued_at ??
|
|
118
|
+
message.received_at ??
|
|
119
|
+
message.timestamp ??
|
|
120
|
+
""));
|
|
133
121
|
if (!preview)
|
|
134
122
|
return undefined;
|
|
135
123
|
return {
|
|
136
124
|
...preview,
|
|
137
125
|
branch: entry.name,
|
|
138
|
-
...(typeof message.id === "string"
|
|
139
|
-
|
|
126
|
+
...(typeof message.id === "string"
|
|
127
|
+
? { message_id: message.id }
|
|
128
|
+
: {}),
|
|
129
|
+
...(typeof message.status === "string"
|
|
130
|
+
? { inbox_status: message.status }
|
|
131
|
+
: {}),
|
|
140
132
|
};
|
|
141
133
|
})
|
|
142
134
|
.filter((preview) => Boolean(preview)));
|
|
@@ -156,19 +148,28 @@ function readOutboxPreviews(run, stateDir) {
|
|
|
156
148
|
.filter((preview) => Boolean(preview));
|
|
157
149
|
}
|
|
158
150
|
function getRunOwnerId(stateDir) {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
return typeof meta.ownerId === "string" ? meta.ownerId : undefined;
|
|
162
|
-
}
|
|
163
|
-
catch {
|
|
164
|
-
return undefined;
|
|
165
|
-
}
|
|
151
|
+
const meta = readJsonFileResilient(path.join(stateDir, "run.json"), undefined).value;
|
|
152
|
+
return typeof meta?.ownerId === "string" ? meta.ownerId : undefined;
|
|
166
153
|
}
|
|
167
154
|
function matchesOwner(stateDir, ownerId) {
|
|
168
155
|
return ownerId === undefined || getRunOwnerId(stateDir) === ownerId;
|
|
169
156
|
}
|
|
170
|
-
function
|
|
171
|
-
return
|
|
157
|
+
export function inspectorPreviewReadKey(preview) {
|
|
158
|
+
return [
|
|
159
|
+
preview.channel,
|
|
160
|
+
preview.run,
|
|
161
|
+
preview.branch ?? "",
|
|
162
|
+
preview.event_id ?? preview.message_id ?? preview.timestamp,
|
|
163
|
+
preview.from ?? "",
|
|
164
|
+
preview.to,
|
|
165
|
+
preview.type,
|
|
166
|
+
].join("|");
|
|
167
|
+
}
|
|
168
|
+
function isUnreadPreview(preview, readKeys) {
|
|
169
|
+
if (readKeys?.has(inspectorPreviewReadKey(preview)))
|
|
170
|
+
return false;
|
|
171
|
+
return (preview.inbox_status === "queued" ||
|
|
172
|
+
(preview.inbox_status === undefined && preview.branch !== undefined));
|
|
172
173
|
}
|
|
173
174
|
function matchesBranchFilter(preview, branch) {
|
|
174
175
|
const name = branch?.trim();
|
|
@@ -183,7 +184,8 @@ function matchesPreviewFilter(preview, options) {
|
|
|
183
184
|
if (options.channels?.length && !options.channels.includes(preview.channel)) {
|
|
184
185
|
return false;
|
|
185
186
|
}
|
|
186
|
-
|
|
187
|
+
const readKeys = options.readKeys ? new Set(options.readKeys) : undefined;
|
|
188
|
+
if (options.unreadOnly && !isUnreadPreview(preview, readKeys))
|
|
187
189
|
return false;
|
|
188
190
|
if (!matchesBranchFilter(preview, options.branch))
|
|
189
191
|
return false;
|
|
@@ -298,6 +300,9 @@ function routeText(preview) {
|
|
|
298
300
|
return `${actor} ⇢ ${preview.to}`;
|
|
299
301
|
return `${actor} → ${actorName(preview.to)}`;
|
|
300
302
|
}
|
|
303
|
+
function attentionMarker(preview) {
|
|
304
|
+
return preview.needs_response ? "! " : "";
|
|
305
|
+
}
|
|
301
306
|
function style(styleFn, text) {
|
|
302
307
|
return styleFn ? styleFn(text) : text;
|
|
303
308
|
}
|
|
@@ -351,7 +356,7 @@ function renderCompactInspectorEntry(preview, width, sequenceWidth, routeWidth,
|
|
|
351
356
|
const contentWidth = Math.max(8, width - prefix.length - suffix.length);
|
|
352
357
|
const sequence = String(preview.sequence ?? 0).padStart(sequenceWidth, " ");
|
|
353
358
|
const sequencePrefix = `${sequence}${separator}`;
|
|
354
|
-
const route = routeText(preview)
|
|
359
|
+
const route = `${attentionMarker(preview)}${routeText(preview)}`;
|
|
355
360
|
const routePadding = " ".repeat(Math.max(0, routeWidth - displayWidth(route)));
|
|
356
361
|
const typePadding = " ".repeat(Math.max(0, typeWidth - displayWidth(preview.type)));
|
|
357
362
|
const headline = previewText(preview);
|
|
@@ -382,7 +387,7 @@ function renderInspectorEntry(preview, width, sequenceWidth, routeWidth, typeWid
|
|
|
382
387
|
const contentWidth = Math.max(8, width - prefix.length - suffix.length);
|
|
383
388
|
const sequence = String(preview.sequence ?? 0).padStart(sequenceWidth, " ");
|
|
384
389
|
const sequencePrefix = `${sequence}${separator}`;
|
|
385
|
-
const route = routeText(preview)
|
|
390
|
+
const route = `${attentionMarker(preview)}${routeText(preview)}`;
|
|
386
391
|
const type = preview.type;
|
|
387
392
|
const summary = preview.summary?.trim() ?? "";
|
|
388
393
|
const body = preview.body_preview?.trim() || (!summary ? previewText(preview) : "-");
|
|
@@ -430,7 +435,10 @@ export function readActorInspectorRoster(stateRoot = Paths.getRunStateRoot(), ru
|
|
|
430
435
|
}
|
|
431
436
|
function rosterRoleText(role) {
|
|
432
437
|
const roleLabel = role?.split(";")[0] ?? "";
|
|
433
|
-
const cleaned = roleLabel
|
|
438
|
+
const cleaned = roleLabel
|
|
439
|
+
.replaceAll(/\s*\([^)]*\)\s*$/g, "")
|
|
440
|
+
.trim()
|
|
441
|
+
.toLowerCase();
|
|
434
442
|
if (!cleaned || cleaned === "actor")
|
|
435
443
|
return undefined;
|
|
436
444
|
return cleaned.replaceAll(/\s+/g, "-");
|
|
@@ -444,7 +452,10 @@ function rosterMemberText(member) {
|
|
|
444
452
|
}
|
|
445
453
|
function isRosterMemberActive(member) {
|
|
446
454
|
const status = member.status?.trim().toLowerCase();
|
|
447
|
-
return !status ||
|
|
455
|
+
return (!status ||
|
|
456
|
+
status === "present" ||
|
|
457
|
+
status === "active" ||
|
|
458
|
+
status === "running");
|
|
448
459
|
}
|
|
449
460
|
export function renderInspectorRosterLine(members, width = 80, styles = {}) {
|
|
450
461
|
return renderInspectorRosterPanel(members, width, styles)?.[0];
|
|
@@ -491,12 +502,15 @@ export function renderInspectorItemView(previews, width = 80, styles = {}, optio
|
|
|
491
502
|
const orderedKeys = [
|
|
492
503
|
"channel",
|
|
493
504
|
"run",
|
|
505
|
+
"event_id",
|
|
494
506
|
"from",
|
|
495
507
|
"from_display",
|
|
496
508
|
"to",
|
|
497
509
|
"type",
|
|
498
510
|
"summary",
|
|
499
511
|
"body_preview",
|
|
512
|
+
"message_id",
|
|
513
|
+
"needs_response",
|
|
500
514
|
"timestamp",
|
|
501
515
|
"stripe",
|
|
502
516
|
];
|
|
@@ -540,7 +554,7 @@ export function renderInspectorWidget(previews, width = 80, styles = {}, options
|
|
|
540
554
|
const sequencePrefixWidth = sequenceWidth + separatorWidth;
|
|
541
555
|
const fixedSeparatorsWidth = separatorWidth * 3;
|
|
542
556
|
const availableForColumns = Math.max(0, safeWidth - 1 - sequencePrefixWidth - fixedSeparatorsWidth);
|
|
543
|
-
const naturalRouteWidth = Math.max(...visible.map(({ preview }) => displayWidth(routeText(preview))));
|
|
557
|
+
const naturalRouteWidth = Math.max(...visible.map(({ preview }) => displayWidth(`${attentionMarker(preview)}${routeText(preview)}`)));
|
|
544
558
|
const naturalTypeWidth = Math.max(...visible.map(({ preview }) => displayWidth(preview.type)));
|
|
545
559
|
const routeWidth = Math.min(naturalRouteWidth, Math.max(4, Math.floor(availableForColumns * 0.35)));
|
|
546
560
|
const typeWidth = Math.min(naturalTypeWidth, Math.max(4, Math.floor(availableForColumns * 0.25)));
|
|
@@ -32,10 +32,20 @@ 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;
|
|
47
|
+
diagnostics?: string[];
|
|
48
|
+
diagnostics_count?: number;
|
|
39
49
|
last_message_at?: string;
|
|
40
50
|
last_message_from?: string;
|
|
41
51
|
last_message_summary?: string;
|
|
@@ -63,6 +73,11 @@ export interface ActorCommunicationSnapshot {
|
|
|
63
73
|
}
|
|
64
74
|
export declare function readRoomRoster(stateDir: string, room: string): Record<string, RoomMember>;
|
|
65
75
|
export interface BranchInboxRecord extends ActorMessage {
|
|
76
|
+
claimed_at?: string;
|
|
77
|
+
claimed_by?: string;
|
|
78
|
+
error?: string;
|
|
79
|
+
failed_at?: string;
|
|
80
|
+
handled_at?: string;
|
|
66
81
|
id?: string;
|
|
67
82
|
queued_at?: string;
|
|
68
83
|
status?: string;
|
|
@@ -75,6 +90,7 @@ export declare function readBranchInboxMessages(stateDir: string, run: string, a
|
|
|
75
90
|
export declare function readBranchInboxDiagnostics(stateDir: string, run: string, address: string, limit?: number): BranchInboxReadResult;
|
|
76
91
|
export declare function getBranchInboxTerminalRetainLimit(): number;
|
|
77
92
|
export declare function appendBranchInboxMessage(stateDir: string, run: string, address: string, message: ActorMessage): void;
|
|
93
|
+
export declare function claimBranchInboxMessage(stateDir: string, run: string, address: string, owner?: string, statuses?: string[]): BranchInboxRecord | undefined;
|
|
78
94
|
export declare function updateBranchInboxMessageStatus(stateDir: string, run: string, address: string, id: string, status: "claimed" | "handled" | "failed", metadata?: Record<string, unknown>): boolean;
|
|
79
95
|
export declare function appendRoomMessage(stateDir: string, room: string, message: ActorMessage): RoomAppendResult;
|
|
80
96
|
export declare function readRoomMessages(stateDir: string, room: string, limit?: number): RoomTimelineEntry[];
|