@botiverse/raft-sdk 0.7.0 → 0.9.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/dist/esm/index.js CHANGED
@@ -4712,7 +4712,7 @@ const AGENT_API_ROUTE_META = {
4712
4712
  mentionActionsExecute: write,
4713
4713
  taskClaim: write,
4714
4714
  taskList: read,
4715
- taskCreate: write,
4715
+ taskCreate: keyedWrite,
4716
4716
  taskUnclaim: destructive,
4717
4717
  taskAssign: naturalDestructive,
4718
4718
  taskUpdateStatus: naturalDestructive,
@@ -4744,7 +4744,7 @@ const AGENT_API_ROUTE_META = {
4744
4744
  integrationAppLogoUpdate: naturalDestructive,
4745
4745
  integrationAppList: read,
4746
4746
  integrationAppStatus: read,
4747
- actionPrepare: write,
4747
+ actionPrepare: keyedWrite,
4748
4748
  attachmentUpload: write,
4749
4749
  attachmentUploadCapabilities: read,
4750
4750
  attachmentUploadSessionCreate: write,
@@ -5395,7 +5395,15 @@ const agentApiTaskCreateBodySchema = passthroughObject({
5395
5395
  title: string().trim().min(1),
5396
5396
  creates_resource: boolean().optional()
5397
5397
  })).min(1),
5398
- assignee: string().trim().refine((value) => value.startsWith("@") && value.slice(1).trim().length > 0, { message: "assignee must be an @handle" }).optional()
5398
+ assignee: string().trim().refine((value) => value.startsWith("@") && value.slice(1).trim().length > 0, { message: "assignee must be an @handle" }).optional(),
5399
+ /**
5400
+ * Retry key (same rules as message send's): a repeat with the same key and
5401
+ * the same request replays the first response without creating anything;
5402
+ * the same key with a different request is refused (409
5403
+ * `idempotency_key_reused`). Scoped to the agent and this route, and valid
5404
+ * for 24 hours; after that the key is forgotten and is a new request.
5405
+ */
5406
+ idempotencyKey: optionalStringSchema
5399
5407
  });
