@linkedclaw/cli 0.1.0 → 0.1.2

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/dist/bin.js CHANGED
@@ -3878,7 +3878,7 @@ function withTimeout(p, ms, code) {
3878
3878
  function escapeRegex(s) {
3879
3879
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
3880
3880
  }
3881
- var LinkedClawError, NetworkError, ApiError, ConfigError, HandlerError, CloudClient, RequesterFlows, TOOL_CALL_PATTERNS, SYSTEM_PATTERNS, DEFAULT_OUTPUT_PATTERNS, DEFAULT_STRIP_PATTERNS, DEFAULT_CLOUD_URL, DEFAULT_RELAY_URL, MessageType, RelayClient, nodeWsConnector, DEFAULT_INVOKE_TIMEOUT_MS, DEFAULT_SESSION_TURN_TIMEOUT_MS, DEFAULT_BROADCAST_OFFER_TIMEOUT_MS, DEFAULT_BROADCAST_EXECUTE_TIMEOUT_MS, BROADCAST_SUBMIT_MAX_RETRIES, BROADCAST_SUBMIT_BASE_MS, BROADCAST_SUBMIT_CAP_MS, ProviderRuntime, CORE_VERSION;
3881
+ var LinkedClawError, NetworkError, ApiError, ConfigError, HandlerError, CloudClient, RequesterFlows, TOOL_CALL_PATTERNS, SYSTEM_PATTERNS, DEFAULT_OUTPUT_PATTERNS, DEFAULT_STRIP_PATTERNS, DEFAULT_CLOUD_URL, DEFAULT_RELAY_URL, MessageType, DEFAULT_AUTH_FAILURE_CODES, RelayClient, nodeWsConnector, DEFAULT_INVOKE_TIMEOUT_MS, DEFAULT_SESSION_TURN_TIMEOUT_MS, DEFAULT_BROADCAST_OFFER_TIMEOUT_MS, DEFAULT_BROADCAST_EXECUTE_TIMEOUT_MS, BROADCAST_SUBMIT_MAX_RETRIES, BROADCAST_SUBMIT_BASE_MS, BROADCAST_SUBMIT_CAP_MS, ProviderRuntime, CORE_VERSION;
3882
3882
  var init_dist = __esm({
3883
3883
  "../core/dist/index.js"() {
3884
3884
  "use strict";
@@ -3953,14 +3953,16 @@ var init_dist = __esm({
3953
3953
  };
3954
3954
  // --- Agents ---------------------------------------------------------
3955
3955
  agents = {
3956
+ /**
3957
+ * Server's `GET /api/v1/agents` accepts `capability`, `owner`, `status`,
3958
+ * `sort`. It does NOT paginate via `limit`/`offset` — if you need that,
3959
+ * filter client-side after fetching.
3960
+ */
3956
3961
  search: (query) => this.request("/api/v1/agents", { query }),
3957
3962
  get: (agentId) => this.request(`/api/v1/agents/${encodeURIComponent(agentId)}`),
3958
- create: (body) => this.request("/api/v1/agents", { method: "PUT", body }).catch(() => this.request("/api/v1/agents", { method: "POST", body })),
3959
- // ^ Server uses PUT /agents/{id} for update, POST /agents for create on some builds;
3960
- // prefer POST for first-create. The .catch here is defensive, not load-bearing.
3961
- // See agents_service.py for exact verb wiring.
3963
+ create: (body) => this.request("/api/v1/agents", { method: "POST", body }),
3962
3964
  update: (agentId, body) => this.request(`/api/v1/agents/${encodeURIComponent(agentId)}`, {
3963
- method: "PATCH",
3965
+ method: "PUT",
3964
3966
  body
3965
3967
  }),
3966
3968
  delete: (agentId) => this.request(`/api/v1/agents/${encodeURIComponent(agentId)}`, { method: "DELETE" }),
@@ -3970,27 +3972,42 @@ var init_dist = __esm({
3970
3972
  sessions = {
3971
3973
  list: (query) => this.request("/api/v1/sessions", { query }),
3972
3974
  get: (sessionId) => this.request(`/api/v1/sessions/${encodeURIComponent(sessionId)}`),
3973
- events: (sessionId) => this.request(`/api/v1/sessions/${encodeURIComponent(sessionId)}/events`),
3975
+ /**
3976
+ * Server returns `{ events: [...], next_offset: N }`, not a bare array.
3977
+ * Supports `offset` / `limit` query params (default 0 / 100; limit clamped to [1, 1000]).
3978
+ * The events' `seq` field is renamed to `event_seq` in the response.
3979
+ */
3980
+ events: (sessionId, query) => this.request(
3981
+ `/api/v1/sessions/${encodeURIComponent(sessionId)}/events`,
3982
+ { query }
3983
+ ),
3974
3984
  create: (body) => this.request("/api/v1/sessions", { method: "POST", body }),
3975
3985
  activate: (sessionId) => this.request(
3976
3986
  `/api/v1/sessions/${encodeURIComponent(sessionId)}/activate`,
3977
3987
  { method: "POST" }
3978
3988
  ),
3979
- sendMessage: (sessionId, payload, seq) => this.request(
3980
- `/api/v1/sessions/${encodeURIComponent(sessionId)}/messages`,
3981
- { method: "POST", body: { payload, seq } }
3982
- ),
3983
- end: (sessionId, messageCount) => this.request(
3989
+ /**
3990
+ * Send a message in an open session.
3991
+ *
3992
+ * Server requires:
3993
+ * - `seq: int 1`
3994
+ * - `payload: dict` (MUST be an object, not a string)
3995
+ * - JSON size ≤ 64 KiB
3996
+ */
3997
+ sendMessage: (sessionId, payload, seq) => {
3998
+ const body = { seq, payload };
3999
+ return this.request(
4000
+ `/api/v1/sessions/${encodeURIComponent(sessionId)}/messages`,
4001
+ { method: "POST", body }
4002
+ );
4003
+ },
4004
+ end: (sessionId, body) => this.request(
3984
4005
  `/api/v1/sessions/${encodeURIComponent(sessionId)}/end`,
3985
- {
3986
- method: "POST",
3987
- body: messageCount !== void 0 ? { message_count: messageCount } : void 0
3988
- }
3989
- ),
3990
- resume: (sessionId) => this.request(
3991
- `/api/v1/sessions/${encodeURIComponent(sessionId)}/resume`,
3992
- { method: "POST" }
4006
+ { method: "POST", body: body ?? {} }
3993
4007
  ),
4008
+ resume: (sessionId) => this.request(`/api/v1/sessions/${encodeURIComponent(sessionId)}/resume`, {
4009
+ method: "POST"
4010
+ }),
3994
4011
  flag: (sessionId) => this.request(
3995
4012
  `/api/v1/sessions/${encodeURIComponent(sessionId)}/flag`,
3996
4013
  { method: "POST" }
@@ -4006,13 +4023,23 @@ var init_dist = __esm({
4006
4023
  // --- Broadcasts -----------------------------------------------------
4007
4024
  broadcasts = {
4008
4025
  list: (query) => this.request("/api/v1/broadcasts", { query }),
4009
- available: (query) => this.request("/api/v1/broadcasts/available", { query }),
4026
+ available: () => this.request("/api/v1/broadcasts/available"),
4010
4027
  get: (taskId) => this.request(`/api/v1/broadcasts/${encodeURIComponent(taskId)}`),
4011
4028
  create: (body) => this.request("/api/v1/broadcasts", { method: "POST", body }),
4029
+ /**
4030
+ * Accept a broadcast task. Server's `AcceptBroadcastRequest` requires
4031
+ * `agent_id` — the provider must declare which of their agents is accepting.
4032
+ */
4012
4033
  accept: (taskId, body) => this.request(
4013
4034
  `/api/v1/broadcasts/${encodeURIComponent(taskId)}/accept`,
4014
- { method: "POST", body: body ?? {} }
4035
+ { method: "POST", body }
4015
4036
  ),
4037
+ /**
4038
+ * Submit a broadcast result. Server's `SubmitBroadcastRequest`:
4039
+ * - `result_data: str` — required (free-text summary)
4040
+ * - `result_payload: dict | null` — optional structured payload (≤64 KiB)
4041
+ * - `proof: ProofItem[] | null` — optional evidence
4042
+ */
4016
4043
  submit: (taskId, body) => this.request(
4017
4044
  `/api/v1/broadcasts/${encodeURIComponent(taskId)}/submit`,
4018
4045
  { method: "POST", body }
@@ -4053,16 +4080,19 @@ var init_dist = __esm({
4053
4080
  search(capability, extra) {
4054
4081
  return this.cloud.agents.search({ capability, ...extra });
4055
4082
  }
4083
+ /**
4084
+ * Create a session against a provider agent. The server field is
4085
+ * `provider_agent_id` (not `agent_id`). Escrow is computed server-side as
4086
+ * `listing.price_credits × max_messages` — no `max_credits` body field.
4087
+ * Manifests are attached at invoke/message time, not at session create.
4088
+ */
4056
4089
  async hire(params) {
4057
4090
  const req = {
4058
- agent_id: params.agentId,
4091
+ provider_agent_id: params.providerAgentId,
4059
4092
  capability: params.capability
4060
4093
  };
4061
4094
  if (params.maxMessages !== void 0) req.max_messages = params.maxMessages;
4062
- if (params.maxCredits !== void 0) req.max_credits = params.maxCredits;
4063
4095
  if (params.referredBy !== void 0) req.referred_by = params.referredBy;
4064
- if (params.manifestId !== void 0) req.manifest_id = params.manifestId;
4065
- if (params.manifest !== void 0) req.manifest = params.manifest;
4066
4096
  const session = await this.cloud.sessions.create(req);
4067
4097
  if (params.autoActivate === false) {
4068
4098
  return { session };
@@ -4070,11 +4100,19 @@ var init_dist = __esm({
4070
4100
  const activation = await this.cloud.sessions.activate(session.session_id);
4071
4101
  return { session: activation, activation };
4072
4102
  }
4103
+ /**
4104
+ * Send a message in an active session.
4105
+ *
4106
+ * Server requires `seq: int ≥ 1` and `payload: dict`. If the caller passes
4107
+ * a plain string we wrap it as `{ text: <string> }` so the server accepts
4108
+ * it — common shape for the default `coding`/`assistant` capabilities.
4109
+ */
4073
4110
  send(sessionId, payload, seq) {
4074
- return this.cloud.sessions.sendMessage(sessionId, payload, seq);
4111
+ const normalized = typeof payload === "string" ? { text: payload } : payload;
4112
+ return this.cloud.sessions.sendMessage(sessionId, normalized, seq);
4075
4113
  }
4076
- end(sessionId, messageCount) {
4077
- return this.cloud.sessions.end(sessionId, messageCount);
4114
+ end(sessionId, body) {
4115
+ return this.cloud.sessions.end(sessionId, body);
4078
4116
  }
4079
4117
  invoke(agentId, body) {
4080
4118
  return this.cloud.invokes.call(agentId, body);
@@ -4088,9 +4126,11 @@ var init_dist = __esm({
4088
4126
  listBroadcasts(query) {
4089
4127
  return this.cloud.broadcasts.list(query);
4090
4128
  }
4091
- acceptBroadcast(taskId, slotKey) {
4092
- return this.cloud.broadcasts.accept(taskId, slotKey !== void 0 ? { slot_key: slotKey } : void 0);
4129
+ /** Provider-side helper: accept a broadcast slot (requires `agent_id`). */
4130
+ acceptBroadcast(taskId, body) {
4131
+ return this.cloud.broadcasts.accept(taskId, body);
4093
4132
  }
4133
+ /** Provider-side helper: submit a broadcast result. */
4094
4134
  submitBroadcast(taskId, body) {
4095
4135
  return this.cloud.broadcasts.submit(taskId, body);
4096
4136
  }
@@ -4144,6 +4184,10 @@ var init_dist = __esm({
4144
4184
  INVOKE: "invoke",
4145
4185
  INVOKE_RESULT: "invoke_result"
4146
4186
  };
4187
+ DEFAULT_AUTH_FAILURE_CODES = Object.freeze([
4188
+ 1008,
4189
+ ...Array.from({ length: 99 }, (_, i) => 4001 + i)
4190
+ ]);
4147
4191
  RelayClient = class extends EventEmitter {
4148
4192
  url;
4149
4193
  agentId;
@@ -4152,11 +4196,15 @@ var init_dist = __esm({
4152
4196
  heartbeatMs;
4153
4197
  reconnectBaseMs;
4154
4198
  reconnectMaxMs;
4199
+ authGraceMs;
4200
+ authFailureCloseCodes;
4155
4201
  connector;
4156
4202
  transport;
4157
4203
  heartbeatTimer;
4204
+ authGraceTimer;
4158
4205
  stopped = false;
4159
4206
  reconnectAttempt = 0;
4207
+ fatalState = null;
4160
4208
  constructor(opts) {
4161
4209
  super();
4162
4210
  this.url = opts.url;
@@ -4166,8 +4214,16 @@ var init_dist = __esm({
4166
4214
  this.heartbeatMs = opts.heartbeatMs ?? 3e4;
4167
4215
  this.reconnectBaseMs = opts.reconnectBaseMs ?? 1e3;
4168
4216
  this.reconnectMaxMs = opts.reconnectMaxMs ?? 3e4;
4217
+ this.authGraceMs = opts.authGraceMs ?? 5e3;
4218
+ this.authFailureCloseCodes = new Set(
4219
+ opts.authFailureCloseCodes ?? DEFAULT_AUTH_FAILURE_CODES
4220
+ );
4169
4221
  this.connector = opts.connector ?? nodeWsConnector;
4170
4222
  }
4223
+ /** Last detected permanent-auth-failure, or null when OK / still retrying. */
4224
+ getFatal() {
4225
+ return this.fatalState;
4226
+ }
4171
4227
  on(event, listener) {
4172
4228
  return super.on(event, listener);
4173
4229
  }
@@ -4183,13 +4239,15 @@ var init_dist = __esm({
4183
4239
  const { transport, ready } = await this.connector(this.url);
4184
4240
  this.transport = transport;
4185
4241
  transport.addMessageListener((data) => this.handleFrame(data));
4186
- transport.addCloseListener((code, reason) => this.handleClose(`close ${code}: ${reason}`));
4187
- transport.addErrorListener((err) => this.handleClose(`error: ${err.message}`));
4242
+ transport.addCloseListener(
4243
+ (code, reason) => this.handleClose(code, `close ${code}: ${reason}`)
4244
+ );
4245
+ transport.addErrorListener((err) => this.handleClose(null, `error: ${err.message}`));
4188
4246
  await ready;
4189
4247
  await this.sendIdentify();
4190
4248
  this.startHeartbeat();
4191
- this.reconnectAttempt = 0;
4192
4249
  this.emit("connected");
4250
+ this.startAuthGraceTimer();
4193
4251
  } catch (err) {
4194
4252
  throw new NetworkError(`relay connect failed: ${err.message}`, err);
4195
4253
  }
@@ -4201,6 +4259,7 @@ var init_dist = __esm({
4201
4259
  async stop() {
4202
4260
  this.stopped = true;
4203
4261
  this.stopHeartbeat();
4262
+ this.cancelAuthGraceTimer();
4204
4263
  if (this.transport) {
4205
4264
  try {
4206
4265
  await this.transport.close(1e3, "client_stop");
@@ -4248,11 +4307,39 @@ var init_dist = __esm({
4248
4307
  const evt = parseInbound(frame);
4249
4308
  if (evt) this.emit("event", evt);
4250
4309
  }
4251
- handleClose(reason) {
4310
+ handleClose(code, reason) {
4252
4311
  this.stopHeartbeat();
4312
+ this.cancelAuthGraceTimer();
4253
4313
  this.transport = void 0;
4254
4314
  this.emit("disconnected", reason);
4255
- if (!this.stopped) void this.scheduleReconnect();
4315
+ if (this.stopped) return;
4316
+ if (code !== null && this.authFailureCloseCodes.has(code)) {
4317
+ this.stopped = true;
4318
+ this.fatalState = { reason, code };
4319
+ this.emit("fatal", { reason, code });
4320
+ return;
4321
+ }
4322
+ void this.scheduleReconnect();
4323
+ }
4324
+ startAuthGraceTimer() {
4325
+ this.cancelAuthGraceTimer();
4326
+ if (this.authGraceMs <= 0) {
4327
+ this.reconnectAttempt = 0;
4328
+ return;
4329
+ }
4330
+ this.authGraceTimer = setTimeout(() => {
4331
+ this.authGraceTimer = void 0;
4332
+ if (this.transport) this.reconnectAttempt = 0;
4333
+ }, this.authGraceMs);
4334
+ if (typeof this.authGraceTimer.unref === "function") {
4335
+ this.authGraceTimer.unref();
4336
+ }
4337
+ }
4338
+ cancelAuthGraceTimer() {
4339
+ if (this.authGraceTimer) {
4340
+ clearTimeout(this.authGraceTimer);
4341
+ this.authGraceTimer = void 0;
4342
+ }
4256
4343
  }
4257
4344
  async scheduleReconnect() {
4258
4345
  this.reconnectAttempt += 1;
@@ -4320,6 +4407,7 @@ var init_dist = __esm({
4320
4407
  inFlightBroadcasts = /* @__PURE__ */ new Set();
4321
4408
  running = false;
4322
4409
  connected = false;
4410
+ fatal = null;
4323
4411
  constructor(deps) {
4324
4412
  this.cloud = deps.cloud;
4325
4413
  this.relay = deps.relay;
@@ -4331,10 +4419,18 @@ var init_dist = __esm({
4331
4419
  this.running = true;
4332
4420
  this.relay.on("connected", () => {
4333
4421
  this.connected = true;
4422
+ this.fatal = null;
4334
4423
  });
4335
4424
  this.relay.on("disconnected", () => {
4336
4425
  this.connected = false;
4337
4426
  });
4427
+ this.relay.on("fatal", (info) => {
4428
+ this.fatal = info;
4429
+ this.connected = false;
4430
+ console.error(
4431
+ `linkedclaw: relay rejected our credentials (code=${info.code ?? "?"}: ${info.reason}). Not retrying. Check apiKey/agentId and restart the plugin.`
4432
+ );
4433
+ });
4338
4434
  this.relay.on("event", (evt) => {
4339
4435
  void this.dispatch(evt);
4340
4436
  });
@@ -4351,7 +4447,8 @@ var init_dist = __esm({
4351
4447
  activeSessions: this.activeSessions.size,
4352
4448
  inFlightInvokes: this.inFlightInvokes.size,
4353
4449
  inFlightBroadcasts: this.inFlightBroadcasts.size,
4354
- ...this.config.agentId !== void 0 ? { agentId: this.config.agentId } : {}
4450
+ ...this.config.agentId !== void 0 ? { agentId: this.config.agentId } : {},
4451
+ ...this.fatal !== null ? { fatal: this.fatal } : {}
4355
4452
  };
4356
4453
  }
4357
4454
  // ────────── dispatch ──────────
@@ -4526,11 +4623,12 @@ var init_dist = __esm({
4526
4623
  try {
4527
4624
  const decision = await this.runOffer(offer);
4528
4625
  if (!decision || !decision.accept) return;
4626
+ const acceptBody = {
4627
+ agent_id: this.config.agentId ?? ""
4628
+ };
4629
+ if (decision.slot_key !== void 0) acceptBody.slot_key = decision.slot_key;
4529
4630
  try {
4530
- await this.cloud.broadcasts.accept(
4531
- offer.task_id,
4532
- decision.slot_key !== void 0 ? { slot_key: decision.slot_key } : void 0
4533
- );
4631
+ await this.cloud.broadcasts.accept(offer.task_id, acceptBody);
4534
4632
  } catch {
4535
4633
  return;
4536
4634
  }
@@ -4573,13 +4671,16 @@ var init_dist = __esm({
4573
4671
  return null;
4574
4672
  }
4575
4673
  }
4576
- async submitWithRetry(taskId, result, slotKey) {
4674
+ async submitWithRetry(taskId, result, _slotKey) {
4675
+ const payload = this.sanitizeOut(result.result_payload ?? {});
4676
+ const resultData = typeof result.result_data === "string" && result.result_data.length > 0 ? result.result_data : JSON.stringify(payload);
4577
4677
  const body = {
4578
- output: this.sanitizeOut(result.result_payload ?? {}),
4579
- ...result.quality_self_report !== void 0 ? { quality_self_report: result.quality_self_report } : {},
4580
- ...slotKey !== void 0 ? { slot_key: slotKey } : {},
4581
- ...result.proof !== void 0 ? { evidence: result.proof } : {}
4678
+ result_data: resultData,
4679
+ result_payload: payload
4582
4680
  };
4681
+ if (Array.isArray(result.proof)) {
4682
+ body.proof = result.proof;
4683
+ }
4583
4684
  for (let attempt = 0; attempt < BROADCAST_SUBMIT_MAX_RETRIES; attempt += 1) {
4584
4685
  try {
4585
4686
  await this.cloud.broadcasts.submit(taskId, body);
@@ -4920,9 +5021,8 @@ function registerProviderCommands(program2) {
4920
5021
  });
4921
5022
  provider.command("listings").description("Show my own agent listings (as provider)").option("--human", "Human-readable output").action(async (opts) => {
4922
5023
  await runCommand(async () => {
4923
- const { cloud, config } = buildContext();
4924
- const all = await cloud.agents.search({});
4925
- return all.filter((a) => a.owner_id === (config.agentId ? void 0 : void 0) || true);
5024
+ const { cloud } = buildContext();
5025
+ return cloud.agents.search({ owner: "me" });
4926
5026
  }, { human: opts.human });
4927
5027
  });
4928
5028
  provider.command("run <config>").description("Run a provider daemon: connect WS, dispatch events to handler subprocess").option("--handler-cmd <cmd>", "Shell command to spawn as the handler child process").option("--handler-http <url>", "HTTP webhook URL to POST each event to (alternative to --handler-cmd)").option("--human", "Human-readable status output").action(async (path, opts) => {
@@ -4979,10 +5079,12 @@ function registerProviderCommands(program2) {
4979
5079
  await new Promise(() => {
4980
5080
  });
4981
5081
  });
4982
- provider.command("pick <bct_id>").description("Manually accept a broadcast task (provider side)").option("--slot-key <key>", "Slot key for sliced broadcasts").option("--human", "Human-readable output").action(async (taskId, opts) => {
5082
+ provider.command("pick <bct_id>").description("Manually accept a broadcast task (provider side)").requiredOption("--agent-id <agt_id>", "Which of your agents is accepting").option("--slot-key <key>", "Slot key for sliced broadcasts").option("--human", "Human-readable output").action(async (taskId, opts) => {
4983
5083
  await runCommand(async () => {
4984
5084
  const { flows } = buildContext();
4985
- return flows.acceptBroadcast(taskId, opts.slotKey);
5085
+ const body = { agent_id: opts.agentId };
5086
+ if (opts.slotKey !== void 0) body.slot_key = opts.slotKey;
5087
+ return flows.acceptBroadcast(taskId, body);
4986
5088
  }, { human: opts.human });
4987
5089
  });
4988
5090
  provider.command("submit <bct_id> <result_file>").description('Submit a broadcast result. result_file = JSON path or "-" for stdin.').option("--human", "Human-readable output").action(async (taskId, resultFile, opts) => {
@@ -5010,7 +5112,6 @@ function buildCreateAgentRequest(cfg) {
5010
5112
  }
5011
5113
  if (!cfg.pricingModel) throw new Error("provider config missing `pricingModel`");
5012
5114
  if (cfg.priceCredits === void 0) throw new Error("provider config missing `priceCredits`");
5013
- if (!cfg.providerType) throw new Error("provider config missing `providerType`");
5014
5115
  return {
5015
5116
  slug: cfg.slug,
5016
5117
  name: cfg.agentName,
@@ -5018,7 +5119,6 @@ function buildCreateAgentRequest(cfg) {
5018
5119
  capabilities: cfg.capabilities,
5019
5120
  pricing_model: cfg.pricingModel,
5020
5121
  price_credits: cfg.priceCredits,
5021
- provider_type: cfg.providerType,
5022
5122
  ...cfg.verifyMethod ? { verify_method: cfg.verifyMethod } : {}
5023
5123
  };
5024
5124
  }
@@ -5067,56 +5167,64 @@ import { readFileSync as readFileSync3 } from "fs";
5067
5167
  import { load as yamlLoad3 } from "js-yaml";
5068
5168
  init_output();
5069
5169
  function registerRequesterCommands(program2) {
5070
- program2.command("search <capability>").description("Search public agent listings by capability").option("--topology <t>", "invoke | session | one_to_many | broadcast").option("--limit <n>", "Max results", (v) => parseInt(v, 10)).option("--human", "Human-readable output").action(async (capability, opts) => {
5170
+ program2.command("search <capability>").description("Search public agent listings by capability").option("--owner <owner>", '"me" or a "usr_..." id').option("--status <status>", "filter by status (online/offline/disabled)").option("--sort <sort>", "newest | price_asc | price_desc | trust").option("--human", "Human-readable output").action(async (capability, opts) => {
5071
5171
  await runCommand(async () => {
5072
5172
  const { flows } = buildContext();
5073
5173
  return flows.search(capability, {
5074
- ...opts.topology ? { topology: opts.topology } : {},
5075
- ...opts.limit ? { limit: opts.limit } : {}
5174
+ ...opts.owner ? { owner: opts.owner } : {},
5175
+ ...opts.status ? { status: opts.status } : {},
5176
+ ...opts.sort ? { sort: opts.sort } : {}
5076
5177
  });
5077
5178
  }, { human: opts.human });
5078
5179
  });
5079
- program2.command("hire <agent_id>").description("Create and activate a 1:1 session with an agent").requiredOption("--capability <cap>", "Capability being hired").option("--max-messages <n>", "Message cap", (v) => parseInt(v, 10)).option("--max-credits <n>", "Credit cap", (v) => parseInt(v, 10)).option("--referred-by <ref_id>", "Attribution: referrer agent id").option("--manifest-id <mft_id>", "Pre-registered task manifest id").option(
5080
- "--manifest <json>",
5081
- 'Inline task manifest JSON (literal, @file, or "-" for stdin). Minimum: {"intention":"..."}'
5082
- ).option("--no-activate", "Create session but do not activate (returns session only)").option("--human", "Human-readable output").action(async (agentId, opts) => {
5180
+ program2.command("hire <agent_id>").description("Create and activate a 1:1 session with an agent").requiredOption("--capability <cap>", "Capability being hired").option("--max-messages <n>", "Message cap (server default 1)", (v) => parseInt(v, 10)).option("--referred-by <ref_id>", "Attribution: referrer agent id").option("--no-activate", "Create session but do not activate (returns session only)").option("--human", "Human-readable output").action(async (agentId, opts) => {
5083
5181
  await runCommand(async () => {
5084
5182
  const { flows } = buildContext();
5085
- const manifest = await resolveManifestOpt(opts.manifest, opts.manifestId);
5086
5183
  return flows.hire({
5087
- agentId,
5184
+ providerAgentId: agentId,
5088
5185
  capability: opts.capability,
5089
5186
  ...opts.maxMessages !== void 0 ? { maxMessages: opts.maxMessages } : {},
5090
- ...opts.maxCredits !== void 0 ? { maxCredits: opts.maxCredits } : {},
5091
5187
  ...opts.referredBy !== void 0 ? { referredBy: opts.referredBy } : {},
5092
- ...opts.manifestId !== void 0 ? { manifestId: opts.manifestId } : {},
5093
- ...manifest !== void 0 ? { manifest } : {},
5094
5188
  autoActivate: opts.activate !== false
5095
5189
  });
5096
5190
  }, { human: opts.human });
5097
5191
  });
5098
- program2.command("send <session_id> <message>").description('Send a message in an active session. Use "-" to read from stdin.').option("--seq <n>", "Client-side sequence number", (v) => parseInt(v, 10)).option("--human", "Human-readable output").action(async (sessionId, message, opts) => {
5192
+ program2.command("send <session_id> <message>").description(
5193
+ `Send a message in an active session. Message is wrapped as {"text": "..."} if it's a plain string, or passed through if it's a JSON object. Use "-" to read from stdin.`
5194
+ ).requiredOption("--seq <n>", "Sequence number (server requires \u2265 1)", (v) => parseInt(v, 10)).option("--json", "Interpret message as a JSON object literal (default: wrap as {text})").option("--human", "Human-readable output").action(async (sessionId, message, opts) => {
5099
5195
  await runCommand(async () => {
5100
5196
  const { flows } = buildContext();
5101
- const payload = message === "-" ? await readStdin() : message;
5197
+ const raw = message === "-" ? await readStdin() : message;
5198
+ const payload = opts.json ? parseJsonOrFail(raw, "<message>") : raw;
5102
5199
  return flows.send(sessionId, payload, opts.seq);
5103
5200
  }, { human: opts.human });
5104
5201
  });
5105
- program2.command("end <session_id>").description("Mark a session ended").option("--message-count <n>", "Declare final message count", (v) => parseInt(v, 10)).option("--human", "Human-readable output").action(async (sessionId, opts) => {
5202
+ program2.command("end <session_id>").description("Mark a session ended").option("--message-count <n>", "Declare final message count", (v) => parseInt(v, 10)).option("--final-output <text>", "Final output blurb (optional)").option("--human", "Human-readable output").action(async (sessionId, opts) => {
5106
5203
  await runCommand(async () => {
5107
5204
  const { flows } = buildContext();
5108
- return flows.end(sessionId, opts.messageCount);
5205
+ const body = {};
5206
+ if (opts.messageCount !== void 0) body.message_count = opts.messageCount;
5207
+ if (opts.finalOutput !== void 0) body.final_output = opts.finalOutput;
5208
+ return flows.end(sessionId, body);
5109
5209
  }, { human: opts.human });
5110
5210
  });
5111
- program2.command("invoke <agent_id>").description("One-shot stateless invoke").requiredOption("--capability <cap>", "Capability").requiredOption("--input <json>", 'JSON input (or "-" to read from stdin)').option("--max-credits <n>", "Max credits", (v) => parseInt(v, 10)).option("--timeout <s>", "Server-side timeout seconds", (v) => parseInt(v, 10)).option("--referred-by <ref_id>", "Attribution: referrer agent id").option("--manifest-id <mft_id>", "Pre-registered task manifest id").option(
5211
+ program2.command("invoke <agent_id>").description("One-shot stateless invoke").requiredOption("--capability <cap>", "Capability").requiredOption("--input <json>", 'JSON input (or "-" to read from stdin)').option("--max-credits <n>", "Max credits", (v) => parseInt(v, 10)).option("--timeout <s>", "Server-side timeout seconds (5..300, default 60)", (v) => parseInt(v, 10)).option("--referred-by <ref_id>", "Attribution: referrer agent id").option("--manifest-id <mft_id>", "Pre-registered task manifest id").option(
5112
5212
  "--manifest <json>",
5113
5213
  'Inline task manifest JSON (literal, @file, or "-" for stdin). Minimum: {"intention":"..."}'
5214
+ ).option(
5215
+ "--intention <text>",
5216
+ "Shortcut: builds a minimal manifest {intention: <text>} if --manifest/--manifest-id are not set."
5114
5217
  ).option("--human", "Human-readable output").action(async (agentId, opts) => {
5115
5218
  await runCommand(async () => {
5116
5219
  const { flows } = buildContext();
5117
5220
  const inputJson = opts.input === "-" ? await readStdin() : opts.input;
5118
5221
  const input = parseJsonOrFail(inputJson, "--input");
5119
- const manifest = await resolveManifestOpt(opts.manifest, opts.manifestId);
5222
+ const manifest = await resolveManifestOpt(
5223
+ opts.manifest,
5224
+ opts.manifestId,
5225
+ opts.intention,
5226
+ `invoke: ${opts.capability}`
5227
+ );
5120
5228
  const body = { capability: opts.capability, input };
5121
5229
  if (opts.maxCredits !== void 0) body.max_credits = opts.maxCredits;
5122
5230
  if (opts.timeout !== void 0) body.timeout_seconds = opts.timeout;
@@ -5127,7 +5235,9 @@ function registerRequesterCommands(program2) {
5127
5235
  }, { human: opts.human });
5128
5236
  });
5129
5237
  const broadcast = program2.command("broadcast").description("Broadcast task commands");
5130
- broadcast.command("create <manifest>").description('Create a broadcast task from a YAML/JSON manifest file. Use "-" for stdin.').option("--human", "Human-readable output").action(async (manifestPath, opts) => {
5238
+ broadcast.command("create <manifest>").description(
5239
+ 'Create a broadcast task from a YAML/JSON manifest file. Use "-" for stdin. Required fields: capability, instruction, target_providers, credits_per_provider.'
5240
+ ).option("--human", "Human-readable output").action(async (manifestPath, opts) => {
5131
5241
  await runCommand(async () => {
5132
5242
  const { flows } = buildContext();
5133
5243
  const raw = manifestPath === "-" ? await readStdin() : readFileSync3(manifestPath, "utf8");
@@ -5141,37 +5251,37 @@ function registerRequesterCommands(program2) {
5141
5251
  return flows.getBroadcast(taskId);
5142
5252
  }, { human: opts.human });
5143
5253
  });
5144
- broadcast.command("list").description("List broadcasts I own").option("--status <s>", "Filter by status").option("--capability <c>", "Filter by capability").option("--human", "Human-readable output").action(async (opts) => {
5254
+ broadcast.command("list").description("List broadcasts I own").option("--status <s>", "Filter by status").option("--human", "Human-readable output").action(async (opts) => {
5145
5255
  await runCommand(async () => {
5146
5256
  const { flows } = buildContext();
5147
5257
  return flows.listBroadcasts({
5148
- ...opts.status ? { status: opts.status } : {},
5149
- ...opts.capability ? { capability: opts.capability } : {}
5258
+ ...opts.status ? { status: opts.status } : {}
5150
5259
  });
5151
5260
  }, { human: opts.human });
5152
5261
  });
5153
- broadcast.command("available").description("List open broadcasts I could pick up (as provider)").option("--capability <c>", "Filter by capability").option("--limit <n>", "Max results", (v) => parseInt(v, 10)).option("--human", "Human-readable output").action(async (opts) => {
5262
+ broadcast.command("available").description("List open broadcasts I could pick up (as provider)").option("--human", "Human-readable output").action(async (opts) => {
5154
5263
  await runCommand(async () => {
5155
5264
  const { cloud } = buildContext();
5156
- return cloud.broadcasts.available({
5157
- ...opts.capability ? { capability: opts.capability } : {},
5158
- ...opts.limit ? { limit: opts.limit } : {}
5159
- });
5265
+ return cloud.broadcasts.available();
5160
5266
  }, { human: opts.human });
5161
5267
  });
5162
- broadcast.command("accept <bct_id>").description("Accept a broadcast (provider side) \u2014 returns a result_id").option("--slot-key <key>", "Slot key for sliced broadcasts").option("--human", "Human-readable output").action(async (taskId, opts) => {
5268
+ broadcast.command("accept <bct_id>").description("Accept a broadcast (provider side) \u2014 returns a result_id").requiredOption("--agent-id <agt_id>", "Which of your agents is accepting").option("--slot-key <key>", "Slot key for sliced broadcasts").option("--human", "Human-readable output").action(async (taskId, opts) => {
5163
5269
  await runCommand(async () => {
5164
5270
  const { flows } = buildContext();
5165
- return flows.acceptBroadcast(taskId, opts.slotKey);
5271
+ const body = { agent_id: opts.agentId };
5272
+ if (opts.slotKey !== void 0) body.slot_key = opts.slotKey;
5273
+ return flows.acceptBroadcast(taskId, body);
5166
5274
  }, { human: opts.human });
5167
5275
  });
5168
- broadcast.command("submit <bct_id>").description("Submit broadcast result (provider side). Body = JSON file or stdin.").requiredOption("--body <json>", 'JSON body (or "-" to read from stdin)').option("--human", "Human-readable output").action(async (taskId, opts) => {
5276
+ broadcast.command("submit <bct_id>").description(
5277
+ "Submit broadcast result (provider side). Body must include `result_data` (string) and may include `result_payload` (object) and `proof` (array)."
5278
+ ).requiredOption("--body <json>", 'JSON body (or "-" to read from stdin)').option("--human", "Human-readable output").action(async (taskId, opts) => {
5169
5279
  await runCommand(async () => {
5170
5280
  const { flows } = buildContext();
5171
5281
  const raw = opts.body === "-" ? await readStdin() : readFileSync3(opts.body, "utf8");
5172
5282
  const body = parseJsonOrFail(raw, "--body");
5173
- if (typeof body !== "object" || body === null || !("output" in body)) {
5174
- throw new Error("--body must include an `output` object");
5283
+ if (typeof body !== "object" || body === null || typeof body.result_data !== "string") {
5284
+ throw new Error("--body must include a `result_data` string field");
5175
5285
  }
5176
5286
  return flows.submitBroadcast(taskId, body);
5177
5287
  }, { human: opts.human });
@@ -5182,7 +5292,7 @@ function registerRequesterCommands(program2) {
5182
5292
  return cloud.receipts.get(receiptId);
5183
5293
  }, { human: opts.human });
5184
5294
  });
5185
- program2.command("trust <agent_id>").description("Get trust summary for an agent").option("--human", "Human-readable output").action(async (agentId, opts) => {
5295
+ program2.command("trust <agent_id>").description("Get trust summary for an agent (per-capability)").option("--human", "Human-readable output").action(async (agentId, opts) => {
5186
5296
  await runCommand(async () => {
5187
5297
  const { cloud } = buildContext();
5188
5298
  return cloud.agents.trust(agentId);
@@ -5211,24 +5321,29 @@ function parseYamlOrJson(raw) {
5211
5321
  if (trimmed.startsWith("{") || trimmed.startsWith("[")) return JSON.parse(raw);
5212
5322
  return yamlLoad3(raw);
5213
5323
  }
5214
- async function resolveManifestOpt(manifestOpt, manifestId) {
5215
- if (manifestOpt === void 0) return void 0;
5216
- if (manifestId !== void 0) {
5324
+ async function resolveManifestOpt(manifestOpt, manifestId, intention, defaultIntention) {
5325
+ if (manifestOpt !== void 0 && manifestId !== void 0) {
5217
5326
  throw new Error("--manifest and --manifest-id are mutually exclusive");
5218
5327
  }
5219
- let raw;
5220
- if (manifestOpt === "-") {
5221
- raw = await readStdin();
5222
- } else if (manifestOpt.startsWith("@")) {
5223
- raw = readFileSync3(manifestOpt.slice(1), "utf8");
5224
- } else {
5225
- raw = manifestOpt;
5328
+ if (manifestId !== void 0) {
5329
+ return void 0;
5226
5330
  }
5227
- const parsed = parseJsonOrFail(raw, "--manifest");
5228
- if (typeof parsed.intention !== "string" || parsed.intention.length === 0) {
5229
- throw new Error('--manifest must include a non-empty "intention" field');
5331
+ if (manifestOpt !== void 0) {
5332
+ let raw;
5333
+ if (manifestOpt === "-") {
5334
+ raw = await readStdin();
5335
+ } else if (manifestOpt.startsWith("@")) {
5336
+ raw = readFileSync3(manifestOpt.slice(1), "utf8");
5337
+ } else {
5338
+ raw = manifestOpt;
5339
+ }
5340
+ const parsed = parseJsonOrFail(raw, "--manifest");
5341
+ if (typeof parsed.intention !== "string" || parsed.intention.length === 0) {
5342
+ throw new Error('--manifest must include a non-empty "intention" field');
5343
+ }
5344
+ return parsed;
5230
5345
  }
5231
- return parsed;
5346
+ return { intention: intention ?? defaultIntention };
5232
5347
  }
5233
5348
 
5234
5349
  // src/bin.ts