@haywoodmarx/agent-pager 0.1.3 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/dist/src/broker/address.d.ts +7 -0
- package/dist/src/broker/address.js +9 -0
- package/dist/src/broker/broker.d.ts +112 -24
- package/dist/src/broker/broker.js +604 -132
- package/dist/src/broker/operator-projection.d.ts +22 -0
- package/dist/src/broker/operator-projection.js +43 -5
- package/dist/src/broker/protocol.d.ts +1 -1
- package/dist/src/broker/protocol.js +1 -1
- package/dist/src/broker/schema.d.ts +4 -0
- package/dist/src/broker/schema.js +20 -8
- package/dist/src/broker/snapshot.d.ts +4 -2
- package/dist/src/implementations/claude/gateway-cli.js +1 -2
- package/dist/src/implementations/claude/gateway.d.ts +11 -4
- package/dist/src/implementations/claude/gateway.js +44 -14
- package/dist/src/implementations/claude/instructions.js +1 -1
- package/dist/src/implementations/model.d.ts +6 -3
- package/dist/src/implementations/opencode/plugin.d.ts +7 -2
- package/dist/src/implementations/opencode/plugin.js +103 -7
- package/dist/src/implementations/pi/broker-client.d.ts +13 -4
- package/dist/src/implementations/pi/broker-client.js +71 -9
- package/dist/src/implementations/pi/extension.d.ts +7 -2
- package/dist/src/implementations/pi/extension.js +15 -3
- package/dist/src/index.d.ts +2 -2
- package/dist/src/index.js +2 -2
- package/dist/src/launch/broker-lock.d.ts +58 -4
- package/dist/src/launch/broker-lock.js +140 -7
- package/dist/src/launch/launch.d.ts +1 -1
- package/dist/src/launch/on-demand.d.ts +8 -8
- package/dist/src/launch/on-demand.js +54 -35
- package/dist/src/launch/runtime-composition.js +2 -0
- package/dist/src/launch/runtime.js +4 -14
- package/dist/src/launch/service.d.ts +1 -0
- package/dist/src/launch/service.js +23 -1
- package/dist/src/launch/workspace-branch.d.ts +3 -3
- package/dist/src/launch/workspace-branch.js +7 -15
- package/dist/src/launch/workspace-root.d.ts +13 -0
- package/dist/src/launch/workspace-root.js +27 -0
- package/dist/src/messaging/delivery-client.d.ts +17 -0
- package/dist/src/messaging/delivery-client.js +31 -1
- package/dist/src/messaging/identity-statement.d.ts +7 -0
- package/dist/src/messaging/identity-statement.js +8 -0
- package/dist/src/messaging/mcp.d.ts +8 -2
- package/dist/src/messaging/mcp.js +54 -1
- package/dist/src/messaging/notifications.d.ts +31 -3
- package/dist/src/messaging/notifications.js +25 -0
- package/dist/src/messaging/push-delivery.d.ts +2 -1
- package/dist/src/messaging/push-delivery.js +24 -7
- package/dist/src/messaging/tools.js +22 -2
- package/dist/src/messaging/wake.js +7 -0
- package/dist/src/operator/agent-projection.d.ts +8 -5
- package/dist/src/operator/agent-projection.js +29 -9
- package/dist/src/operator/commands.d.ts +2 -0
- package/dist/src/operator/commands.js +57 -21
- package/dist/src/operator/protocol.d.ts +34 -2
- package/dist/src/operator/protocol.js +9 -0
- package/dist/src/operator/repository-system.d.ts +29 -0
- package/dist/src/operator/repository-system.js +39 -12
- package/dist/src/operator/repository.d.ts +28 -11
- package/dist/src/operator/repository.js +37 -4
- package/dist/src/operator/transport.js +10 -5
- package/dist/src/operator/updates.js +7 -1
- package/dist/src/operator/validation.js +35 -1
- package/dist/src/shared/versions.d.ts +18 -0
- package/dist/src/shared/versions.js +26 -0
- package/dist/src/tui/agent-tree.d.ts +8 -5
- package/dist/src/tui/agent-tree.js +195 -22
- package/dist/src/tui/app.js +6 -2
- package/dist/src/tui/message-views.js +4 -3
- package/dist/src/tui/model.d.ts +25 -1
- package/dist/src/tui/model.js +33 -9
- package/dist/src/tui/presentation.d.ts +11 -2
- package/dist/src/tui/presentation.js +26 -4
- package/dist/src/version.d.ts +7 -0
- package/dist/src/version.js +14 -6
- package/package.json +1 -1
- package/skills/pager/SKILL.md +35 -45
|
@@ -119,12 +119,21 @@ export declare function formatDiagnostic(diagnostic: OperatorDiagnostic, width:
|
|
|
119
119
|
* An answer is admission, not the resulting state change, so an accepted command is worded as
|
|
120
120
|
* accepted. A command that got no answer at all is worded as unknown, because the broker may have
|
|
121
121
|
* applied it.
|
|
122
|
-
* @param
|
|
122
|
+
* @param target - What the command acted on, as `describeCommandTarget` named it when the command was submitted.
|
|
123
123
|
* @param command - Command the operator submitted.
|
|
124
124
|
* @param result - The broker's admission answer, or null when none came back.
|
|
125
125
|
* @returns Severity and content-free summary for the log row.
|
|
126
126
|
*/
|
|
127
|
-
export declare function describeCommandOutcome(
|
|
127
|
+
export declare function describeCommandOutcome(target: string, command: OperatorCommand, result: OperatorCommandResult | null): Pick<OperatorDiagnostic, "severity" | "summary">;
|
|
128
|
+
/**
|
|
129
|
+
* Name what one operator command acts on, in the words the diagnostics log uses.
|
|
130
|
+
*
|
|
131
|
+
* Read at submission: a purge removes its agents from the projection before its answer arrives.
|
|
132
|
+
* @param state - Current projection, which names the agents a command targets while they remain in it.
|
|
133
|
+
* @param command - Command the operator is submitting.
|
|
134
|
+
* @returns - The message id, the agent handle, or the number of agents a multi-agent purge names.
|
|
135
|
+
*/
|
|
136
|
+
export declare function describeCommandTarget(state: TuiOperatorModelState, command: OperatorCommand): string;
|
|
128
137
|
/**
|
|
129
138
|
* Select the colour role one diagnostic severity carries.
|
|
130
139
|
* @param severity - Attention the condition asks for.
|
|
@@ -135,20 +135,42 @@ export function formatDiagnostic(diagnostic, width) {
|
|
|
135
135
|
* An answer is admission, not the resulting state change, so an accepted command is worded as
|
|
136
136
|
* accepted. A command that got no answer at all is worded as unknown, because the broker may have
|
|
137
137
|
* applied it.
|
|
138
|
-
* @param
|
|
138
|
+
* @param target - What the command acted on, as `describeCommandTarget` named it when the command was submitted.
|
|
139
139
|
* @param command - Command the operator submitted.
|
|
140
140
|
* @param result - The broker's admission answer, or null when none came back.
|
|
141
141
|
* @returns Severity and content-free summary for the log row.
|
|
142
142
|
*/
|
|
143
|
-
export function describeCommandOutcome(
|
|
144
|
-
const verb = { ping_agent: "ping", archive_agent: "archive", expire_message: "expire" }[command.type];
|
|
143
|
+
export function describeCommandOutcome(target, command, result) {
|
|
144
|
+
const verb = { ping_agent: "ping", archive_agent: "archive", expire_message: "expire", purge_agents: "purge" }[command.type];
|
|
145
145
|
if (result === null)
|
|
146
146
|
return { severity: "error", summary: `${verb} outcome unknown: no answer came back from the broker` };
|
|
147
147
|
if (result.status === "rejected")
|
|
148
148
|
return { severity: "warning", summary: `${verb} refused: ${result.reason}` };
|
|
149
|
-
const target = command.type === "expire_message" ? command.messageId : agentHandle(state, command.targetAgentId);
|
|
150
149
|
return { severity: "info", summary: `${verb} accepted for ${target}` };
|
|
151
150
|
}
|
|
151
|
+
/**
|
|
152
|
+
* Name what one operator command acts on, in the words the diagnostics log uses.
|
|
153
|
+
*
|
|
154
|
+
* Read at submission: a purge removes its agents from the projection before its answer arrives.
|
|
155
|
+
* @param state - Current projection, which names the agents a command targets while they remain in it.
|
|
156
|
+
* @param command - Command the operator is submitting.
|
|
157
|
+
* @returns - The message id, the agent handle, or the number of agents a multi-agent purge names.
|
|
158
|
+
*/
|
|
159
|
+
export function describeCommandTarget(state, command) {
|
|
160
|
+
switch (command.type) {
|
|
161
|
+
case "expire_message":
|
|
162
|
+
return command.messageId;
|
|
163
|
+
case "ping_agent":
|
|
164
|
+
case "archive_agent":
|
|
165
|
+
return agentHandle(state, command.targetAgentId);
|
|
166
|
+
case "purge_agents": {
|
|
167
|
+
const [only] = command.targetAgentIds;
|
|
168
|
+
return command.targetAgentIds.length === 1 && only !== undefined
|
|
169
|
+
? agentHandle(state, only)
|
|
170
|
+
: `${String(command.targetAgentIds.length)} agents`;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
152
174
|
/**
|
|
153
175
|
* Select the colour role one diagnostic severity carries.
|
|
154
176
|
* @param severity - Attention the condition asks for.
|
package/dist/src/version.d.ts
CHANGED
|
@@ -9,3 +9,10 @@
|
|
|
9
9
|
export declare function manifestVersion(contents: string, source: string): string;
|
|
10
10
|
/** Names the published package version, read once from the nearest `package.json`. */
|
|
11
11
|
export declare const PAGER_VERSION: string;
|
|
12
|
+
/**
|
|
13
|
+
* Reports whether this code runs from a git checkout, detected by a `.git` entry beside
|
|
14
|
+
* `package.json`, which a published tarball never carries.
|
|
15
|
+
*
|
|
16
|
+
* A checkout's version names its last release, not the unreleased code it runs.
|
|
17
|
+
*/
|
|
18
|
+
export declare const PAGER_SOURCE_CHECKOUT: boolean;
|
package/dist/src/version.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
import { isPlainObject } from "./shared/guards.js";
|
|
@@ -24,19 +24,19 @@ export function manifestVersion(contents, source) {
|
|
|
24
24
|
return parsed.version;
|
|
25
25
|
}
|
|
26
26
|
/**
|
|
27
|
-
*
|
|
27
|
+
* Find the nearest `package.json` above this file and read the version it declares.
|
|
28
28
|
*
|
|
29
29
|
* Walks up rather than using one fixed relative path: this module runs both directly from `src/`
|
|
30
30
|
* (Bun executing TypeScript unbuilt) and from the compiled `dist/src/` tree, one directory deeper, so
|
|
31
31
|
* no single relative path reaches `package.json` in both.
|
|
32
|
-
* @returns - The
|
|
32
|
+
* @returns - The directory holding that `package.json`, and its version field.
|
|
33
33
|
*/
|
|
34
|
-
function
|
|
34
|
+
function readPackage() {
|
|
35
35
|
let directory = dirname(fileURLToPath(import.meta.url));
|
|
36
36
|
for (;;) {
|
|
37
37
|
try {
|
|
38
38
|
const path = join(directory, "package.json");
|
|
39
|
-
return manifestVersion(readFileSync(path, "utf8"), path);
|
|
39
|
+
return { root: directory, version: manifestVersion(readFileSync(path, "utf8"), path) };
|
|
40
40
|
}
|
|
41
41
|
catch (error) {
|
|
42
42
|
if (!(typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT"))
|
|
@@ -48,5 +48,13 @@ function readPackageVersion() {
|
|
|
48
48
|
directory = parent;
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
|
+
const PACKAGE = readPackage();
|
|
51
52
|
/** Names the published package version, read once from the nearest `package.json`. */
|
|
52
|
-
export const PAGER_VERSION =
|
|
53
|
+
export const PAGER_VERSION = PACKAGE.version;
|
|
54
|
+
/**
|
|
55
|
+
* Reports whether this code runs from a git checkout, detected by a `.git` entry beside
|
|
56
|
+
* `package.json`, which a published tarball never carries.
|
|
57
|
+
*
|
|
58
|
+
* A checkout's version names its last release, not the unreleased code it runs.
|
|
59
|
+
*/
|
|
60
|
+
export const PAGER_SOURCE_CHECKOUT = existsSync(join(PACKAGE.root, ".git"));
|
package/package.json
CHANGED
package/skills/pager/SKILL.md
CHANGED
|
@@ -5,18 +5,17 @@ description: Send and receive durable messages between agents over the Pager MCP
|
|
|
5
5
|
|
|
6
6
|
# Pager
|
|
7
7
|
|
|
8
|
+
This skill covers receiving and acknowledging messages, your identity, sending, and what each error code asks you to do.
|
|
9
|
+
|
|
8
10
|
## When a message arrives
|
|
9
11
|
|
|
10
|
-
Pager delivers to your session
|
|
12
|
+
Pager delivers to your session in one of two forms:
|
|
11
13
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
└─ a body-free line beginning "pager-inbox" with reason "operator_ping"
|
|
18
|
-
└─ a human pinged you. Nothing to fetch
|
|
19
|
-
```
|
|
14
|
+
- A delivery whose first line is `pager push` carries messages already claimed for you, each with its `claimToken`. Acknowledge them, then do the work.
|
|
15
|
+
- A body-free line beginning `pager-inbox` with reason `operator_ping` means a human pinged you. There is nothing to fetch.
|
|
16
|
+
- A body-free line beginning `pager-inbox` with reason `session_claimed` means another session took your alias over and ended your session. Your next call runs as a fresh identity. There is nothing to fetch, and messages for the old alias now go to the new holder.
|
|
17
|
+
|
|
18
|
+
The calls:
|
|
20
19
|
|
|
21
20
|
```jsonc
|
|
22
21
|
// only to recover a claim_expired message: fetch_agent_messages { "limit": 50 } →
|
|
@@ -40,34 +39,27 @@ A token in `rejected` acknowledged nothing. Its `reason` says what to do:
|
|
|
40
39
|
| `foreign_token` | The token belongs to another agent. Ack only tokens delivered to you |
|
|
41
40
|
| `unknown_token` | No such token. Check that it was copied whole from the claim |
|
|
42
41
|
|
|
43
|
-
Ack as soon as you hold a message, within 5 minutes, or
|
|
44
|
-
yours to act on, not finished. Redelivery backs off and gives up after 24 hours from that message's
|
|
45
|
-
arrival: one still unclaimed past that budget is dead-lettered, with no wake to the recipient.
|
|
42
|
+
Ack as soon as you hold a message, within 5 minutes, or the broker redelivers it. An ack means the message is received and yours to act on, not that the work is finished. The broker retries redelivery with growing delays for up to 24 hours from the message's arrival. It dead-letters a message still unclaimed after that, without waking the recipient.
|
|
46
43
|
|
|
47
|
-
A message carrying `to: *@workspace
|
|
48
|
-
that workspace's agents. A reply to its `fromAddress` reaches the sender alone.
|
|
44
|
+
A message carrying `to: *@workspace`, shown as `broadcastAddress` in a fetch, is one copy of a broadcast to that workspace's agents. A reply to its `fromAddress` reaches the sender alone.
|
|
49
45
|
|
|
50
|
-
##
|
|
46
|
+
## Your identity and alias
|
|
51
47
|
|
|
52
|
-
`whoami`
|
|
48
|
+
Call `whoami` for the address an agent in another workspace uses to reach you.
|
|
53
49
|
|
|
54
|
-
`update_agent_alias` replaces your alias and durable session name
|
|
55
|
-
the alias is taken. Prior names stay reserved, so a stale sender gets `recipient_alias_changed` rather
|
|
56
|
-
than a silent redirect.
|
|
50
|
+
`update_agent_alias` replaces your alias and durable session name. `move_to_workspace` moves you into another workspace, named as `list_agents` reports it or as an absolute directory, with an optional new alias. Both fail with `alias_conflict` naming the holder when the alias is taken there. Pass `force` only when that holder is your own earlier session. You take its identity over, it is told, and its session ends, so its next call runs as a fresh unnamed agent. Every name and address you held stays reserved, so a stale sender gets `recipient_alias_changed` rather than a silent redirect.
|
|
57
51
|
|
|
58
|
-
## Sending
|
|
52
|
+
## Sending a message
|
|
59
53
|
|
|
60
|
-
|
|
61
|
-
workspace explicitly — your own or another's.
|
|
54
|
+
Your workspace is your Git repository, so agents in its other worktrees are in it too. Choose the address by who you are addressing:
|
|
62
55
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
```
|
|
56
|
+
- Answering a message: its `from` or `fromAddress`. There is no reply tool.
|
|
57
|
+
- An id or address a listing gave you: send it back verbatim.
|
|
58
|
+
- An agent in your own workspace: its alias.
|
|
59
|
+
- An agent in another workspace: `alias@workspace`.
|
|
60
|
+
- Every agent in a workspace: `broadcast_agent_message`.
|
|
61
|
+
|
|
62
|
+
The calls:
|
|
71
63
|
|
|
72
64
|
```jsonc
|
|
73
65
|
// send_agent_message
|
|
@@ -82,31 +74,29 @@ Who are you addressing?
|
|
|
82
74
|
// → { "address": "*@web-app", "sent": [{ "messageId": "msg_…", "to": "pgr://agent/…" }], "refused": [] }
|
|
83
75
|
```
|
|
84
76
|
|
|
85
|
-
A broadcast skips archived agents and ended ephemeral sessions. Each entry in `refused` is a
|
|
86
|
-
recipient a rate or inbox limit turned away, with the error `code` the table below explains; the rest
|
|
87
|
-
still received it.
|
|
77
|
+
A broadcast skips archived agents and ended ephemeral sessions. Each entry in `refused` is a recipient that a rate or inbox limit turned away, with an error `code` from the error code table. Every other recipient received the message.
|
|
88
78
|
|
|
89
|
-
- `list_team_members` lists your workspace
|
|
90
|
-
- `subject` is required and capped at 40 characters. Write it like a commit summary
|
|
91
|
-
- `type` is required free text capped at 8 characters,
|
|
92
|
-
- The broker treats `body` as opaque
|
|
93
|
-
-
|
|
79
|
+
- `list_team_members` lists your workspace. `list_agents` lists every agent with the `address` that reaches it.
|
|
80
|
+
- `subject` is required and capped at 40 characters. Write it like a commit summary, because the operator scans a column of them, and put the detail in `body`.
|
|
81
|
+
- `type` is required free text capped at 8 characters, naming a coarse category such as `"brief"`, `"idle"` or `"status"`. The broker enforces no fixed vocabulary. The recipient sees it in the claim, and the operator sees it in their views.
|
|
82
|
+
- The broker treats `body` as opaque text. Write the detail itself in plain sentences, not a structured envelope.
|
|
83
|
+
- `body` is capped at 12 KB. Send a path or an id, not a file's contents.
|
|
94
84
|
- Add `idempotencyKey` on any send you might retry.
|
|
95
|
-
- `get_message_status { messageId }`
|
|
85
|
+
- Call `get_message_status { messageId }` to check a message you sent.
|
|
96
86
|
|
|
97
|
-
##
|
|
87
|
+
## Error codes
|
|
98
88
|
|
|
99
89
|
| Code | Do |
|
|
100
90
|
| ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
101
91
|
| `unknown_recipient` | `list_agents`, then use a listed `address`. Do not retry the same one |
|
|
102
|
-
| `recipient_alias_changed` | Resend to the
|
|
103
|
-
| `alias_conflict` | Requested alias is taken in
|
|
92
|
+
| `recipient_alias_changed` | Resend to the address named in the error |
|
|
93
|
+
| `alias_conflict` | Requested alias is taken in that workspace, or is a previous name reserved for its old holder. Pick another, or `force` if it is your own |
|
|
104
94
|
| `conflict` | Rate (60/min per pair) or inbox (1000) limit: back off, do not loop. Any other cause: the request cannot succeed as sent, so read the message |
|
|
105
95
|
| `oversized_content` | The named field (body, subject, or type) exceeds its limit; shorten that field |
|
|
106
96
|
| `validation_failed` | The error message names the cause (a field, an unknown id, a malformed request); read it, do not retry unchanged |
|
|
107
97
|
|
|
108
|
-
## Never
|
|
98
|
+
## Never do these
|
|
109
99
|
|
|
110
|
-
- Poll `fetch_agent_messages` on a timer
|
|
100
|
+
- Poll `fetch_agent_messages` on a timer. The broker delivers messages to you.
|
|
111
101
|
- Ack a message you have not read.
|
|
112
|
-
- Put tokens, credentials, or reservations in a body.
|
|
102
|
+
- Put tokens, credentials, or reservations in a body. Operator tools show bodies.
|