5400
5408
  const agentApiTaskUnclaimBodySchema = passthroughObject({
5401
5409
  channel: string().trim().min(1),
@@ -5646,7 +5654,15 @@ const agentApiIntegrationAppStatusQuerySchema = passthroughObject({
5646
5654
  });
5647
5655
  const agentApiActionPrepareBodySchema = passthroughObject({
5648
5656
  target: string().trim().min(1),
5649
- action: actionCardActionSchema
5657
+ action: actionCardActionSchema,
5658
+ /**
5659
+ * Retry key (same rules as message send's): a repeat with the same key and
5660
+ * the same request replays the first response (same card messageId)
5661
+ * without preparing another card; the same key with a different request is
5662
+ * refused (409 `idempotency_key_reused`). Scoped to the agent and this
5663
+ * route, and valid for 24 hours; after that the key is forgotten.
5664
+ */
5665
+ idempotencyKey: optionalStringSchema
5650
5666
  });
5651
5667
  const agentApiServerUpdateBodySchema = passthroughObject({
5652
5668
  name: string().trim().min(1).max(100).optional(),
@@ -8727,7 +8743,7 @@ const AGENT_API_ROUTE_MANIFEST = [
8727
8743
  "capability": "tasks",
8728
8744
  "description": "Create one or more tasks in a channel.",
8729
8745
  "sideEffect": "write",
8730
- "idempotency": "none",
8746
+ "idempotency": "key",
8731
8747
  "destructive": false,
8732
8748
  "audience": "both",
8733
8749
  "request": {
@@ -9527,7 +9543,7 @@ const AGENT_API_ROUTE_MANIFEST = [
9527
9543
  "capability": "tasks",
9528
9544
  "description": "Prepare an action card for a human to commit.",
9529
9545
  "sideEffect": "write",
9530
- "idempotency": "none",
9546
+ "idempotency": "key",
9531
9547
  "destructive": false,
9532
9548
  "audience": "both",
9533
9549
  "request": {
@@ -9842,7 +9858,7 @@ const AGENT_API_ROUTE_MANIFEST = [
9842
9858
  }
9843
9859
  ];
9844
9860
  /** Content hash of AGENT_API_ROUTE_MANIFEST; see computeAgentApiManifestVersion. */
9845
- const AGENT_API_MANIFEST_VERSION = "c7a793816a7a90ed";
9861
+ const AGENT_API_MANIFEST_VERSION = "2a3c2201ea57a9d1";
9846
9862
  //#endregion
9847
9863
  //#region src/routes.ts
9848
9864
  const ROUTE_INFO = Object.fromEntries(AGENT_API_ROUTE_MANIFEST.map((entry) => {
@@ -10448,7 +10464,7 @@ const DEFAULT_MESSAGES = {
10448
10464
  SCOPE_DENIED: "This agent's scope set does not allow this operation.",
10449
10465
  NOT_FOUND: "The target or message does not exist or is not visible to this agent.",
10450
10466
  CONFLICT: "The Raft Server refused the operation because of the current state.",
10451
- IDEMPOTENCY_KEY_REUSED: "This idempotency key was already used for a different message.",
10467
+ IDEMPOTENCY_KEY_REUSED: "This idempotency key was already used for a different request.",
10452
10468
  UNSUPPORTED_FOR_EXTERNAL_AGENTS: "This operation is not available to External Agents.",
10453
10469
  UNAVAILABLE: "The Raft Server could not serve this operation right now.",
10454
10470
  MODEL_ONLY: "This operation only counts when the model sees its result, so it cannot be run from code; nothing was sent."
@@ -10462,7 +10478,7 @@ const DEFAULT_NEXT_ACTION = {
10462
10478
  SCOPE_DENIED: "Ask a human with editAgents authority to extend this agent's scopes.",
10463
10479
  NOT_FOUND: "Check the target spelling with `raft server info --channels` or resolve the message id first.",
10464
10480
  CONFLICT: "Read the current state before repeating this operation.",
10465
- IDEMPOTENCY_KEY_REUSED: "Use a new idempotency key for a different message, or resend the identical payload to reconcile.",
10481
+ IDEMPOTENCY_KEY_REUSED: "Use a new idempotency key for a different request, or resend the identical request to reconcile.",
10466
10482
  UNSUPPORTED_FOR_EXTERNAL_AGENTS: "Use your own runtime for this; the Server does not provide it to External Agents.",
10467
10483
  UNAVAILABLE: "Retry in a moment.",
10468
10484
  MODEL_ONLY: "Call it as a model tool call instead of from code."
@@ -10551,6 +10567,24 @@ function failureOutcome(error) {
10551
10567
  text: formatOpErrorText(error)
10552
10568
  };
10553
10569
  }
10570
+ /**
10571
+ * A failure of a keyed write (`idempotencyKey`). A retryable failure (the
10572
+ * request may not have reached the Server, or the Server was unavailable)
10573
+ * says to repeat the SAME request with the SAME key, and carries the key in
10574
+ * `next.args.idempotencyKey`, so a caller that let the SDK generate it can
10575
+ * still retry without acting twice.
10576
+ */
10577
+ function keyedWriteFailure(failure, idempotencyKey) {
10578
+ if (!failure.error.retryable) return failure;
10579
+ return {
10580
+ ...failure,
10581
+ next: {
10582
+ kind: "retry_same_key",
10583
+ args: { idempotencyKey },
10584
+ why: "Repeat the same request with this idempotencyKey: if the first attempt was committed, the Server returns its result instead of acting twice."
10585
+ }
10586
+ };
10587
+ }
10554
10588
  /** Map a shared-client failure to a failure outcome. */
10555
10589
  function failureFromClientResult(result) {
10556
10590
  return failureOutcome(opErrorFromClientError(result.error, result.status));
@@ -12078,6 +12112,22 @@ function formatAgentTaskHistory(data) {
12078
12112
  return `seq=${event.seq} time=${event.createdAt} actor=${actor} type=${event.eventType}\n ${JSON.stringify(event.payload)}`;
12079
12113
  }).join("\n")}`;
12080
12114
  }
12115
+ /**
12116
+ * `raft task show`: one task's current title and description (moved verbatim
12117
+ * from the CLI's commands/task/show.ts). Labels match the agent delivery
12118
+ * surface (`Current title:` / `Current description:`). `description` has three
12119
+ * states that must not collapse: a string, an explicit null, and a field the
12120
+ * envelope omitted.
12121
+ */
12122
+ function formatAgentTaskShow(target, task) {
12123
+ const descriptionLine = typeof task.description === "string" ? `Current description: ${task.description}` : task.description === null ? "Current description: (none set)" : "Current description: (not returned by this surface)";
12124
+ return [
12125
+ `#${task.taskNumber} [${task.status ?? "unknown"}] in ${target}`,
12126
+ `Current title: ${task.title ?? "(none set)"}`,
12127
+ descriptionLine,
12128
+ ""
12129
+ ].join("\n");
12130
+ }
12081
12131
  //#endregion
12082
12132
  //#region ../shared/src/agentOps/tasks.ts
12083
12133
  const taskChannelSchema = string().describe("The channel the task board belongs to, for example `#proj-sdk`.");
@@ -12250,21 +12300,24 @@ const createTasksRequestSchema = requestSchema()(object({
12250
12300
  title: string().describe("Task title."),
12251
12301
  createsResource: boolean().optional().describe("The task produces a resource (for example a document) that needs a receipt.")
12252
12302
  })).describe("One entry per task to create."),
12253
- assignee: string().optional().describe("`@handle`: yourself to start in_progress, or (owner/admin) someone else to reserve a todo.")
12303
+ assignee: string().optional().describe("`@handle`: yourself to start in_progress, or (owner/admin) someone else to reserve a todo."),
12304
+ idempotencyKey: string().optional().describe("One key per logical create; generated when omitted and returned. Repeat the same request with the same key within 24 hours to retry without creating the tasks twice.")
12254
12305
  }));
12255
12306
  async function createTasks(client, request) {
12256
12307
  const invalid = validateOpRequest(createTasksRequestSchema, request);
12257
12308
  if (invalid) return invalid;
12258
12309
  if (!request.target?.trim() || !request.tasks?.length) return failureOutcome(opError("INVALID_REQUEST", { message: "A channel target and at least one task title are required." }));
12310
+ const idempotencyKey = request.idempotencyKey?.trim() || globalThis.crypto.randomUUID();
12259
12311
  const result = await client.tasks.create({
12260
12312
  channel: request.target,
12261
12313
  tasks: request.tasks.map((t) => ({
12262
12314
  title: t.title,
12263
12315
  ...t.createsResource ? { creates_resource: true } : {}
12264
12316
  })),
12265
- ...request.assignee ? { assignee: request.assignee } : {}
12317
+ ...request.assignee ? { assignee: request.assignee } : {},
12318
+ idempotencyKey
12266
12319
  });
12267
- if (!result.ok) return failureFromClientResult(result);
12320
+ if (!result.ok) return keyedWriteFailure(failureFromClientResult(result), idempotencyKey);
12268
12321
  const data = result.data;
12269
12322
  const first = data.tasks[0];
12270
12323
  return {
@@ -12272,7 +12325,8 @@ async function createTasks(client, request) {
12272
12325
  state: "created",
12273
12326
  data: {
12274
12327
  ...data,
12275
- target: request.target
12328
+ target: request.target,
12329
+ idempotencyKey
12276
12330
  },
12277
12331
  next: first ? {
12278
12332
  kind: "post_in_task_thread",
@@ -12467,6 +12521,38 @@ async function taskHistory(client, request) {
12467
12521
  text: formatAgentTaskHistory(result.data)
12468
12522
  };
12469
12523
  }
12524
+ /**
12525
+ * `raft task show`: one task's current title and description. Reads the
12526
+ * channel's whole board (`status: "all"`, so done and closed tasks are found)
12527
+ * and picks the task; a miss says whether the Server asserted the list is
12528
+ * complete, exactly as the CLI does.
12529
+ */
12530
+ async function showTask(client, request) {
12531
+ const invalid = requireTaskRef(request);
12532
+ if (invalid) return invalid;
12533
+ const { target, taskNumber } = request;
12534
+ const result = await client.tasks.list({
12535
+ channel: target,
12536
+ status: "all"
12537
+ });
12538
+ if (!result.ok) return failureFromClientResult(result);
12539
+ const tasks = result.data.tasks ?? [];
12540
+ const task = tasks.find((candidate) => candidate.taskNumber === taskNumber);
12541
+ if (!task) return failureOutcome(opError("NOT_FOUND", {
12542
+ message: result.data.pagination?.mode === "complete" && result.data.pagination.truncated === false ? `task #${taskNumber} not found in ${target} (searched ${tasks.length} task(s), status=all; server asserts this list is complete)` : tasks.length === 0 ? `task #${taskNumber} not found in ${target}: the server returned 0 tasks and did not assert the list is complete. That can mean the channel has no tasks, or that the server failed to read them (it currently reports some read errors as an empty list), and this command cannot tell which — so this is not evidence that task #${taskNumber} does not exist` : `task #${taskNumber} not found in ${target} (searched ${tasks.length} task(s), status=all; this surface does NOT assert completeness — so this is "absent from what was returned", not "does not exist")`,
12543
+ nextAction: `Check the number with \`raft task list --target "${target}" --status all\`.`
12544
+ }));
12545
+ return {
12546
+ ok: true,
12547
+ state: "task",
12548
+ data: {
12549
+ target,
12550
+ task
12551
+ },
12552
+ next: null,
12553
+ text: formatAgentTaskShow(target, task)
12554
+ };
12555
+ }
12470
12556
  const convertMessageToTaskRequestSchema = requestSchema()(object({
12471
12557
  target: taskChannelSchema,
12472
12558
  messageId: string().describe("Full or short id of a top-level message in that channel.")
@@ -12795,6 +12881,30 @@ function formatPageFooter(page) {
12795
12881
  if (page.nextCommand && end < page.total) lines.push(`More: ${page.nextCommand}`);
12796
12882
  return `${lines.join("\n")}\n`;
12797
12883
  }
12884
+ /** Single channel detail block. */
12885
+ function formatAgentChannelInfo(channel, memberCounts) {
12886
+ const lines = ["## Channel", ""];
12887
+ lines.push(`Channel: ${agentChannelRef(channel.name, channel.type)}`);
12888
+ if (channel.id) lines.push(`ID: ${channel.id}`);
12889
+ lines.push(`Visibility: ${channelVisibility(channel)}`);
12890
+ lines.push(`Joined: ${channel.joined ? "yes" : "no"}`);
12891
+ if (channel.channelRole) lines.push(`Channel role: ${channel.channelRole}`);
12892
+ if (channel.channelAdminBasis) lines.push(`Channel admin basis: ${channel.channelAdminBasis}`);
12893
+ const callableCapabilities = Object.entries(channel.channelCapabilities ?? {}).filter(([, allowed]) => allowed).map(([capability]) => capability);
12894
+ if (callableCapabilities.length > 0) lines.push(`Channel capabilities: ${callableCapabilities.join(", ")}`);
12895
+ const muted = channelMuted(channel);
12896
+ if (muted !== void 0) lines.push(`Muted: ${muted ? "yes" : "no"}`);
12897
+ if (typeof channel.archived === "boolean") lines.push(`Archived: ${channel.archived ? "yes" : "no"}`);
12898
+ lines.push(`Description: ${channel.description?.trim() || "(none)"}`);
12899
+ if (memberCounts) {
12900
+ const agents = memberCounts.agents ?? 0;
12901
+ const humans = memberCounts.humans ?? 0;
12902
+ lines.push(`Members: ${agents + humans} (${agents} agents, ${humans} humans)`);
12903
+ }
12904
+ lines.push("");
12905
+ lines.push(`More: raft channel members "${agentChannelRef(channel.name, channel.type)}"`);
12906
+ return `${lines.join("\n")}\n`;
12907
+ }
12798
12908
  /** Compact server summary. */
12799
12909
  function formatAgentServerSummary(data) {
12800
12910
  const channels = data.channels ?? [];
@@ -12861,6 +12971,23 @@ function formatAgentServerHumans(humans, page) {
12861
12971
  }
12862
12972
  return `${lines.join("\n")}${formatPageFooter(page)}`;
12863
12973
  }
12974
+ /** Narrow visible facts for one user/agent. */
12975
+ function formatAgentUserInfo(user, memberships, page, skippedChannels = 0) {
12976
+ const name = user.value.name;
12977
+ const role = roleLabel(user.value.role);
12978
+ const lines = ["## User", ""];
12979
+ lines.push(`User: @${name}`);
12980
+ lines.push(`Kind: ${user.kind}`);
12981
+ if (user.kind === "agent") lines.push(`Status: ${agentStatusLabel(user.value)}`);
12982
+ if (role) lines.push(`Role: ${role.slice(2, -1)}`);
12983
+ if (user.value.description) lines.push(`Description: ${user.value.description}`);
12984
+ lines.push("");
12985
+ lines.push("### Visible Channel Memberships");
12986
+ if (memberships.length === 0) lines.push("(none found in inspected visible channels)");
12987
+ else for (const channel of memberships) lines.push(`${agentChannelRef(channel.name, channel.type)} [${channelStatus(channel)}]`);
12988
+ if (skippedChannels > 0) lines.push(`Skipped ${skippedChannels} visible channel roster checks because the server rejected them.`);
12989
+ return `${lines.join("\n")}${formatPageFooter(page)}`;
12990
+ }
12864
12991
  /** Channel membership with server-role labels. */
12865
12992
  function formatAgentChannelMembers(data) {
12866
12993
  let text = "## Channel Members\n\n";
@@ -13251,6 +13378,41 @@ async function unfollowThread(client, request) {
13251
13378
  text: `Unfollowed ${request.target}. Ordinary delivery from this thread stops; a direct @mention reactivates the follow.`
13252
13379
  };
13253
13380
  }
13381
+ const channelInfoRequestSchema = requestSchema()(object({ target: string().describe("A regular channel, `#channel-name` (the `#` may be omitted). DMs and threads are not accepted.") }));
13382
+ /**
13383
+ * `raft channel info <target>`: the channel's facts from `server.info`, plus
13384
+ * member counts from its roster when the Server shows it.
13385
+ */
13386
+ async function channelInfo(client, request) {
13387
+ const invalid = validateOpRequest(channelInfoRequestSchema, request);
13388
+ if (invalid) return invalid;
13389
+ const trimmed = request.target.trim();
13390
+ const input = trimmed.startsWith("#") ? trimmed : `#${trimmed}`;
13391
+ const name = parseRaftRegularChannelTarget$1(input);
13392
+ if (!name) return failureOutcome(opError("INVALID_REQUEST", { message: "Target must be a regular channel name, e.g. '#engineering' or 'engineering'. DMs and thread targets are not supported." }));
13393
+ const info = await client.server.info();
13394
+ if (!info.ok) return failureFromClientResult(info);
13395
+ const channel = info.data.channels.find((candidate) => candidate.name === name);
13396
+ if (!channel) return failureOutcome(opError("NOT_FOUND", {
13397
+ message: `Channel not found or not visible: ${input}`,
13398
+ nextAction: "Run `raft server info --channels --query <name>` to inspect visible channels, or ask a channel member to add you if this is private."
13399
+ }));
13400
+ const members = await client.channels.members({ channel: `#${name}` });
13401
+ const memberCounts = members.ok ? {
13402
+ agents: members.data.agents?.length ?? 0,
13403
+ humans: members.data.humans?.length ?? 0
13404
+ } : null;
13405
+ return {
13406
+ ok: true,
13407
+ state: "info",
13408
+ data: {
13409
+ channel,
13410
+ memberCounts
13411
+ },
13412
+ next: null,
13413
+ text: formatAgentChannelInfo(channel, memberCounts)
13414
+ };
13415
+ }
13254
13416
  //#endregion
13255
13417
  //#region ../shared/src/agentOps/server.ts
13256
13418
  const serverInfoRequestSchema = requestSchema()(object({
@@ -13374,6 +13536,85 @@ async function updateProfile(client, request, options = {}) {
13374
13536
  text: formatAgentProfile(result.data, options)
13375
13537
  };
13376
13538
  }
13539
+ const userInfoRequestSchema = requestSchema()(object({
13540
+ name: string().describe("The human or agent, `@handle` (or the bare handle)."),
13541
+ offset: number$1().int().nonnegative().optional().describe("Membership paging: visible channels to skip before inspecting (default 0)."),
13542
+ limit: number$1().int().positive().optional().describe("Membership paging: visible channels to inspect (default 50).")
13543
+ }));
13544
+ /**
13545
+ * `raft user info <name>`: the user's visible facts from `server.info`, and
13546
+ * their memberships among one page of the visible channels, checked one
13547
+ * channel roster at a time (a rejected roster is skipped and counted).
13548
+ */
13549
+ async function userInfo(client, request) {
13550
+ const invalid = validateOpRequest(userInfoRequestSchema, request);
13551
+ if (invalid) return invalid;
13552
+ const trimmed = request.name.trim();
13553
+ const name = trimmed.startsWith("@") ? trimmed.slice(1) : trimmed;
13554
+ if (!name) return failureOutcome(opError("INVALID_REQUEST", { message: "user name is required" }));
13555
+ const limit = request.limit ?? 50;
13556
+ const offset = request.offset ?? 0;
13557
+ const info = await client.server.info();
13558
+ if (!info.ok) return failureFromClientResult(info);
13559
+ const agent = info.data.agents.find((candidate) => candidate.name === name);
13560
+ const human = info.data.humans.find((candidate) => candidate.name === name);
13561
+ const user = agent ? {
13562
+ kind: "agent",
13563
+ value: agent
13564
+ } : human ? {
13565
+ kind: "human",
13566
+ value: human
13567
+ } : null;
13568
+ if (!user) return failureOutcome(opError("NOT_FOUND", {
13569
+ message: `User not found or not visible: @${name}`,
13570
+ nextAction: "Run `raft server info --agents --query <name>` or `raft server info --humans --query <name>` to inspect visible users."
13571
+ }));
13572
+ const visibleChannels = info.data.channels;
13573
+ const memberships = [];
13574
+ let skippedChannels = 0;
13575
+ for (const channel of visibleChannels.slice(offset, offset + limit)) {
13576
+ const members = await client.channels.members({ channel: `#${channel.name}` });
13577
+ if (!members.ok) {
13578
+ skippedChannels += 1;
13579
+ continue;
13580
+ }
13581
+ if ((user.kind === "agent" ? members.data.agents ?? [] : members.data.humans ?? []).some((candidate) => candidate.name === name)) memberships.push({
13582
+ ...channel,
13583
+ joined: true,
13584
+ muted: void 0,
13585
+ activityMuted: void 0
13586
+ });
13587
+ }
13588
+ const nextOffset = offset + limit;
13589
+ const page = {
13590
+ total: visibleChannels.length,
13591
+ offset,
13592
+ limit,
13593
+ nextCommand: nextOffset < visibleChannels.length ? `raft user info @${name} --offset ${nextOffset} --limit ${limit}` : void 0
13594
+ };
13595
+ const next = page.nextCommand ? {
13596
+ kind: "next_page",
13597
+ command: page.nextCommand,
13598
+ args: {
13599
+ name: `@${name}`,
13600
+ offset: nextOffset,
13601
+ limit
13602
+ },
13603
+ why: "Only one page of visible channels was inspected for memberships."
13604
+ } : null;
13605
+ return {
13606
+ ok: true,
13607
+ state: "info",
13608
+ data: {
13609
+ user,
13610
+ memberships,
13611
+ skippedChannels,
13612
+ page
13613
+ },
13614
+ next,
13615
+ text: formatAgentUserInfo(user, memberships, page, skippedChannels)
13616
+ };
13617
+ }
13377
13618
  //#endregion
13378
13619
  //#region ../shared/src/agentText/attachments.ts
13379
13620
  /** Upload receipt with attachment id and send-usage hint. */
@@ -14480,11 +14721,16 @@ async function prepareActionCard(client, request) {
14480
14721
  if (typeof request?.target !== "string" || !request.target.trim() || !request.action) return failureOutcome(opError("INVALID_REQUEST", { message: "A target and an action are required to prepare a card." }));
14481
14722
  const invalid = validateOpRequest(prepareActionCardRequestSchema, request);
14482
14723
  if (invalid) return invalid;
14483
- const result = await client.actions.prepare(request);
14484
- if (!result.ok) return failureFromClientResult(result);
14724
+ const idempotencyKey = request.idempotencyKey?.trim() || globalThis.crypto.randomUUID();
14725
+ const result = await client.actions.prepare({
14726
+ ...request,
14727
+ idempotencyKey
14728
+ });
14729
+ if (!result.ok) return keyedWriteFailure(failureFromClientResult(result), idempotencyKey);
14485
14730
  const card = {
14486
14731
  target: request.target,
14487
- messageId: result.data.messageId
14732
+ messageId: result.data.messageId,
14733
+ idempotencyKey
14488
14734
  };
14489
14735
  return {
14490
14736
  ok: true,
@@ -14945,9 +15191,11 @@ const OPERATION_DEFS = [
14945
15191
  schema: prepareActionCardRequestSchema,
14946
15192
  fieldDescriptions: {
14947
15193
  target: "Conversation to post the card in: `#channel`, `dm:@peer`, or a thread.",
14948
- action: "The operation the card proposes: `type` picks it, and the other fields apply per type as described."
15194
+ action: "The operation the card proposes: `type` picks it, and the other fields apply per type as described.",
15195
+ idempotencyKey: "One key per logical prepare; generated when omitted and returned. Repeat the same request with the same key within 24 hours to retry without posting a second card."
14949
15196
  },
14950
15197
  routes: ["actionPrepare"],
15198
+ idempotencyArg: "idempotencyKey",
14951
15199
  consumes: nothing,
14952
15200
  output: small
14953
15201
  },
@@ -14998,6 +15246,7 @@ const OPERATION_DEFS = [
14998
15246
  description: "Create one or more tasks on a channel's board; each gets its own thread.",
14999
15247
  schema: createTasksRequestSchema,
15000
15248
  routes: ["taskCreate"],
15249
+ idempotencyArg: "idempotencyKey",
15001
15250
  consumes: nothing,
15002
15251
  output: small
15003
15252
  },
@@ -15054,6 +15303,17 @@ const OPERATION_DEFS = [
15054
15303
  boundBy: []
15055
15304
  }
15056
15305
  },
15306
+ {
15307
+ name: "tasks.show",
15308
+ description: "One task's current status, title, and description. Finds done and closed tasks too.",
15309
+ schema: taskRefSchema,
15310
+ routes: ["taskList"],
15311
+ consumes: nothing,
15312
+ output: {
15313
+ mayBeLarge: true,
15314
+ boundBy: []
15315
+ }
15316
+ },
15057
15317
  {
15058
15318
  name: "tasks.convert",
15059
15319
  description: "Turn a top-level message into an unassigned task.",
@@ -15113,6 +15373,14 @@ const OPERATION_DEFS = [
15113
15373
  boundBy: []
15114
15374
  }
15115
15375
  },
15376
+ {
15377
+ name: "channels.info",
15378
+ description: "A regular channel's facts: visibility, whether you joined it, your role and mute state, description, and member counts.",
15379
+ schema: channelInfoRequestSchema,
15380
+ routes: ["serverInfo", "channelMembers"],
15381
+ consumes: nothing,
15382
+ output: small
15383
+ },
15116
15384
  {
15117
15385
  name: "threads.list",
15118
15386
  description: "The threads you follow.",
@@ -15147,6 +15415,17 @@ const OPERATION_DEFS = [
15147
15415
  ]
15148
15416
  }
15149
15417
  },
15418
+ {
15419
+ name: "users.info",
15420
+ description: "A human's or agent's visible facts (kind, status, role, description) and which visible channels they are in. Memberships are checked over one page of visible channels; page with offset and limit.",
15421
+ schema: userInfoRequestSchema,
15422
+ routes: ["serverInfo", "channelMembers"],
15423
+ consumes: nothing,
15424
+ output: {
15425
+ mayBeLarge: true,
15426
+ boundBy: ["offset", "limit"]
15427
+ }
15428
+ },
15150
15429
  {
15151
15430
  name: "profile.show",
15152
15431
  description: "Show your profile, or someone else's by @handle.",
@@ -15392,6 +15671,7 @@ function createRaft(options) {
15392
15671
  updateStatus: (request) => updateTaskStatus(api, request),
15393
15672
  amend: (request) => amendTask(api, request),
15394
15673
  history: (request) => taskHistory(api, request),
15674
+ show: (request) => showTask(api, request),
15395
15675
  convert: (request) => convertMessageToTask(api, request),
15396
15676
  delete: (request) => deleteTask(api, request)
15397
15677
  },
@@ -15400,13 +15680,15 @@ function createRaft(options) {
15400
15680
  leave: (request) => leaveChannel(api, request),
15401
15681
  mute: (request) => muteChannel(api, request),
15402
15682
  unmute: (request) => unmuteChannel(api, request),
15403
- members: (request) => channelMembers(api, request)
15683
+ members: (request) => channelMembers(api, request),
15684
+ info: (request) => channelInfo(api, request)
15404
15685
  },
15405
15686
  threads: {
15406
15687
  list: () => listThreads(api),
15407
15688
  unfollow: (request) => unfollowThread(api, request)
15408
15689
  },
15409
15690
  server: { info: (request) => serverInfo(api, request) },
15691
+ users: { info: (request) => userInfo(api, request) },
15410
15692
  profile: {
15411
15693
  show: (request) => showProfile(api, request),
15412
15694
  update: (request) => updateProfile(api, request)
@@ -15474,6 +15756,7 @@ function createRaft(options) {
15474
15756
  "tasks.updateStatus": (args) => raft.tasks.updateStatus(args),
15475
15757
  "tasks.amend": (args) => raft.tasks.amend(args),
15476
15758
  "tasks.history": (args) => raft.tasks.history(args),
15759
+ "tasks.show": (args) => raft.tasks.show(args),
15477
15760
  "tasks.convert": (args) => raft.tasks.convert(args),
15478
15761
  "tasks.delete": (args) => raft.tasks.delete(args),
15479
15762
  "channels.join": (args) => raft.channels.join(args),
@@ -15481,9 +15764,11 @@ function createRaft(options) {
15481
15764
  "channels.mute": (args) => raft.channels.mute(args),
15482
15765
  "channels.unmute": (args) => raft.channels.unmute(args),
15483
15766
  "channels.members": (args) => raft.channels.members(args),
15767
+ "channels.info": (args) => raft.channels.info(args),
15484
15768
  "threads.list": () => raft.threads.list(),
15485
15769
  "threads.unfollow": (args) => raft.threads.unfollow(args),
15486
15770
  "server.info": (args) => raft.server.info(args),
15771
+ "users.info": (args) => raft.users.info(args),
15487
15772
  "profile.show": (args) => raft.profile.show(args),
15488
15773
  "profile.update": (args) => raft.profile.update(args)
15489
15774
  };
@@ -15527,4 +15812,4 @@ function whoamiOutcome(result) {
15527
15812
  };
15528
15813
  }
15529
15814
  //#endregion
15530
- export { RAFT_INBOX_NOTICE_SCHEMA, RAFT_JSON_SCHEMA_KEYWORDS, RAFT_NOTICE_DELIVERY_ID_HEADER, RAFT_NOTICE_SIGNATURE_HEADER, RAFT_OPERATIONS, RAFT_OPERATIONS_SCHEMA, RAFT_OPERATIONS_VERSION, RAFT_STATE_CONTINUATIONS_PER_TARGET, RAFT_STATE_CONTINUATIONS_TOTAL, RAFT_STATE_SCHEMA, RaftCredentialError, RaftSdkConfigurationError, SeenFrontier, amendTaskRequestSchema, assignTaskRequestSchema, attachmentCommentsRequestSchema, bootstrapRaftCredential, channelMembersRequestSchema, channelTargetRequestSchema, checkInboxRequestSchema, claimTasksRequestSchema, commitInboxRequestSchema, convertMessageToTaskRequestSchema, createFileCredentialStore, createRaft, createRaftClient, createRaftClientFromStore, createRaftRoutes, createTasksRequestSchema, describeRaftRoute, drainInboxRequestSchema, executeMentionActionRequestSchema, getManualTopicRequestSchema, hasAgentMessageIdentity, hashRaftSendContent, inferAttachmentMimeType, isInterrupted, joinRaftChannelByTarget, listInboxRequestSchema, listRaftRoutes, listTasksRequestSchema, listThreadsRequestSchema, parseRaftRegularChannelTarget, parseRaftState, pendingMentionActionsRequestSchema, prepareActionCardRequestSchema, projectRaftMessage, projectRaftMessages, raftToolNameFor, reactRequestSchema, readHistoryRequestSchema, readLatestReadThread, replyToRequestSchema, resolveMessageRequestSchema, searchManualRequestSchema, searchMessagesRequestSchema, sendMessageRequestSchema, senderMentionDeliveriesRequestSchema, serverInfoRequestSchema, showProfileRequestSchema, taskRefSchema, unfollowThreadRequestSchema, updateProfileRequestSchema, updateTaskStatusRequestSchema, verifyInboxNotice, whoamiRequestSchema };
15815
+ export { RAFT_INBOX_NOTICE_SCHEMA, RAFT_JSON_SCHEMA_KEYWORDS, RAFT_NOTICE_DELIVERY_ID_HEADER, RAFT_NOTICE_SIGNATURE_HEADER, RAFT_OPERATIONS, RAFT_OPERATIONS_SCHEMA, RAFT_OPERATIONS_VERSION, RAFT_STATE_CONTINUATIONS_PER_TARGET, RAFT_STATE_CONTINUATIONS_TOTAL, RAFT_STATE_SCHEMA, RaftCredentialError, RaftSdkConfigurationError, SeenFrontier, amendTaskRequestSchema, assignTaskRequestSchema, attachmentCommentsRequestSchema, bootstrapRaftCredential, channelInfoRequestSchema, channelMembersRequestSchema, channelTargetRequestSchema, checkInboxRequestSchema, claimTasksRequestSchema, commitInboxRequestSchema, convertMessageToTaskRequestSchema, createFileCredentialStore, createRaft, createRaftClient, createRaftClientFromStore, createRaftRoutes, createTasksRequestSchema, describeRaftRoute, drainInboxRequestSchema, executeMentionActionRequestSchema, getManualTopicRequestSchema, hasAgentMessageIdentity, hashRaftSendContent, inferAttachmentMimeType, isInterrupted, joinRaftChannelByTarget, listInboxRequestSchema, listRaftRoutes, listTasksRequestSchema, listThreadsRequestSchema, parseRaftRegularChannelTarget, parseRaftState, pendingMentionActionsRequestSchema, prepareActionCardRequestSchema, projectRaftMessage, projectRaftMessages, raftToolNameFor, reactRequestSchema, readHistoryRequestSchema, readLatestReadThread, replyToRequestSchema, resolveMessageRequestSchema, searchManualRequestSchema, searchMessagesRequestSchema, sendMessageRequestSchema, senderMentionDeliveriesRequestSchema, serverInfoRequestSchema, showProfileRequestSchema, taskRefSchema, unfollowThreadRequestSchema, updateProfileRequestSchema, updateTaskStatusRequestSchema, userInfoRequestSchema, verifyInboxNotice, whoamiRequestSchema };