@botiverse/raft-daemon 0.58.1 → 0.59.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.
@@ -175,6 +175,7 @@ function emitCliTransportNormalizedError(attrs, env = process.env) {
175
175
  function routeFamilyForPath(pathname) {
176
176
  const normalized = pathname.split("?")[0] || "/";
177
177
  if (normalized === "/internal/agent-api/send") return "agent-api/send";
178
+ if (normalized === "/internal/agent-api/activity") return "agent-api/activity";
178
179
  if (normalized === "/internal/agent-api/events") return "agent-api/events";
179
180
  if (normalized === "/internal/agent-api/inbox") return "agent-api/inbox";
180
181
  if (normalized === "/internal/agent-api/receive-ack") return "agent-api/events";
@@ -332,6 +333,9 @@ var ApiClient = class {
332
333
  if (suffix === "/reminders" || suffix.startsWith("/reminders?") || suffix.startsWith("/reminders/")) {
333
334
  return `/internal/agent-api${suffix}`;
334
335
  }
336
+ if (suffix === "/mention-actions/pending" || suffix === "/mention-actions/execute") {
337
+ return `/internal/agent-api${suffix}`;
338
+ }
335
339
  if (suffix === "/receive" || suffix.startsWith("/receive?")) {
336
340
  return "/internal/agent-api/events?since=latest";
337
341
  }
@@ -15526,6 +15530,11 @@ var SERVER_CAPABILITY_MATRIX = {
15526
15530
  joinPublicChannels: true
15527
15531
  })
15528
15532
  };
15533
+ var EXTERNAL_AGENT_ACTIVITY_EVENT_SCHEMA = "raft-activity.v1";
15534
+ var EXTERNAL_AGENT_ACTIVITY_DRAIN_SCHEMA = "raft-activity-drain.v1";
15535
+ var EXTERNAL_AGENT_ACTIVITY_INGEST_SCHEMA = "raft-agent-activity-ingest.v1";
15536
+ var EXTERNAL_AGENT_ACTIVITY_TEXT_LIMIT = 4096;
15537
+ var EXTERNAL_AGENT_ACTIVITY_TOOL_NAME_LIMIT = 120;
15529
15538
  var EXTERNAL_AGENT_RUNTIME_ID = "external";
15530
15539
  var EXTERNAL_AGENT_RUNTIME_MODEL = "external";
15531
15540
  var EXTERNAL_AGENT_RUNTIME_DISPLAY_NAME = "External agent";
@@ -15820,6 +15829,15 @@ async function runAgentCommsBridgeOnce(input) {
15820
15829
  }
15821
15830
  const fetchedLastSeq = typeof fetched.last_seen_hint_seq === "number" ? fetched.last_seen_hint_seq : typeof fetched.last_hint_seq === "number" ? fetched.last_hint_seq : void 0;
15822
15831
  if (typeof fetchedLastSeq === "number") lastSeenHintSeq = Math.max(lastSeenHintSeq ?? 0, fetchedLastSeq);
15832
+ if (input.activitySource && input.activitySink) {
15833
+ output.push(await drainAndForwardActivity({
15834
+ identity,
15835
+ source: input.activitySource,
15836
+ sink: input.activitySink,
15837
+ max: input.activityDrainLimit ?? input.limit ?? 50,
15838
+ now
15839
+ }));
15840
+ }
15823
15841
  store.writeSession({
15824
15842
  coreSessionId,
15825
15843
  ...typeof lastSeenHintSeq === "number" ? { lastSeenHintSeq } : {}
@@ -15827,6 +15845,126 @@ async function runAgentCommsBridgeOnce(input) {
15827
15845
  output.push(lifecycle(identity, processedHintCount > 0 ? "handoff_pending" : "listening_idle", now));
15828
15846
  return output;
15829
15847
  }
15848
+ async function drainAndForwardActivity(input) {
15849
+ let drained;
15850
+ try {
15851
+ drained = await input.source.drainActivity({ max: input.max });
15852
+ } catch (err) {
15853
+ return activityDrainEvent(input.identity, input.now, {
15854
+ outcome: "failed",
15855
+ drainedCount: 0,
15856
+ forwardedCount: 0,
15857
+ rejectedCount: 0,
15858
+ droppedCount: 0,
15859
+ errorClass: err instanceof Error ? err.name : typeof err,
15860
+ errorMessage: errorMessage2(err)
15861
+ });
15862
+ }
15863
+ if (drained.schema !== EXTERNAL_AGENT_ACTIVITY_DRAIN_SCHEMA || !Array.isArray(drained.events)) {
15864
+ return activityDrainEvent(input.identity, input.now, {
15865
+ outcome: "failed",
15866
+ drainedCount: 0,
15867
+ forwardedCount: 0,
15868
+ rejectedCount: 0,
15869
+ droppedCount: normalizeNonNegativeInteger(drained.dropped),
15870
+ errorClass: "ProtocolError",
15871
+ errorMessage: "activity drain response did not match raft-activity-drain.v1"
15872
+ });
15873
+ }
15874
+ const sanitized = sanitizeExternalAgentActivityEvents(drained.events, input.now);
15875
+ if (sanitized.events.length === 0) {
15876
+ return activityDrainEvent(input.identity, input.now, {
15877
+ outcome: "no_events",
15878
+ drainedCount: drained.events.length,
15879
+ forwardedCount: 0,
15880
+ rejectedCount: sanitized.rejectedCount,
15881
+ droppedCount: normalizeNonNegativeInteger(drained.dropped)
15882
+ });
15883
+ }
15884
+ try {
15885
+ await input.sink.forwardActivity({
15886
+ schema: EXTERNAL_AGENT_ACTIVITY_INGEST_SCHEMA,
15887
+ coreSessionId: input.identity.coreSessionId,
15888
+ adapterInstance: input.identity.adapterInstance,
15889
+ events: sanitized.events,
15890
+ dropped: normalizeNonNegativeInteger(drained.dropped)
15891
+ });
15892
+ } catch (err) {
15893
+ return activityDrainEvent(input.identity, input.now, {
15894
+ outcome: "failed",
15895
+ drainedCount: drained.events.length,
15896
+ forwardedCount: 0,
15897
+ rejectedCount: sanitized.rejectedCount,
15898
+ droppedCount: normalizeNonNegativeInteger(drained.dropped),
15899
+ errorClass: err instanceof Error ? err.name : typeof err,
15900
+ errorMessage: errorMessage2(err)
15901
+ });
15902
+ }
15903
+ return activityDrainEvent(input.identity, input.now, {
15904
+ outcome: "forwarded",
15905
+ drainedCount: drained.events.length,
15906
+ forwardedCount: sanitized.events.length,
15907
+ rejectedCount: sanitized.rejectedCount,
15908
+ droppedCount: normalizeNonNegativeInteger(drained.dropped)
15909
+ });
15910
+ }
15911
+ function sanitizeExternalAgentActivityEvents(rawEvents, now = () => /* @__PURE__ */ new Date()) {
15912
+ const events = [];
15913
+ let rejectedCount = 0;
15914
+ for (const raw of rawEvents) {
15915
+ const hookEventName = stringField(raw.hookEventName ?? raw.hook_event_name, 80);
15916
+ if (!hookEventName) {
15917
+ rejectedCount += 1;
15918
+ continue;
15919
+ }
15920
+ const eventId = stringField(raw.eventId ?? raw.event_id, 160) ?? `event_${randomUUID()}`;
15921
+ const sessionId = stringField(raw.sessionId ?? raw.session_id, 200);
15922
+ const toolName = stringField(raw.toolName ?? raw.tool_name, EXTERNAL_AGENT_ACTIVITY_TOOL_NAME_LIMIT);
15923
+ const status = stringField(raw.status, 40);
15924
+ const errorClass = stringField(raw.errorClass ?? raw.error_class, 120);
15925
+ const occurredAt = validIsoDate(raw.occurredAt ?? raw.occurred_at) ?? now().toISOString();
15926
+ const durationMs = normalizeNonNegativeInteger(raw.durationMs ?? raw.duration_ms);
15927
+ const toolInput = truncateActivityText(
15928
+ raw.toolInput ?? raw.tool_input,
15929
+ raw.toolInputTruncated ?? raw.tool_input_truncated ?? raw.truncated
15930
+ );
15931
+ const toolOutput = truncateActivityText(
15932
+ raw.toolOutput ?? raw.tool_output,
15933
+ raw.toolOutputTruncated ?? raw.tool_output_truncated ?? raw.truncated
15934
+ );
15935
+ events.push({
15936
+ schema: EXTERNAL_AGENT_ACTIVITY_EVENT_SCHEMA,
15937
+ eventId,
15938
+ ...sessionId ? { sessionId } : {},
15939
+ hookEventName,
15940
+ ...toolName ? { toolName } : {},
15941
+ ...status ? { status } : {},
15942
+ occurredAt,
15943
+ ...durationMs > 0 ? { durationMs } : {},
15944
+ ...errorClass ? { errorClass } : {},
15945
+ ...toolInput.text !== void 0 ? { toolInput: toolInput.text, toolInputTruncated: toolInput.truncated } : {},
15946
+ ...toolOutput.text !== void 0 ? { toolOutput: toolOutput.text, toolOutputTruncated: toolOutput.truncated } : {}
15947
+ });
15948
+ }
15949
+ return { events, rejectedCount };
15950
+ }
15951
+ function activityDrainEvent(identity, now, result2) {
15952
+ return {
15953
+ type: "agent_comms.activity_drain",
15954
+ eventId: `event_${randomUUID()}`,
15955
+ protocolVersion: AGENT_COMMS_PROTOCOL_VERSION,
15956
+ timestamp: now().toISOString(),
15957
+ coreSessionId: identity.coreSessionId,
15958
+ agentId: identity.agentId,
15959
+ profile: identity.profileSlug,
15960
+ profileSlug: identity.profileSlug,
15961
+ adapterInstance: identity.adapterInstance,
15962
+ runtimeSession: null,
15963
+ source: "slock-agent-bridge",
15964
+ provenance: commsCoreProvenance("comms_core"),
15965
+ ...result2
15966
+ };
15967
+ }
15830
15968
  var BRIDGE_LOG_MAX_BYTES = 5 * 1024 * 1024;
15831
15969
  function rotateBridgeLogIfNeeded(logFile) {
15832
15970
  try {
@@ -16156,6 +16294,46 @@ function stripContentFields(wakeHint) {
16156
16294
  delete clone2.message;
16157
16295
  return clone2;
16158
16296
  }
16297
+ function stringField(value, maxLength) {
16298
+ if (typeof value !== "string") return void 0;
16299
+ const trimmed = value.replace(/\s+/g, " ").trim();
16300
+ if (!trimmed) return void 0;
16301
+ return trimmed.slice(0, maxLength);
16302
+ }
16303
+ function validIsoDate(value) {
16304
+ if (typeof value !== "string") return void 0;
16305
+ const parsed = Date.parse(value);
16306
+ if (Number.isNaN(parsed)) return void 0;
16307
+ return new Date(parsed).toISOString();
16308
+ }
16309
+ function normalizeNonNegativeInteger(value) {
16310
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) return 0;
16311
+ return Math.floor(value);
16312
+ }
16313
+ function truncateActivityText(value, alreadyTruncated) {
16314
+ if (value === void 0 || value === null) return { truncated: Boolean(alreadyTruncated) };
16315
+ let text;
16316
+ if (typeof value === "string") {
16317
+ text = value;
16318
+ } else {
16319
+ try {
16320
+ text = JSON.stringify(value);
16321
+ } catch {
16322
+ text = String(value);
16323
+ }
16324
+ }
16325
+ const marker = "\n[truncated]";
16326
+ if (text.length > EXTERNAL_AGENT_ACTIVITY_TEXT_LIMIT) {
16327
+ return {
16328
+ text: `${text.slice(0, Math.max(0, EXTERNAL_AGENT_ACTIVITY_TEXT_LIMIT - marker.length))}${marker}`,
16329
+ truncated: true
16330
+ };
16331
+ }
16332
+ return { text, truncated: Boolean(alreadyTruncated) };
16333
+ }
16334
+ function errorMessage2(err) {
16335
+ return (err instanceof Error ? err.message : String(err)).slice(0, 200);
16336
+ }
16159
16337
  function safePathSegment(value) {
16160
16338
  return value.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 120) || "unknown";
16161
16339
  }
@@ -16309,7 +16487,10 @@ var agentBridgeCommand = defineCommand(
16309
16487
  { flags: "--wake-channel-endpoint <url>", description: "Localhost wake endpoint exposed by the runtime's Raft channel plugin (see docs/wake-endpoint-contract.md in raft-external-agents)." },
16310
16488
  { flags: "--wake-channel-token <token>", description: "Optional shared token for the Raft channel wake endpoint (env: RAFT_CHANNEL_TOKEN)." },
16311
16489
  { flags: "--runtime-session <id>", description: "Optional runtime session id when the adapter endpoint does not return one." },
16312
- { flags: "--reconcile-interval-ms <ms>", description: "Re-peek the full server-pending set every <ms> and re-wake hints that were injected but never consumed (0 disables; default 120000)." }
16490
+ { flags: "--reconcile-interval-ms <ms>", description: "Re-peek the full server-pending set every <ms> and re-wake hints that were injected but never consumed (0 disables; default 120000)." },
16491
+ { flags: "--activity-channel-endpoint <url>", description: "Localhost activity drain endpoint exposed by the runtime's Raft channel plugin. Defaults to /activity/drain derived from --wake-channel-endpoint." },
16492
+ { flags: "--activity-channel-token <token>", description: "Optional shared token for the activity drain endpoint (env: RAFT_CHANNEL_TOKEN)." },
16493
+ { flags: "--activity-drain-limit <n>", description: "Maximum plugin activity events to drain per bridge iteration." }
16313
16494
  ]
16314
16495
  },
16315
16496
  async (ctx, options) => {
@@ -16324,10 +16505,13 @@ var agentBridgeCommand = defineCommand(
16324
16505
  const pollIntervalMs = parsePositiveInt(options.pollIntervalMs, 5e3, "poll-interval-ms");
16325
16506
  const reconcileIntervalMs = options.reconcileIntervalMs === "0" ? 0 : parsePositiveInt(options.reconcileIntervalMs, 12e4, "reconcile-interval-ms");
16326
16507
  const limit = parsePositiveInt(options.limit, 50, "limit");
16508
+ const activityDrainLimit = parsePositiveInt(options.activityDrainLimit, 50, "activity-drain-limit");
16327
16509
  const client = ctx.createApiClient(agentContext);
16328
16510
  const pollSource = createAgentApiWakeHintSource(client);
16329
16511
  const streamSource = options.once ? null : createAgentApiWakeHintStreamSource(client, ctx.env);
16330
16512
  const wakeAdapter = createWakeAdapter(options, ctx.env);
16513
+ const activitySource = createActivityDrainSource(options, ctx.env);
16514
+ const activitySink = activitySource ? createAgentApiActivitySink(client) : void 0;
16331
16515
  let bridgeLock;
16332
16516
  try {
16333
16517
  bridgeLock = acquireAgentCommsBridgeLock({
@@ -16381,6 +16565,9 @@ var agentBridgeCommand = defineCommand(
16381
16565
  replayPending,
16382
16566
  wakeAdapter,
16383
16567
  runtimeSession: options.runtimeSession ?? null,
16568
+ activitySource,
16569
+ activitySink,
16570
+ activityDrainLimit,
16384
16571
  recentInjections
16385
16572
  });
16386
16573
  for (const event of events) emit(event);
@@ -16663,6 +16850,59 @@ function createWakeAdapter(options, env = process.env) {
16663
16850
  token: options.wakeChannelToken ?? env.RAFT_CHANNEL_TOKEN
16664
16851
  });
16665
16852
  }
16853
+ function createActivityDrainSource(options, env = process.env) {
16854
+ const endpointUrl = options.activityChannelEndpoint ?? deriveActivityDrainEndpoint(options.wakeChannelEndpoint);
16855
+ if (!endpointUrl) return void 0;
16856
+ const token = options.activityChannelToken ?? options.wakeChannelToken ?? env.RAFT_CHANNEL_TOKEN;
16857
+ return {
16858
+ async drainActivity(input) {
16859
+ const url2 = new URL(endpointUrl);
16860
+ url2.searchParams.set("max", String(input.max));
16861
+ const signal = typeof AbortSignal.timeout === "function" ? AbortSignal.timeout(3e3) : void 0;
16862
+ const response = await fetch(url2, {
16863
+ method: "GET",
16864
+ signal,
16865
+ headers: {
16866
+ ...token ? { "x-raft-bridge-token": token } : {}
16867
+ }
16868
+ });
16869
+ const contentType = response.headers.get("content-type") ?? "";
16870
+ const data = contentType.includes("application/json") ? await response.json() : {};
16871
+ if (!response.ok) {
16872
+ throw new CliError({
16873
+ code: response.status >= 500 ? "SERVER_5XX" : "BRIDGE_ACTIVITY_DRAIN_FAILED",
16874
+ message: typeof data?.error === "string" ? data.error : `HTTP ${response.status}`
16875
+ });
16876
+ }
16877
+ return data;
16878
+ }
16879
+ };
16880
+ }
16881
+ function createAgentApiActivitySink(client) {
16882
+ return {
16883
+ async forwardActivity(input) {
16884
+ const response = await client.request("POST", "/internal/agent-api/activity", input);
16885
+ if (!response.ok) {
16886
+ throw new CliError({
16887
+ code: response.status >= 500 ? "SERVER_5XX" : "BRIDGE_ACTIVITY_FORWARD_FAILED",
16888
+ message: response.error ?? `HTTP ${response.status}`
16889
+ });
16890
+ }
16891
+ }
16892
+ };
16893
+ }
16894
+ function deriveActivityDrainEndpoint(wakeChannelEndpoint) {
16895
+ if (!wakeChannelEndpoint) return void 0;
16896
+ try {
16897
+ const url2 = new URL(wakeChannelEndpoint);
16898
+ url2.pathname = "/activity/drain";
16899
+ url2.search = "";
16900
+ url2.hash = "";
16901
+ return url2.toString();
16902
+ } catch {
16903
+ return void 0;
16904
+ }
16905
+ }
16666
16906
  function sleep(ms) {
16667
16907
  return new Promise((resolve) => setTimeout(resolve, ms));
16668
16908
  }
@@ -17548,6 +17788,84 @@ ${opts.heldAction} Review the bounded context shown here, then choose one path.$
17548
17788
 
17549
17789
  ` + (opts.draftInstructions ?? "") + continueAnyway;
17550
17790
  }
17791
+ function normalizeAction(action) {
17792
+ if (action === "notify" || action === "notify_only") return "notify";
17793
+ if (action === "invite" || action === "add") return "invite";
17794
+ return null;
17795
+ }
17796
+ function formatActionCommands(action) {
17797
+ const verbs = action.availableActions.map(normalizeAction).filter((verb) => verb !== null);
17798
+ return Array.from(new Set(verbs)).map((verb) => ` ${verb}: slock mention ${verb} ${action.resolutionId}`);
17799
+ }
17800
+ function normalizePendingMentionActions(data) {
17801
+ const value = data;
17802
+ const raw = Array.isArray(value?.pendingMentionActions) ? value.pendingMentionActions : Array.isArray(value?.actions) ? value.actions : Array.isArray(value?.results) ? value.results : [];
17803
+ return raw.filter((item) => Boolean(item && typeof item === "object")).map((item) => ({
17804
+ resolutionId: String(item.resolutionId ?? item.id ?? ""),
17805
+ messageId: String(item.messageId ?? ""),
17806
+ targetType: String(item.targetType ?? "unknown"),
17807
+ targetHandle: String(item.targetHandle ?? ""),
17808
+ reason: String(item.reason ?? "Mention target was not notified at send time."),
17809
+ availableActions: Array.isArray(item.availableActions) ? item.availableActions.map(String) : [],
17810
+ expiresAt: typeof item.expiresAt === "string" ? item.expiresAt : null
17811
+ })).filter((item) => item.resolutionId.length > 0);
17812
+ }
17813
+ function normalizeMentionActionResults(data) {
17814
+ const value = data;
17815
+ const raw = Array.isArray(value?.results) ? value.results : Array.isArray(value?.actionResults) ? value.actionResults : [];
17816
+ return raw.filter((item) => Boolean(item && typeof item === "object")).map((item) => ({
17817
+ resolutionId: String(item.resolutionId ?? item.id ?? ""),
17818
+ status: String(item.status ?? "not_found"),
17819
+ action: typeof item.action === "string" ? normalizeAction(item.action) : null,
17820
+ messageId: typeof item.messageId === "string" ? item.messageId : null,
17821
+ channelId: typeof item.channelId === "string" ? item.channelId : null,
17822
+ targetType: typeof item.targetType === "string" ? item.targetType : null,
17823
+ targetId: typeof item.targetId === "string" ? item.targetId : null,
17824
+ targetHandle: typeof item.targetHandle === "string" ? item.targetHandle : null,
17825
+ message: typeof item.message === "string" ? item.message : null,
17826
+ reason: typeof item.reason === "string" ? item.reason : null,
17827
+ dedupedResolutionIds: Array.isArray(item.dedupedResolutionIds) ? item.dedupedResolutionIds.filter((id) => typeof id === "string" && id.length > 0) : []
17828
+ })).filter((item) => item.resolutionId.length > 0);
17829
+ }
17830
+ function formatPendingMentionActions(actions, opts = {}) {
17831
+ if (actions.length === 0) {
17832
+ return opts.source === "pending" ? "Pending mention actions\n\nNo pending mention actions.\n" : "";
17833
+ }
17834
+ const lines = ["Pending mention actions", ""];
17835
+ for (const action of actions) {
17836
+ const target = action.targetHandle ? `${action.targetHandle} (${action.targetType})` : action.targetType;
17837
+ lines.push(`- ${action.resolutionId} \u2014 ${target}`);
17838
+ if (action.messageId) lines.push(` message: ${action.messageId}`);
17839
+ lines.push(` reason: ${action.reason}`);
17840
+ if (action.expiresAt) lines.push(` expires: ${action.expiresAt}`);
17841
+ const commands = formatActionCommands(action);
17842
+ if (commands.length > 0) {
17843
+ lines.push(" available commands:");
17844
+ lines.push(...commands);
17845
+ }
17846
+ }
17847
+ return `${lines.join("\n")}
17848
+ `;
17849
+ }
17850
+ function formatMentionActionResults(action, results) {
17851
+ const lines = [`Mention ${action} results`, ""];
17852
+ if (results.length === 0) {
17853
+ lines.push("No result rows returned.");
17854
+ return `${lines.join("\n")}
17855
+ `;
17856
+ }
17857
+ for (const result2 of results) {
17858
+ const target = result2.targetHandle ? ` ${result2.targetHandle}` : "";
17859
+ const detail = result2.message ?? result2.reason;
17860
+ const suffix = detail ? ` \u2014 ${detail}` : "";
17861
+ lines.push(`- ${result2.resolutionId}${target}: ${result2.status}${suffix}`);
17862
+ if (result2.dedupedResolutionIds && result2.dedupedResolutionIds.length > 1) {
17863
+ lines.push(` deduped: ${result2.dedupedResolutionIds.join(", ")}`);
17864
+ }
17865
+ }
17866
+ return `${lines.join("\n")}
17867
+ `;
17868
+ }
17551
17869
  var DEFAULT_LOCAL_DRAFT_TTL_MS = 10 * 60 * 1e3;
17552
17870
  function stateFilePath2(agentId) {
17553
17871
  return path6.join(process.env.SLOCK_CLI_DRAFT_STATE_DIR ?? os3.tmpdir(), "slock-cli-attested-send", agentId, "continue-state.json");
@@ -17850,7 +18168,11 @@ var messageSendCommand = defineCommand(
17850
18168
  --- New messages you may have missed ---
17851
18169
  ${formatMessages(data.recentUnread)}`;
17852
18170
  }
17853
- writeText(ctx.io, `Message sent to ${opts.target}. Message ID: ${data.messageId}${replyHint}${unreadSection}
18171
+ const pendingMentionActions = normalizePendingMentionActions(data);
18172
+ const mentionSection = pendingMentionActions.length > 0 ? `
18173
+
18174
+ ${formatPendingMentionActions(pendingMentionActions, { source: "send" }).trimEnd()}` : "";
18175
+ writeText(ctx.io, `Message sent to ${opts.target}. Message ID: ${data.messageId}${replyHint}${mentionSection}${unreadSection}
17854
18176
  `);
17855
18177
  }
17856
18178
  );
@@ -18906,6 +19228,77 @@ var taskUpdateCommand = defineCommand(
18906
19228
  function registerTaskUpdateCommand(parent, runtimeOptions) {
18907
19229
  registerCliCommand(parent, taskUpdateCommand, runtimeOptions);
18908
19230
  }
19231
+ function normalizeResolutionIds(rawIds) {
19232
+ const ids = (rawIds ?? []).map((id) => id.trim()).filter(Boolean);
19233
+ if (ids.length === 0) {
19234
+ throw cliError("INVALID_ARG", "At least one resolution id is required.");
19235
+ }
19236
+ return ids;
19237
+ }
19238
+ function buildMentionExecuteCommand(action) {
19239
+ return defineCommand(
19240
+ {
19241
+ name: action,
19242
+ description: `${action === "notify" ? "Notify" : "Invite"} unresolved mention targets by resolution id`,
19243
+ arguments: ["<resolutionIds...>"],
19244
+ options: [{ flags: "--json", description: "Emit machine-readable JSON" }]
19245
+ },
19246
+ async (ctx, resolutionIds, opts = {}) => {
19247
+ const ids = normalizeResolutionIds(resolutionIds);
19248
+ const agentContext = ctx.loadAgentContext();
19249
+ const client = ctx.createApiClient(agentContext);
19250
+ const res = await client.request(
19251
+ "POST",
19252
+ `/internal/agent/${encodeURIComponent(agentContext.agentId)}/mention-actions/execute`,
19253
+ { action, resolutionIds: ids }
19254
+ );
19255
+ if (!res.ok || !res.data) {
19256
+ throw cliError(res.status >= 500 ? "SERVER_5XX" : "MENTION_ACTION_FAILED", res.error ?? `HTTP ${res.status}`);
19257
+ }
19258
+ const results = normalizeMentionActionResults(res.data);
19259
+ if (opts.json) {
19260
+ writeJson(ctx.io, { ok: true, action, results });
19261
+ return;
19262
+ }
19263
+ writeText(ctx.io, formatMentionActionResults(action, results));
19264
+ }
19265
+ );
19266
+ }
19267
+ function registerMentionExecuteCommands(parent, runtimeOptions = {}) {
19268
+ registerCliCommand(parent, buildMentionExecuteCommand("notify"), runtimeOptions);
19269
+ registerCliCommand(parent, buildMentionExecuteCommand("invite"), runtimeOptions);
19270
+ }
19271
+ var mentionPendingCommand = defineCommand(
19272
+ {
19273
+ name: "pending",
19274
+ description: "List sender-side pending mention actions",
19275
+ options: [{ flags: "--json", description: "Emit machine-readable JSON" }]
19276
+ },
19277
+ async (ctx, opts = {}) => {
19278
+ const agentContext = ctx.loadAgentContext();
19279
+ const client = ctx.createApiClient(agentContext);
19280
+ const res = await client.request(
19281
+ "GET",
19282
+ `/internal/agent/${encodeURIComponent(agentContext.agentId)}/mention-actions/pending`
19283
+ );
19284
+ if (!res.ok || !res.data) {
19285
+ throw cliError(res.status >= 500 ? "SERVER_5XX" : "MENTION_PENDING_FAILED", res.error ?? `HTTP ${res.status}`);
19286
+ }
19287
+ const actions = normalizePendingMentionActions(res.data);
19288
+ if (opts.json) {
19289
+ writeJson(ctx.io, { ok: true, pendingMentionActions: actions });
19290
+ return;
19291
+ }
19292
+ writeText(ctx.io, formatPendingMentionActions(actions, { source: "pending" }));
19293
+ }
19294
+ );
19295
+ function registerMentionPendingCommand(parent, runtimeOptions = {}) {
19296
+ registerCliCommand(parent, mentionPendingCommand, runtimeOptions);
19297
+ }
19298
+ function registerMentionCommands(parent, runtimeOptions = {}) {
19299
+ registerMentionPendingCommand(parent, runtimeOptions);
19300
+ registerMentionExecuteCommands(parent, runtimeOptions);
19301
+ }
18909
19302
  function formatCreatedAgents(createdAgents) {
18910
19303
  if (createdAgents.length === 0) {
18911
19304
  return ["- Created Agents: none"];
@@ -20181,6 +20574,8 @@ registerTaskCreateCommand(taskCmd);
20181
20574
  registerTaskClaimCommand(taskCmd);
20182
20575
  registerTaskUnclaimCommand(taskCmd);
20183
20576
  registerTaskUpdateCommand(taskCmd);
20577
+ var mentionCmd = program.command("mention").description("Sender-side mention action operations");
20578
+ registerMentionCommands(mentionCmd);
20184
20579
  var profileCmd = program.command("profile").description("Profile operations");
20185
20580
  registerProfileShowCommand(profileCmd);
20186
20581
  registerProfileUpdateCommand(profileCmd);
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  DAEMON_CLI_USAGE,
4
4
  DaemonCore,
5
5
  parseDaemonCliArgs
6
- } from "./chunk-G324C7NF.js";
6
+ } from "./chunk-FTEZQN4P.js";
7
7
 
8
8
  // src/index.ts
9
9
  var parsedArgs = parseDaemonCliArgs(process.argv.slice(2));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botiverse/raft-daemon",
3
- "version": "0.58.1",
3
+ "version": "0.59.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "raft-daemon": "dist/raft-daemon.js",