@botiverse/raft-daemon 0.70.3 → 0.71.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/cli/index.js CHANGED
@@ -28001,6 +28001,7 @@ var CliError = class extends Error {
28001
28001
  code;
28002
28002
  exitCode;
28003
28003
  suggestedNextAction;
28004
+ draftSaved;
28004
28005
  constructor(options) {
28005
28006
  super(options.message);
28006
28007
  this.name = "CliError";
@@ -28008,6 +28009,7 @@ var CliError = class extends Error {
28008
28009
  this.exitCode = options.exitCode ?? 1;
28009
28010
  this.cause = options.cause;
28010
28011
  this.suggestedNextAction = options.suggestedNextAction;
28012
+ this.draftSaved = options.draftSaved;
28011
28013
  }
28012
28014
  };
28013
28015
  var CliExit = class extends Error {
@@ -28034,7 +28036,8 @@ function cliError(code, message, options = {}) {
28034
28036
  message,
28035
28037
  exitCode: options.exitCode,
28036
28038
  cause: options.cause,
28037
- suggestedNextAction: options.suggestedNextAction
28039
+ suggestedNextAction: options.suggestedNextAction,
28040
+ draftSaved: options.draftSaved
28038
28041
  });
28039
28042
  }
28040
28043
  function toCliError(err) {
@@ -28873,6 +28876,7 @@ var TRACE_B0_FIELD_DEFINITIONS = defineTraceFields([
28873
28876
  { key: "error_class", fieldClass: "query_axis", placement: "span_or_event", valueKind: "closed_enum", enumBinding: "pending_457" },
28874
28877
  { key: "query_name", fieldClass: "query_axis", placement: "span_or_event", valueKind: "closed_enum", enumBinding: "query_registry" },
28875
28878
  { key: "phase", fieldClass: "query_axis", placement: "span_or_event", valueKind: "closed_enum", enumBinding: "pending_457" },
28879
+ { key: "eligibility_subcheck", fieldClass: "query_axis", placement: "event", valueKind: "closed_enum", enumBinding: "pending_457" },
28876
28880
  { key: "hint_source", fieldClass: "family_query_axis", placement: "event", valueKind: "closed_enum", scope: "family:activity" },
28877
28881
  { key: "resolved_activity", fieldClass: "family_query_axis", placement: "event", valueKind: "closed_enum", scope: "family:activity" },
28878
28882
  { key: "previous_activity", fieldClass: "family_query_axis", placement: "event", valueKind: "closed_enum", scope: "family:activity" },
@@ -42944,6 +42948,24 @@ var agentApiKnowledgeGetResponseSchema = passthroughObject({
42944
42948
  contentType: external_exports.string(),
42945
42949
  content: external_exports.string()
42946
42950
  });
42951
+ var agentApiKnowledgeSearchQuerySchema = passthroughObject({
42952
+ query: external_exports.string().trim().min(1),
42953
+ scope: optionalStringSchema,
42954
+ reason: optionalStringSchema,
42955
+ turn_id: optionalStringSchema,
42956
+ trace_id: optionalStringSchema
42957
+ });
42958
+ var agentApiKnowledgeSearchResultSchema = passthroughObject({
42959
+ slug: external_exports.string(),
42960
+ title: external_exports.string(),
42961
+ firstScreen: external_exports.string()
42962
+ });
42963
+ var agentApiKnowledgeSearchResponseSchema = passthroughObject({
42964
+ ok: external_exports.literal(true),
42965
+ query: external_exports.string(),
42966
+ scope: external_exports.string().nullable(),
42967
+ results: external_exports.array(agentApiKnowledgeSearchResultSchema)
42968
+ });
42947
42969
  var agentApiMessageSearchQuerySchema = passthroughObject({
42948
42970
  q: optionalStringSchema,
42949
42971
  channel: optionalStringSchema,
@@ -43395,7 +43417,14 @@ var agentApiSendSentResponseSchema = passthroughObject({
43395
43417
  messageId: external_exports.string(),
43396
43418
  messageSeq: optionalNumberSchema,
43397
43419
  recentUnread: external_exports.array(agentApiMessageEnvelopeSchema).optional(),
43398
- pendingMentionActions: external_exports.array(agentApiMessageEnvelopeSchema).optional()
43420
+ pendingMentionActions: external_exports.array(agentApiMessageEnvelopeSchema).optional(),
43421
+ attention: passthroughObject({
43422
+ driveByJoinedToPost: passthroughObject({
43423
+ reason: optionalStringSchema,
43424
+ muteCommand: optionalStringSchema,
43425
+ stillArrives: optionalStringArraySchema
43426
+ }).optional()
43427
+ }).optional()
43399
43428
  });
43400
43429
  var agentApiSendResponseSchema = external_exports.discriminatedUnion("state", [
43401
43430
  agentApiSendSentResponseSchema,
@@ -43584,6 +43613,16 @@ var agentApiContract = {
43584
43613
  request: { query: agentApiKnowledgeGetQuerySchema },
43585
43614
  response: { body: agentApiKnowledgeGetResponseSchema }
43586
43615
  }),
43616
+ knowledgeSearch: route({
43617
+ key: "knowledgeSearch",
43618
+ method: "GET",
43619
+ path: "/knowledge/search",
43620
+ client: { resource: "knowledge", method: "search" },
43621
+ capability: "knowledge",
43622
+ description: "Search Slock Manual for Agents topics from the current server.",
43623
+ request: { query: agentApiKnowledgeSearchQuerySchema },
43624
+ response: { body: agentApiKnowledgeSearchResponseSchema }
43625
+ }),
43587
43626
  messageSend: route({
43588
43627
  key: "messageSend",
43589
43628
  method: "POST",
@@ -45018,6 +45057,15 @@ var SERVER_CAPABILITY_MATRIX = {
45018
45057
  })
45019
45058
  };
45020
45059
 
45060
+ // ../shared/src/tracing/traceFamilyRegistry.ts
45061
+ init_esm_shims();
45062
+
45063
+ // ../shared/src/tracing/stateTransitionTrace.ts
45064
+ init_esm_shims();
45065
+
45066
+ // ../shared/src/tracing/stateViolationTrace.ts
45067
+ init_esm_shims();
45068
+
45021
45069
  // ../shared/src/index.ts
45022
45070
  var BUILTIN_RUNTIME_PROVIDER_ENV_KEYS = PI_BUILTIN_PROVIDER_API_KEY_ENV_KEYS_GENERATED;
45023
45071
  var BUILTIN_RUNTIME_PROVIDERS = Object.entries(BUILTIN_RUNTIME_PROVIDER_ENV_KEYS).map(([id, envKey]) => ({ id, envKey }));
@@ -45460,7 +45508,8 @@ function createAgentApiSurfaceClient(client) {
45460
45508
  read: (query) => requestClientAsApiResponse(agentApi.history.read(query))
45461
45509
  },
45462
45510
  knowledge: {
45463
- get: (query) => requestClientAsApiResponse(agentApi.knowledge.get(query))
45511
+ get: (query) => requestClientAsApiResponse(agentApi.knowledge.get(query)),
45512
+ search: (query) => requestClientAsApiResponse(agentApi.knowledge.search(query))
45464
45513
  },
45465
45514
  tasks: {
45466
45515
  list: (query) => requestClientAsApiResponse(agentApi.tasks.list(query)),
@@ -46211,6 +46260,10 @@ function renderError(io, err) {
46211
46260
  `);
46212
46261
  io.stderr.write(`Code: ${err.code}
46213
46262
  `);
46263
+ if (err.draftSaved !== void 0) {
46264
+ io.stderr.write(`Draft saved: ${err.draftSaved ? "yes" : "no"}
46265
+ `);
46266
+ }
46214
46267
  if (err.suggestedNextAction) {
46215
46268
  io.stderr.write(`Next action: ${err.suggestedNextAction}
46216
46269
  `);
@@ -48575,6 +48628,156 @@ function formatServerInfo(data) {
48575
48628
  }
48576
48629
  return text;
48577
48630
  }
48631
+ function channelRef(name) {
48632
+ return name.startsWith("#") ? name : `#${name}`;
48633
+ }
48634
+ function channelVisibility(channel) {
48635
+ const type = channel.type?.trim();
48636
+ return type === "private" ? "private" : "public";
48637
+ }
48638
+ function channelMuted(channel) {
48639
+ if (typeof channel.muted === "boolean") return channel.muted;
48640
+ if (typeof channel.activityMuted === "boolean") return channel.activityMuted;
48641
+ return void 0;
48642
+ }
48643
+ function channelStatus(channel) {
48644
+ const parts = [
48645
+ channelVisibility(channel),
48646
+ channel.joined ? "joined" : "not joined"
48647
+ ];
48648
+ const muted = channelMuted(channel);
48649
+ if (muted !== void 0) parts.push(muted ? "muted" : "not muted");
48650
+ if (typeof channel.archived === "boolean") parts.push(channel.archived ? "archived" : "not archived");
48651
+ return parts.join(", ");
48652
+ }
48653
+ function formatPageFooter(page) {
48654
+ if (!page) return "";
48655
+ const start = page.total === 0 ? 0 : Math.min(page.offset + 1, page.total);
48656
+ const end = Math.min(page.offset + page.limit, page.total);
48657
+ const lines = [`
48658
+ Showing ${start}-${end} of ${page.total}.`];
48659
+ if (page.nextCommand && end < page.total) {
48660
+ lines.push(`More: ${page.nextCommand}`);
48661
+ }
48662
+ return `${lines.join("\n")}
48663
+ `;
48664
+ }
48665
+ function formatChannelInfo(channel, memberCounts) {
48666
+ const lines = ["## Channel", ""];
48667
+ lines.push(`Channel: ${channelRef(channel.name)}`);
48668
+ if (channel.id) lines.push(`ID: ${channel.id}`);
48669
+ lines.push(`Visibility: ${channelVisibility(channel)}`);
48670
+ lines.push(`Joined: ${channel.joined ? "yes" : "no"}`);
48671
+ const muted = channelMuted(channel);
48672
+ if (muted !== void 0) lines.push(`Muted: ${muted ? "yes" : "no"}`);
48673
+ if (typeof channel.archived === "boolean") lines.push(`Archived: ${channel.archived ? "yes" : "no"}`);
48674
+ lines.push(`Description: ${channel.description?.trim() || "(none)"}`);
48675
+ if (memberCounts) {
48676
+ const agents = memberCounts.agents ?? 0;
48677
+ const humans = memberCounts.humans ?? 0;
48678
+ lines.push(`Members: ${agents + humans} (${agents} agents, ${humans} humans)`);
48679
+ }
48680
+ lines.push("");
48681
+ lines.push(`More: raft channel members "${channelRef(channel.name)}"`);
48682
+ return `${lines.join("\n")}
48683
+ `;
48684
+ }
48685
+ function formatServerSummary(data) {
48686
+ const channels = data.channels ?? [];
48687
+ const agents = data.agents ?? [];
48688
+ const humans = data.humans ?? [];
48689
+ const joined = channels.filter((channel) => channel.joined).length;
48690
+ const lines = [
48691
+ "## Server",
48692
+ "",
48693
+ `Channels: ${channels.length} visible (${joined} joined)`,
48694
+ `Agents: ${agents.length}`,
48695
+ `Humans: ${humans.length}`,
48696
+ "",
48697
+ "Narrow queries:",
48698
+ "- raft server info --channels",
48699
+ "- raft server info --agents",
48700
+ "- raft server info --humans",
48701
+ "- raft channel info <name>",
48702
+ "- raft user info <name>",
48703
+ "",
48704
+ "Full dump: raft server info --full"
48705
+ ];
48706
+ return `${lines.join("\n")}
48707
+ `;
48708
+ }
48709
+ function formatServerChannels(channels, page) {
48710
+ const lines = [
48711
+ "## Server Channels",
48712
+ "",
48713
+ "Private channels are shown only when this agent is a member. Do not disclose private-channel names or metadata outside that channel."
48714
+ ];
48715
+ if (channels.length === 0) {
48716
+ lines.push("(none)");
48717
+ } else {
48718
+ for (const channel of channels) {
48719
+ const description = channel.description?.trim();
48720
+ lines.push(description ? `${channelRef(channel.name)} [${channelStatus(channel)}] \u2014 ${description}` : `${channelRef(channel.name)} [${channelStatus(channel)}]`);
48721
+ }
48722
+ }
48723
+ return `${lines.join("\n")}${formatPageFooter(page)}`;
48724
+ }
48725
+ function formatServerAgents(agents, page) {
48726
+ const lines = [
48727
+ "## Server Agents",
48728
+ "",
48729
+ "Role labels show server-level owner/admin authority; no role label means ordinary member."
48730
+ ];
48731
+ if (agents.length === 0) {
48732
+ lines.push("(none)");
48733
+ } else {
48734
+ for (const agent of agents) {
48735
+ const role = roleLabel(agent.role);
48736
+ const status = agentStatusLabel(agent);
48737
+ lines.push(agent.description ? `@${agent.name} (${status})${role} \u2014 ${agent.description}` : `@${agent.name} (${status})${role}`);
48738
+ }
48739
+ }
48740
+ return `${lines.join("\n")}${formatPageFooter(page)}`;
48741
+ }
48742
+ function formatServerHumans(humans, page) {
48743
+ const lines = [
48744
+ "## Server Humans",
48745
+ "",
48746
+ "Role labels show server-level owner/admin authority; no role label means ordinary member."
48747
+ ];
48748
+ if (humans.length === 0) {
48749
+ lines.push("(none)");
48750
+ } else {
48751
+ for (const human of humans) {
48752
+ const role = roleLabel(human.role);
48753
+ lines.push(human.description ? `@${human.name}${role} \u2014 ${human.description}` : `@${human.name}${role}`);
48754
+ }
48755
+ }
48756
+ return `${lines.join("\n")}${formatPageFooter(page)}`;
48757
+ }
48758
+ function formatUserInfo(user, memberships, page, skippedChannels = 0) {
48759
+ const name = user.value.name;
48760
+ const role = roleLabel(user.value.role);
48761
+ const lines = ["## User", ""];
48762
+ lines.push(`User: @${name}`);
48763
+ lines.push(`Kind: ${user.kind}`);
48764
+ if (user.kind === "agent") lines.push(`Status: ${agentStatusLabel(user.value)}`);
48765
+ if (role) lines.push(`Role: ${role.slice(2, -1)}`);
48766
+ if (user.value.description) lines.push(`Description: ${user.value.description}`);
48767
+ lines.push("");
48768
+ lines.push("### Visible Channel Memberships");
48769
+ if (memberships.length === 0) {
48770
+ lines.push("(none found in inspected visible channels)");
48771
+ } else {
48772
+ for (const channel of memberships) {
48773
+ lines.push(`${channelRef(channel.name)} [${channelStatus(channel)}]`);
48774
+ }
48775
+ }
48776
+ if (skippedChannels > 0) {
48777
+ lines.push(`Skipped ${skippedChannels} visible channel roster checks because the server rejected them.`);
48778
+ }
48779
+ return `${lines.join("\n")}${formatPageFooter(page)}`;
48780
+ }
48578
48781
  function formatChannelMembers(data) {
48579
48782
  let text = "## Channel Members\n\n";
48580
48783
  const ref = data.channel?.ref ?? "(unknown)";
@@ -48644,68 +48847,7 @@ function registerChannelMembersCommand(parent, runtimeOptions) {
48644
48847
  registerCliCommand(parent, channelMembersCommand, runtimeOptions);
48645
48848
  }
48646
48849
 
48647
- // src/commands/channel/create.ts
48648
- init_esm_shims();
48649
- function normalizeChannelName(raw) {
48650
- return (raw ?? "").trim().replace(/^#/, "");
48651
- }
48652
- function formatCreateChannelResult(channel) {
48653
- const target = `#${channel.name}`;
48654
- const visibility = channel.type === "private" ? "private" : "public";
48655
- return `Created ${target} (${visibility}). You are joined and can send messages there.`;
48656
- }
48657
- var channelCreateCommand = defineCommand(
48658
- {
48659
- name: "create",
48660
- description: "Create a public or private channel when this agent has server admin authority",
48661
- options: [
48662
- {
48663
- flags: "--name <name>",
48664
- description: "Channel name, with or without a leading '#'"
48665
- },
48666
- {
48667
- flags: "--description <description>",
48668
- description: "Optional channel description"
48669
- },
48670
- {
48671
- flags: "--private",
48672
- description: "Create a private channel instead of a public channel"
48673
- }
48674
- ]
48675
- },
48676
- async (ctx, opts) => {
48677
- const name = normalizeChannelName(opts.name);
48678
- if (!name) {
48679
- throw new CliError({
48680
- code: "INVALID_ARG",
48681
- message: "--name is required"
48682
- });
48683
- }
48684
- const agentContext = ctx.loadAgentContext();
48685
- const client = ctx.createApiClient(agentContext);
48686
- const res = await client.request(
48687
- "POST",
48688
- `/internal/agent/${encodeURIComponent(agentContext.agentId)}/channels`,
48689
- {
48690
- name,
48691
- description: opts.description,
48692
- visibility: opts.private ? "private" : "public"
48693
- }
48694
- );
48695
- if (!res.ok || !res.data) {
48696
- throw new CliError({
48697
- code: res.status >= 500 ? "SERVER_5XX" : "CREATE_FAILED",
48698
- message: res.error ?? `HTTP ${res.status}`
48699
- });
48700
- }
48701
- writeText(ctx.io, formatCreateChannelResult(res.data) + "\n");
48702
- }
48703
- );
48704
- function registerChannelCreateCommand(parent, runtimeOptions) {
48705
- registerCliCommand(parent, channelCreateCommand, runtimeOptions);
48706
- }
48707
-
48708
- // src/commands/channel/update.ts
48850
+ // src/commands/channel/info.ts
48709
48851
  init_esm_shims();
48710
48852
 
48711
48853
  // src/commands/channel/leave.ts
@@ -48779,7 +48921,123 @@ function registerChannelLeaveCommand(parent, runtimeOptions) {
48779
48921
  registerCliCommand(parent, channelLeaveCommand, runtimeOptions);
48780
48922
  }
48781
48923
 
48924
+ // src/commands/channel/info.ts
48925
+ function normalizeChannelInfoTarget(target) {
48926
+ const input = target?.trim() ?? "";
48927
+ const normalized = input.startsWith("#") ? input : `#${input}`;
48928
+ const name = parseRegularChannelTarget(normalized);
48929
+ if (!name) {
48930
+ throw new CliError({
48931
+ code: "INVALID_TARGET",
48932
+ message: "Target must be a regular channel name, e.g. '#engineering' or 'engineering'. DMs and thread targets are not supported."
48933
+ });
48934
+ }
48935
+ return { input: normalized, name };
48936
+ }
48937
+ var channelInfoCommand = defineCommand(
48938
+ {
48939
+ name: "info",
48940
+ description: "Show narrow channel facts: existence, joined state, description, and member count when visible",
48941
+ arguments: ["<target>"]
48942
+ },
48943
+ async (ctx, target) => {
48944
+ const { input, name } = normalizeChannelInfoTarget(target);
48945
+ const agentContext = ctx.loadAgentContext();
48946
+ const client = ctx.createApiClient(agentContext);
48947
+ const agentApi = createAgentApiSurfaceClient(client);
48948
+ const infoRes = await agentApi.server.info();
48949
+ if (!infoRes.ok) {
48950
+ throw new CliError({
48951
+ code: infoRes.status >= 500 ? "SERVER_5XX" : "INFO_FAILED",
48952
+ message: infoRes.error ?? `HTTP ${infoRes.status}`
48953
+ });
48954
+ }
48955
+ const channel = (infoRes.data?.channels ?? []).find((candidate) => candidate.name === name);
48956
+ if (!channel) {
48957
+ throw new CliError({
48958
+ code: "NOT_FOUND",
48959
+ message: `Channel not found or not visible: ${input}`,
48960
+ suggestedNextAction: "Run `raft server info --channels --query <name>` to inspect visible channels, or ask a channel member to add you if this is private."
48961
+ });
48962
+ }
48963
+ let memberCounts = null;
48964
+ const membersRes = await agentApi.channels.members({ channel: `#${name}` });
48965
+ if (membersRes.ok) {
48966
+ memberCounts = {
48967
+ agents: membersRes.data?.agents?.length ?? 0,
48968
+ humans: membersRes.data?.humans?.length ?? 0
48969
+ };
48970
+ }
48971
+ writeText(ctx.io, formatChannelInfo(channel, memberCounts));
48972
+ }
48973
+ );
48974
+ function registerChannelInfoCommand(parent, runtimeOptions) {
48975
+ registerCliCommand(parent, channelInfoCommand, runtimeOptions);
48976
+ }
48977
+
48978
+ // src/commands/channel/create.ts
48979
+ init_esm_shims();
48980
+ function normalizeChannelName(raw) {
48981
+ return (raw ?? "").trim().replace(/^#/, "");
48982
+ }
48983
+ function formatCreateChannelResult(channel) {
48984
+ const target = `#${channel.name}`;
48985
+ const visibility = channel.type === "private" ? "private" : "public";
48986
+ return `Created ${target} (${visibility}). You are joined and can send messages there.`;
48987
+ }
48988
+ var channelCreateCommand = defineCommand(
48989
+ {
48990
+ name: "create",
48991
+ description: "Create a public or private channel when this agent has server admin authority",
48992
+ options: [
48993
+ {
48994
+ flags: "--name <name>",
48995
+ description: "Channel name, with or without a leading '#'"
48996
+ },
48997
+ {
48998
+ flags: "--description <description>",
48999
+ description: "Optional channel description"
49000
+ },
49001
+ {
49002
+ flags: "--private",
49003
+ description: "Create a private channel instead of a public channel"
49004
+ }
49005
+ ]
49006
+ },
49007
+ async (ctx, opts) => {
49008
+ const name = normalizeChannelName(opts.name);
49009
+ if (!name) {
49010
+ throw new CliError({
49011
+ code: "INVALID_ARG",
49012
+ message: "--name is required"
49013
+ });
49014
+ }
49015
+ const agentContext = ctx.loadAgentContext();
49016
+ const client = ctx.createApiClient(agentContext);
49017
+ const res = await client.request(
49018
+ "POST",
49019
+ `/internal/agent/${encodeURIComponent(agentContext.agentId)}/channels`,
49020
+ {
49021
+ name,
49022
+ description: opts.description,
49023
+ visibility: opts.private ? "private" : "public"
49024
+ }
49025
+ );
49026
+ if (!res.ok || !res.data) {
49027
+ throw new CliError({
49028
+ code: res.status >= 500 ? "SERVER_5XX" : "CREATE_FAILED",
49029
+ message: res.error ?? `HTTP ${res.status}`
49030
+ });
49031
+ }
49032
+ writeText(ctx.io, formatCreateChannelResult(res.data) + "\n");
49033
+ }
49034
+ );
49035
+ function registerChannelCreateCommand(parent, runtimeOptions) {
49036
+ registerCliCommand(parent, channelCreateCommand, runtimeOptions);
49037
+ }
49038
+
48782
49039
  // src/commands/channel/update.ts
49040
+ init_esm_shims();
48783
49041
  function normalizeChannelName2(raw) {
48784
49042
  return (raw ?? "").trim().replace(/^#/, "");
48785
49043
  }
@@ -49052,7 +49310,12 @@ function registerChannelRemoveMemberCommand(parent, runtimeOptions) {
49052
49310
  // src/commands/channel/join.ts
49053
49311
  init_esm_shims();
49054
49312
  function formatJoinChannelResult(target) {
49055
- return `Joined ${target}. You can now send messages there and receive ordinary channel delivery.`;
49313
+ return [
49314
+ `Joined ${target}. You can now send messages there and receive ordinary channel delivery.`,
49315
+ "Still arrives:",
49316
+ "- Personal @mentions still reach you even if you later mute ordinary channel updates.",
49317
+ "- Threads you started or follow stay followed even if you later mute this channel."
49318
+ ].join("\n");
49056
49319
  }
49057
49320
  function formatAlreadyJoined(target) {
49058
49321
  return `Already joined ${target}.`;
@@ -49208,12 +49471,90 @@ function registerChannelUnmuteCommand(parent, runtimeOptions) {
49208
49471
 
49209
49472
  // src/commands/server/info.ts
49210
49473
  init_esm_shims();
49474
+ function parseNonNegativeInt(raw, name, fallback) {
49475
+ if (raw === void 0) return fallback;
49476
+ if (!/^\d+$/.test(raw)) {
49477
+ throw new CliError({
49478
+ code: "INVALID_ARG",
49479
+ message: `${name} must be a non-negative integer`
49480
+ });
49481
+ }
49482
+ return Number(raw);
49483
+ }
49484
+ function parsePositiveInt2(raw, name, fallback) {
49485
+ const value = parseNonNegativeInt(raw, name, fallback);
49486
+ if (value <= 0) {
49487
+ throw new CliError({
49488
+ code: "INVALID_ARG",
49489
+ message: `${name} must be greater than 0`
49490
+ });
49491
+ }
49492
+ return value;
49493
+ }
49494
+ function selectedSections(opts) {
49495
+ const sections = [];
49496
+ if (opts.channels) sections.push("channels");
49497
+ if (opts.agents) sections.push("agents");
49498
+ if (opts.humans) sections.push("humans");
49499
+ return sections;
49500
+ }
49501
+ function hasListModifier(opts) {
49502
+ return Boolean(opts.joined || opts.query !== void 0 || opts.limit !== void 0 || opts.offset !== void 0);
49503
+ }
49504
+ function includesQuery(row, query) {
49505
+ const needle = query?.trim().toLowerCase();
49506
+ if (!needle) return true;
49507
+ const values = Object.values(row).filter((value) => typeof value === "string").map((value) => value.toLowerCase());
49508
+ return values.some((value) => value.includes(needle));
49509
+ }
49510
+ function pageRows(rows, offset, limit) {
49511
+ return rows.slice(offset, offset + limit);
49512
+ }
49513
+ function nextCommand(section, opts, offset, limit, total) {
49514
+ const nextOffset = offset + limit;
49515
+ if (nextOffset >= total) return void 0;
49516
+ const parts = ["raft server info", `--${section}`, `--offset ${nextOffset}`, `--limit ${limit}`];
49517
+ if (opts.query?.trim()) parts.push(`--query ${JSON.stringify(opts.query.trim())}`);
49518
+ if (opts.joined) parts.push("--joined");
49519
+ return parts.join(" ");
49520
+ }
49211
49521
  var serverInfoCommand = defineCommand(
49212
49522
  {
49213
49523
  name: "info",
49214
- description: "List channels, agents, and humans on the current server"
49524
+ description: "Show bounded server facts; use --full for the legacy full inventory",
49525
+ options: [
49526
+ { flags: "--full", description: "Print the full channels, agents, humans, and runtime inventory" },
49527
+ { flags: "--channels", description: "List visible channels only" },
49528
+ { flags: "--agents", description: "List agents only" },
49529
+ { flags: "--humans", description: "List humans only" },
49530
+ { flags: "--joined", description: "With --channels, show only joined channels" },
49531
+ { flags: "--query <text>", description: "Filter the selected list by visible text" },
49532
+ { flags: "--limit <n>", description: "Maximum rows for list output (default: 50)" },
49533
+ { flags: "--offset <n>", description: "Rows to skip for list output (default: 0)" }
49534
+ ]
49215
49535
  },
49216
- async (ctx) => {
49536
+ async (ctx, opts = {}) => {
49537
+ const sections = selectedSections(opts);
49538
+ if (opts.full && sections.length > 0) {
49539
+ throw new CliError({
49540
+ code: "INVALID_ARG",
49541
+ message: "--full cannot be combined with --channels, --agents, or --humans"
49542
+ });
49543
+ }
49544
+ if (sections.length === 0 && hasListModifier(opts)) {
49545
+ throw new CliError({
49546
+ code: "INVALID_ARG",
49547
+ message: "--query, --limit, --offset, and --joined require --channels, --agents, or --humans"
49548
+ });
49549
+ }
49550
+ if (opts.joined && sections.some((section) => section !== "channels")) {
49551
+ throw new CliError({
49552
+ code: "INVALID_ARG",
49553
+ message: "--joined can only be used with --channels"
49554
+ });
49555
+ }
49556
+ const limit = parsePositiveInt2(opts.limit, "--limit", 50);
49557
+ const offset = parseNonNegativeInt(opts.offset, "--offset", 0);
49217
49558
  const agentContext = ctx.loadAgentContext();
49218
49559
  const client = ctx.createApiClient(agentContext);
49219
49560
  const res = await createAgentApiSurfaceClient(client).server.info();
@@ -49224,14 +49565,56 @@ var serverInfoCommand = defineCommand(
49224
49565
  message: res.error ?? `HTTP ${res.status}`
49225
49566
  });
49226
49567
  }
49227
- const data = res.data;
49228
- if (data?.runtimeContext) {
49229
- data.runtimeContext = {
49230
- ...data.runtimeContext,
49231
- workspacePath: data.runtimeContext.workspacePath ?? ctx.env.SLOCK_CURRENT_WORKSPACE_PATH ?? null
49232
- };
49568
+ if (!res.data) {
49569
+ throw new CliError({
49570
+ code: "INVALID_JSON_RESPONSE",
49571
+ message: "Agent API serverInfo returned an empty response body"
49572
+ });
49233
49573
  }
49234
- writeText(ctx.io, formatServerInfo(data));
49574
+ const data = {
49575
+ ...res.data,
49576
+ runtimeContext: {
49577
+ ...res.data.runtimeContext,
49578
+ workspacePath: res.data.runtimeContext.workspacePath ?? ctx.env.SLOCK_CURRENT_WORKSPACE_PATH ?? null
49579
+ }
49580
+ };
49581
+ if (opts.full) {
49582
+ writeText(ctx.io, formatServerInfo(data));
49583
+ return;
49584
+ }
49585
+ if (sections.length === 0) {
49586
+ writeText(ctx.io, formatServerSummary(data));
49587
+ return;
49588
+ }
49589
+ const chunks = [];
49590
+ for (const section of sections) {
49591
+ if (section === "channels") {
49592
+ const rows = (data.channels ?? []).filter((channel) => !opts.joined || channel.joined).filter((channel) => includesQuery(channel, opts.query));
49593
+ chunks.push(formatServerChannels(pageRows(rows, offset, limit), {
49594
+ total: rows.length,
49595
+ offset,
49596
+ limit,
49597
+ nextCommand: nextCommand(section, opts, offset, limit, rows.length)
49598
+ }));
49599
+ } else if (section === "agents") {
49600
+ const rows = (data.agents ?? []).filter((agent) => includesQuery(agent, opts.query));
49601
+ chunks.push(formatServerAgents(pageRows(rows, offset, limit), {
49602
+ total: rows.length,
49603
+ offset,
49604
+ limit,
49605
+ nextCommand: nextCommand(section, opts, offset, limit, rows.length)
49606
+ }));
49607
+ } else {
49608
+ const rows = (data.humans ?? []).filter((human) => includesQuery(human, opts.query));
49609
+ chunks.push(formatServerHumans(pageRows(rows, offset, limit), {
49610
+ total: rows.length,
49611
+ offset,
49612
+ limit,
49613
+ nextCommand: nextCommand(section, opts, offset, limit, rows.length)
49614
+ }));
49615
+ }
49616
+ }
49617
+ writeText(ctx.io, chunks.join("\n"));
49235
49618
  }
49236
49619
  );
49237
49620
  function registerServerInfoCommand(parent, runtimeOptions) {
@@ -49571,6 +49954,100 @@ function registerServerUpdateCommand(parent, runtimeOptions) {
49571
49954
  registerCliCommand(parent, serverUpdateCommand, runtimeOptions);
49572
49955
  }
49573
49956
 
49957
+ // src/commands/user/info.ts
49958
+ init_esm_shims();
49959
+ function parseNonNegativeInt2(raw, name, fallback) {
49960
+ if (raw === void 0) return fallback;
49961
+ if (!/^\d+$/.test(raw)) {
49962
+ throw new CliError({
49963
+ code: "INVALID_ARG",
49964
+ message: `${name} must be a non-negative integer`
49965
+ });
49966
+ }
49967
+ return Number(raw);
49968
+ }
49969
+ function parsePositiveInt3(raw, name, fallback) {
49970
+ const value = parseNonNegativeInt2(raw, name, fallback);
49971
+ if (value <= 0) {
49972
+ throw new CliError({
49973
+ code: "INVALID_ARG",
49974
+ message: `${name} must be greater than 0`
49975
+ });
49976
+ }
49977
+ return value;
49978
+ }
49979
+ function normalizeUserName(target) {
49980
+ const trimmed = target?.trim() ?? "";
49981
+ const name = trimmed.startsWith("@") ? trimmed.slice(1) : trimmed;
49982
+ if (!name) {
49983
+ throw new CliError({
49984
+ code: "INVALID_ARG",
49985
+ message: "user name is required"
49986
+ });
49987
+ }
49988
+ return name;
49989
+ }
49990
+ var userInfoCommand = defineCommand(
49991
+ {
49992
+ name: "info",
49993
+ description: "Show narrow visible facts for a human or agent and its visible channel memberships",
49994
+ arguments: ["<name>"],
49995
+ options: [
49996
+ { flags: "--limit <n>", description: "Maximum visible channels to inspect (default: 50)" },
49997
+ { flags: "--offset <n>", description: "Visible channels to skip before inspection (default: 0)" }
49998
+ ]
49999
+ },
50000
+ async (ctx, target, opts = {}) => {
50001
+ const name = normalizeUserName(target);
50002
+ const limit = parsePositiveInt3(opts.limit, "--limit", 50);
50003
+ const offset = parseNonNegativeInt2(opts.offset, "--offset", 0);
50004
+ const agentContext = ctx.loadAgentContext();
50005
+ const client = ctx.createApiClient(agentContext);
50006
+ const agentApi = createAgentApiSurfaceClient(client);
50007
+ const infoRes = await agentApi.server.info();
50008
+ if (!infoRes.ok) {
50009
+ throw new CliError({
50010
+ code: infoRes.status >= 500 ? "SERVER_5XX" : "INFO_FAILED",
50011
+ message: infoRes.error ?? `HTTP ${infoRes.status}`
50012
+ });
50013
+ }
50014
+ const agent = (infoRes.data?.agents ?? []).find((candidate) => candidate.name === name);
50015
+ const human = (infoRes.data?.humans ?? []).find((candidate) => candidate.name === name);
50016
+ const user = agent ? { kind: "agent", value: agent } : human ? { kind: "human", value: human } : null;
50017
+ if (!user) {
50018
+ throw new CliError({
50019
+ code: "NOT_FOUND",
50020
+ message: `User not found or not visible: @${name}`,
50021
+ suggestedNextAction: "Run `raft server info --agents --query <name>` or `raft server info --humans --query <name>` to inspect visible users."
50022
+ });
50023
+ }
50024
+ const visibleChannels = infoRes.data?.channels ?? [];
50025
+ const inspectedChannels = visibleChannels.slice(offset, offset + limit);
50026
+ const memberships = [];
50027
+ let skippedChannels = 0;
50028
+ for (const channel of inspectedChannels) {
50029
+ const membersRes = await agentApi.channels.members({ channel: `#${channel.name}` });
50030
+ if (!membersRes.ok) {
50031
+ skippedChannels += 1;
50032
+ continue;
50033
+ }
50034
+ const agents = membersRes.data?.agents ?? [];
50035
+ const humans = membersRes.data?.humans ?? [];
50036
+ const found = user.kind === "agent" ? agents.some((candidate) => candidate.name === name) : humans.some((candidate) => candidate.name === name);
50037
+ if (found) memberships.push(channel);
50038
+ }
50039
+ writeText(ctx.io, formatUserInfo(user, memberships, {
50040
+ total: visibleChannels.length,
50041
+ offset,
50042
+ limit,
50043
+ nextCommand: offset + limit < visibleChannels.length ? `raft user info @${name} --offset ${offset + limit} --limit ${limit}` : void 0
50044
+ }, skippedChannels));
50045
+ }
50046
+ );
50047
+ function registerUserInfoCommand(parent, runtimeOptions) {
50048
+ registerCliCommand(parent, userInfoCommand, runtimeOptions);
50049
+ }
50050
+
49574
50051
  // src/commands/knowledge/get.ts
49575
50052
  init_esm_shims();
49576
50053
  function formatKnowledgeStdout(content) {
@@ -49646,6 +50123,91 @@ function registerKnowledgeGetCommand(parent, runtimeOptions) {
49646
50123
  registerCliCommand(parent, knowledgeGetCommand, runtimeOptions);
49647
50124
  }
49648
50125
 
50126
+ // src/commands/knowledge/search.ts
50127
+ init_esm_shims();
50128
+ function formatKnowledgeSearchResults(results) {
50129
+ return results.map((result2, index) => {
50130
+ const firstScreen = result2.firstScreen.trim();
50131
+ const body = firstScreen.split(/\r?\n/).filter(Boolean).map((line) => ` ${line}`).join("\n");
50132
+ return `${index + 1}. ${result2.slug} \u2014 ${result2.title}${body ? `
50133
+ ${body}` : ""}`;
50134
+ }).join("\n\n") + "\n";
50135
+ }
50136
+ function toKnowledgeSearchErrorCode(errorCode2, status) {
50137
+ switch (errorCode2) {
50138
+ case "INVALID_JSON_RESPONSE":
50139
+ case "SCOPE_DENIED":
50140
+ case "knowledge_agent_missing":
50141
+ case "knowledge_internal_error":
50142
+ case "knowledge_not_found":
50143
+ case "knowledge_query_invalid":
50144
+ case "knowledge_reason_invalid":
50145
+ case "knowledge_scope_invalid":
50146
+ case "knowledge_source_invalid":
50147
+ case "knowledge_trace_id_invalid":
50148
+ case "knowledge_turn_id_invalid":
50149
+ case "unsupported_capability":
50150
+ return errorCode2;
50151
+ default:
50152
+ return status >= 500 ? "SERVER_5XX" : "KNOWLEDGE_SEARCH_FAILED";
50153
+ }
50154
+ }
50155
+ var knowledgeSearchCommand = defineCommand(
50156
+ {
50157
+ name: "search",
50158
+ description: "Search Raft Manual for Agents topics from the current server",
50159
+ arguments: ["<keywords>"],
50160
+ options: [
50161
+ {
50162
+ flags: "--scope <scope>",
50163
+ description: "Optional search scope. Currently supports: recipes"
50164
+ },
50165
+ {
50166
+ flags: "--reason <text>",
50167
+ description: "Optional rationale for this search (>=12 chars when provided)"
50168
+ },
50169
+ {
50170
+ flags: "--turn-id <id>",
50171
+ description: "Optional turn id for correlation in the knowledge event"
50172
+ },
50173
+ {
50174
+ flags: "--trace-id <id>",
50175
+ description: "Optional trace id for correlation in the knowledge event"
50176
+ }
50177
+ ],
50178
+ helpAfter: '\nExamples:\n raft manual search "preview before merge" --scope recipes\n raft manual get recipes/technique/preview-env\n'
50179
+ },
50180
+ async (ctx, keywords, opts) => {
50181
+ const agentContext = ctx.loadAgentContext();
50182
+ const client = ctx.createApiClient(agentContext);
50183
+ const res = await createAgentApiSurfaceClient(client).knowledge.search({
50184
+ query: keywords,
50185
+ scope: opts.scope,
50186
+ reason: opts.reason,
50187
+ turn_id: opts.turnId,
50188
+ trace_id: opts.traceId
50189
+ });
50190
+ if (!res.ok) {
50191
+ throw new CliError({
50192
+ code: toKnowledgeSearchErrorCode(res.errorCode, res.status),
50193
+ message: res.error ?? `HTTP ${res.status}`,
50194
+ suggestedNextAction: res.suggestedNextAction ?? (res.errorCode === "knowledge_not_found" ? "Try different keywords, or run `raft manual get index` to browse available topics." : void 0)
50195
+ });
50196
+ }
50197
+ const data = res.data;
50198
+ if (!data || data.ok !== true || !Array.isArray(data.results)) {
50199
+ throw new CliError({
50200
+ code: "KNOWLEDGE_SEARCH_FAILED",
50201
+ message: "Server returned an unexpected response shape"
50202
+ });
50203
+ }
50204
+ writeText(ctx.io, formatKnowledgeSearchResults(data.results));
50205
+ }
50206
+ );
50207
+ function registerKnowledgeSearchCommand(parent, runtimeOptions) {
50208
+ registerCliCommand(parent, knowledgeSearchCommand, runtimeOptions);
50209
+ }
50210
+
49649
50211
  // src/commands/inbox/check.ts
49650
50212
  init_esm_shims();
49651
50213
 
@@ -49707,7 +50269,11 @@ function parseThreadTarget(target) {
49707
50269
  return null;
49708
50270
  }
49709
50271
  function formatUnfollowThreadResult(target) {
49710
- return `Unfollowed ${target}. You can still inspect the thread when its parent conversation is visible, but you will no longer receive ordinary thread delivery unless you follow it again or are mentioned.`;
50272
+ return [
50273
+ `Unfollowed ${target}. Ordinary delivery for this thread has stopped.`,
50274
+ "Still arrives: personal @mentions pierce as single messages \u2014 they do NOT re-follow you.",
50275
+ "Posting in this thread re-follows you automatically."
50276
+ ].join("\n");
49711
50277
  }
49712
50278
  var threadUnfollowCommand = defineCommand(
49713
50279
  {
@@ -50360,6 +50926,168 @@ You can also choose not to send anything.
50360
50926
  `
50361
50927
  });
50362
50928
  }
50929
+ function formatDriveByJoinedToPostTip(target, data) {
50930
+ const attention = data.attention?.driveByJoinedToPost;
50931
+ if (!attention) return "";
50932
+ const muteCommand = attention.muteCommand?.trim() || `raft channel mute "${target}"`;
50933
+ const stillArrives = attention.stillArrives?.[0]?.trim() || "@mentions still reach you, and threads you started stay followed.";
50934
+ return [
50935
+ "Tip: you joined this channel to post this message. If you don't need its ordinary updates:",
50936
+ ` ${muteCommand}`,
50937
+ stillArrives
50938
+ ].join("\n");
50939
+ }
50940
+ function markSendFailureDraftSaved(err, draftSaved) {
50941
+ if (err instanceof CliError) {
50942
+ if (err.draftSaved !== void 0) return err;
50943
+ return new CliError({
50944
+ code: err.code,
50945
+ message: err.message,
50946
+ exitCode: err.exitCode,
50947
+ cause: err.cause,
50948
+ suggestedNextAction: err.suggestedNextAction,
50949
+ draftSaved
50950
+ });
50951
+ }
50952
+ const message = err instanceof Error ? err.message : String(err);
50953
+ return new CliError({
50954
+ code: "INTERNAL_BUG",
50955
+ message: `Unexpected error: ${message}`,
50956
+ cause: err,
50957
+ draftSaved
50958
+ });
50959
+ }
50960
+ async function handleMessageSend(ctx, positionalContent, opts, setFailureDraftSaved) {
50961
+ const target = opts.target?.trim() ?? "";
50962
+ if (!target) {
50963
+ throw cliError("INVALID_ARG", "--target is required");
50964
+ }
50965
+ try {
50966
+ rejectArgContent(positionalContent, opts);
50967
+ } catch (err) {
50968
+ if (err instanceof SendContentError) throw cliError(err.code, err.message, { cause: err });
50969
+ throw err;
50970
+ }
50971
+ try {
50972
+ validateDraftSendFlags(opts);
50973
+ } catch (err) {
50974
+ if (err instanceof SendContentError) throw cliError(err.code, err.message, { cause: err });
50975
+ throw err;
50976
+ }
50977
+ let content;
50978
+ let outgoingContent = "";
50979
+ let outgoingAttachmentIds = [];
50980
+ let previousDraftReholdCount = 0;
50981
+ let seenUpToSeq;
50982
+ if (opts.sendDraft) {
50983
+ content = await resolveOptionalSendContent(ctx.io.stdin ?? process.stdin);
50984
+ try {
50985
+ rejectSendDraftStdin(content, opts.target);
50986
+ } catch (err) {
50987
+ if (err instanceof SendContentError) throw cliError(err.code, err.message, { cause: err });
50988
+ throw err;
50989
+ }
50990
+ } else {
50991
+ try {
50992
+ content = await resolveSendContent(ctx.io.stdin ?? process.stdin);
50993
+ } catch (err) {
50994
+ if (err instanceof SendContentError) throw cliError(err.code, err.message, { cause: err });
50995
+ throw err;
50996
+ }
50997
+ outgoingContent = content;
50998
+ outgoingAttachmentIds = opts.attachmentId && opts.attachmentId.length > 0 ? opts.attachmentId : [];
50999
+ }
51000
+ const agentContext = ctx.loadAgentContext();
51001
+ const client = ctx.createApiClient(agentContext);
51002
+ if (opts.sendDraft) {
51003
+ const savedDraft = getSavedDraft(agentContext.agentId, target);
51004
+ if (!savedDraft) {
51005
+ throw cliError(
51006
+ "SEND_DRAFT_NOT_FOUND",
51007
+ [
51008
+ "No saved draft exists for this target.",
51009
+ "To create or update a draft, send message content normally:",
51010
+ ` raft message send --target "${target}" <<'${MESSAGE_HEREDOC_DELIMITER}'`,
51011
+ " message body",
51012
+ ` ${MESSAGE_HEREDOC_DELIMITER}`
51013
+ ].join("\n")
51014
+ );
51015
+ }
51016
+ outgoingContent = savedDraft.content;
51017
+ outgoingAttachmentIds = savedDraft.attachmentIds;
51018
+ previousDraftReholdCount = savedDraft.reholdCount;
51019
+ seenUpToSeq = savedDraft.seenUpToSeq;
51020
+ setFailureDraftSaved(true);
51021
+ } else {
51022
+ const previousDraft = getSavedDraft(agentContext.agentId, target);
51023
+ previousDraftReholdCount = previousDraft?.reholdCount ?? 0;
51024
+ seenUpToSeq = previousDraft?.seenUpToSeq;
51025
+ }
51026
+ if (seenUpToSeq === void 0) {
51027
+ seenUpToSeq = getConsumedSeq(agentContext.agentId, target);
51028
+ }
51029
+ const body = {
51030
+ target,
51031
+ content: outgoingContent,
51032
+ draftReholdCount: previousDraftReholdCount
51033
+ };
51034
+ if (seenUpToSeq !== void 0) {
51035
+ body.seenUpToSeq = seenUpToSeq;
51036
+ }
51037
+ if (opts.sendDraft) {
51038
+ body.sendDraft = true;
51039
+ if (opts.anyway) body.continueAnyway = true;
51040
+ } else {
51041
+ body.draftReplacedExisting = previousDraftReholdCount > 0;
51042
+ }
51043
+ if (outgoingAttachmentIds.length > 0) {
51044
+ body.attachmentIds = outgoingAttachmentIds;
51045
+ }
51046
+ const agentApi = createAgentApiSurfaceClient(client);
51047
+ const res = await agentApi.messages.send(body);
51048
+ if (!res.ok) {
51049
+ const code = res.status >= 500 ? "SERVER_5XX" : "SEND_FAILED";
51050
+ throw cliError(code, res.error ?? `HTTP ${res.status}`);
51051
+ }
51052
+ const data = res.data;
51053
+ if (!data) {
51054
+ throw cliError("INVALID_JSON_RESPONSE", "Agent API messageSend returned an empty response body");
51055
+ }
51056
+ if (data.state === "held") {
51057
+ if (typeof data.seenUpToSeq === "number" && Number.isFinite(data.seenUpToSeq)) {
51058
+ recordConsumedSeqs(agentContext.agentId, { [target]: data.seenUpToSeq });
51059
+ }
51060
+ setSavedDraft(agentContext.agentId, target, {
51061
+ content: outgoingContent,
51062
+ attachmentIds: outgoingAttachmentIds,
51063
+ savedAt: Date.now(),
51064
+ reholdCount: previousDraftReholdCount + 1,
51065
+ seenUpToSeq: data.seenUpToSeq
51066
+ });
51067
+ writeText(ctx.io, formatHeldSendOutput(target, data));
51068
+ return;
51069
+ }
51070
+ clearSavedDraft(agentContext.agentId, target);
51071
+ const shortId = data.messageId ? data.messageId.slice(0, 8) : null;
51072
+ const replyHint = shortId ? ` (to reply in this message's thread, use target "${target.includes(":") ? target : target + ":" + shortId}")` : "";
51073
+ let unreadSection = "";
51074
+ if (data.recentUnread && data.recentUnread.length > 0) {
51075
+ unreadSection = `
51076
+
51077
+ --- New messages you may have missed ---
51078
+ ${formatMessages(data.recentUnread)}`;
51079
+ }
51080
+ const pendingMentionActions = normalizePendingMentionActions(data);
51081
+ const mentionSection = pendingMentionActions.length > 0 ? `
51082
+
51083
+ ${formatPendingMentionActions(pendingMentionActions, { source: "send" }).trimEnd()}` : "";
51084
+ const driveByTip = formatDriveByJoinedToPostTip(target, data);
51085
+ const driveBySection = driveByTip ? `
51086
+
51087
+ ${driveByTip}` : "";
51088
+ writeText(ctx.io, `Message sent to ${target}. Message ID: ${data.messageId}${replyHint}${driveBySection}${mentionSection}${unreadSection}
51089
+ `);
51090
+ }
50363
51091
  var messageSendCommand = defineCommand(
50364
51092
  {
50365
51093
  name: "send",
@@ -50378,131 +51106,14 @@ var messageSendCommand = defineCommand(
50378
51106
  ]
50379
51107
  },
50380
51108
  async (ctx, positionalContent, opts) => {
50381
- const target = opts.target?.trim() ?? "";
50382
- if (!target) {
50383
- throw cliError("INVALID_ARG", "--target is required");
50384
- }
50385
- try {
50386
- rejectArgContent(positionalContent, opts);
50387
- } catch (err) {
50388
- if (err instanceof SendContentError) throw cliError(err.code, err.message, { cause: err });
50389
- throw err;
50390
- }
51109
+ let failureDraftSaved = false;
50391
51110
  try {
50392
- validateDraftSendFlags(opts);
50393
- } catch (err) {
50394
- if (err instanceof SendContentError) throw cliError(err.code, err.message, { cause: err });
50395
- throw err;
50396
- }
50397
- let content;
50398
- let outgoingContent = "";
50399
- let outgoingAttachmentIds = [];
50400
- let previousDraftReholdCount = 0;
50401
- let seenUpToSeq;
50402
- if (opts.sendDraft) {
50403
- content = await resolveOptionalSendContent(ctx.io.stdin ?? process.stdin);
50404
- try {
50405
- rejectSendDraftStdin(content, opts.target);
50406
- } catch (err) {
50407
- if (err instanceof SendContentError) throw cliError(err.code, err.message, { cause: err });
50408
- throw err;
50409
- }
50410
- } else {
50411
- try {
50412
- content = await resolveSendContent(ctx.io.stdin ?? process.stdin);
50413
- } catch (err) {
50414
- if (err instanceof SendContentError) throw cliError(err.code, err.message, { cause: err });
50415
- throw err;
50416
- }
50417
- outgoingContent = content;
50418
- outgoingAttachmentIds = opts.attachmentId && opts.attachmentId.length > 0 ? opts.attachmentId : [];
50419
- }
50420
- const agentContext = ctx.loadAgentContext();
50421
- const client = ctx.createApiClient(agentContext);
50422
- if (opts.sendDraft) {
50423
- const savedDraft = getSavedDraft(agentContext.agentId, target);
50424
- if (!savedDraft) {
50425
- throw cliError(
50426
- "SEND_DRAFT_NOT_FOUND",
50427
- [
50428
- "No saved draft exists for this target.",
50429
- "To create or update a draft, send message content normally:",
50430
- ` raft message send --target "${target}" <<'${MESSAGE_HEREDOC_DELIMITER}'`,
50431
- " message body",
50432
- ` ${MESSAGE_HEREDOC_DELIMITER}`
50433
- ].join("\n")
50434
- );
50435
- return;
50436
- }
50437
- outgoingContent = savedDraft.content;
50438
- outgoingAttachmentIds = savedDraft.attachmentIds;
50439
- previousDraftReholdCount = savedDraft.reholdCount;
50440
- seenUpToSeq = savedDraft.seenUpToSeq;
50441
- } else {
50442
- const previousDraft = getSavedDraft(agentContext.agentId, target);
50443
- previousDraftReholdCount = previousDraft?.reholdCount ?? 0;
50444
- seenUpToSeq = previousDraft?.seenUpToSeq;
50445
- }
50446
- if (seenUpToSeq === void 0) {
50447
- seenUpToSeq = getConsumedSeq(agentContext.agentId, target);
50448
- }
50449
- const body = {
50450
- target,
50451
- content: outgoingContent,
50452
- draftReholdCount: previousDraftReholdCount
50453
- };
50454
- if (seenUpToSeq !== void 0) {
50455
- body.seenUpToSeq = seenUpToSeq;
50456
- }
50457
- if (opts.sendDraft) {
50458
- body.sendDraft = true;
50459
- if (opts.anyway) body.continueAnyway = true;
50460
- } else {
50461
- body.draftReplacedExisting = previousDraftReholdCount > 0;
50462
- }
50463
- if (outgoingAttachmentIds.length > 0) {
50464
- body.attachmentIds = outgoingAttachmentIds;
50465
- }
50466
- const agentApi = createAgentApiSurfaceClient(client);
50467
- const res = await agentApi.messages.send(body);
50468
- if (!res.ok) {
50469
- const code = res.status >= 500 ? "SERVER_5XX" : "SEND_FAILED";
50470
- throw cliError(code, res.error ?? `HTTP ${res.status}`);
50471
- }
50472
- const data = res.data;
50473
- if (!data) {
50474
- throw cliError("INVALID_JSON_RESPONSE", "Agent API messageSend returned an empty response body");
50475
- }
50476
- if (data.state === "held") {
50477
- if (typeof data.seenUpToSeq === "number" && Number.isFinite(data.seenUpToSeq)) {
50478
- recordConsumedSeqs(agentContext.agentId, { [target]: data.seenUpToSeq });
50479
- }
50480
- setSavedDraft(agentContext.agentId, target, {
50481
- content: outgoingContent,
50482
- attachmentIds: outgoingAttachmentIds,
50483
- savedAt: Date.now(),
50484
- reholdCount: previousDraftReholdCount + 1,
50485
- seenUpToSeq: data.seenUpToSeq
51111
+ await handleMessageSend(ctx, positionalContent, opts, (draftSaved) => {
51112
+ failureDraftSaved = draftSaved;
50486
51113
  });
50487
- writeText(ctx.io, formatHeldSendOutput(target, data));
50488
- return;
50489
- }
50490
- clearSavedDraft(agentContext.agentId, target);
50491
- const shortId = data.messageId ? data.messageId.slice(0, 8) : null;
50492
- const replyHint = shortId ? ` (to reply in this message's thread, use target "${target.includes(":") ? target : target + ":" + shortId}")` : "";
50493
- let unreadSection = "";
50494
- if (data.recentUnread && data.recentUnread.length > 0) {
50495
- unreadSection = `
50496
-
50497
- --- New messages you may have missed ---
50498
- ${formatMessages(data.recentUnread)}`;
51114
+ } catch (err) {
51115
+ throw markSendFailureDraftSaved(err, failureDraftSaved);
50499
51116
  }
50500
- const pendingMentionActions = normalizePendingMentionActions(data);
50501
- const mentionSection = pendingMentionActions.length > 0 ? `
50502
-
50503
- ${formatPendingMentionActions(pendingMentionActions, { source: "send" }).trimEnd()}` : "";
50504
- writeText(ctx.io, `Message sent to ${target}. Message ID: ${data.messageId}${replyHint}${mentionSection}${unreadSection}
50505
- `);
50506
51117
  }
50507
51118
  );
50508
51119
  function registerSendCommand(parent, runtimeOptions = {}) {
@@ -50614,7 +51225,7 @@ function requireTargetAlias(opts) {
50614
51225
  }
50615
51226
 
50616
51227
  // src/commands/message/read.ts
50617
- function parsePositiveInt2(name, raw) {
51228
+ function parsePositiveInt4(name, raw) {
50618
51229
  if (raw === void 0) return void 0;
50619
51230
  const n = Number(raw);
50620
51231
  if (!Number.isFinite(n) || !Number.isInteger(n) || n <= 0) {
@@ -50653,7 +51264,7 @@ function mapReadFailure(res) {
50653
51264
  }
50654
51265
  function validateReadOpts(opts) {
50655
51266
  const channel = requireTargetAlias(opts);
50656
- const limit = parsePositiveInt2("limit", opts.limit);
51267
+ const limit = parsePositiveInt4("limit", opts.limit);
50657
51268
  const before = opts.before?.trim();
50658
51269
  const after = opts.after?.trim();
50659
51270
  return {
@@ -50745,7 +51356,7 @@ function normalizeMemberHandleRef(raw) {
50745
51356
  }
50746
51357
  return handle;
50747
51358
  }
50748
- function parsePositiveInt3(name, raw) {
51359
+ function parsePositiveInt5(name, raw) {
50749
51360
  if (raw === void 0) return void 0;
50750
51361
  const n = Number(raw);
50751
51362
  if (!Number.isFinite(n) || !Number.isInteger(n) || n <= 0) {
@@ -50756,7 +51367,7 @@ function parsePositiveInt3(name, raw) {
50756
51367
  }
50757
51368
  return n;
50758
51369
  }
50759
- function parseNonNegativeInt(name, raw) {
51370
+ function parseNonNegativeInt3(name, raw) {
50760
51371
  if (raw === void 0) return void 0;
50761
51372
  const n = Number(raw);
50762
51373
  if (!Number.isFinite(n) || !Number.isInteger(n) || n < 0) {
@@ -50790,8 +51401,8 @@ function normalizeSearchOpts(opts) {
50790
51401
  message: "--sort relevance requires --query; filter-only search is sorted by recent"
50791
51402
  });
50792
51403
  }
50793
- const limit = parsePositiveInt3("limit", opts.limit);
50794
- const offset = parseNonNegativeInt("offset", opts.offset);
51404
+ const limit = parsePositiveInt5("limit", opts.limit);
51405
+ const offset = parseNonNegativeInt3("offset", opts.offset);
50795
51406
  const sort = opts.sort ?? (query ? void 0 : "recent");
50796
51407
  return {
50797
51408
  ...query ? { query } : {},
@@ -53755,6 +54366,7 @@ registerAgentLoginCommand(agentCmd);
53755
54366
  registerAgentListCommand(agentCmd);
53756
54367
  registerAgentBridgeCommand(agentCmd);
53757
54368
  var channelCmd = program2.command("channel").description("Channel membership and attention operations");
54369
+ registerChannelInfoCommand(channelCmd);
53758
54370
  registerChannelMembersCommand(channelCmd);
53759
54371
  registerChannelCreateCommand(channelCmd);
53760
54372
  registerChannelUpdateCommand(channelCmd);
@@ -53769,10 +54381,14 @@ registerThreadUnfollowCommand(threadCmd);
53769
54381
  var serverCmd = program2.command("server").description("Server / workspace introspection");
53770
54382
  registerServerInfoCommand(serverCmd);
53771
54383
  registerServerUpdateCommand(serverCmd);
54384
+ var userCmd = program2.command("user").description("User and agent introspection");
54385
+ registerUserInfoCommand(userCmd);
53772
54386
  var manualCmd = program2.command("manual").description("Raft Manual for Agents retrieval (canonical operating topics)");
53773
54387
  registerKnowledgeGetCommand(manualCmd);
54388
+ registerKnowledgeSearchCommand(manualCmd);
53774
54389
  var knowledgeCmd = program2.command("knowledge").description("Legacy alias for `raft manual`");
53775
54390
  registerKnowledgeGetCommand(knowledgeCmd);
54391
+ registerKnowledgeSearchCommand(knowledgeCmd);
53776
54392
  var inboxCmd = program2.command("inbox").description("Inbox target summary operations");
53777
54393
  registerInboxCheckCommand(inboxCmd);
53778
54394
  var messageCmd = program2.command("message").description("Message operations");