@oh-hai/cli 0.1.0-beta.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/README.md +154 -0
- package/dist/auth/file-backend.d.ts +16 -0
- package/dist/auth/file-backend.js +98 -0
- package/dist/auth/file-backend.js.map +1 -0
- package/dist/auth/keychain.d.ts +54 -0
- package/dist/auth/keychain.js +232 -0
- package/dist/auth/keychain.js.map +1 -0
- package/dist/auth/resolve-token.d.ts +34 -0
- package/dist/auth/resolve-token.js +91 -0
- package/dist/auth/resolve-token.js.map +1 -0
- package/dist/auth/secure-write.d.ts +2 -0
- package/dist/auth/secure-write.js +30 -0
- package/dist/auth/secure-write.js.map +1 -0
- package/dist/auth/token-store.d.ts +104 -0
- package/dist/auth/token-store.js +208 -0
- package/dist/auth/token-store.js.map +1 -0
- package/dist/cli.d.ts +16 -0
- package/dist/cli.js +238 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/agents.d.ts +2 -0
- package/dist/commands/agents.js +370 -0
- package/dist/commands/agents.js.map +1 -0
- package/dist/commands/ask.d.ts +2 -0
- package/dist/commands/ask.js +246 -0
- package/dist/commands/ask.js.map +1 -0
- package/dist/commands/context.d.ts +72 -0
- package/dist/commands/context.js +7 -0
- package/dist/commands/context.js.map +1 -0
- package/dist/commands/doctor.d.ts +2 -0
- package/dist/commands/doctor.js +237 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/flags.d.ts +25 -0
- package/dist/commands/flags.js +100 -0
- package/dist/commands/flags.js.map +1 -0
- package/dist/commands/handlers.d.ts +2 -0
- package/dist/commands/handlers.js +26 -0
- package/dist/commands/handlers.js.map +1 -0
- package/dist/commands/http.d.ts +8 -0
- package/dist/commands/http.js +19 -0
- package/dist/commands/http.js.map +1 -0
- package/dist/commands/inbox.d.ts +2 -0
- package/dist/commands/inbox.js +111 -0
- package/dist/commands/inbox.js.map +1 -0
- package/dist/commands/login.d.ts +2 -0
- package/dist/commands/login.js +272 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/logout.d.ts +2 -0
- package/dist/commands/logout.js +35 -0
- package/dist/commands/logout.js.map +1 -0
- package/dist/commands/messaging/await.d.ts +43 -0
- package/dist/commands/messaging/await.js +125 -0
- package/dist/commands/messaging/await.js.map +1 -0
- package/dist/commands/messaging/build.d.ts +46 -0
- package/dist/commands/messaging/build.js +66 -0
- package/dist/commands/messaging/build.js.map +1 -0
- package/dist/commands/messaging/http.d.ts +22 -0
- package/dist/commands/messaging/http.js +270 -0
- package/dist/commands/messaging/http.js.map +1 -0
- package/dist/commands/messaging/identity.d.ts +29 -0
- package/dist/commands/messaging/identity.js +63 -0
- package/dist/commands/messaging/identity.js.map +1 -0
- package/dist/commands/messaging/shared.d.ts +53 -0
- package/dist/commands/messaging/shared.js +135 -0
- package/dist/commands/messaging/shared.js.map +1 -0
- package/dist/commands/messaging/state.d.ts +26 -0
- package/dist/commands/messaging/state.js +82 -0
- package/dist/commands/messaging/state.js.map +1 -0
- package/dist/commands/messaging/validate.d.ts +40 -0
- package/dist/commands/messaging/validate.js +193 -0
- package/dist/commands/messaging/validate.js.map +1 -0
- package/dist/commands/messaging/wire.d.ts +133 -0
- package/dist/commands/messaging/wire.js +16 -0
- package/dist/commands/messaging/wire.js.map +1 -0
- package/dist/commands/notify.d.ts +2 -0
- package/dist/commands/notify.js +68 -0
- package/dist/commands/notify.js.map +1 -0
- package/dist/commands/registry.d.ts +14 -0
- package/dist/commands/registry.js +144 -0
- package/dist/commands/registry.js.map +1 -0
- package/dist/commands/stub.d.ts +1 -0
- package/dist/commands/stub.js +9 -0
- package/dist/commands/stub.js.map +1 -0
- package/dist/commands/task.d.ts +2 -0
- package/dist/commands/task.js +223 -0
- package/dist/commands/task.js.map +1 -0
- package/dist/commands/whoami.d.ts +6 -0
- package/dist/commands/whoami.js +90 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/config-file.d.ts +38 -0
- package/dist/config-file.js +233 -0
- package/dist/config-file.js.map +1 -0
- package/dist/config.d.ts +64 -0
- package/dist/config.js +97 -0
- package/dist/config.js.map +1 -0
- package/dist/envelope.d.ts +25 -0
- package/dist/envelope.js +41 -0
- package/dist/envelope.js.map +1 -0
- package/dist/exit-codes.d.ts +51 -0
- package/dist/exit-codes.js +57 -0
- package/dist/exit-codes.js.map +1 -0
- package/dist/help.d.ts +1 -0
- package/dist/help.js +17 -0
- package/dist/help.js.map +1 -0
- package/dist/terminal.d.ts +5 -0
- package/dist/terminal.js +18 -0
- package/dist/terminal.js.map +1 -0
- package/dist/version.d.ts +8 -0
- package/dist/version.js +23 -0
- package/dist/version.js.map +1 -0
- package/package.json +38 -0
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
// Shared Hub HTTP for the messaging commands (notify / ask / task) — submit an envelope and
|
|
2
|
+
// poll a message, over the INJECTABLE `ctx.runtime.fetchImpl` so command tests stay hermetic
|
|
3
|
+
// (never a live Hub). The one thing worth centralizing is the HTTP-status → §7 exit-code
|
|
4
|
+
// mapping, so every messaging command surfaces the same codes/messages (cli spec §7/§8).
|
|
5
|
+
//
|
|
6
|
+
// The tiny defensive body readers + terminal sanitizer mirror the private copies in
|
|
7
|
+
// `commands/login.ts`; they are duplicated (not imported) so this stays a self-contained layer
|
|
8
|
+
// with FULL status coverage (409 conflict / 422 validation_error), which the device-code flow
|
|
9
|
+
// in login.ts never needs. A future shared CLI-core package could unify them (distinct from
|
|
10
|
+
// `@oh-hai/ma2h-core`, the protocol crypto/lifecycle/validation core, not these HTTP readers).
|
|
11
|
+
import { CliError } from "../../envelope.js";
|
|
12
|
+
import { exitCodeForError, isErrorCode } from "../../exit-codes.js";
|
|
13
|
+
import { throwTransportError } from "../http.js";
|
|
14
|
+
import { MAX_TIMER_MS, sanitizeForTerminal } from "./shared.js";
|
|
15
|
+
/** Default per-request bound when no `--timeout`/`MA2H_TIMEOUT_MS` is set — mirrors the scripts
|
|
16
|
+
* layer's DEFAULT_TIMEOUT_MS so an unresponsive Hub can't hang a command indefinitely. */
|
|
17
|
+
const DEFAULT_TIMEOUT_MS = 10_000;
|
|
18
|
+
/** The per-request bound for a single Hub call: `config.timeoutMs` (from `--timeout` /
|
|
19
|
+
* `MA2H_TIMEOUT_MS`, §6), defaulted and clamped to the timer ceiling so an oversized/negative value
|
|
20
|
+
* can't overflow `AbortSignal.timeout` and fail the request spuriously. */
|
|
21
|
+
function requestTimeoutMs(ctx) {
|
|
22
|
+
const t = ctx.config.timeoutMs;
|
|
23
|
+
return Math.min(t !== undefined && t > 0 ? t : DEFAULT_TIMEOUT_MS, MAX_TIMER_MS);
|
|
24
|
+
}
|
|
25
|
+
/** Redact any occurrence of the bearer from a Hub-supplied string before it can reach
|
|
26
|
+
* stdout/stderr/logs/the `--json` envelope (§5.4) — a hostile/buggy Hub could echo the
|
|
27
|
+
* Authorization value back in an error message, an ack field, or (inbox watch) a directive. */
|
|
28
|
+
export function redactToken(message, token) {
|
|
29
|
+
if (message === undefined || token === "")
|
|
30
|
+
return message;
|
|
31
|
+
return message.split(token).join("[redacted]");
|
|
32
|
+
}
|
|
33
|
+
/** POST an envelope to the Hub's ingest endpoint (agent bearer). `202` → the SubmitAck; every
|
|
34
|
+
* other status maps to the right §7 exit code (via the Hub's error envelope when present). */
|
|
35
|
+
export async function submitEnvelope(ctx, token, envelope) {
|
|
36
|
+
const url = `${ctx.config.baseUrl}/v1/messages`;
|
|
37
|
+
const init = {
|
|
38
|
+
method: "POST",
|
|
39
|
+
headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` },
|
|
40
|
+
body: JSON.stringify(envelope),
|
|
41
|
+
signal: AbortSignal.timeout(requestTimeoutMs(ctx)),
|
|
42
|
+
};
|
|
43
|
+
let res;
|
|
44
|
+
try {
|
|
45
|
+
res = await ctx.runtime.fetchImpl(url, init);
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
throwTransportError(error, ctx.config.baseUrl);
|
|
49
|
+
}
|
|
50
|
+
if (res.status !== 202) {
|
|
51
|
+
const { code, message } = await readErrorEnvelope(res);
|
|
52
|
+
throw hubStatusToCliError(res.status, redactToken(message, token), code);
|
|
53
|
+
}
|
|
54
|
+
const body = await readJson(res);
|
|
55
|
+
// A conformant Hub returns `{ id, status, poll_url, review_url? }` for every message type.
|
|
56
|
+
// Validate the fields the submit paths consume — `id` + `status` (printSubmitAck echoes status,
|
|
57
|
+
// which would throw on `undefined`) + `poll_url` (the ack contract + ask `--json`'s promised
|
|
58
|
+
// resume URL), and a present `review_url` must be a string too (else printSubmitAck /--json break)
|
|
59
|
+
// — rather than casting a malformed 202 body through and crashing / emitting an incomplete payload
|
|
60
|
+
// AFTER the message was accepted.
|
|
61
|
+
if (typeof body.id !== "string" || body.id === "" ||
|
|
62
|
+
typeof body.status !== "string" || body.status === "" ||
|
|
63
|
+
typeof body.poll_url !== "string" || body.poll_url === "" ||
|
|
64
|
+
(body.review_url !== undefined && typeof body.review_url !== "string")) {
|
|
65
|
+
throw new CliError("server", "the Hub accepted the message but returned an incomplete or malformed ack.");
|
|
66
|
+
}
|
|
67
|
+
// Redact the bearer from every ack field before returning — a hostile/buggy Hub could echo the
|
|
68
|
+
// Authorization value into id/status/poll_url/review_url, which the submit handlers print to
|
|
69
|
+
// stdout / the --json envelope (§5.4). Build a clean ack (drops any extra Hub fields too).
|
|
70
|
+
const ack = {
|
|
71
|
+
id: redactToken(body.id, token),
|
|
72
|
+
status: redactToken(body.status, token),
|
|
73
|
+
poll_url: redactToken(body.poll_url, token),
|
|
74
|
+
...(typeof body.review_url === "string" ? { review_url: redactToken(body.review_url, token) } : {}),
|
|
75
|
+
};
|
|
76
|
+
return ack;
|
|
77
|
+
}
|
|
78
|
+
/** GET one message (the submitter-bound pull, agent bearer). Embeds the terminal Response.
|
|
79
|
+
* A `2xx` returns the parsed body; every other status maps to a §7 exit code. */
|
|
80
|
+
export async function pollMessage(ctx, token, id, timeoutMs) {
|
|
81
|
+
const url = `${ctx.config.baseUrl}/v1/messages/${encodeURIComponent(id)}`;
|
|
82
|
+
const init = {
|
|
83
|
+
method: "GET",
|
|
84
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
85
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
86
|
+
};
|
|
87
|
+
let res;
|
|
88
|
+
try {
|
|
89
|
+
res = await ctx.runtime.fetchImpl(url, init);
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
throwTransportError(error, ctx.config.baseUrl);
|
|
93
|
+
}
|
|
94
|
+
if (res.status < 200 || res.status >= 300) {
|
|
95
|
+
const { code, message } = await readErrorEnvelope(res);
|
|
96
|
+
throw hubStatusToCliError(res.status, redactToken(message, token), code);
|
|
97
|
+
}
|
|
98
|
+
const body = await readJson(res);
|
|
99
|
+
// Validate the body shape before the await loop keys terminality on it: the `id` must be present
|
|
100
|
+
// AND match the requested id (a proxy returning a different message would otherwise report the
|
|
101
|
+
// wrong outcome under the requested id), and a `status` valid globally but IMPOSSIBLE for the
|
|
102
|
+
// message's `type` (e.g. an ask-only `cancelled` on a task) would be reported as a real outcome.
|
|
103
|
+
// A malformed / mismatched poll body is a server error, not a completed await.
|
|
104
|
+
if (typeof body.id !== "string" || body.id !== id || !isValidTypeStatus(body.type, body.status)) {
|
|
105
|
+
throw new CliError("server", "the Hub returned a malformed or mismatched message (bad/other id, or a status invalid for its type).");
|
|
106
|
+
}
|
|
107
|
+
// A TERMINAL ask/task body must embed its Response (the pull contract) — else `await` would exit
|
|
108
|
+
// "successfully" with no resolution value/actor. `open`/`delivered` are pre-terminal (no Response).
|
|
109
|
+
if (body.status !== "open" && body.status !== "delivered" && (typeof body.response !== "object" || body.response === null)) {
|
|
110
|
+
throw new CliError("server", "the Hub returned a resolved message with no embedded Response.");
|
|
111
|
+
}
|
|
112
|
+
return body;
|
|
113
|
+
}
|
|
114
|
+
/** GET the agent's mailbox — the human→agent drain (spec §13, agent bearer). A `2xx` returns the
|
|
115
|
+
* signed deliveries; every other status maps to a §7 exit code. `max`, when set, caps the batch via
|
|
116
|
+
* `?max=`. The drain also touches `agent_seen` server-side, so an authenticated poll is itself the
|
|
117
|
+
* presence heartbeat (§15) — nothing extra to send. */
|
|
118
|
+
export async function drainInbox(ctx, token, max) {
|
|
119
|
+
const query = max !== undefined ? `?max=${max}` : "";
|
|
120
|
+
const url = `${ctx.config.baseUrl}/v1/inbox${query}`;
|
|
121
|
+
const init = {
|
|
122
|
+
method: "GET",
|
|
123
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
124
|
+
signal: AbortSignal.timeout(requestTimeoutMs(ctx)),
|
|
125
|
+
};
|
|
126
|
+
let res;
|
|
127
|
+
try {
|
|
128
|
+
res = await ctx.runtime.fetchImpl(url, init);
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
throwTransportError(error, ctx.config.baseUrl);
|
|
132
|
+
}
|
|
133
|
+
if (res.status < 200 || res.status >= 300) {
|
|
134
|
+
const { code, message } = await readErrorEnvelope(res);
|
|
135
|
+
throw hubStatusToCliError(res.status, redactToken(message, token), code);
|
|
136
|
+
}
|
|
137
|
+
const body = await readJson(res);
|
|
138
|
+
// Validate the drain shape before the loop trusts it: `directives` MUST be an array, and every
|
|
139
|
+
// element MUST carry an object `directive` with a string `id` (the dedup + ack key) and a string
|
|
140
|
+
// `signature` (forwarded to the runtime). A malformed body is a server error, not an empty drain —
|
|
141
|
+
// silently treating garbage as "no directives" would strand real mail. Mirrors submitEnvelope's
|
|
142
|
+
// defensive 202 validation.
|
|
143
|
+
const directives = body.directives;
|
|
144
|
+
if (!Array.isArray(directives) || !directives.every(isInboundDelivery)) {
|
|
145
|
+
throw new CliError("server", "the Hub returned a malformed inbox drain (expected { directives: [{ directive: { id }, signature }] }).");
|
|
146
|
+
}
|
|
147
|
+
return { directives: directives };
|
|
148
|
+
}
|
|
149
|
+
/** POST a single batched consume-ack for the drained ids — the §14 directive receipt (agent bearer).
|
|
150
|
+
* A `2xx` returns the consumed count; every other status maps to a §7 exit code. */
|
|
151
|
+
export async function ackInbox(ctx, token, ids) {
|
|
152
|
+
const url = `${ctx.config.baseUrl}/v1/inbox/ack`;
|
|
153
|
+
const init = {
|
|
154
|
+
method: "POST",
|
|
155
|
+
headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` },
|
|
156
|
+
body: JSON.stringify({ ids }),
|
|
157
|
+
signal: AbortSignal.timeout(requestTimeoutMs(ctx)),
|
|
158
|
+
};
|
|
159
|
+
let res;
|
|
160
|
+
try {
|
|
161
|
+
res = await ctx.runtime.fetchImpl(url, init);
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
throwTransportError(error, ctx.config.baseUrl);
|
|
165
|
+
}
|
|
166
|
+
if (res.status < 200 || res.status >= 300) {
|
|
167
|
+
const { code, message } = await readErrorEnvelope(res);
|
|
168
|
+
throw hubStatusToCliError(res.status, redactToken(message, token), code);
|
|
169
|
+
}
|
|
170
|
+
const body = await readJson(res);
|
|
171
|
+
// The Hub returns the ids it actually consumed (spec §14; server `ackDirectives` → string[]), not a
|
|
172
|
+
// count — validate that shape so a contract drift surfaces as a clean server error, not a silent cast.
|
|
173
|
+
const acked = body.acked;
|
|
174
|
+
if (!Array.isArray(acked) || !acked.every((id) => typeof id === "string")) {
|
|
175
|
+
throw new CliError("server", "the Hub consumed the directives but returned a malformed ack result.");
|
|
176
|
+
}
|
|
177
|
+
return { acked: acked };
|
|
178
|
+
}
|
|
179
|
+
/** Structural guard for one drained delivery: an object `directive` carrying string `id` / `from` /
|
|
180
|
+
* `title` (and, when present, a string `priority`), plus a string `signature`. `id` is the dedup +
|
|
181
|
+
* ack key; `from`/`title`/`priority` are dereferenced on the human emit path (`sanitizeForTerminal`
|
|
182
|
+
* would throw on a non-string), so a directive whose value for any of them isn't a string must be
|
|
183
|
+
* rejected here as a `server` error at drain — never handed to the loop to crash mid-stream. */
|
|
184
|
+
function isInboundDelivery(value) {
|
|
185
|
+
if (value === null || typeof value !== "object")
|
|
186
|
+
return false;
|
|
187
|
+
const { directive, signature } = value;
|
|
188
|
+
if (typeof signature !== "string")
|
|
189
|
+
return false;
|
|
190
|
+
if (directive === null || typeof directive !== "object")
|
|
191
|
+
return false;
|
|
192
|
+
const d = directive;
|
|
193
|
+
if (typeof d.id !== "string" || typeof d.from !== "string" || typeof d.title !== "string")
|
|
194
|
+
return false;
|
|
195
|
+
return d.priority === undefined || typeof d.priority === "string";
|
|
196
|
+
}
|
|
197
|
+
/** Valid lifecycle statuses per message type (spec §7). A status valid for one type but not the
|
|
198
|
+
* message's actual type is a malformed body. `delivered` is terminal-on-acceptance for `notify`
|
|
199
|
+
* ONLY — ask/task go from `open` straight to a resolution, so a `{type:"ask", status:"delivered"}`
|
|
200
|
+
* must be rejected (else the await loop would treat it as non-terminal and hang to timeout). */
|
|
201
|
+
const STATUSES_BY_TYPE = {
|
|
202
|
+
notify: new Set(["open", "delivered"]),
|
|
203
|
+
ask: new Set(["open", "answered", "declined", "cancelled", "expired"]),
|
|
204
|
+
task: new Set(["open", "completed", "dismissed", "expired"]),
|
|
205
|
+
};
|
|
206
|
+
function isValidTypeStatus(type, status) {
|
|
207
|
+
if (typeof type !== "string" || typeof status !== "string")
|
|
208
|
+
return false;
|
|
209
|
+
const allowed = STATUSES_BY_TYPE[type];
|
|
210
|
+
return allowed !== undefined && allowed.has(status);
|
|
211
|
+
}
|
|
212
|
+
/** Map a Hub error response to a CliError. The exit code comes from the HTTP status; the stable
|
|
213
|
+
* `error.code` string (§8) prefers the Hub's own `error.code` when it maps to the SAME exit tier
|
|
214
|
+
* — so a documented code like `version_not_supported` survives instead of being flattened to
|
|
215
|
+
* `bad_request` (both exit 9), without letting a Hub-supplied code change the exit semantics. The
|
|
216
|
+
* server message is stripped of terminal control chars (the top-level catch prints it). */
|
|
217
|
+
function hubStatusToCliError(status, message, hubCode) {
|
|
218
|
+
const detail = message !== undefined ? sanitizeForTerminal(message) : `Hub returned ${status}.`;
|
|
219
|
+
const base = statusToErrorCode(status);
|
|
220
|
+
// Preserve the Hub's code ONLY when it is a documented §8 code AND maps to the same exit tier —
|
|
221
|
+
// an unrecognized code (e.g. `rate_limited` on a 429) must not leak into the CLI envelope, and a
|
|
222
|
+
// recognized code from a different tier must not change the exit semantics.
|
|
223
|
+
if (hubCode !== undefined && isErrorCode(hubCode) && exitCodeForError(hubCode) === exitCodeForError(base)) {
|
|
224
|
+
return new CliError(hubCode, detail);
|
|
225
|
+
}
|
|
226
|
+
return new CliError(base, detail);
|
|
227
|
+
}
|
|
228
|
+
/** The stable `error.code` implied by an HTTP status (§7/§8). */
|
|
229
|
+
function statusToErrorCode(status) {
|
|
230
|
+
if (status === 401 || status === 403)
|
|
231
|
+
return "auth";
|
|
232
|
+
if (status === 404)
|
|
233
|
+
return "not_found";
|
|
234
|
+
if (status === 409)
|
|
235
|
+
return "conflict";
|
|
236
|
+
if (status === 413)
|
|
237
|
+
return "payload_too_large";
|
|
238
|
+
if (status === 422)
|
|
239
|
+
return "validation_error";
|
|
240
|
+
if (status === 400)
|
|
241
|
+
return "bad_request";
|
|
242
|
+
if (status >= 500)
|
|
243
|
+
return "server";
|
|
244
|
+
return "error";
|
|
245
|
+
}
|
|
246
|
+
/** Parse a response body as a JSON object, defensively — a fake without `json()`, a non-JSON
|
|
247
|
+
* body, or a non-object all collapse to `{}`, so callers read fields off a plain record. */
|
|
248
|
+
async function readJson(res) {
|
|
249
|
+
if (typeof res.json !== "function")
|
|
250
|
+
return {};
|
|
251
|
+
try {
|
|
252
|
+
const parsed = await res.json();
|
|
253
|
+
return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)
|
|
254
|
+
? parsed
|
|
255
|
+
: {};
|
|
256
|
+
}
|
|
257
|
+
catch {
|
|
258
|
+
return {};
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
/** Read the A2H error envelope `{ error: { code, message } }` from a non-2xx response. */
|
|
262
|
+
async function readErrorEnvelope(res) {
|
|
263
|
+
const body = await readJson(res);
|
|
264
|
+
const error = body.error;
|
|
265
|
+
const record = error !== null && typeof error === "object" ? error : {};
|
|
266
|
+
const message = typeof record.message === "string" && record.message.trim() !== "" ? record.message.trim() : undefined;
|
|
267
|
+
const code = typeof record.code === "string" && record.code.trim() !== "" ? record.code.trim() : undefined;
|
|
268
|
+
return { code, message };
|
|
269
|
+
}
|
|
270
|
+
//# sourceMappingURL=http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../../src/commands/messaging/http.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { CommandContext } from "../context.js";
|
|
2
|
+
/** Resolve the effective bearer, opening the local store only when the CI env token is absent
|
|
3
|
+
* (matches `whoami` — skip probing the OS keychain when `MA2H_AGENT_TOKEN` already resolves it).
|
|
4
|
+
* `accountOverride`, when given, is the AUTHORITATIVE store lookup key and wins over
|
|
5
|
+
* `ctx.config.account` — used by `--envelope` replay: a verbatim replay authenticates as the
|
|
6
|
+
* captured envelope's `agent.id` (the Hub 403s if the bearer's agent ≠ the envelope's), so the
|
|
7
|
+
* token must be looked up by that id, not by a configured `default_account`. The env token (CI)
|
|
8
|
+
* still wins over both. */
|
|
9
|
+
export declare function resolveBearer(ctx: CommandContext, accountOverride?: string): Promise<string | undefined>;
|
|
10
|
+
/** The bearer + submitting agent id required for a REAL (non-dry-run) submit. Uses the same
|
|
11
|
+
* `resolveIdentity` helper `whoami`/`agents` use — so besides an explicit `--account`/`MA2H_AGENT_ID`
|
|
12
|
+
* it also DISCOVERS the sole stored identity for the Hub (the zero-config path after a device-code
|
|
13
|
+
* `oh-hai login`), letting `notify`/`ask`/`task` work without redundantly naming the account. A
|
|
14
|
+
* missing/ambiguous account is a usage error (exit 2, "pass --account") — actionable, and it beats
|
|
15
|
+
* an auth error that would wrongly send the caller to re-login; a known account with no token is
|
|
16
|
+
* the auth error (exit 3). The submitting `agent.id` MUST equal the bound bearer or the Hub 403s. */
|
|
17
|
+
export declare function resolveSubmitIdentity(ctx: CommandContext): Promise<{
|
|
18
|
+
token: string;
|
|
19
|
+
agentId: string;
|
|
20
|
+
}>;
|
|
21
|
+
/** The bearer required when no resolved account is needed — an `await` (poll keyed by message id
|
|
22
|
+
* + the submitter-bound bearer). Uses `resolveIdentity` so a zero-config single stored identity is
|
|
23
|
+
* discovered for the token lookup. A missing token is an auth error (exit 3). */
|
|
24
|
+
export declare function requireToken(ctx: CommandContext): Promise<string>;
|
|
25
|
+
/** The bearer for an `--envelope` replay. The captured envelope already carries the submitting
|
|
26
|
+
* `agent.id`, so fall back to it for the store lookup when no explicit `--account` was given —
|
|
27
|
+
* otherwise a user with a stored login but no `default_account` following the replay example
|
|
28
|
+
* would hit a spurious auth error. A missing token is an auth error (exit 3). */
|
|
29
|
+
export declare function requireReplayToken(ctx: CommandContext, envelopeAgentId: string): Promise<string>;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// Account-aware credential resolution for the messaging commands (spec §5/§6). This is the
|
|
2
|
+
// productization delta over `scripts/*`: instead of reading `MA2H_AGENT_TOKEN`/`MA2H_AGENT_ID`
|
|
3
|
+
// straight from env, the bearer is resolved through the same layered store `whoami` uses —
|
|
4
|
+
// `MA2H_AGENT_TOKEN` (CI path) wins, else the keychain, else the 0600 file — and the submitting
|
|
5
|
+
// agent id comes from resolved config (`--account`/`--agent`/`MA2H_AGENT_ID`/`default_account`).
|
|
6
|
+
import { resolveIdentity, resolveToken } from "../../auth/resolve-token.js";
|
|
7
|
+
import { CliError } from "../../envelope.js";
|
|
8
|
+
/** The "no token" auth error (exit 3), shared by the submit and await/replay resolvers. */
|
|
9
|
+
const NOT_AUTHENTICATED = "not authenticated — no stored token (run `oh-hai login`, or set MA2H_AGENT_TOKEN).";
|
|
10
|
+
/** Resolve the effective bearer, opening the local store only when the CI env token is absent
|
|
11
|
+
* (matches `whoami` — skip probing the OS keychain when `MA2H_AGENT_TOKEN` already resolves it).
|
|
12
|
+
* `accountOverride`, when given, is the AUTHORITATIVE store lookup key and wins over
|
|
13
|
+
* `ctx.config.account` — used by `--envelope` replay: a verbatim replay authenticates as the
|
|
14
|
+
* captured envelope's `agent.id` (the Hub 403s if the bearer's agent ≠ the envelope's), so the
|
|
15
|
+
* token must be looked up by that id, not by a configured `default_account`. The env token (CI)
|
|
16
|
+
* still wins over both. */
|
|
17
|
+
export async function resolveBearer(ctx, accountOverride) {
|
|
18
|
+
const store = ctx.config.tokenSource === "env" ? undefined : await ctx.runtime.openStore();
|
|
19
|
+
const config = accountOverride !== undefined ? { ...ctx.config, account: accountOverride } : ctx.config;
|
|
20
|
+
const { token } = await resolveToken(config, store);
|
|
21
|
+
return token;
|
|
22
|
+
}
|
|
23
|
+
/** The bearer + submitting agent id required for a REAL (non-dry-run) submit. Uses the same
|
|
24
|
+
* `resolveIdentity` helper `whoami`/`agents` use — so besides an explicit `--account`/`MA2H_AGENT_ID`
|
|
25
|
+
* it also DISCOVERS the sole stored identity for the Hub (the zero-config path after a device-code
|
|
26
|
+
* `oh-hai login`), letting `notify`/`ask`/`task` work without redundantly naming the account. A
|
|
27
|
+
* missing/ambiguous account is a usage error (exit 2, "pass --account") — actionable, and it beats
|
|
28
|
+
* an auth error that would wrongly send the caller to re-login; a known account with no token is
|
|
29
|
+
* the auth error (exit 3). The submitting `agent.id` MUST equal the bound bearer or the Hub 403s. */
|
|
30
|
+
export async function resolveSubmitIdentity(ctx) {
|
|
31
|
+
const store = ctx.config.tokenSource === "env" ? undefined : await ctx.runtime.openStore();
|
|
32
|
+
const { account, token } = await resolveIdentity(ctx.config, store);
|
|
33
|
+
if (account === undefined) {
|
|
34
|
+
throw new CliError("usage", "an agent id is required — pass --account/--agent, set MA2H_AGENT_ID, or log in so a single stored identity is discovered.");
|
|
35
|
+
}
|
|
36
|
+
if (token === undefined) {
|
|
37
|
+
throw new CliError("auth", NOT_AUTHENTICATED);
|
|
38
|
+
}
|
|
39
|
+
return { token, agentId: account };
|
|
40
|
+
}
|
|
41
|
+
/** The bearer required when no resolved account is needed — an `await` (poll keyed by message id
|
|
42
|
+
* + the submitter-bound bearer). Uses `resolveIdentity` so a zero-config single stored identity is
|
|
43
|
+
* discovered for the token lookup. A missing token is an auth error (exit 3). */
|
|
44
|
+
export async function requireToken(ctx) {
|
|
45
|
+
const store = ctx.config.tokenSource === "env" ? undefined : await ctx.runtime.openStore();
|
|
46
|
+
const { token } = await resolveIdentity(ctx.config, store);
|
|
47
|
+
if (token === undefined) {
|
|
48
|
+
throw new CliError("auth", NOT_AUTHENTICATED);
|
|
49
|
+
}
|
|
50
|
+
return token;
|
|
51
|
+
}
|
|
52
|
+
/** The bearer for an `--envelope` replay. The captured envelope already carries the submitting
|
|
53
|
+
* `agent.id`, so fall back to it for the store lookup when no explicit `--account` was given —
|
|
54
|
+
* otherwise a user with a stored login but no `default_account` following the replay example
|
|
55
|
+
* would hit a spurious auth error. A missing token is an auth error (exit 3). */
|
|
56
|
+
export async function requireReplayToken(ctx, envelopeAgentId) {
|
|
57
|
+
const token = await resolveBearer(ctx, envelopeAgentId);
|
|
58
|
+
if (token === undefined) {
|
|
59
|
+
throw new CliError("auth", NOT_AUTHENTICATED);
|
|
60
|
+
}
|
|
61
|
+
return token;
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=identity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity.js","sourceRoot":"","sources":["../../../src/commands/messaging/identity.ts"],"names":[],"mappings":"AAAA,2FAA2F;AAC3F,+FAA+F;AAC/F,2FAA2F;AAC3F,gGAAgG;AAChG,iGAAiG;AAEjG,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAG7C,2FAA2F;AAC3F,MAAM,iBAAiB,GAAG,oFAAoF,CAAC;AAE/G;;;;;;4BAM4B;AAC5B,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,GAAmB,EAAE,eAAwB;IAC/E,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,WAAW,KAAK,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;IAC3F,MAAM,MAAM,GAAG,eAAe,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,eAAe,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;IACxG,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,YAAY,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACpD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;sGAMsG;AACtG,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,GAAmB;IAC7D,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,WAAW,KAAK,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;IAC3F,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,MAAM,eAAe,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACpE,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,MAAM,IAAI,QAAQ,CAChB,OAAO,EACP,2HAA2H,CAC5H,CAAC;IACJ,CAAC;IACD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,MAAM,IAAI,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IAChD,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AACrC,CAAC;AAED;;kFAEkF;AAClF,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,GAAmB;IACpD,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,WAAW,KAAK,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;IAC3F,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,eAAe,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAC3D,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,MAAM,IAAI,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IAChD,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;kFAGkF;AAClF,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,GAAmB,EAAE,eAAuB;IACnF,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC;IACxD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,MAAM,IAAI,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IAChD,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { CommandContext } from "../context.js";
|
|
2
|
+
import type { SubmitAck } from "./wire.js";
|
|
3
|
+
/** The connection flags to append to a printed `await` resume hint so it is copy-paste-runnable
|
|
4
|
+
* regardless of how the submit resolved them: a non-default `--base-url` and a set `--account`.
|
|
5
|
+
* Without these, a hint after a CLI-routed submit (`--base-url … --account …`, no env/config) would
|
|
6
|
+
* poll the default Hub / have no account for the token lookup. These are LOCAL config (not
|
|
7
|
+
* Hub-supplied), so no terminal-sanitization is needed. */
|
|
8
|
+
export declare function resumeRoutingSuffix(ctx: CommandContext): string;
|
|
9
|
+
/** Strip terminal control characters (C0/C1 + DEL) from a Hub-supplied string before echoing it
|
|
10
|
+
* to the terminal on a HUMAN output path — a malicious/compromised Hub could otherwise inject
|
|
11
|
+
* ANSI/escape sequences via an ack field or a resolution's value/comment/actor. The `--json`
|
|
12
|
+
* path is unaffected (JSON.stringify escapes control chars). Mirrors login.ts / http.ts; built by
|
|
13
|
+
* code point to avoid a control-char regex literal. */
|
|
14
|
+
export declare function sanitizeForTerminal(value: string): string;
|
|
15
|
+
/** Node's setTimeout / AbortSignal.timeout ceiling (max 32-bit signed int) — a larger delay
|
|
16
|
+
* overflows to ~immediate. Shared by every ms-flag validator so the ceiling lives in one place. */
|
|
17
|
+
export declare const MAX_TIMER_MS = 2147483647;
|
|
18
|
+
/** Parse a strictly-positive INTEGER flag; a NaN / fractional / 0 / negative / over-`ceiling` value is
|
|
19
|
+
* a usage error (exit 2). `ceiling` defaults to the timer range (correct for delay flags like
|
|
20
|
+
* `--interval` that would overflow setTimeout if huge); pass a smaller cap for count flags like
|
|
21
|
+
* `--max`. `detail` tailors the message to the flag's unit (e.g. "a positive integer number of
|
|
22
|
+
* milliseconds"). */
|
|
23
|
+
export declare function positiveInt(raw: string | undefined, flag: string, detail?: string, ceiling?: number): number;
|
|
24
|
+
/** Coerce a `parseArgs` value (string | boolean | string[] | undefined under strict:false) to a
|
|
25
|
+
* plain string, or undefined. A repeated single-value flag arrives as an array — take the last. */
|
|
26
|
+
export declare function stringFlag(value: unknown): string | undefined;
|
|
27
|
+
/** Strictly parse a boolean switch. Unlike the lenient `flagOn`, an unrecognized explicit value
|
|
28
|
+
* (`--flag=treu`) is a USAGE error rather than silently `false` — otherwise a typo on a
|
|
29
|
+
* behavior-changing switch falls through to the wrong mode (a LIVE submit, or an infinite loop
|
|
30
|
+
* instead of a one-shot). Absent → false; bare or a recognized on/off token → the boolean;
|
|
31
|
+
* anything else → exit 2. */
|
|
32
|
+
export declare function strictBoolFlag(value: unknown, flag: string): boolean;
|
|
33
|
+
/** The `--dry-run` safety switch — a `strictBoolFlag` so a typo (`--dry-run=treu`) is a usage error,
|
|
34
|
+
* not a silent fall-through to a LIVE submit. */
|
|
35
|
+
export declare function dryRunFlag(value: unknown): boolean;
|
|
36
|
+
/** A value flag that, when present, must be non-empty. An explicit `--flag=` would otherwise ship
|
|
37
|
+
* a blank `idempotency_key`/`created_at`; the Hub dedupes on the key, so a blank collides (and a
|
|
38
|
+
* blank timestamp is invalid). Returns undefined when the flag is absent. Shared by ask + task. */
|
|
39
|
+
export declare function requireNonEmpty(flags: Record<string, unknown>, name: string): string | undefined;
|
|
40
|
+
/** Reject flags that belong to a DIFFERENT subcommand (e.g. `ask await --resolver`, `ask submit
|
|
41
|
+
* --interval`) rather than silently ignoring them (spec's loud-fail discipline). `values` is the
|
|
42
|
+
* parsed flag map; `keys` are the foreign flag names to reject for this subcommand. */
|
|
43
|
+
export declare function assertNoForeignFlags(values: Record<string, unknown>, keys: readonly string[], context: string): void;
|
|
44
|
+
/** The run id stamped on the envelope — `MA2H_AGENT_RUN_ID` (env-only, kept stable across an
|
|
45
|
+
* idempotent retry, §6) or a fresh `run_<uuid>`. Matches the scripts layer. */
|
|
46
|
+
export declare function resolveRunId(): string;
|
|
47
|
+
/** Print the common human-readable submit acknowledgement (headline + id + status, plus the
|
|
48
|
+
* poll URL when relevant and a review URL when the Hub returned one). Commands append their own
|
|
49
|
+
* next-step hint after calling this. Never prints the token (§5.4). */
|
|
50
|
+
export declare function printSubmitAck(ctx: CommandContext, headline: string, ack: SubmitAck, includePoll?: boolean): void;
|
|
51
|
+
/** Print a composed envelope under `--dry-run`: human → pretty JSON; `--json` → the uniform
|
|
52
|
+
* envelope wrapping it (`{ dry_run: true, envelope }`). Posts nothing. */
|
|
53
|
+
export declare function printDryRunEnvelope(ctx: CommandContext, command: string, envelope: unknown): void;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
// Small helpers shared by the notify / ask / task command handlers: flag coercion, the
|
|
2
|
+
// deferred-`--state` rejection, the submitting run id, and the human-readable submit
|
|
3
|
+
// acknowledgement. Kept here so the three commands stay consistent (cli spec §4.4 / §8).
|
|
4
|
+
import { randomUUID } from "node:crypto";
|
|
5
|
+
import { DEFAULT_BASE_URL } from "../../config.js";
|
|
6
|
+
import { CliError, buildOk, serializeEnvelope } from "../../envelope.js";
|
|
7
|
+
/** The connection flags to append to a printed `await` resume hint so it is copy-paste-runnable
|
|
8
|
+
* regardless of how the submit resolved them: a non-default `--base-url` and a set `--account`.
|
|
9
|
+
* Without these, a hint after a CLI-routed submit (`--base-url … --account …`, no env/config) would
|
|
10
|
+
* poll the default Hub / have no account for the token lookup. These are LOCAL config (not
|
|
11
|
+
* Hub-supplied), so no terminal-sanitization is needed. */
|
|
12
|
+
export function resumeRoutingSuffix(ctx) {
|
|
13
|
+
const parts = [];
|
|
14
|
+
if (ctx.config.baseUrl !== DEFAULT_BASE_URL)
|
|
15
|
+
parts.push(`--base-url ${ctx.config.baseUrl}`);
|
|
16
|
+
if (ctx.config.account !== undefined)
|
|
17
|
+
parts.push(`--account ${ctx.config.account}`);
|
|
18
|
+
return parts.length > 0 ? ` ${parts.join(" ")}` : "";
|
|
19
|
+
}
|
|
20
|
+
/** Strip terminal control characters (C0/C1 + DEL) from a Hub-supplied string before echoing it
|
|
21
|
+
* to the terminal on a HUMAN output path — a malicious/compromised Hub could otherwise inject
|
|
22
|
+
* ANSI/escape sequences via an ack field or a resolution's value/comment/actor. The `--json`
|
|
23
|
+
* path is unaffected (JSON.stringify escapes control chars). Mirrors login.ts / http.ts; built by
|
|
24
|
+
* code point to avoid a control-char regex literal. */
|
|
25
|
+
export function sanitizeForTerminal(value) {
|
|
26
|
+
let out = "";
|
|
27
|
+
for (const ch of value) {
|
|
28
|
+
const code = ch.codePointAt(0) ?? 0;
|
|
29
|
+
if (code > 0x1f && code !== 0x7f && !(code >= 0x80 && code <= 0x9f))
|
|
30
|
+
out += ch;
|
|
31
|
+
}
|
|
32
|
+
return out;
|
|
33
|
+
}
|
|
34
|
+
/** Node's setTimeout / AbortSignal.timeout ceiling (max 32-bit signed int) — a larger delay
|
|
35
|
+
* overflows to ~immediate. Shared by every ms-flag validator so the ceiling lives in one place. */
|
|
36
|
+
export const MAX_TIMER_MS = 2_147_483_647;
|
|
37
|
+
/** Parse a strictly-positive INTEGER flag; a NaN / fractional / 0 / negative / over-`ceiling` value is
|
|
38
|
+
* a usage error (exit 2). `ceiling` defaults to the timer range (correct for delay flags like
|
|
39
|
+
* `--interval` that would overflow setTimeout if huge); pass a smaller cap for count flags like
|
|
40
|
+
* `--max`. `detail` tailors the message to the flag's unit (e.g. "a positive integer number of
|
|
41
|
+
* milliseconds"). */
|
|
42
|
+
export function positiveInt(raw, flag, detail = "a positive integer", ceiling = MAX_TIMER_MS) {
|
|
43
|
+
const n = raw !== undefined ? Number(raw) : NaN;
|
|
44
|
+
if (!Number.isInteger(n) || n <= 0 || n > ceiling) {
|
|
45
|
+
throw new CliError("usage", `${flag} must be ${detail} (at most ${ceiling}).`);
|
|
46
|
+
}
|
|
47
|
+
return n;
|
|
48
|
+
}
|
|
49
|
+
/** Coerce a `parseArgs` value (string | boolean | string[] | undefined under strict:false) to a
|
|
50
|
+
* plain string, or undefined. A repeated single-value flag arrives as an array — take the last. */
|
|
51
|
+
export function stringFlag(value) {
|
|
52
|
+
if (typeof value === "string")
|
|
53
|
+
return value;
|
|
54
|
+
if (Array.isArray(value)) {
|
|
55
|
+
const last = value[value.length - 1];
|
|
56
|
+
return typeof last === "string" ? last : undefined;
|
|
57
|
+
}
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
/** Strictly parse a boolean switch. Unlike the lenient `flagOn`, an unrecognized explicit value
|
|
61
|
+
* (`--flag=treu`) is a USAGE error rather than silently `false` — otherwise a typo on a
|
|
62
|
+
* behavior-changing switch falls through to the wrong mode (a LIVE submit, or an infinite loop
|
|
63
|
+
* instead of a one-shot). Absent → false; bare or a recognized on/off token → the boolean;
|
|
64
|
+
* anything else → exit 2. */
|
|
65
|
+
export function strictBoolFlag(value, flag) {
|
|
66
|
+
if (value === undefined)
|
|
67
|
+
return false;
|
|
68
|
+
if (value === true)
|
|
69
|
+
return true;
|
|
70
|
+
if (Array.isArray(value))
|
|
71
|
+
return value.length > 0 ? strictBoolFlag(value[value.length - 1], flag) : false;
|
|
72
|
+
if (typeof value === "string") {
|
|
73
|
+
const v = value.trim().toLowerCase();
|
|
74
|
+
if (v === "" || v === "true" || v === "1" || v === "yes" || v === "on")
|
|
75
|
+
return true;
|
|
76
|
+
if (v === "false" || v === "0" || v === "no" || v === "off")
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
throw new CliError("usage", `${flag} does not accept the value ${JSON.stringify(value)}; use ${flag} or ${flag}=true|false.`);
|
|
80
|
+
}
|
|
81
|
+
/** The `--dry-run` safety switch — a `strictBoolFlag` so a typo (`--dry-run=treu`) is a usage error,
|
|
82
|
+
* not a silent fall-through to a LIVE submit. */
|
|
83
|
+
export function dryRunFlag(value) {
|
|
84
|
+
return strictBoolFlag(value, "--dry-run");
|
|
85
|
+
}
|
|
86
|
+
/** A value flag that, when present, must be non-empty. An explicit `--flag=` would otherwise ship
|
|
87
|
+
* a blank `idempotency_key`/`created_at`; the Hub dedupes on the key, so a blank collides (and a
|
|
88
|
+
* blank timestamp is invalid). Returns undefined when the flag is absent. Shared by ask + task. */
|
|
89
|
+
export function requireNonEmpty(flags, name) {
|
|
90
|
+
const v = stringFlag(flags[name]);
|
|
91
|
+
if (v !== undefined && v.trim() === "") {
|
|
92
|
+
throw new CliError("usage", `--${name} was given an empty value — omit the flag for a fresh key, or pass a concrete value.`);
|
|
93
|
+
}
|
|
94
|
+
return v;
|
|
95
|
+
}
|
|
96
|
+
/** Reject flags that belong to a DIFFERENT subcommand (e.g. `ask await --resolver`, `ask submit
|
|
97
|
+
* --interval`) rather than silently ignoring them (spec's loud-fail discipline). `values` is the
|
|
98
|
+
* parsed flag map; `keys` are the foreign flag names to reject for this subcommand. */
|
|
99
|
+
export function assertNoForeignFlags(values, keys, context) {
|
|
100
|
+
const present = keys.filter((k) => values[k] !== undefined);
|
|
101
|
+
if (present.length > 0) {
|
|
102
|
+
const list = present.map((k) => `--${k}`).join(", ");
|
|
103
|
+
throw new CliError("usage", `${list} ${present.length > 1 ? "are" : "is"} not valid for '${context}'.`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/** The run id stamped on the envelope — `MA2H_AGENT_RUN_ID` (env-only, kept stable across an
|
|
107
|
+
* idempotent retry, §6) or a fresh `run_<uuid>`. Matches the scripts layer. */
|
|
108
|
+
export function resolveRunId() {
|
|
109
|
+
const raw = process.env.MA2H_AGENT_RUN_ID?.trim();
|
|
110
|
+
return raw !== undefined && raw !== "" ? raw : `run_${randomUUID()}`;
|
|
111
|
+
}
|
|
112
|
+
/** Print the common human-readable submit acknowledgement (headline + id + status, plus the
|
|
113
|
+
* poll URL when relevant and a review URL when the Hub returned one). Commands append their own
|
|
114
|
+
* next-step hint after calling this. Never prints the token (§5.4). */
|
|
115
|
+
export function printSubmitAck(ctx, headline, ack, includePoll = false) {
|
|
116
|
+
// ack fields are Hub-supplied — sanitize before echoing to the terminal (§5.4 posture).
|
|
117
|
+
ctx.io.log(`✅ ${headline}`);
|
|
118
|
+
ctx.io.log(` id: ${sanitizeForTerminal(ack.id)}`);
|
|
119
|
+
ctx.io.log(` status: ${sanitizeForTerminal(ack.status)}`);
|
|
120
|
+
if (includePoll && ack.poll_url)
|
|
121
|
+
ctx.io.log(` poll_url: ${sanitizeForTerminal(ack.poll_url)}`);
|
|
122
|
+
if (ack.review_url)
|
|
123
|
+
ctx.io.log(` review_url: ${sanitizeForTerminal(ack.review_url)}`);
|
|
124
|
+
}
|
|
125
|
+
/** Print a composed envelope under `--dry-run`: human → pretty JSON; `--json` → the uniform
|
|
126
|
+
* envelope wrapping it (`{ dry_run: true, envelope }`). Posts nothing. */
|
|
127
|
+
export function printDryRunEnvelope(ctx, command, envelope) {
|
|
128
|
+
if (ctx.json) {
|
|
129
|
+
ctx.io.log(serializeEnvelope(buildOk(command, { dry_run: true, envelope: envelope })));
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
ctx.io.log(JSON.stringify(envelope, null, 2));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=shared.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../../../src/commands/messaging/shared.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { A2hResponse, GetMessageBody, JsonObject } from "./wire.js";
|
|
2
|
+
/** The env var carrying the agent's 32-byte state-seal key (base64url). Agent-runtime-provisioned,
|
|
3
|
+
* Hub-invisible, distinct from the bearer, and never embedded in `state` (spec §9.3). */
|
|
4
|
+
export declare const STATE_SEAL_KEY_ENV = "MA2H_STATE_SEAL_KEY";
|
|
5
|
+
/** Read + validate the agent state-seal key from the env. Returns undefined when unset; throws a
|
|
6
|
+
* usage error (exit 2) when set but not exactly 32 bytes. */
|
|
7
|
+
export declare function readSealKey(): Buffer | undefined;
|
|
8
|
+
/** Wrap an agent-owned resume object as a sealed envelope `state` value (`{ sealed: "MA2HSEALv1.…" }`).
|
|
9
|
+
* The seal key is Hub-invisible (spec §9.3). */
|
|
10
|
+
export declare function sealResumeState(resume: JsonObject, key: Buffer): JsonObject;
|
|
11
|
+
/** Open the agent-owned sealed `state` round-tripped in a Response (`{ sealed: "MA2HSEALv1.…" }`).
|
|
12
|
+
* Returns undefined when the Response carries no sealed state. Throws on tamper / wrong key. */
|
|
13
|
+
export declare function openSealedState(response: A2hResponse, key: Buffer): JsonObject | undefined;
|
|
14
|
+
/** Await-side opener shared by `ask await` / `task await`: when the resolved message carries a
|
|
15
|
+
* sealed `state` AND `MA2H_STATE_SEAL_KEY` is set, open it. Returns undefined when there is no
|
|
16
|
+
* sealed blob or the key is unset (opening is opt-in — a missing key is not an error). Only the
|
|
17
|
+
* presence of a sealed blob makes the key relevant, so the key is read *after* confirming there is
|
|
18
|
+
* something to open: a set-but-malformed key then fails only the awaits that actually need to open
|
|
19
|
+
* state (a usage error, exit 2) instead of breaking every await. An open failure on a present
|
|
20
|
+
* blob (tamper / wrong key) is a generic error (non-zero) rather than a silent drop of the resume
|
|
21
|
+
* context. (This defers the key check the scripts layer does eagerly — a deliberate CLI nicety.) */
|
|
22
|
+
export declare function openResumeState(body: GetMessageBody): JsonObject | undefined;
|
|
23
|
+
/** Submit-side resolver shared by notify / ask / task: parse the `--state` flag (must be a JSON
|
|
24
|
+
* object), require the seal key, and return the sealed envelope `state`. Returns undefined when
|
|
25
|
+
* `--state` is absent. A non-object payload or a missing key is a usage error (exit 2). */
|
|
26
|
+
export declare function resolveState(raw: string | undefined): JsonObject | undefined;
|