@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.
@@ -27788,6 +27788,7 @@ var CliError = class extends Error {
27788
27788
  code;
27789
27789
  exitCode;
27790
27790
  suggestedNextAction;
27791
+ draftSaved;
27791
27792
  constructor(options) {
27792
27793
  super(options.message);
27793
27794
  this.name = "CliError";
@@ -27795,6 +27796,7 @@ var CliError = class extends Error {
27795
27796
  this.exitCode = options.exitCode ?? 1;
27796
27797
  this.cause = options.cause;
27797
27798
  this.suggestedNextAction = options.suggestedNextAction;
27799
+ this.draftSaved = options.draftSaved;
27798
27800
  }
27799
27801
  };
27800
27802
  var CliExit = class extends Error {
@@ -27821,7 +27823,8 @@ function cliError(code, message, options = {}) {
27821
27823
  message,
27822
27824
  exitCode: options.exitCode,
27823
27825
  cause: options.cause,
27824
- suggestedNextAction: options.suggestedNextAction
27826
+ suggestedNextAction: options.suggestedNextAction,
27827
+ draftSaved: options.draftSaved
27825
27828
  });
27826
27829
  }
27827
27830
  function toCliError(err) {
@@ -28615,6 +28618,7 @@ var TRACE_B0_FIELD_DEFINITIONS = defineTraceFields([
28615
28618
  { key: "error_class", fieldClass: "query_axis", placement: "span_or_event", valueKind: "closed_enum", enumBinding: "pending_457" },
28616
28619
  { key: "query_name", fieldClass: "query_axis", placement: "span_or_event", valueKind: "closed_enum", enumBinding: "query_registry" },
28617
28620
  { key: "phase", fieldClass: "query_axis", placement: "span_or_event", valueKind: "closed_enum", enumBinding: "pending_457" },
28621
+ { key: "eligibility_subcheck", fieldClass: "query_axis", placement: "event", valueKind: "closed_enum", enumBinding: "pending_457" },
28618
28622
  { key: "hint_source", fieldClass: "family_query_axis", placement: "event", valueKind: "closed_enum", scope: "family:activity" },
28619
28623
  { key: "resolved_activity", fieldClass: "family_query_axis", placement: "event", valueKind: "closed_enum", scope: "family:activity" },
28620
28624
  { key: "previous_activity", fieldClass: "family_query_axis", placement: "event", valueKind: "closed_enum", scope: "family:activity" },
@@ -42500,6 +42504,24 @@ var agentApiKnowledgeGetResponseSchema = passthroughObject({
42500
42504
  contentType: external_exports.string(),
42501
42505
  content: external_exports.string()
42502
42506
  });
42507
+ var agentApiKnowledgeSearchQuerySchema = passthroughObject({
42508
+ query: external_exports.string().trim().min(1),
42509
+ scope: optionalStringSchema,
42510
+ reason: optionalStringSchema,
42511
+ turn_id: optionalStringSchema,
42512
+ trace_id: optionalStringSchema
42513
+ });
42514
+ var agentApiKnowledgeSearchResultSchema = passthroughObject({
42515
+ slug: external_exports.string(),
42516
+ title: external_exports.string(),
42517
+ firstScreen: external_exports.string()
42518
+ });
42519
+ var agentApiKnowledgeSearchResponseSchema = passthroughObject({
42520
+ ok: external_exports.literal(true),
42521
+ query: external_exports.string(),
42522
+ scope: external_exports.string().nullable(),
42523
+ results: external_exports.array(agentApiKnowledgeSearchResultSchema)
42524
+ });
42503
42525
  var agentApiMessageSearchQuerySchema = passthroughObject({
42504
42526
  q: optionalStringSchema,
42505
42527
  channel: optionalStringSchema,
@@ -42951,7 +42973,14 @@ var agentApiSendSentResponseSchema = passthroughObject({
42951
42973
  messageId: external_exports.string(),
42952
42974
  messageSeq: optionalNumberSchema,
42953
42975
  recentUnread: external_exports.array(agentApiMessageEnvelopeSchema).optional(),
42954
- pendingMentionActions: external_exports.array(agentApiMessageEnvelopeSchema).optional()
42976
+ pendingMentionActions: external_exports.array(agentApiMessageEnvelopeSchema).optional(),
42977
+ attention: passthroughObject({
42978
+ driveByJoinedToPost: passthroughObject({
42979
+ reason: optionalStringSchema,
42980
+ muteCommand: optionalStringSchema,
42981
+ stillArrives: optionalStringArraySchema
42982
+ }).optional()
42983
+ }).optional()
42955
42984
  });
42956
42985
  var agentApiSendResponseSchema = external_exports.discriminatedUnion("state", [
42957
42986
  agentApiSendSentResponseSchema,
@@ -43140,6 +43169,16 @@ var agentApiContract = {
43140
43169
  request: { query: agentApiKnowledgeGetQuerySchema },
43141
43170
  response: { body: agentApiKnowledgeGetResponseSchema }
43142
43171
  }),
43172
+ knowledgeSearch: route({
43173
+ key: "knowledgeSearch",
43174
+ method: "GET",
43175
+ path: "/knowledge/search",
43176
+ client: { resource: "knowledge", method: "search" },
43177
+ capability: "knowledge",
43178
+ description: "Search Slock Manual for Agents topics from the current server.",
43179
+ request: { query: agentApiKnowledgeSearchQuerySchema },
43180
+ response: { body: agentApiKnowledgeSearchResponseSchema }
43181
+ }),
43143
43182
  messageSend: route({
43144
43183
  key: "messageSend",
43145
43184
  method: "POST",
@@ -44543,6 +44582,9 @@ var SERVER_CAPABILITY_MATRIX = {
44543
44582
  joinPublicChannels: true
44544
44583
  })
44545
44584
  };
44585
+ init_esm_shims();
44586
+ init_esm_shims();
44587
+ init_esm_shims();
44546
44588
  var BUILTIN_RUNTIME_PROVIDER_ENV_KEYS = PI_BUILTIN_PROVIDER_API_KEY_ENV_KEYS_GENERATED;
44547
44589
  var BUILTIN_RUNTIME_PROVIDERS = Object.entries(BUILTIN_RUNTIME_PROVIDER_ENV_KEYS).map(([id, envKey]) => ({ id, envKey }));
44548
44590
  var PI_BUILTIN_PROVIDER_ENV_KEYS = {
@@ -44982,7 +45024,8 @@ function createAgentApiSurfaceClient(client) {
44982
45024
  read: (query) => requestClientAsApiResponse(agentApi.history.read(query))
44983
45025
  },
44984
45026
  knowledge: {
44985
- get: (query) => requestClientAsApiResponse(agentApi.knowledge.get(query))
45027
+ get: (query) => requestClientAsApiResponse(agentApi.knowledge.get(query)),
45028
+ search: (query) => requestClientAsApiResponse(agentApi.knowledge.search(query))
44986
45029
  },
44987
45030
  tasks: {
44988
45031
  list: (query) => requestClientAsApiResponse(agentApi.tasks.list(query)),
@@ -45713,6 +45756,10 @@ function renderError(io, err) {
45713
45756
  `);
45714
45757
  io.stderr.write(`Code: ${err.code}
45715
45758
  `);
45759
+ if (err.draftSaved !== void 0) {
45760
+ io.stderr.write(`Draft saved: ${err.draftSaved ? "yes" : "no"}
45761
+ `);
45762
+ }
45716
45763
  if (err.suggestedNextAction) {
45717
45764
  io.stderr.write(`Next action: ${err.suggestedNextAction}
45718
45765
  `);
@@ -48041,6 +48088,156 @@ function formatServerInfo(data) {
48041
48088
  }
48042
48089
  return text;
48043
48090
  }
48091
+ function channelRef(name) {
48092
+ return name.startsWith("#") ? name : `#${name}`;
48093
+ }
48094
+ function channelVisibility(channel) {
48095
+ const type = channel.type?.trim();
48096
+ return type === "private" ? "private" : "public";
48097
+ }
48098
+ function channelMuted(channel) {
48099
+ if (typeof channel.muted === "boolean") return channel.muted;
48100
+ if (typeof channel.activityMuted === "boolean") return channel.activityMuted;
48101
+ return void 0;
48102
+ }
48103
+ function channelStatus(channel) {
48104
+ const parts = [
48105
+ channelVisibility(channel),
48106
+ channel.joined ? "joined" : "not joined"
48107
+ ];
48108
+ const muted = channelMuted(channel);
48109
+ if (muted !== void 0) parts.push(muted ? "muted" : "not muted");
48110
+ if (typeof channel.archived === "boolean") parts.push(channel.archived ? "archived" : "not archived");
48111
+ return parts.join(", ");
48112
+ }
48113
+ function formatPageFooter(page) {
48114
+ if (!page) return "";
48115
+ const start = page.total === 0 ? 0 : Math.min(page.offset + 1, page.total);
48116
+ const end = Math.min(page.offset + page.limit, page.total);
48117
+ const lines = [`
48118
+ Showing ${start}-${end} of ${page.total}.`];
48119
+ if (page.nextCommand && end < page.total) {
48120
+ lines.push(`More: ${page.nextCommand}`);
48121
+ }
48122
+ return `${lines.join("\n")}
48123
+ `;
48124
+ }
48125
+ function formatChannelInfo(channel, memberCounts) {
48126
+ const lines = ["## Channel", ""];
48127
+ lines.push(`Channel: ${channelRef(channel.name)}`);
48128
+ if (channel.id) lines.push(`ID: ${channel.id}`);
48129
+ lines.push(`Visibility: ${channelVisibility(channel)}`);
48130
+ lines.push(`Joined: ${channel.joined ? "yes" : "no"}`);
48131
+ const muted = channelMuted(channel);
48132
+ if (muted !== void 0) lines.push(`Muted: ${muted ? "yes" : "no"}`);
48133
+ if (typeof channel.archived === "boolean") lines.push(`Archived: ${channel.archived ? "yes" : "no"}`);
48134
+ lines.push(`Description: ${channel.description?.trim() || "(none)"}`);
48135
+ if (memberCounts) {
48136
+ const agents = memberCounts.agents ?? 0;
48137
+ const humans = memberCounts.humans ?? 0;
48138
+ lines.push(`Members: ${agents + humans} (${agents} agents, ${humans} humans)`);
48139
+ }
48140
+ lines.push("");
48141
+ lines.push(`More: raft channel members "${channelRef(channel.name)}"`);
48142
+ return `${lines.join("\n")}
48143
+ `;
48144
+ }
48145
+ function formatServerSummary(data) {
48146
+ const channels = data.channels ?? [];
48147
+ const agents = data.agents ?? [];
48148
+ const humans = data.humans ?? [];
48149
+ const joined = channels.filter((channel) => channel.joined).length;
48150
+ const lines = [
48151
+ "## Server",
48152
+ "",
48153
+ `Channels: ${channels.length} visible (${joined} joined)`,
48154
+ `Agents: ${agents.length}`,
48155
+ `Humans: ${humans.length}`,
48156
+ "",
48157
+ "Narrow queries:",
48158
+ "- raft server info --channels",
48159
+ "- raft server info --agents",
48160
+ "- raft server info --humans",
48161
+ "- raft channel info <name>",
48162
+ "- raft user info <name>",
48163
+ "",
48164
+ "Full dump: raft server info --full"
48165
+ ];
48166
+ return `${lines.join("\n")}
48167
+ `;
48168
+ }
48169
+ function formatServerChannels(channels, page) {
48170
+ const lines = [
48171
+ "## Server Channels",
48172
+ "",
48173
+ "Private channels are shown only when this agent is a member. Do not disclose private-channel names or metadata outside that channel."
48174
+ ];
48175
+ if (channels.length === 0) {
48176
+ lines.push("(none)");
48177
+ } else {
48178
+ for (const channel of channels) {
48179
+ const description = channel.description?.trim();
48180
+ lines.push(description ? `${channelRef(channel.name)} [${channelStatus(channel)}] \u2014 ${description}` : `${channelRef(channel.name)} [${channelStatus(channel)}]`);
48181
+ }
48182
+ }
48183
+ return `${lines.join("\n")}${formatPageFooter(page)}`;
48184
+ }
48185
+ function formatServerAgents(agents, page) {
48186
+ const lines = [
48187
+ "## Server Agents",
48188
+ "",
48189
+ "Role labels show server-level owner/admin authority; no role label means ordinary member."
48190
+ ];
48191
+ if (agents.length === 0) {
48192
+ lines.push("(none)");
48193
+ } else {
48194
+ for (const agent of agents) {
48195
+ const role = roleLabel(agent.role);
48196
+ const status = agentStatusLabel(agent);
48197
+ lines.push(agent.description ? `@${agent.name} (${status})${role} \u2014 ${agent.description}` : `@${agent.name} (${status})${role}`);
48198
+ }
48199
+ }
48200
+ return `${lines.join("\n")}${formatPageFooter(page)}`;
48201
+ }
48202
+ function formatServerHumans(humans, page) {
48203
+ const lines = [
48204
+ "## Server Humans",
48205
+ "",
48206
+ "Role labels show server-level owner/admin authority; no role label means ordinary member."
48207
+ ];
48208
+ if (humans.length === 0) {
48209
+ lines.push("(none)");
48210
+ } else {
48211
+ for (const human of humans) {
48212
+ const role = roleLabel(human.role);
48213
+ lines.push(human.description ? `@${human.name}${role} \u2014 ${human.description}` : `@${human.name}${role}`);
48214
+ }
48215
+ }
48216
+ return `${lines.join("\n")}${formatPageFooter(page)}`;
48217
+ }
48218
+ function formatUserInfo(user, memberships, page, skippedChannels = 0) {
48219
+ const name = user.value.name;
48220
+ const role = roleLabel(user.value.role);
48221
+ const lines = ["## User", ""];
48222
+ lines.push(`User: @${name}`);
48223
+ lines.push(`Kind: ${user.kind}`);
48224
+ if (user.kind === "agent") lines.push(`Status: ${agentStatusLabel(user.value)}`);
48225
+ if (role) lines.push(`Role: ${role.slice(2, -1)}`);
48226
+ if (user.value.description) lines.push(`Description: ${user.value.description}`);
48227
+ lines.push("");
48228
+ lines.push("### Visible Channel Memberships");
48229
+ if (memberships.length === 0) {
48230
+ lines.push("(none found in inspected visible channels)");
48231
+ } else {
48232
+ for (const channel of memberships) {
48233
+ lines.push(`${channelRef(channel.name)} [${channelStatus(channel)}]`);
48234
+ }
48235
+ }
48236
+ if (skippedChannels > 0) {
48237
+ lines.push(`Skipped ${skippedChannels} visible channel roster checks because the server rejected them.`);
48238
+ }
48239
+ return `${lines.join("\n")}${formatPageFooter(page)}`;
48240
+ }
48044
48241
  function formatChannelMembers(data) {
48045
48242
  let text = "## Channel Members\n\n";
48046
48243
  const ref = data.channel?.ref ?? "(unknown)";
@@ -48108,65 +48305,6 @@ function registerChannelMembersCommand(parent, runtimeOptions) {
48108
48305
  registerCliCommand(parent, channelMembersCommand, runtimeOptions);
48109
48306
  }
48110
48307
  init_esm_shims();
48111
- function normalizeChannelName(raw) {
48112
- return (raw ?? "").trim().replace(/^#/, "");
48113
- }
48114
- function formatCreateChannelResult(channel) {
48115
- const target = `#${channel.name}`;
48116
- const visibility = channel.type === "private" ? "private" : "public";
48117
- return `Created ${target} (${visibility}). You are joined and can send messages there.`;
48118
- }
48119
- var channelCreateCommand = defineCommand(
48120
- {
48121
- name: "create",
48122
- description: "Create a public or private channel when this agent has server admin authority",
48123
- options: [
48124
- {
48125
- flags: "--name <name>",
48126
- description: "Channel name, with or without a leading '#'"
48127
- },
48128
- {
48129
- flags: "--description <description>",
48130
- description: "Optional channel description"
48131
- },
48132
- {
48133
- flags: "--private",
48134
- description: "Create a private channel instead of a public channel"
48135
- }
48136
- ]
48137
- },
48138
- async (ctx, opts) => {
48139
- const name = normalizeChannelName(opts.name);
48140
- if (!name) {
48141
- throw new CliError({
48142
- code: "INVALID_ARG",
48143
- message: "--name is required"
48144
- });
48145
- }
48146
- const agentContext = ctx.loadAgentContext();
48147
- const client = ctx.createApiClient(agentContext);
48148
- const res = await client.request(
48149
- "POST",
48150
- `/internal/agent/${encodeURIComponent(agentContext.agentId)}/channels`,
48151
- {
48152
- name,
48153
- description: opts.description,
48154
- visibility: opts.private ? "private" : "public"
48155
- }
48156
- );
48157
- if (!res.ok || !res.data) {
48158
- throw new CliError({
48159
- code: res.status >= 500 ? "SERVER_5XX" : "CREATE_FAILED",
48160
- message: res.error ?? `HTTP ${res.status}`
48161
- });
48162
- }
48163
- writeText(ctx.io, formatCreateChannelResult(res.data) + "\n");
48164
- }
48165
- );
48166
- function registerChannelCreateCommand(parent, runtimeOptions) {
48167
- registerCliCommand(parent, channelCreateCommand, runtimeOptions);
48168
- }
48169
- init_esm_shims();
48170
48308
  init_esm_shims();
48171
48309
  function parseRegularChannelTarget(target) {
48172
48310
  if (!target.startsWith("#")) return null;
@@ -48236,6 +48374,118 @@ var channelLeaveCommand = defineCommand(
48236
48374
  function registerChannelLeaveCommand(parent, runtimeOptions) {
48237
48375
  registerCliCommand(parent, channelLeaveCommand, runtimeOptions);
48238
48376
  }
48377
+ function normalizeChannelInfoTarget(target) {
48378
+ const input = target?.trim() ?? "";
48379
+ const normalized = input.startsWith("#") ? input : `#${input}`;
48380
+ const name = parseRegularChannelTarget(normalized);
48381
+ if (!name) {
48382
+ throw new CliError({
48383
+ code: "INVALID_TARGET",
48384
+ message: "Target must be a regular channel name, e.g. '#engineering' or 'engineering'. DMs and thread targets are not supported."
48385
+ });
48386
+ }
48387
+ return { input: normalized, name };
48388
+ }
48389
+ var channelInfoCommand = defineCommand(
48390
+ {
48391
+ name: "info",
48392
+ description: "Show narrow channel facts: existence, joined state, description, and member count when visible",
48393
+ arguments: ["<target>"]
48394
+ },
48395
+ async (ctx, target) => {
48396
+ const { input, name } = normalizeChannelInfoTarget(target);
48397
+ const agentContext = ctx.loadAgentContext();
48398
+ const client = ctx.createApiClient(agentContext);
48399
+ const agentApi = createAgentApiSurfaceClient(client);
48400
+ const infoRes = await agentApi.server.info();
48401
+ if (!infoRes.ok) {
48402
+ throw new CliError({
48403
+ code: infoRes.status >= 500 ? "SERVER_5XX" : "INFO_FAILED",
48404
+ message: infoRes.error ?? `HTTP ${infoRes.status}`
48405
+ });
48406
+ }
48407
+ const channel = (infoRes.data?.channels ?? []).find((candidate) => candidate.name === name);
48408
+ if (!channel) {
48409
+ throw new CliError({
48410
+ code: "NOT_FOUND",
48411
+ message: `Channel not found or not visible: ${input}`,
48412
+ suggestedNextAction: "Run `raft server info --channels --query <name>` to inspect visible channels, or ask a channel member to add you if this is private."
48413
+ });
48414
+ }
48415
+ let memberCounts = null;
48416
+ const membersRes = await agentApi.channels.members({ channel: `#${name}` });
48417
+ if (membersRes.ok) {
48418
+ memberCounts = {
48419
+ agents: membersRes.data?.agents?.length ?? 0,
48420
+ humans: membersRes.data?.humans?.length ?? 0
48421
+ };
48422
+ }
48423
+ writeText(ctx.io, formatChannelInfo(channel, memberCounts));
48424
+ }
48425
+ );
48426
+ function registerChannelInfoCommand(parent, runtimeOptions) {
48427
+ registerCliCommand(parent, channelInfoCommand, runtimeOptions);
48428
+ }
48429
+ init_esm_shims();
48430
+ function normalizeChannelName(raw) {
48431
+ return (raw ?? "").trim().replace(/^#/, "");
48432
+ }
48433
+ function formatCreateChannelResult(channel) {
48434
+ const target = `#${channel.name}`;
48435
+ const visibility = channel.type === "private" ? "private" : "public";
48436
+ return `Created ${target} (${visibility}). You are joined and can send messages there.`;
48437
+ }
48438
+ var channelCreateCommand = defineCommand(
48439
+ {
48440
+ name: "create",
48441
+ description: "Create a public or private channel when this agent has server admin authority",
48442
+ options: [
48443
+ {
48444
+ flags: "--name <name>",
48445
+ description: "Channel name, with or without a leading '#'"
48446
+ },
48447
+ {
48448
+ flags: "--description <description>",
48449
+ description: "Optional channel description"
48450
+ },
48451
+ {
48452
+ flags: "--private",
48453
+ description: "Create a private channel instead of a public channel"
48454
+ }
48455
+ ]
48456
+ },
48457
+ async (ctx, opts) => {
48458
+ const name = normalizeChannelName(opts.name);
48459
+ if (!name) {
48460
+ throw new CliError({
48461
+ code: "INVALID_ARG",
48462
+ message: "--name is required"
48463
+ });
48464
+ }
48465
+ const agentContext = ctx.loadAgentContext();
48466
+ const client = ctx.createApiClient(agentContext);
48467
+ const res = await client.request(
48468
+ "POST",
48469
+ `/internal/agent/${encodeURIComponent(agentContext.agentId)}/channels`,
48470
+ {
48471
+ name,
48472
+ description: opts.description,
48473
+ visibility: opts.private ? "private" : "public"
48474
+ }
48475
+ );
48476
+ if (!res.ok || !res.data) {
48477
+ throw new CliError({
48478
+ code: res.status >= 500 ? "SERVER_5XX" : "CREATE_FAILED",
48479
+ message: res.error ?? `HTTP ${res.status}`
48480
+ });
48481
+ }
48482
+ writeText(ctx.io, formatCreateChannelResult(res.data) + "\n");
48483
+ }
48484
+ );
48485
+ function registerChannelCreateCommand(parent, runtimeOptions) {
48486
+ registerCliCommand(parent, channelCreateCommand, runtimeOptions);
48487
+ }
48488
+ init_esm_shims();
48239
48489
  function normalizeChannelName2(raw) {
48240
48490
  return (raw ?? "").trim().replace(/^#/, "");
48241
48491
  }
@@ -48502,7 +48752,12 @@ function registerChannelRemoveMemberCommand(parent, runtimeOptions) {
48502
48752
  }
48503
48753
  init_esm_shims();
48504
48754
  function formatJoinChannelResult(target) {
48505
- return `Joined ${target}. You can now send messages there and receive ordinary channel delivery.`;
48755
+ return [
48756
+ `Joined ${target}. You can now send messages there and receive ordinary channel delivery.`,
48757
+ "Still arrives:",
48758
+ "- Personal @mentions still reach you even if you later mute ordinary channel updates.",
48759
+ "- Threads you started or follow stay followed even if you later mute this channel."
48760
+ ].join("\n");
48506
48761
  }
48507
48762
  function formatAlreadyJoined(target) {
48508
48763
  return `Already joined ${target}.`;
@@ -48654,12 +48909,90 @@ function registerChannelUnmuteCommand(parent, runtimeOptions) {
48654
48909
  registerCliCommand(parent, channelUnmuteCommand, runtimeOptions);
48655
48910
  }
48656
48911
  init_esm_shims();
48912
+ function parseNonNegativeInt(raw, name, fallback) {
48913
+ if (raw === void 0) return fallback;
48914
+ if (!/^\d+$/.test(raw)) {
48915
+ throw new CliError({
48916
+ code: "INVALID_ARG",
48917
+ message: `${name} must be a non-negative integer`
48918
+ });
48919
+ }
48920
+ return Number(raw);
48921
+ }
48922
+ function parsePositiveInt2(raw, name, fallback) {
48923
+ const value = parseNonNegativeInt(raw, name, fallback);
48924
+ if (value <= 0) {
48925
+ throw new CliError({
48926
+ code: "INVALID_ARG",
48927
+ message: `${name} must be greater than 0`
48928
+ });
48929
+ }
48930
+ return value;
48931
+ }
48932
+ function selectedSections(opts) {
48933
+ const sections = [];
48934
+ if (opts.channels) sections.push("channels");
48935
+ if (opts.agents) sections.push("agents");
48936
+ if (opts.humans) sections.push("humans");
48937
+ return sections;
48938
+ }
48939
+ function hasListModifier(opts) {
48940
+ return Boolean(opts.joined || opts.query !== void 0 || opts.limit !== void 0 || opts.offset !== void 0);
48941
+ }
48942
+ function includesQuery(row, query) {
48943
+ const needle = query?.trim().toLowerCase();
48944
+ if (!needle) return true;
48945
+ const values = Object.values(row).filter((value) => typeof value === "string").map((value) => value.toLowerCase());
48946
+ return values.some((value) => value.includes(needle));
48947
+ }
48948
+ function pageRows(rows, offset, limit) {
48949
+ return rows.slice(offset, offset + limit);
48950
+ }
48951
+ function nextCommand(section, opts, offset, limit, total) {
48952
+ const nextOffset = offset + limit;
48953
+ if (nextOffset >= total) return void 0;
48954
+ const parts = ["raft server info", `--${section}`, `--offset ${nextOffset}`, `--limit ${limit}`];
48955
+ if (opts.query?.trim()) parts.push(`--query ${JSON.stringify(opts.query.trim())}`);
48956
+ if (opts.joined) parts.push("--joined");
48957
+ return parts.join(" ");
48958
+ }
48657
48959
  var serverInfoCommand = defineCommand(
48658
48960
  {
48659
48961
  name: "info",
48660
- description: "List channels, agents, and humans on the current server"
48962
+ description: "Show bounded server facts; use --full for the legacy full inventory",
48963
+ options: [
48964
+ { flags: "--full", description: "Print the full channels, agents, humans, and runtime inventory" },
48965
+ { flags: "--channels", description: "List visible channels only" },
48966
+ { flags: "--agents", description: "List agents only" },
48967
+ { flags: "--humans", description: "List humans only" },
48968
+ { flags: "--joined", description: "With --channels, show only joined channels" },
48969
+ { flags: "--query <text>", description: "Filter the selected list by visible text" },
48970
+ { flags: "--limit <n>", description: "Maximum rows for list output (default: 50)" },
48971
+ { flags: "--offset <n>", description: "Rows to skip for list output (default: 0)" }
48972
+ ]
48661
48973
  },
48662
- async (ctx) => {
48974
+ async (ctx, opts = {}) => {
48975
+ const sections = selectedSections(opts);
48976
+ if (opts.full && sections.length > 0) {
48977
+ throw new CliError({
48978
+ code: "INVALID_ARG",
48979
+ message: "--full cannot be combined with --channels, --agents, or --humans"
48980
+ });
48981
+ }
48982
+ if (sections.length === 0 && hasListModifier(opts)) {
48983
+ throw new CliError({
48984
+ code: "INVALID_ARG",
48985
+ message: "--query, --limit, --offset, and --joined require --channels, --agents, or --humans"
48986
+ });
48987
+ }
48988
+ if (opts.joined && sections.some((section) => section !== "channels")) {
48989
+ throw new CliError({
48990
+ code: "INVALID_ARG",
48991
+ message: "--joined can only be used with --channels"
48992
+ });
48993
+ }
48994
+ const limit = parsePositiveInt2(opts.limit, "--limit", 50);
48995
+ const offset = parseNonNegativeInt(opts.offset, "--offset", 0);
48663
48996
  const agentContext = ctx.loadAgentContext();
48664
48997
  const client = ctx.createApiClient(agentContext);
48665
48998
  const res = await createAgentApiSurfaceClient(client).server.info();
@@ -48670,14 +49003,56 @@ var serverInfoCommand = defineCommand(
48670
49003
  message: res.error ?? `HTTP ${res.status}`
48671
49004
  });
48672
49005
  }
48673
- const data = res.data;
48674
- if (data?.runtimeContext) {
48675
- data.runtimeContext = {
48676
- ...data.runtimeContext,
48677
- workspacePath: data.runtimeContext.workspacePath ?? ctx.env.SLOCK_CURRENT_WORKSPACE_PATH ?? null
48678
- };
49006
+ if (!res.data) {
49007
+ throw new CliError({
49008
+ code: "INVALID_JSON_RESPONSE",
49009
+ message: "Agent API serverInfo returned an empty response body"
49010
+ });
49011
+ }
49012
+ const data = {
49013
+ ...res.data,
49014
+ runtimeContext: {
49015
+ ...res.data.runtimeContext,
49016
+ workspacePath: res.data.runtimeContext.workspacePath ?? ctx.env.SLOCK_CURRENT_WORKSPACE_PATH ?? null
49017
+ }
49018
+ };
49019
+ if (opts.full) {
49020
+ writeText(ctx.io, formatServerInfo(data));
49021
+ return;
48679
49022
  }
48680
- writeText(ctx.io, formatServerInfo(data));
49023
+ if (sections.length === 0) {
49024
+ writeText(ctx.io, formatServerSummary(data));
49025
+ return;
49026
+ }
49027
+ const chunks = [];
49028
+ for (const section of sections) {
49029
+ if (section === "channels") {
49030
+ const rows = (data.channels ?? []).filter((channel) => !opts.joined || channel.joined).filter((channel) => includesQuery(channel, opts.query));
49031
+ chunks.push(formatServerChannels(pageRows(rows, offset, limit), {
49032
+ total: rows.length,
49033
+ offset,
49034
+ limit,
49035
+ nextCommand: nextCommand(section, opts, offset, limit, rows.length)
49036
+ }));
49037
+ } else if (section === "agents") {
49038
+ const rows = (data.agents ?? []).filter((agent) => includesQuery(agent, opts.query));
49039
+ chunks.push(formatServerAgents(pageRows(rows, offset, limit), {
49040
+ total: rows.length,
49041
+ offset,
49042
+ limit,
49043
+ nextCommand: nextCommand(section, opts, offset, limit, rows.length)
49044
+ }));
49045
+ } else {
49046
+ const rows = (data.humans ?? []).filter((human) => includesQuery(human, opts.query));
49047
+ chunks.push(formatServerHumans(pageRows(rows, offset, limit), {
49048
+ total: rows.length,
49049
+ offset,
49050
+ limit,
49051
+ nextCommand: nextCommand(section, opts, offset, limit, rows.length)
49052
+ }));
49053
+ }
49054
+ }
49055
+ writeText(ctx.io, chunks.join("\n"));
48681
49056
  }
48682
49057
  );
48683
49058
  function registerServerInfoCommand(parent, runtimeOptions) {
@@ -49005,6 +49380,98 @@ function registerServerUpdateCommand(parent, runtimeOptions) {
49005
49380
  registerCliCommand(parent, serverUpdateCommand, runtimeOptions);
49006
49381
  }
49007
49382
  init_esm_shims();
49383
+ function parseNonNegativeInt2(raw, name, fallback) {
49384
+ if (raw === void 0) return fallback;
49385
+ if (!/^\d+$/.test(raw)) {
49386
+ throw new CliError({
49387
+ code: "INVALID_ARG",
49388
+ message: `${name} must be a non-negative integer`
49389
+ });
49390
+ }
49391
+ return Number(raw);
49392
+ }
49393
+ function parsePositiveInt3(raw, name, fallback) {
49394
+ const value = parseNonNegativeInt2(raw, name, fallback);
49395
+ if (value <= 0) {
49396
+ throw new CliError({
49397
+ code: "INVALID_ARG",
49398
+ message: `${name} must be greater than 0`
49399
+ });
49400
+ }
49401
+ return value;
49402
+ }
49403
+ function normalizeUserName(target) {
49404
+ const trimmed = target?.trim() ?? "";
49405
+ const name = trimmed.startsWith("@") ? trimmed.slice(1) : trimmed;
49406
+ if (!name) {
49407
+ throw new CliError({
49408
+ code: "INVALID_ARG",
49409
+ message: "user name is required"
49410
+ });
49411
+ }
49412
+ return name;
49413
+ }
49414
+ var userInfoCommand = defineCommand(
49415
+ {
49416
+ name: "info",
49417
+ description: "Show narrow visible facts for a human or agent and its visible channel memberships",
49418
+ arguments: ["<name>"],
49419
+ options: [
49420
+ { flags: "--limit <n>", description: "Maximum visible channels to inspect (default: 50)" },
49421
+ { flags: "--offset <n>", description: "Visible channels to skip before inspection (default: 0)" }
49422
+ ]
49423
+ },
49424
+ async (ctx, target, opts = {}) => {
49425
+ const name = normalizeUserName(target);
49426
+ const limit = parsePositiveInt3(opts.limit, "--limit", 50);
49427
+ const offset = parseNonNegativeInt2(opts.offset, "--offset", 0);
49428
+ const agentContext = ctx.loadAgentContext();
49429
+ const client = ctx.createApiClient(agentContext);
49430
+ const agentApi = createAgentApiSurfaceClient(client);
49431
+ const infoRes = await agentApi.server.info();
49432
+ if (!infoRes.ok) {
49433
+ throw new CliError({
49434
+ code: infoRes.status >= 500 ? "SERVER_5XX" : "INFO_FAILED",
49435
+ message: infoRes.error ?? `HTTP ${infoRes.status}`
49436
+ });
49437
+ }
49438
+ const agent = (infoRes.data?.agents ?? []).find((candidate) => candidate.name === name);
49439
+ const human = (infoRes.data?.humans ?? []).find((candidate) => candidate.name === name);
49440
+ const user = agent ? { kind: "agent", value: agent } : human ? { kind: "human", value: human } : null;
49441
+ if (!user) {
49442
+ throw new CliError({
49443
+ code: "NOT_FOUND",
49444
+ message: `User not found or not visible: @${name}`,
49445
+ suggestedNextAction: "Run `raft server info --agents --query <name>` or `raft server info --humans --query <name>` to inspect visible users."
49446
+ });
49447
+ }
49448
+ const visibleChannels = infoRes.data?.channels ?? [];
49449
+ const inspectedChannels = visibleChannels.slice(offset, offset + limit);
49450
+ const memberships = [];
49451
+ let skippedChannels = 0;
49452
+ for (const channel of inspectedChannels) {
49453
+ const membersRes = await agentApi.channels.members({ channel: `#${channel.name}` });
49454
+ if (!membersRes.ok) {
49455
+ skippedChannels += 1;
49456
+ continue;
49457
+ }
49458
+ const agents = membersRes.data?.agents ?? [];
49459
+ const humans = membersRes.data?.humans ?? [];
49460
+ const found = user.kind === "agent" ? agents.some((candidate) => candidate.name === name) : humans.some((candidate) => candidate.name === name);
49461
+ if (found) memberships.push(channel);
49462
+ }
49463
+ writeText(ctx.io, formatUserInfo(user, memberships, {
49464
+ total: visibleChannels.length,
49465
+ offset,
49466
+ limit,
49467
+ nextCommand: offset + limit < visibleChannels.length ? `raft user info @${name} --offset ${offset + limit} --limit ${limit}` : void 0
49468
+ }, skippedChannels));
49469
+ }
49470
+ );
49471
+ function registerUserInfoCommand(parent, runtimeOptions) {
49472
+ registerCliCommand(parent, userInfoCommand, runtimeOptions);
49473
+ }
49474
+ init_esm_shims();
49008
49475
  function formatKnowledgeStdout(content) {
49009
49476
  return content.endsWith("\n") ? content : `${content}
49010
49477
  `;
@@ -49078,6 +49545,89 @@ function registerKnowledgeGetCommand(parent, runtimeOptions) {
49078
49545
  registerCliCommand(parent, knowledgeGetCommand, runtimeOptions);
49079
49546
  }
49080
49547
  init_esm_shims();
49548
+ function formatKnowledgeSearchResults(results) {
49549
+ return results.map((result2, index) => {
49550
+ const firstScreen = result2.firstScreen.trim();
49551
+ const body = firstScreen.split(/\r?\n/).filter(Boolean).map((line) => ` ${line}`).join("\n");
49552
+ return `${index + 1}. ${result2.slug} \u2014 ${result2.title}${body ? `
49553
+ ${body}` : ""}`;
49554
+ }).join("\n\n") + "\n";
49555
+ }
49556
+ function toKnowledgeSearchErrorCode(errorCode2, status) {
49557
+ switch (errorCode2) {
49558
+ case "INVALID_JSON_RESPONSE":
49559
+ case "SCOPE_DENIED":
49560
+ case "knowledge_agent_missing":
49561
+ case "knowledge_internal_error":
49562
+ case "knowledge_not_found":
49563
+ case "knowledge_query_invalid":
49564
+ case "knowledge_reason_invalid":
49565
+ case "knowledge_scope_invalid":
49566
+ case "knowledge_source_invalid":
49567
+ case "knowledge_trace_id_invalid":
49568
+ case "knowledge_turn_id_invalid":
49569
+ case "unsupported_capability":
49570
+ return errorCode2;
49571
+ default:
49572
+ return status >= 500 ? "SERVER_5XX" : "KNOWLEDGE_SEARCH_FAILED";
49573
+ }
49574
+ }
49575
+ var knowledgeSearchCommand = defineCommand(
49576
+ {
49577
+ name: "search",
49578
+ description: "Search Raft Manual for Agents topics from the current server",
49579
+ arguments: ["<keywords>"],
49580
+ options: [
49581
+ {
49582
+ flags: "--scope <scope>",
49583
+ description: "Optional search scope. Currently supports: recipes"
49584
+ },
49585
+ {
49586
+ flags: "--reason <text>",
49587
+ description: "Optional rationale for this search (>=12 chars when provided)"
49588
+ },
49589
+ {
49590
+ flags: "--turn-id <id>",
49591
+ description: "Optional turn id for correlation in the knowledge event"
49592
+ },
49593
+ {
49594
+ flags: "--trace-id <id>",
49595
+ description: "Optional trace id for correlation in the knowledge event"
49596
+ }
49597
+ ],
49598
+ helpAfter: '\nExamples:\n raft manual search "preview before merge" --scope recipes\n raft manual get recipes/technique/preview-env\n'
49599
+ },
49600
+ async (ctx, keywords, opts) => {
49601
+ const agentContext = ctx.loadAgentContext();
49602
+ const client = ctx.createApiClient(agentContext);
49603
+ const res = await createAgentApiSurfaceClient(client).knowledge.search({
49604
+ query: keywords,
49605
+ scope: opts.scope,
49606
+ reason: opts.reason,
49607
+ turn_id: opts.turnId,
49608
+ trace_id: opts.traceId
49609
+ });
49610
+ if (!res.ok) {
49611
+ throw new CliError({
49612
+ code: toKnowledgeSearchErrorCode(res.errorCode, res.status),
49613
+ message: res.error ?? `HTTP ${res.status}`,
49614
+ suggestedNextAction: res.suggestedNextAction ?? (res.errorCode === "knowledge_not_found" ? "Try different keywords, or run `raft manual get index` to browse available topics." : void 0)
49615
+ });
49616
+ }
49617
+ const data = res.data;
49618
+ if (!data || data.ok !== true || !Array.isArray(data.results)) {
49619
+ throw new CliError({
49620
+ code: "KNOWLEDGE_SEARCH_FAILED",
49621
+ message: "Server returned an unexpected response shape"
49622
+ });
49623
+ }
49624
+ writeText(ctx.io, formatKnowledgeSearchResults(data.results));
49625
+ }
49626
+ );
49627
+ function registerKnowledgeSearchCommand(parent, runtimeOptions) {
49628
+ registerCliCommand(parent, knowledgeSearchCommand, runtimeOptions);
49629
+ }
49630
+ init_esm_shims();
49081
49631
  init_esm_shims();
49082
49632
  var inboxCheckCommand = defineCommand(
49083
49633
  {
@@ -49131,7 +49681,11 @@ function parseThreadTarget(target) {
49131
49681
  return null;
49132
49682
  }
49133
49683
  function formatUnfollowThreadResult(target) {
49134
- 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.`;
49684
+ return [
49685
+ `Unfollowed ${target}. Ordinary delivery for this thread has stopped.`,
49686
+ "Still arrives: personal @mentions pierce as single messages \u2014 they do NOT re-follow you.",
49687
+ "Posting in this thread re-follows you automatically."
49688
+ ].join("\n");
49135
49689
  }
49136
49690
  var threadUnfollowCommand = defineCommand(
49137
49691
  {
@@ -49762,6 +50316,168 @@ You can also choose not to send anything.
49762
50316
  `
49763
50317
  });
49764
50318
  }
50319
+ function formatDriveByJoinedToPostTip(target, data) {
50320
+ const attention = data.attention?.driveByJoinedToPost;
50321
+ if (!attention) return "";
50322
+ const muteCommand = attention.muteCommand?.trim() || `raft channel mute "${target}"`;
50323
+ const stillArrives = attention.stillArrives?.[0]?.trim() || "@mentions still reach you, and threads you started stay followed.";
50324
+ return [
50325
+ "Tip: you joined this channel to post this message. If you don't need its ordinary updates:",
50326
+ ` ${muteCommand}`,
50327
+ stillArrives
50328
+ ].join("\n");
50329
+ }
50330
+ function markSendFailureDraftSaved(err, draftSaved) {
50331
+ if (err instanceof CliError) {
50332
+ if (err.draftSaved !== void 0) return err;
50333
+ return new CliError({
50334
+ code: err.code,
50335
+ message: err.message,
50336
+ exitCode: err.exitCode,
50337
+ cause: err.cause,
50338
+ suggestedNextAction: err.suggestedNextAction,
50339
+ draftSaved
50340
+ });
50341
+ }
50342
+ const message = err instanceof Error ? err.message : String(err);
50343
+ return new CliError({
50344
+ code: "INTERNAL_BUG",
50345
+ message: `Unexpected error: ${message}`,
50346
+ cause: err,
50347
+ draftSaved
50348
+ });
50349
+ }
50350
+ async function handleMessageSend(ctx, positionalContent, opts, setFailureDraftSaved) {
50351
+ const target = opts.target?.trim() ?? "";
50352
+ if (!target) {
50353
+ throw cliError("INVALID_ARG", "--target is required");
50354
+ }
50355
+ try {
50356
+ rejectArgContent(positionalContent, opts);
50357
+ } catch (err) {
50358
+ if (err instanceof SendContentError) throw cliError(err.code, err.message, { cause: err });
50359
+ throw err;
50360
+ }
50361
+ try {
50362
+ validateDraftSendFlags(opts);
50363
+ } catch (err) {
50364
+ if (err instanceof SendContentError) throw cliError(err.code, err.message, { cause: err });
50365
+ throw err;
50366
+ }
50367
+ let content;
50368
+ let outgoingContent = "";
50369
+ let outgoingAttachmentIds = [];
50370
+ let previousDraftReholdCount = 0;
50371
+ let seenUpToSeq;
50372
+ if (opts.sendDraft) {
50373
+ content = await resolveOptionalSendContent(ctx.io.stdin ?? process.stdin);
50374
+ try {
50375
+ rejectSendDraftStdin(content, opts.target);
50376
+ } catch (err) {
50377
+ if (err instanceof SendContentError) throw cliError(err.code, err.message, { cause: err });
50378
+ throw err;
50379
+ }
50380
+ } else {
50381
+ try {
50382
+ content = await resolveSendContent(ctx.io.stdin ?? process.stdin);
50383
+ } catch (err) {
50384
+ if (err instanceof SendContentError) throw cliError(err.code, err.message, { cause: err });
50385
+ throw err;
50386
+ }
50387
+ outgoingContent = content;
50388
+ outgoingAttachmentIds = opts.attachmentId && opts.attachmentId.length > 0 ? opts.attachmentId : [];
50389
+ }
50390
+ const agentContext = ctx.loadAgentContext();
50391
+ const client = ctx.createApiClient(agentContext);
50392
+ if (opts.sendDraft) {
50393
+ const savedDraft = getSavedDraft(agentContext.agentId, target);
50394
+ if (!savedDraft) {
50395
+ throw cliError(
50396
+ "SEND_DRAFT_NOT_FOUND",
50397
+ [
50398
+ "No saved draft exists for this target.",
50399
+ "To create or update a draft, send message content normally:",
50400
+ ` raft message send --target "${target}" <<'${MESSAGE_HEREDOC_DELIMITER}'`,
50401
+ " message body",
50402
+ ` ${MESSAGE_HEREDOC_DELIMITER}`
50403
+ ].join("\n")
50404
+ );
50405
+ }
50406
+ outgoingContent = savedDraft.content;
50407
+ outgoingAttachmentIds = savedDraft.attachmentIds;
50408
+ previousDraftReholdCount = savedDraft.reholdCount;
50409
+ seenUpToSeq = savedDraft.seenUpToSeq;
50410
+ setFailureDraftSaved(true);
50411
+ } else {
50412
+ const previousDraft = getSavedDraft(agentContext.agentId, target);
50413
+ previousDraftReholdCount = previousDraft?.reholdCount ?? 0;
50414
+ seenUpToSeq = previousDraft?.seenUpToSeq;
50415
+ }
50416
+ if (seenUpToSeq === void 0) {
50417
+ seenUpToSeq = getConsumedSeq(agentContext.agentId, target);
50418
+ }
50419
+ const body = {
50420
+ target,
50421
+ content: outgoingContent,
50422
+ draftReholdCount: previousDraftReholdCount
50423
+ };
50424
+ if (seenUpToSeq !== void 0) {
50425
+ body.seenUpToSeq = seenUpToSeq;
50426
+ }
50427
+ if (opts.sendDraft) {
50428
+ body.sendDraft = true;
50429
+ if (opts.anyway) body.continueAnyway = true;
50430
+ } else {
50431
+ body.draftReplacedExisting = previousDraftReholdCount > 0;
50432
+ }
50433
+ if (outgoingAttachmentIds.length > 0) {
50434
+ body.attachmentIds = outgoingAttachmentIds;
50435
+ }
50436
+ const agentApi = createAgentApiSurfaceClient(client);
50437
+ const res = await agentApi.messages.send(body);
50438
+ if (!res.ok) {
50439
+ const code = res.status >= 500 ? "SERVER_5XX" : "SEND_FAILED";
50440
+ throw cliError(code, res.error ?? `HTTP ${res.status}`);
50441
+ }
50442
+ const data = res.data;
50443
+ if (!data) {
50444
+ throw cliError("INVALID_JSON_RESPONSE", "Agent API messageSend returned an empty response body");
50445
+ }
50446
+ if (data.state === "held") {
50447
+ if (typeof data.seenUpToSeq === "number" && Number.isFinite(data.seenUpToSeq)) {
50448
+ recordConsumedSeqs(agentContext.agentId, { [target]: data.seenUpToSeq });
50449
+ }
50450
+ setSavedDraft(agentContext.agentId, target, {
50451
+ content: outgoingContent,
50452
+ attachmentIds: outgoingAttachmentIds,
50453
+ savedAt: Date.now(),
50454
+ reholdCount: previousDraftReholdCount + 1,
50455
+ seenUpToSeq: data.seenUpToSeq
50456
+ });
50457
+ writeText(ctx.io, formatHeldSendOutput(target, data));
50458
+ return;
50459
+ }
50460
+ clearSavedDraft(agentContext.agentId, target);
50461
+ const shortId = data.messageId ? data.messageId.slice(0, 8) : null;
50462
+ const replyHint = shortId ? ` (to reply in this message's thread, use target "${target.includes(":") ? target : target + ":" + shortId}")` : "";
50463
+ let unreadSection = "";
50464
+ if (data.recentUnread && data.recentUnread.length > 0) {
50465
+ unreadSection = `
50466
+
50467
+ --- New messages you may have missed ---
50468
+ ${formatMessages(data.recentUnread)}`;
50469
+ }
50470
+ const pendingMentionActions = normalizePendingMentionActions(data);
50471
+ const mentionSection = pendingMentionActions.length > 0 ? `
50472
+
50473
+ ${formatPendingMentionActions(pendingMentionActions, { source: "send" }).trimEnd()}` : "";
50474
+ const driveByTip = formatDriveByJoinedToPostTip(target, data);
50475
+ const driveBySection = driveByTip ? `
50476
+
50477
+ ${driveByTip}` : "";
50478
+ writeText(ctx.io, `Message sent to ${target}. Message ID: ${data.messageId}${replyHint}${driveBySection}${mentionSection}${unreadSection}
50479
+ `);
50480
+ }
49765
50481
  var messageSendCommand = defineCommand(
49766
50482
  {
49767
50483
  name: "send",
@@ -49780,131 +50496,14 @@ var messageSendCommand = defineCommand(
49780
50496
  ]
49781
50497
  },
49782
50498
  async (ctx, positionalContent, opts) => {
49783
- const target = opts.target?.trim() ?? "";
49784
- if (!target) {
49785
- throw cliError("INVALID_ARG", "--target is required");
49786
- }
50499
+ let failureDraftSaved = false;
49787
50500
  try {
49788
- rejectArgContent(positionalContent, opts);
49789
- } catch (err) {
49790
- if (err instanceof SendContentError) throw cliError(err.code, err.message, { cause: err });
49791
- throw err;
49792
- }
49793
- try {
49794
- validateDraftSendFlags(opts);
49795
- } catch (err) {
49796
- if (err instanceof SendContentError) throw cliError(err.code, err.message, { cause: err });
49797
- throw err;
49798
- }
49799
- let content;
49800
- let outgoingContent = "";
49801
- let outgoingAttachmentIds = [];
49802
- let previousDraftReholdCount = 0;
49803
- let seenUpToSeq;
49804
- if (opts.sendDraft) {
49805
- content = await resolveOptionalSendContent(ctx.io.stdin ?? process.stdin);
49806
- try {
49807
- rejectSendDraftStdin(content, opts.target);
49808
- } catch (err) {
49809
- if (err instanceof SendContentError) throw cliError(err.code, err.message, { cause: err });
49810
- throw err;
49811
- }
49812
- } else {
49813
- try {
49814
- content = await resolveSendContent(ctx.io.stdin ?? process.stdin);
49815
- } catch (err) {
49816
- if (err instanceof SendContentError) throw cliError(err.code, err.message, { cause: err });
49817
- throw err;
49818
- }
49819
- outgoingContent = content;
49820
- outgoingAttachmentIds = opts.attachmentId && opts.attachmentId.length > 0 ? opts.attachmentId : [];
49821
- }
49822
- const agentContext = ctx.loadAgentContext();
49823
- const client = ctx.createApiClient(agentContext);
49824
- if (opts.sendDraft) {
49825
- const savedDraft = getSavedDraft(agentContext.agentId, target);
49826
- if (!savedDraft) {
49827
- throw cliError(
49828
- "SEND_DRAFT_NOT_FOUND",
49829
- [
49830
- "No saved draft exists for this target.",
49831
- "To create or update a draft, send message content normally:",
49832
- ` raft message send --target "${target}" <<'${MESSAGE_HEREDOC_DELIMITER}'`,
49833
- " message body",
49834
- ` ${MESSAGE_HEREDOC_DELIMITER}`
49835
- ].join("\n")
49836
- );
49837
- return;
49838
- }
49839
- outgoingContent = savedDraft.content;
49840
- outgoingAttachmentIds = savedDraft.attachmentIds;
49841
- previousDraftReholdCount = savedDraft.reholdCount;
49842
- seenUpToSeq = savedDraft.seenUpToSeq;
49843
- } else {
49844
- const previousDraft = getSavedDraft(agentContext.agentId, target);
49845
- previousDraftReholdCount = previousDraft?.reholdCount ?? 0;
49846
- seenUpToSeq = previousDraft?.seenUpToSeq;
49847
- }
49848
- if (seenUpToSeq === void 0) {
49849
- seenUpToSeq = getConsumedSeq(agentContext.agentId, target);
49850
- }
49851
- const body = {
49852
- target,
49853
- content: outgoingContent,
49854
- draftReholdCount: previousDraftReholdCount
49855
- };
49856
- if (seenUpToSeq !== void 0) {
49857
- body.seenUpToSeq = seenUpToSeq;
49858
- }
49859
- if (opts.sendDraft) {
49860
- body.sendDraft = true;
49861
- if (opts.anyway) body.continueAnyway = true;
49862
- } else {
49863
- body.draftReplacedExisting = previousDraftReholdCount > 0;
49864
- }
49865
- if (outgoingAttachmentIds.length > 0) {
49866
- body.attachmentIds = outgoingAttachmentIds;
49867
- }
49868
- const agentApi = createAgentApiSurfaceClient(client);
49869
- const res = await agentApi.messages.send(body);
49870
- if (!res.ok) {
49871
- const code = res.status >= 500 ? "SERVER_5XX" : "SEND_FAILED";
49872
- throw cliError(code, res.error ?? `HTTP ${res.status}`);
49873
- }
49874
- const data = res.data;
49875
- if (!data) {
49876
- throw cliError("INVALID_JSON_RESPONSE", "Agent API messageSend returned an empty response body");
49877
- }
49878
- if (data.state === "held") {
49879
- if (typeof data.seenUpToSeq === "number" && Number.isFinite(data.seenUpToSeq)) {
49880
- recordConsumedSeqs(agentContext.agentId, { [target]: data.seenUpToSeq });
49881
- }
49882
- setSavedDraft(agentContext.agentId, target, {
49883
- content: outgoingContent,
49884
- attachmentIds: outgoingAttachmentIds,
49885
- savedAt: Date.now(),
49886
- reholdCount: previousDraftReholdCount + 1,
49887
- seenUpToSeq: data.seenUpToSeq
50501
+ await handleMessageSend(ctx, positionalContent, opts, (draftSaved) => {
50502
+ failureDraftSaved = draftSaved;
49888
50503
  });
49889
- writeText(ctx.io, formatHeldSendOutput(target, data));
49890
- return;
49891
- }
49892
- clearSavedDraft(agentContext.agentId, target);
49893
- const shortId = data.messageId ? data.messageId.slice(0, 8) : null;
49894
- const replyHint = shortId ? ` (to reply in this message's thread, use target "${target.includes(":") ? target : target + ":" + shortId}")` : "";
49895
- let unreadSection = "";
49896
- if (data.recentUnread && data.recentUnread.length > 0) {
49897
- unreadSection = `
49898
-
49899
- --- New messages you may have missed ---
49900
- ${formatMessages(data.recentUnread)}`;
50504
+ } catch (err) {
50505
+ throw markSendFailureDraftSaved(err, failureDraftSaved);
49901
50506
  }
49902
- const pendingMentionActions = normalizePendingMentionActions(data);
49903
- const mentionSection = pendingMentionActions.length > 0 ? `
49904
-
49905
- ${formatPendingMentionActions(pendingMentionActions, { source: "send" }).trimEnd()}` : "";
49906
- writeText(ctx.io, `Message sent to ${target}. Message ID: ${data.messageId}${replyHint}${mentionSection}${unreadSection}
49907
- `);
49908
50507
  }
49909
50508
  );
49910
50509
  function registerSendCommand(parent, runtimeOptions = {}) {
@@ -50004,7 +50603,7 @@ function requireTargetAlias(opts) {
50004
50603
  }
50005
50604
  return target;
50006
50605
  }
50007
- function parsePositiveInt2(name, raw) {
50606
+ function parsePositiveInt4(name, raw) {
50008
50607
  if (raw === void 0) return void 0;
50009
50608
  const n = Number(raw);
50010
50609
  if (!Number.isFinite(n) || !Number.isInteger(n) || n <= 0) {
@@ -50043,7 +50642,7 @@ function mapReadFailure(res) {
50043
50642
  }
50044
50643
  function validateReadOpts(opts) {
50045
50644
  const channel = requireTargetAlias(opts);
50046
- const limit = parsePositiveInt2("limit", opts.limit);
50645
+ const limit = parsePositiveInt4("limit", opts.limit);
50047
50646
  const before = opts.before?.trim();
50048
50647
  const after = opts.after?.trim();
50049
50648
  return {
@@ -50133,7 +50732,7 @@ function normalizeMemberHandleRef(raw) {
50133
50732
  }
50134
50733
  return handle;
50135
50734
  }
50136
- function parsePositiveInt3(name, raw) {
50735
+ function parsePositiveInt5(name, raw) {
50137
50736
  if (raw === void 0) return void 0;
50138
50737
  const n = Number(raw);
50139
50738
  if (!Number.isFinite(n) || !Number.isInteger(n) || n <= 0) {
@@ -50144,7 +50743,7 @@ function parsePositiveInt3(name, raw) {
50144
50743
  }
50145
50744
  return n;
50146
50745
  }
50147
- function parseNonNegativeInt(name, raw) {
50746
+ function parseNonNegativeInt3(name, raw) {
50148
50747
  if (raw === void 0) return void 0;
50149
50748
  const n = Number(raw);
50150
50749
  if (!Number.isFinite(n) || !Number.isInteger(n) || n < 0) {
@@ -50178,8 +50777,8 @@ function normalizeSearchOpts(opts) {
50178
50777
  message: "--sort relevance requires --query; filter-only search is sorted by recent"
50179
50778
  });
50180
50779
  }
50181
- const limit = parsePositiveInt3("limit", opts.limit);
50182
- const offset = parseNonNegativeInt("offset", opts.offset);
50780
+ const limit = parsePositiveInt5("limit", opts.limit);
50781
+ const offset = parseNonNegativeInt3("offset", opts.offset);
50183
50782
  const sort = opts.sort ?? (query ? void 0 : "recent");
50184
50783
  return {
50185
50784
  ...query ? { query } : {},
@@ -53051,6 +53650,7 @@ registerAgentLoginCommand(agentCmd);
53051
53650
  registerAgentListCommand(agentCmd);
53052
53651
  registerAgentBridgeCommand(agentCmd);
53053
53652
  var channelCmd = program2.command("channel").description("Channel membership and attention operations");
53653
+ registerChannelInfoCommand(channelCmd);
53054
53654
  registerChannelMembersCommand(channelCmd);
53055
53655
  registerChannelCreateCommand(channelCmd);
53056
53656
  registerChannelUpdateCommand(channelCmd);
@@ -53065,10 +53665,14 @@ registerThreadUnfollowCommand(threadCmd);
53065
53665
  var serverCmd = program2.command("server").description("Server / workspace introspection");
53066
53666
  registerServerInfoCommand(serverCmd);
53067
53667
  registerServerUpdateCommand(serverCmd);
53668
+ var userCmd = program2.command("user").description("User and agent introspection");
53669
+ registerUserInfoCommand(userCmd);
53068
53670
  var manualCmd = program2.command("manual").description("Raft Manual for Agents retrieval (canonical operating topics)");
53069
53671
  registerKnowledgeGetCommand(manualCmd);
53672
+ registerKnowledgeSearchCommand(manualCmd);
53070
53673
  var knowledgeCmd = program2.command("knowledge").description("Legacy alias for `raft manual`");
53071
53674
  registerKnowledgeGetCommand(knowledgeCmd);
53675
+ registerKnowledgeSearchCommand(knowledgeCmd);
53072
53676
  var inboxCmd = program2.command("inbox").description("Inbox target summary operations");
53073
53677
  registerInboxCheckCommand(inboxCmd);
53074
53678
  var messageCmd = program2.command("message").description("Message operations");