@oh-hai/cli 0.2.3 → 0.3.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/CHANGELOG.md +125 -0
- package/README.md +59 -29
- package/dist/commands/ask.js +71 -10
- package/dist/commands/ask.js.map +1 -1
- package/dist/commands/bridge.d.ts +2 -0
- package/dist/commands/bridge.js +502 -0
- package/dist/commands/bridge.js.map +1 -0
- package/dist/commands/context.d.ts +22 -0
- package/dist/commands/doctor.js +12 -1
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/fleet.d.ts +2 -0
- package/dist/commands/fleet.js +164 -0
- package/dist/commands/fleet.js.map +1 -0
- package/dist/commands/handlers.js +8 -0
- package/dist/commands/handlers.js.map +1 -1
- package/dist/commands/messages.d.ts +2 -0
- package/dist/commands/messages.js +131 -0
- package/dist/commands/messages.js.map +1 -0
- package/dist/commands/messaging/build.d.ts +10 -1
- package/dist/commands/messaging/build.js +22 -4
- package/dist/commands/messaging/build.js.map +1 -1
- package/dist/commands/messaging/capability.d.ts +42 -0
- package/dist/commands/messaging/capability.js +164 -0
- package/dist/commands/messaging/capability.js.map +1 -0
- package/dist/commands/messaging/http.d.ts +28 -1
- package/dist/commands/messaging/http.js +234 -13
- package/dist/commands/messaging/http.js.map +1 -1
- package/dist/commands/messaging/inbox-entries.d.ts +83 -0
- package/dist/commands/messaging/inbox-entries.js +371 -0
- package/dist/commands/messaging/inbox-entries.js.map +1 -0
- package/dist/commands/messaging/inbox-stream.d.ts +37 -0
- package/dist/commands/messaging/inbox-stream.js +224 -0
- package/dist/commands/messaging/inbox-stream.js.map +1 -0
- package/dist/commands/messaging/session-drain.d.ts +50 -0
- package/dist/commands/messaging/session-drain.js +163 -0
- package/dist/commands/messaging/session-drain.js.map +1 -0
- package/dist/commands/messaging/session-scope.d.ts +93 -0
- package/dist/commands/messaging/session-scope.js +0 -0
- package/dist/commands/messaging/session-scope.js.map +1 -0
- package/dist/commands/messaging/sessions-http.d.ts +20 -0
- package/dist/commands/messaging/sessions-http.js +153 -0
- package/dist/commands/messaging/sessions-http.js.map +1 -0
- package/dist/commands/messaging/shared.d.ts +19 -1
- package/dist/commands/messaging/shared.js +69 -2
- package/dist/commands/messaging/shared.js.map +1 -1
- package/dist/commands/messaging/validate.d.ts +33 -1
- package/dist/commands/messaging/validate.js +78 -0
- package/dist/commands/messaging/validate.js.map +1 -1
- package/dist/commands/messaging/wire.d.ts +180 -3
- package/dist/commands/notify.js +47 -5
- package/dist/commands/notify.js.map +1 -1
- package/dist/commands/registry.js +128 -3
- package/dist/commands/registry.js.map +1 -1
- package/dist/commands/self-test.d.ts +17 -0
- package/dist/commands/self-test.js +472 -0
- package/dist/commands/self-test.js.map +1 -0
- package/dist/commands/session.d.ts +2 -0
- package/dist/commands/session.js +158 -0
- package/dist/commands/session.js.map +1 -0
- package/dist/commands/setup.js +44 -0
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/task.js +61 -11
- package/dist/commands/task.js.map +1 -1
- package/dist/commands/teach.js +84 -4
- package/dist/commands/teach.js.map +1 -1
- package/dist/commands/whoami.js +14 -1
- package/dist/commands/whoami.js.map +1 -1
- package/dist/exit-codes.d.ts +37 -1
- package/dist/exit-codes.js +42 -1
- package/dist/exit-codes.js.map +1 -1
- package/dist/help.js +5 -1
- package/dist/help.js.map +1 -1
- package/dist/watch-lock.js +7 -0
- package/dist/watch-lock.js.map +1 -1
- package/package.json +5 -4
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
// `oh-hai fleet ls` (docs/specs/cli.md §4.13) — the sessions visible to this credential, which is
|
|
2
|
+
// how an agent discovers the addresses it can send to (issue #657).
|
|
3
|
+
//
|
|
4
|
+
// THE SCOPE OF THIS LIST IS NOT A PARAMETER — it is a property of the caller and the Hub's policy
|
|
5
|
+
// (§16.4), and the command's main job is to say which one it printed:
|
|
6
|
+
//
|
|
7
|
+
// * An agent ALWAYS sees its own sessions. Unconditional by §16.4, and deliberately so: a
|
|
8
|
+
// restarted or crash-looping agent must be able to find and clear its stale leases before it
|
|
9
|
+
// hits the live-session cap, and gating that read would wedge exactly that agent.
|
|
10
|
+
// * It sees the whole ACCOUNT only where the Hub's `sessions.agent_list_visibility` policy is on.
|
|
11
|
+
// §16.4 makes same-account-agent listing an explicit MAY — "an optimization for fleet
|
|
12
|
+
// dashboards, not the required discovery path" — so it is fail-closed by default.
|
|
13
|
+
//
|
|
14
|
+
// A list that silently narrowed from "the fleet" to "just me" would be actively misleading: the
|
|
15
|
+
// user would conclude the other agents are gone. So the capability document is read (public, no
|
|
16
|
+
// auth) purely to caption the result honestly. That read is best-effort — when it is unavailable
|
|
17
|
+
// the caption falls back to what can be proven from the rows themselves.
|
|
18
|
+
import { buildOk, serializeEnvelope } from "../envelope.js";
|
|
19
|
+
import { sanitizeForTerminal } from "../terminal.js";
|
|
20
|
+
import { parseSubcommandArgs } from "./flags.js";
|
|
21
|
+
import { resolveSubmitIdentity } from "./messaging/identity.js";
|
|
22
|
+
import { fetchCapability } from "./messaging/capability.js";
|
|
23
|
+
import { listSessions } from "./messaging/sessions-http.js";
|
|
24
|
+
import { nonNegativeInt, positiveInt, strictBoolFlag, stringFlag } from "./messaging/shared.js";
|
|
25
|
+
const SUBCOMMANDS = ["ls"];
|
|
26
|
+
const FLEET_LS_OPTIONS = {
|
|
27
|
+
limit: { type: "string" },
|
|
28
|
+
offset: { type: "string" },
|
|
29
|
+
all: { type: "boolean" },
|
|
30
|
+
};
|
|
31
|
+
/** The Hub's own `SESSION_LIST_MAX` / `SESSION_OFFSET_MAX`, mirrored so the "(more …)" hint is
|
|
32
|
+
* computed against the window the Hub ACTUALLY served — a raw request above the ceiling is
|
|
33
|
+
* clamped server-side, and comparing a full clamped page against the raw ask would wrongly report
|
|
34
|
+
* "no more" and stop a scripted pager early. Same convention as `messages list`. */
|
|
35
|
+
const SESSION_LIST_MAX = 200;
|
|
36
|
+
const SESSION_OFFSET_MAX = 10_000;
|
|
37
|
+
const MAX_LIST_INT = 1_000_000;
|
|
38
|
+
export async function fleetCommand(ctx) {
|
|
39
|
+
const { values } = parseSubcommandArgs(ctx.argv, SUBCOMMANDS, FLEET_LS_OPTIONS);
|
|
40
|
+
const flags = values;
|
|
41
|
+
const requestedLimit = flags.limit !== undefined ? positiveInt(stringFlag(flags.limit), "--limit", "a positive integer", MAX_LIST_INT) : SESSION_LIST_MAX;
|
|
42
|
+
const requestedOffset = flags.offset !== undefined ? nonNegativeInt(stringFlag(flags.offset), "--offset", "a non-negative integer", MAX_LIST_INT) : undefined;
|
|
43
|
+
const limit = Math.min(requestedLimit, SESSION_LIST_MAX);
|
|
44
|
+
const offset = requestedOffset !== undefined ? Math.min(requestedOffset, SESSION_OFFSET_MAX) : undefined;
|
|
45
|
+
// Terminal sessions stay readable for the Hub's retention window, which is useful for a post-mortem
|
|
46
|
+
// and noise for "who can I address right now" — so LIVE-only is the default and `--all` opts in.
|
|
47
|
+
// `strictBoolFlag`, not a lenient truthiness check: `--all=treu` must be a usage error rather than
|
|
48
|
+
// silently showing the narrower list, which reads as "those sessions are gone".
|
|
49
|
+
const includeTerminal = strictBoolFlag(flags.all, "--all");
|
|
50
|
+
const identity = await resolveSubmitIdentity(ctx);
|
|
51
|
+
const rows = await listSessions(ctx, identity.token, { limit, ...(offset !== undefined ? { offset } : {}) });
|
|
52
|
+
const sessions = includeTerminal ? rows : rows.filter((s) => s.state === "active");
|
|
53
|
+
// Best-effort caption input (see the file header). `undefined` anywhere below means "the Hub did
|
|
54
|
+
// not say", which is reported as uncertainty rather than guessed either way.
|
|
55
|
+
const capability = await fetchCapability(ctx);
|
|
56
|
+
const accountWide = capability?.sessions?.agent_list_visibility;
|
|
57
|
+
const scope = describeScope(accountWide, rows, identity.agentId);
|
|
58
|
+
const effectiveOffset = offset ?? 0;
|
|
59
|
+
const nextOffset = Math.min(effectiveOffset + rows.length, SESSION_OFFSET_MAX);
|
|
60
|
+
const hasMore = rows.length === limit && effectiveOffset < SESSION_OFFSET_MAX;
|
|
61
|
+
if (ctx.json) {
|
|
62
|
+
ctx.io.log(serializeEnvelope(buildOk("fleet.ls", {
|
|
63
|
+
sessions,
|
|
64
|
+
count: sessions.length,
|
|
65
|
+
// The SCOPE belongs in the machine envelope too, not just the human caption: a script that
|
|
66
|
+
// cannot tell "no other agents are live" from "this Hub won't tell me about them" will
|
|
67
|
+
// reach the wrong conclusion just as readily as a person would.
|
|
68
|
+
scope: accountWide === undefined ? "unknown" : accountWide ? "account" : "own",
|
|
69
|
+
has_more: hasMore,
|
|
70
|
+
next_offset: nextOffset,
|
|
71
|
+
})));
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
// The pager hint is printed from ONE place, after either branch, because the live-only filter is
|
|
75
|
+
// applied client-side: a full raw page whose rows are all terminal filters to empty while
|
|
76
|
+
// `hasMore` is true. Returning early there — the original shape — printed "No live sessions" and
|
|
77
|
+
// swallowed the hint, so a live session one window further back looked like it did not exist.
|
|
78
|
+
// That is precisely the "those sessions are gone" conclusion this command exists to prevent.
|
|
79
|
+
const more = () => {
|
|
80
|
+
if (hasMore)
|
|
81
|
+
ctx.io.err(`(more — re-run with --offset ${nextOffset})`);
|
|
82
|
+
};
|
|
83
|
+
if (sessions.length === 0) {
|
|
84
|
+
ctx.io.log(includeTerminal
|
|
85
|
+
? "No sessions."
|
|
86
|
+
: hasMore
|
|
87
|
+
? "No live sessions in this window — every row here is closed or expired. Keep paging (below), or --all to include them."
|
|
88
|
+
: "No live sessions. (Add --all to include closed/expired ones.)");
|
|
89
|
+
ctx.io.err(scope);
|
|
90
|
+
more();
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const rowsOut = sessions.map((s) => toRow(s, identity.agentId));
|
|
94
|
+
const display = [
|
|
95
|
+
{ address: "ADDRESS", who: "WHO", state: "STATE", age: "AGE", label: "LABEL", kind: "KIND", project: "PROJECT" },
|
|
96
|
+
...rowsOut,
|
|
97
|
+
];
|
|
98
|
+
const w = (key) => Math.max(...display.map((r) => r[key].length));
|
|
99
|
+
const [addressW, whoW, stateW, ageW, labelW, kindW] = [w("address"), w("who"), w("state"), w("age"), w("label"), w("kind")];
|
|
100
|
+
for (const r of display) {
|
|
101
|
+
ctx.io.log(`${r.address.padEnd(addressW)} ${r.who.padEnd(whoW)} ${r.state.padEnd(stateW)} ${r.age.padEnd(ageW)} ${r.label.padEnd(labelW)} ${r.kind.padEnd(kindW)} ${r.project}`);
|
|
102
|
+
}
|
|
103
|
+
// The caption and the pager hint go to stderr so piping the table into a script stays clean.
|
|
104
|
+
ctx.io.err(scope);
|
|
105
|
+
more();
|
|
106
|
+
}
|
|
107
|
+
/** Say what this list covers, without overclaiming. When the capability read failed we can still
|
|
108
|
+
* prove ONE direction from the rows: a session belonging to another agent could only have come
|
|
109
|
+
* from an account-wide read. The reverse is not provable — seeing only your own sessions is
|
|
110
|
+
* equally consistent with "the policy is off" and "you are the only agent running." */
|
|
111
|
+
function describeScope(accountWide, rows, selfAgentId) {
|
|
112
|
+
if (accountWide === true)
|
|
113
|
+
return "scope: every session in this account (this Hub permits same-account agent listing).";
|
|
114
|
+
if (accountWide === false) {
|
|
115
|
+
return ("scope: THIS AGENT's sessions only — this Hub does not permit same-account agent listing (§16.4 makes it " +
|
|
116
|
+
"an explicit MAY, off by default). Other agents may well be live; ask an account human, who always sees the whole account.");
|
|
117
|
+
}
|
|
118
|
+
if (rows.some((s) => s.agent_id !== selfAgentId)) {
|
|
119
|
+
return "scope: the account (inferred — sessions from other agents are present; the Hub's capability document was unreadable).";
|
|
120
|
+
}
|
|
121
|
+
return "scope: could not read this Hub's capability document, so whether other agents' sessions are listed here is unknown.";
|
|
122
|
+
}
|
|
123
|
+
/** Project one session to terminal-safe, single-line columns.
|
|
124
|
+
*
|
|
125
|
+
* The ADDRESS cell holds the `--to` argument and NOTHING else — no "(you)" suffix, no annotation —
|
|
126
|
+
* because the whole point of the column is that it can be copied verbatim into `--to`. A marker
|
|
127
|
+
* glued onto it turns a copy-paste into an invalid extra argument, which is a worse failure than
|
|
128
|
+
* the marker is a convenience. The self marker gets its own WHO column instead. */
|
|
129
|
+
function toRow(session, selfAgentId) {
|
|
130
|
+
const clean = (value) => (typeof value === "string" && value.trim() !== "" ? sanitizeForTerminal(value) : "—");
|
|
131
|
+
return {
|
|
132
|
+
address: `agent:${clean(session.agent_id)}#${clean(session.id)}`,
|
|
133
|
+
who: session.agent_id === selfAgentId ? "you" : "—",
|
|
134
|
+
state: clean(session.state),
|
|
135
|
+
age: describeAge(session),
|
|
136
|
+
label: clean(session.label),
|
|
137
|
+
kind: clean(session.kind),
|
|
138
|
+
project: clean(session.project),
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
/** How long ago the session was last heard from — `last_seen` (client-originated renewal, §15.1)
|
|
142
|
+
* when the Hub reports one, else its creation time, marked so the two are never confused. A
|
|
143
|
+
* malformed timestamp renders as an em dash rather than `NaN`. */
|
|
144
|
+
function describeAge(session) {
|
|
145
|
+
const seen = session.last_seen ?? session.created_at;
|
|
146
|
+
const ms = Date.parse(seen);
|
|
147
|
+
if (Number.isNaN(ms))
|
|
148
|
+
return "—";
|
|
149
|
+
const suffix = session.last_seen === undefined ? " (since start)" : "";
|
|
150
|
+
return `${humanizeAge(Date.now() - ms)}${suffix}`;
|
|
151
|
+
}
|
|
152
|
+
function humanizeAge(deltaMs) {
|
|
153
|
+
const seconds = Math.max(0, Math.round(deltaMs / 1000));
|
|
154
|
+
if (seconds < 60)
|
|
155
|
+
return `${seconds}s`;
|
|
156
|
+
const minutes = Math.round(seconds / 60);
|
|
157
|
+
if (minutes < 60)
|
|
158
|
+
return `${minutes}m`;
|
|
159
|
+
const hours = Math.round(minutes / 60);
|
|
160
|
+
if (hours < 48)
|
|
161
|
+
return `${hours}h`;
|
|
162
|
+
return `${Math.round(hours / 24)}d`;
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=fleet.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fleet.js","sourceRoot":"","sources":["../../src/commands/fleet.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,11 +5,15 @@
|
|
|
5
5
|
// `notImplemented()` as a defensive fallback for any future entry added without a handler.
|
|
6
6
|
import { agentsCommand } from "./agents.js";
|
|
7
7
|
import { askCommand } from "./ask.js";
|
|
8
|
+
import { bridgeCommand } from "./bridge.js";
|
|
8
9
|
import { doctorCommand } from "./doctor.js";
|
|
10
|
+
import { fleetCommand } from "./fleet.js";
|
|
9
11
|
import { inboxCommand } from "./inbox.js";
|
|
10
12
|
import { loginCommand } from "./login.js";
|
|
11
13
|
import { logoutCommand } from "./logout.js";
|
|
14
|
+
import { messagesCommand } from "./messages.js";
|
|
12
15
|
import { notifyCommand } from "./notify.js";
|
|
16
|
+
import { sessionCommand } from "./session.js";
|
|
13
17
|
import { setupCommand } from "./setup.js";
|
|
14
18
|
import { taskCommand } from "./task.js";
|
|
15
19
|
import { teachCommand } from "./teach.js";
|
|
@@ -27,6 +31,10 @@ export const COMMAND_HANDLERS = {
|
|
|
27
31
|
task: taskCommand,
|
|
28
32
|
agents: agentsCommand,
|
|
29
33
|
inbox: inboxCommand,
|
|
34
|
+
bridge: bridgeCommand,
|
|
35
|
+
session: sessionCommand,
|
|
36
|
+
fleet: fleetCommand,
|
|
37
|
+
messages: messagesCommand,
|
|
30
38
|
doctor: doctorCommand,
|
|
31
39
|
teach: teachCommand,
|
|
32
40
|
upgrade: upgradeCommand,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handlers.js","sourceRoot":"","sources":["../../src/commands/handlers.ts"],"names":[],"mappings":"AAAA,gGAAgG;AAChG,4FAA4F;AAC5F,2FAA2F;AAC3F,uFAAuF;AACvF,2FAA2F;AAE3F,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"handlers.js","sourceRoot":"","sources":["../../src/commands/handlers.ts"],"names":[],"mappings":"AAAA,gGAAgG;AAChG,4FAA4F;AAC5F,2FAA2F;AAC3F,uFAAuF;AACvF,2FAA2F;AAE3F,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,CAAC,MAAM,gBAAgB,GAAmC;IAC9D,KAAK,EAAE,YAAY;IACnB,KAAK,EAAE,YAAY;IACnB,MAAM,EAAE,aAAa;IACrB,MAAM,EAAE,aAAa;IACrB,GAAG,EAAE,UAAU;IACf,MAAM,EAAE,aAAa;IACrB,GAAG,EAAE,UAAU;IACf,IAAI,EAAE,WAAW;IACjB,MAAM,EAAE,aAAa;IACrB,KAAK,EAAE,YAAY;IACnB,MAAM,EAAE,aAAa;IACrB,OAAO,EAAE,cAAc;IACvB,KAAK,EAAE,YAAY;IACnB,QAAQ,EAAE,eAAe;IACzB,MAAM,EAAE,aAAa;IACrB,KAAK,EAAE,YAAY;IACnB,OAAO,EAAE,cAAc;CACxB,CAAC"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
// `oh-hai messages` (docs/specs/cli.md §4.11) — read the agent's OWN submitted messages. The
|
|
2
|
+
// productized CLI wrapper for the submitter-bound self-list (`GET /v1/messages` with an agent
|
|
3
|
+
// bearer — the #400 primitive, paginated by #527; issue #572). Subcommand `list`:
|
|
4
|
+
// - Sends the resolved AGENT bearer (`requireToken`, like `ask await`), so the Hub scopes the
|
|
5
|
+
// result to this agent's own submissions — never the account-wide human inbox.
|
|
6
|
+
// - Returns a pure INDEX: each row carries the message's `status` but NOT the resolved answer
|
|
7
|
+
// body (the list strips `response`/`delivery`). To read a specific answer, pull that message
|
|
8
|
+
// by id — the list is for history review / dedupe before resubmitting.
|
|
9
|
+
// - Pages one window per call: `--limit`/`--offset` (default limit 50; the Hub clamps to 200),
|
|
10
|
+
// optionally filtered by `--status`/`--type`. `has_more` (a full page) + `next_offset` tell a
|
|
11
|
+
// scripted pager where to resume.
|
|
12
|
+
//
|
|
13
|
+
// Output posture mirrors `inbox watch` (the sibling "list of server-supplied envelopes" surface),
|
|
14
|
+
// NOT `agents list`: under `--json` the rows are emitted VERBATIM (already bearer-redacted by
|
|
15
|
+
// http.listMessages; JSON.stringify escapes the C0 control range incl. ESC, so no ANSI injection)
|
|
16
|
+
// so a legitimately multi-line message body survives intact — deep-sanitizing would strip its
|
|
17
|
+
// newlines. The HUMAN table renders only single-line index fields (id/type/status/title/created/
|
|
18
|
+
// priority), each `sanitizeForTerminal`'d so a hostile Hub can't inject escape sequences (§5.4).
|
|
19
|
+
import { CliError, buildOk, serializeEnvelope } from "../envelope.js";
|
|
20
|
+
import { sanitizeForTerminal } from "../terminal.js";
|
|
21
|
+
import { parseSubcommandArgs } from "./flags.js";
|
|
22
|
+
import { listMessages } from "./messaging/http.js";
|
|
23
|
+
import { resolveSubmitIdentity } from "./messaging/identity.js";
|
|
24
|
+
import { nonNegativeInt, positiveInt, stringFlag } from "./messaging/shared.js";
|
|
25
|
+
import { isMessageType, isStatus, MESSAGE_TYPES, STATUSES } from "./messaging/validate.js";
|
|
26
|
+
const SUBCOMMANDS = ["list"];
|
|
27
|
+
const MESSAGES_LIST_OPTIONS = {
|
|
28
|
+
limit: { type: "string" },
|
|
29
|
+
offset: { type: "string" },
|
|
30
|
+
status: { type: "string" },
|
|
31
|
+
type: { type: "string" },
|
|
32
|
+
};
|
|
33
|
+
/** Default page size when `--limit` is omitted — bounded so the command doesn't drag the whole
|
|
34
|
+
* history back by default (the Hub treats an absent `?limit` as unbounded for back-compat). */
|
|
35
|
+
const DEFAULT_LIMIT = 50;
|
|
36
|
+
/** The Hub's server-side clamps on `GET /v1/messages` (server `LIST_LIMIT_MAX` / `LIST_OFFSET_MAX`).
|
|
37
|
+
* Mirrored so `has_more` / `next_offset` are computed against the limit/offset the Hub ACTUALLY
|
|
38
|
+
* applied: a request above these is clamped server-side, so a full clamped page compared against
|
|
39
|
+
* the raw request would wrongly report "no more" (the `(more …)` hint disappears / a scripted pager
|
|
40
|
+
* stops early). A local mirror is the codebase's convention (see web `pagination.ts`). */
|
|
41
|
+
const LIST_LIMIT_MAX = 200;
|
|
42
|
+
const LIST_OFFSET_MAX = 10_000;
|
|
43
|
+
/** A sane ceiling for `--limit`/`--offset` PARSING — rejects an absurd value (exit 2) before the
|
|
44
|
+
* call. The effective value is then clamped to the Hub ceilings above for the request + paging math. */
|
|
45
|
+
const MAX_LIST_INT = 1_000_000;
|
|
46
|
+
export async function messagesCommand(ctx) {
|
|
47
|
+
// `list` is the only subcommand; the parse validates the operand (an unknown/absent subcommand is
|
|
48
|
+
// a usage error) before dispatch.
|
|
49
|
+
const { values } = parseSubcommandArgs(ctx.argv, SUBCOMMANDS, MESSAGES_LIST_OPTIONS);
|
|
50
|
+
await messagesList(ctx, values);
|
|
51
|
+
}
|
|
52
|
+
async function messagesList(ctx, flags) {
|
|
53
|
+
// Parse + validate every flag FIRST (a bad invocation is exit 2, before we touch credentials or
|
|
54
|
+
// the Hub), matching notify/agents. Then clamp to the Hub's ceilings so the paging math below
|
|
55
|
+
// matches what the Hub actually serves (a raw value above the ceiling would desync has_more).
|
|
56
|
+
const requestedLimit = flags.limit !== undefined ? positiveInt(stringFlag(flags.limit), "--limit", "a positive integer", MAX_LIST_INT) : DEFAULT_LIMIT;
|
|
57
|
+
const requestedOffset = flags.offset !== undefined ? nonNegativeInt(stringFlag(flags.offset), "--offset", "a non-negative integer", MAX_LIST_INT) : undefined;
|
|
58
|
+
const limit = Math.min(requestedLimit, LIST_LIMIT_MAX);
|
|
59
|
+
const offset = requestedOffset !== undefined ? Math.min(requestedOffset, LIST_OFFSET_MAX) : undefined;
|
|
60
|
+
const status = stringFlag(flags.status);
|
|
61
|
+
if (status !== undefined && !isStatus(status)) {
|
|
62
|
+
throw new CliError("usage", `invalid --status "${status}" (expected one of: ${STATUSES.join(", ")}).`);
|
|
63
|
+
}
|
|
64
|
+
const type = stringFlag(flags.type);
|
|
65
|
+
if (type !== undefined && !isMessageType(type)) {
|
|
66
|
+
throw new CliError("usage", `invalid --type "${type}" (expected one of: ${MESSAGE_TYPES.join(", ")}).`);
|
|
67
|
+
}
|
|
68
|
+
// Resolve BOTH the bearer and this agent's own id (like notify/ask/task): the id is needed to
|
|
69
|
+
// fail closed on a dual-audience `GET /v1/messages` response (see listMessages' ownership guard) —
|
|
70
|
+
// to safely self-list you must know which agent you are. An unresolvable/ambiguous id is a usage
|
|
71
|
+
// error, exactly as for the submit commands.
|
|
72
|
+
const { token, agentId } = await resolveSubmitIdentity(ctx);
|
|
73
|
+
const messages = await listMessages(ctx, token, {
|
|
74
|
+
limit,
|
|
75
|
+
...(offset !== undefined ? { offset } : {}),
|
|
76
|
+
...(status !== undefined ? { status } : {}),
|
|
77
|
+
...(type !== undefined ? { type } : {}),
|
|
78
|
+
}, agentId);
|
|
79
|
+
// has_more follows the route's convention (no `total` field): a FULL page might have more. The Hub
|
|
80
|
+
// clamps offset to LIST_OFFSET_MAX, so the deepest fetchable window starts there — keep paging
|
|
81
|
+
// until offset IS the clamp, then stop. next_offset is clamped to the ceiling so the printed
|
|
82
|
+
// resume hint lands on that final window (de-duping the overlap) instead of a clamped-back repeat.
|
|
83
|
+
const effectiveOffset = offset ?? 0;
|
|
84
|
+
const nextOffset = Math.min(effectiveOffset + messages.length, LIST_OFFSET_MAX);
|
|
85
|
+
const hasMore = messages.length === limit && effectiveOffset < LIST_OFFSET_MAX;
|
|
86
|
+
if (ctx.json) {
|
|
87
|
+
// Rows are emitted verbatim (already bearer-redacted); see the file header on why this surface
|
|
88
|
+
// does NOT deep-sanitize under --json (multi-line bodies must survive).
|
|
89
|
+
ctx.io.log(serializeEnvelope(buildOk("messages.list", { messages, count: messages.length, has_more: hasMore, next_offset: nextOffset })));
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (messages.length === 0) {
|
|
93
|
+
ctx.io.log("No messages.");
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
// Human table — project each row to sanitized, single-line index fields (mirrors agents list's
|
|
97
|
+
// toAgentView). Absent fields render as an em dash.
|
|
98
|
+
const rows = messages.map(toRow);
|
|
99
|
+
const display = [{ id: "ID", type: "TYPE", status: "STATUS", title: "TITLE", created: "CREATED", priority: "PRIORITY" }, ...rows];
|
|
100
|
+
const idW = colWidth(display, "id");
|
|
101
|
+
const typeW = colWidth(display, "type");
|
|
102
|
+
const statusW = colWidth(display, "status");
|
|
103
|
+
const titleW = colWidth(display, "title");
|
|
104
|
+
const createdW = colWidth(display, "created");
|
|
105
|
+
for (const r of display) {
|
|
106
|
+
ctx.io.log(`${r.id.padEnd(idW)} ${r.type.padEnd(typeW)} ${r.status.padEnd(statusW)} ${r.title.padEnd(titleW)} ${r.created.padEnd(createdW)} ${r.priority}`);
|
|
107
|
+
}
|
|
108
|
+
if (hasMore) {
|
|
109
|
+
ctx.io.err(`(more — re-run with --offset ${nextOffset})`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/** Project one self-list row to terminal-safe, single-line columns. Every server string is
|
|
113
|
+
* sanitized HERE (the table prints straight to the terminal and a hostile Hub could otherwise inject
|
|
114
|
+
* escape sequences via any field — §5.4). Defensive about field presence/type so a malformed-but-
|
|
115
|
+
* guard-passing row (the http guard only pins id/type/status) can't crash the render. */
|
|
116
|
+
function toRow(m) {
|
|
117
|
+
const raw = m;
|
|
118
|
+
const clean = (value) => (typeof value === "string" && value.trim() !== "" ? sanitizeForTerminal(value) : "—");
|
|
119
|
+
return {
|
|
120
|
+
id: clean(raw.id),
|
|
121
|
+
type: clean(raw.type),
|
|
122
|
+
status: clean(raw.status),
|
|
123
|
+
title: clean(raw.title),
|
|
124
|
+
created: clean(raw.created_at),
|
|
125
|
+
priority: clean(raw.priority),
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
function colWidth(rows, key) {
|
|
129
|
+
return Math.max(...rows.map((r) => r[key].length));
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=messages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/commands/messages.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AskMessage, AskRequest, JsonObject, NotifyMessage, Priority, Runtime, TaskAction, TaskMessage } from "./wire.js";
|
|
1
|
+
import type { AgentAddress, AskMessage, AskRequest, JsonObject, NotifyMessage, Priority, Runtime, TaskAction, TaskMessage } from "./wire.js";
|
|
2
2
|
/** The submitting agent's identity. `id` MUST equal the bound bearer credential or the Hub 403s. */
|
|
3
3
|
export interface AgentIdentity {
|
|
4
4
|
id: string;
|
|
@@ -6,10 +6,15 @@ export interface AgentIdentity {
|
|
|
6
6
|
/** Defaults to "cli". */
|
|
7
7
|
runtime?: Runtime;
|
|
8
8
|
project?: string;
|
|
9
|
+
/** v0.5 §4.1: the submitter's own live session (`--session` / `MA2H_SESSION_ID` / auto-minted).
|
|
10
|
+
* Its presence forces the envelope to declare 0.5 — see `wireVersion`. */
|
|
11
|
+
session?: string;
|
|
9
12
|
}
|
|
10
13
|
export interface BuildNotifyInput {
|
|
11
14
|
agent: AgentIdentity;
|
|
12
15
|
title: string;
|
|
16
|
+
/** v0.5 §4 destination (`--to`). Absent = the human inbox. */
|
|
17
|
+
to?: AgentAddress;
|
|
13
18
|
body?: string;
|
|
14
19
|
priority?: Priority;
|
|
15
20
|
tags?: string[];
|
|
@@ -24,6 +29,8 @@ export interface BuildAskInput {
|
|
|
24
29
|
agent: AgentIdentity;
|
|
25
30
|
title: string;
|
|
26
31
|
request: AskRequest;
|
|
32
|
+
/** v0.5 §4 destination (`--to`). Absent = the human inbox. */
|
|
33
|
+
to?: AgentAddress;
|
|
27
34
|
body?: string;
|
|
28
35
|
/** Defaults to a fresh `idem_<uuid>`. */
|
|
29
36
|
idempotency_key?: string;
|
|
@@ -36,6 +43,8 @@ export interface BuildTaskInput {
|
|
|
36
43
|
agent: AgentIdentity;
|
|
37
44
|
title: string;
|
|
38
45
|
action: TaskAction;
|
|
46
|
+
/** v0.5 §4 destination (`--to`). Absent = the human inbox. */
|
|
47
|
+
to?: AgentAddress;
|
|
39
48
|
body?: string;
|
|
40
49
|
/** Defaults to a fresh `idem_<uuid>`. */
|
|
41
50
|
idempotency_key?: string;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Pure MA2H envelope builders for the productized messaging commands (spec §4.4).
|
|
2
2
|
//
|
|
3
3
|
// These mirror `scripts/agent-client.ts`'s buildNotify / buildAsk / buildTask in shape —
|
|
4
|
-
// stamp `ma2h_version
|
|
4
|
+
// stamp the declared `ma2h_version` (see `wireVersion`), the `type`, a `created_at` (defaulting to now), the agent
|
|
5
5
|
// descriptor (runtime defaults to "cli"), and — for ask/task — a REQUIRED idempotency key
|
|
6
6
|
// (a fresh `idem_<uuid>` unless the caller pins one). No crypto and no I/O: envelope
|
|
7
7
|
// construction is plain object assembly, so this is not the "no hand-rolled crypto" surface
|
|
@@ -14,8 +14,23 @@ function descriptor(agent) {
|
|
|
14
14
|
run_id: agent.run_id,
|
|
15
15
|
runtime: agent.runtime ?? "cli",
|
|
16
16
|
...(agent.project !== undefined ? { project: agent.project } : {}),
|
|
17
|
+
...(agent.session !== undefined ? { session: agent.session } : {}),
|
|
17
18
|
};
|
|
18
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* The version an envelope DECLARES: 0.5 when it carries v0.5 addressing vocabulary (`to` or
|
|
22
|
+
* `agent.session`), 0.3 otherwise.
|
|
23
|
+
*
|
|
24
|
+
* This is not cosmetic. The Hub routes schema validation by declared minor and REFUSES either field
|
|
25
|
+
* on a pre-0.5 envelope (`422 invalid_field` — "…is a v0.5 field; ma2h_version "0.3" predates it"),
|
|
26
|
+
* because honoring v0.5 semantics on an envelope that never claimed them would be acting on a
|
|
27
|
+
* version mismatch. Bumping per-envelope rather than wholesale is the honest statement in the other
|
|
28
|
+
* direction too: an ordinary human-inbox notify speaks no v0.5 vocabulary, so it keeps saying 0.3
|
|
29
|
+
* and its bytes on the wire are unchanged.
|
|
30
|
+
*/
|
|
31
|
+
function wireVersion(input) {
|
|
32
|
+
return input.to !== undefined || input.agent.session !== undefined ? "0.5" : "0.3";
|
|
33
|
+
}
|
|
19
34
|
function nowIso() {
|
|
20
35
|
return new Date().toISOString();
|
|
21
36
|
}
|
|
@@ -26,7 +41,7 @@ function freshIdempotencyKey() {
|
|
|
26
41
|
* would post a duplicate). An empty `tags` is omitted (the Hub treats absent and `[]` alike). */
|
|
27
42
|
export function buildNotify(input) {
|
|
28
43
|
return {
|
|
29
|
-
ma2h_version:
|
|
44
|
+
ma2h_version: wireVersion(input),
|
|
30
45
|
type: "notify",
|
|
31
46
|
created_at: input.created_at ?? nowIso(),
|
|
32
47
|
agent: descriptor(input.agent),
|
|
@@ -35,11 +50,12 @@ export function buildNotify(input) {
|
|
|
35
50
|
...(input.priority !== undefined ? { priority: input.priority } : {}),
|
|
36
51
|
...(input.tags !== undefined && input.tags.length > 0 ? { tags: input.tags } : {}),
|
|
37
52
|
...(input.state !== undefined ? { state: input.state } : {}),
|
|
53
|
+
...(input.to !== undefined ? { to: input.to } : {}),
|
|
38
54
|
};
|
|
39
55
|
}
|
|
40
56
|
export function buildAsk(input) {
|
|
41
57
|
return {
|
|
42
|
-
ma2h_version:
|
|
58
|
+
ma2h_version: wireVersion(input),
|
|
43
59
|
type: "ask",
|
|
44
60
|
created_at: input.created_at ?? nowIso(),
|
|
45
61
|
agent: descriptor(input.agent),
|
|
@@ -48,11 +64,12 @@ export function buildAsk(input) {
|
|
|
48
64
|
request: input.request,
|
|
49
65
|
...(input.body !== undefined ? { body: input.body } : {}),
|
|
50
66
|
...(input.state !== undefined ? { state: input.state } : {}),
|
|
67
|
+
...(input.to !== undefined ? { to: input.to } : {}),
|
|
51
68
|
};
|
|
52
69
|
}
|
|
53
70
|
export function buildTask(input) {
|
|
54
71
|
return {
|
|
55
|
-
ma2h_version:
|
|
72
|
+
ma2h_version: wireVersion(input),
|
|
56
73
|
type: "task",
|
|
57
74
|
created_at: input.created_at ?? nowIso(),
|
|
58
75
|
agent: descriptor(input.agent),
|
|
@@ -61,6 +78,7 @@ export function buildTask(input) {
|
|
|
61
78
|
action: input.action,
|
|
62
79
|
...(input.body !== undefined ? { body: input.body } : {}),
|
|
63
80
|
...(input.state !== undefined ? { state: input.state } : {}),
|
|
81
|
+
...(input.to !== undefined ? { to: input.to } : {}),
|
|
64
82
|
};
|
|
65
83
|
}
|
|
66
84
|
//# sourceMappingURL=build.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../../src/commands/messaging/build.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAClF,EAAE;AACF,yFAAyF;AACzF,
|
|
1
|
+
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../../src/commands/messaging/build.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { CommandContext } from "../context.js";
|
|
2
|
+
import type { HubCapability } from "./wire.js";
|
|
3
|
+
/** Test seam — a real process wants the cache to live exactly as long as it does. */
|
|
4
|
+
export declare function resetCapabilityCache(): void;
|
|
5
|
+
/**
|
|
6
|
+
* GET /v1/capability — the public capability document (no auth), memoized per process.
|
|
7
|
+
*
|
|
8
|
+
* Best-effort by return type: an unreachable / non-2xx / unparseable document resolves to
|
|
9
|
+
* `undefined`. Callers decide what that means — `fleet ls` degrades its caption to "unknown", while
|
|
10
|
+
* `assertHubSpeaksAddressing` below refuses the send.
|
|
11
|
+
*/
|
|
12
|
+
export declare function fetchCapability(ctx: CommandContext): Promise<HubCapability | undefined>;
|
|
13
|
+
/**
|
|
14
|
+
* The §8.0 gate: refuse an addressed send unless this Hub demonstrably understands `to`.
|
|
15
|
+
*
|
|
16
|
+
* Throws a `usage` CliError (exit 2 — the caller's invocation cannot work against this Hub, and no
|
|
17
|
+
* retry will change that) BEFORE any envelope is posted. See the file header for why the check is
|
|
18
|
+
* a pre-flight, why `inter_agent` is not required, and why an unreadable document fails closed.
|
|
19
|
+
*/
|
|
20
|
+
export declare function assertHubSpeaksAddressing(ctx: CommandContext, to: string): Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* The §8.0 gate for the RECEIVE half — `oh-hai bridge`'s session-presenting drain (#658).
|
|
23
|
+
*
|
|
24
|
+
* The same disclosure logic as the send gate, pointed the other way, and the failure it prevents is
|
|
25
|
+
* worse than a wasted round-trip. A pre-v0.5 Hub does not refuse `?session=`; per §10 it IGNORES the
|
|
26
|
+
* unknown query parameter and answers with the v0.4 body — which means the bridge would issue a
|
|
27
|
+
* **destructive PRINCIPAL-scoped drain**, claiming (and, on ack, consuming) every directive queued
|
|
28
|
+
* for the whole agent, while believing it had drained only its own session's mail. Concurrent runs
|
|
29
|
+
* of the same principal would then eat each other's directives: exactly the race the watch-lock
|
|
30
|
+
* exists to prevent, reintroduced by a silently-dropped parameter.
|
|
31
|
+
*
|
|
32
|
+
* So the gate runs BEFORE the first drain or stream connect, and it fails CLOSED on an unreadable
|
|
33
|
+
* capability document for the same reason the send gate does — we cannot prove the Hub understands
|
|
34
|
+
* `session`, and the cost of being wrong is consuming someone else's mail.
|
|
35
|
+
*
|
|
36
|
+
* What is deliberately NOT required: a present `inbound.session_param`. An ABSENT capability field
|
|
37
|
+
* must never be read as "disabled" (the lesson `assertHubSpeaksAddressing` records in this file's
|
|
38
|
+
* header) — a declared minor >= 0.5 is what makes the Hub *refuse* rather than silently misroute,
|
|
39
|
+
* and that is the property being tested. An EXPLICIT `false` is a different matter: that is the Hub
|
|
40
|
+
* stating the parameter is not honoured, and it is refused.
|
|
41
|
+
*/
|
|
42
|
+
export declare function assertHubSpeaksSessionDrain(ctx: CommandContext): Promise<void>;
|