@botiverse/raft-daemon 0.70.3 → 0.71.1

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" },
@@ -42903,6 +42907,13 @@ function validateActionCardAction(action) {
42903
42907
 
42904
42908
  // ../shared/src/agentApiContract.ts
42905
42909
  init_esm_shims();
42910
+
42911
+ // ../shared/src/attentionDependencyOracle.ts
42912
+ init_esm_shims();
42913
+ var ATTENTION_HINT_SCHEMA = "attention-dependency-hint.v1";
42914
+ var ATTENTION_HINT_DEFAULT_WINDOW_MS = 7 * 24 * 60 * 60 * 1e3;
42915
+
42916
+ // ../shared/src/agentApiContract.ts
42906
42917
  var AGENT_API_BASE_PATH = "/internal/agent-api";
42907
42918
  var optionalStringSchema = external_exports.string().trim().optional();
42908
42919
  var optionalStringArraySchema = external_exports.array(external_exports.string().trim().min(1)).optional();
@@ -42944,6 +42955,24 @@ var agentApiKnowledgeGetResponseSchema = passthroughObject({
42944
42955
  contentType: external_exports.string(),
42945
42956
  content: external_exports.string()
42946
42957
  });
42958
+ var agentApiKnowledgeSearchQuerySchema = passthroughObject({
42959
+ query: external_exports.string().trim().min(1),
42960
+ scope: optionalStringSchema,
42961
+ reason: optionalStringSchema,
42962
+ turn_id: optionalStringSchema,
42963
+ trace_id: optionalStringSchema
42964
+ });
42965
+ var agentApiKnowledgeSearchResultSchema = passthroughObject({
42966
+ slug: external_exports.string(),
42967
+ title: external_exports.string(),
42968
+ firstScreen: external_exports.string()
42969
+ });
42970
+ var agentApiKnowledgeSearchResponseSchema = passthroughObject({
42971
+ ok: external_exports.literal(true),
42972
+ query: external_exports.string(),
42973
+ scope: external_exports.string().nullable(),
42974
+ results: external_exports.array(agentApiKnowledgeSearchResultSchema)
42975
+ });
42947
42976
  var agentApiMessageSearchQuerySchema = passthroughObject({
42948
42977
  q: optionalStringSchema,
42949
42978
  channel: optionalStringSchema,
@@ -43395,7 +43424,14 @@ var agentApiSendSentResponseSchema = passthroughObject({
43395
43424
  messageId: external_exports.string(),
43396
43425
  messageSeq: optionalNumberSchema,
43397
43426
  recentUnread: external_exports.array(agentApiMessageEnvelopeSchema).optional(),
43398
- pendingMentionActions: external_exports.array(agentApiMessageEnvelopeSchema).optional()
43427
+ pendingMentionActions: external_exports.array(agentApiMessageEnvelopeSchema).optional(),
43428
+ attention: passthroughObject({
43429
+ driveByJoinedToPost: passthroughObject({
43430
+ reason: optionalStringSchema,
43431
+ muteCommand: optionalStringSchema,
43432
+ stillArrives: optionalStringArraySchema
43433
+ }).optional()
43434
+ }).optional()
43399
43435
  });
43400
43436
  var agentApiSendResponseSchema = external_exports.discriminatedUnion("state", [
43401
43437
  agentApiSendSentResponseSchema,
@@ -43404,8 +43440,17 @@ var agentApiSendResponseSchema = external_exports.discriminatedUnion("state", [
43404
43440
  var agentApiMessageResolveResponseSchema = passthroughObject({
43405
43441
  message: agentApiMessageEnvelopeSchema
43406
43442
  });
43443
+ var agentApiChannelAttentionSchema = passthroughObject({
43444
+ state: optionalStringSchema,
43445
+ ordinaryActivity: optionalStringSchema,
43446
+ stillArrives: optionalStringArraySchema,
43447
+ threadBoundary: optionalStringSchema,
43448
+ manageCommand: optionalStringSchema,
43449
+ manageApi: optionalStringSchema
43450
+ });
43407
43451
  var agentApiOkResponseSchema = passthroughObject({
43408
- ok: external_exports.literal(true)
43452
+ ok: external_exports.literal(true),
43453
+ attention: agentApiChannelAttentionSchema.optional()
43409
43454
  });
43410
43455
  var agentApiSearchResultSchema = passthroughObject({
43411
43456
  id: external_exports.string(),
@@ -43462,6 +43507,16 @@ var agentApiChannelMuteResponseSchema = passthroughObject({
43462
43507
  catchUp: optionalStringSchema
43463
43508
  }).optional()
43464
43509
  });
43510
+ var agentApiChannelMuteBodySchema = passthroughObject({
43511
+ attentionHintAccepted: passthroughObject({
43512
+ schema: external_exports.literal(ATTENTION_HINT_SCHEMA),
43513
+ trigger: external_exports.enum(["M2", "M3"]),
43514
+ scope: external_exports.string().trim().min(1),
43515
+ suggested_command: optionalStringSchema,
43516
+ copy_version: external_exports.string().trim().min(1),
43517
+ epoch_ms: external_exports.number().int().nonnegative()
43518
+ }).optional()
43519
+ });
43465
43520
  var agentApiTaskClaimResultSchema = passthroughObject({
43466
43521
  taskNumber: external_exports.number().int().positive().optional(),
43467
43522
  messageId: optionalStringSchema,
@@ -43584,6 +43639,16 @@ var agentApiContract = {
43584
43639
  request: { query: agentApiKnowledgeGetQuerySchema },
43585
43640
  response: { body: agentApiKnowledgeGetResponseSchema }
43586
43641
  }),
43642
+ knowledgeSearch: route({
43643
+ key: "knowledgeSearch",
43644
+ method: "GET",
43645
+ path: "/knowledge/search",
43646
+ client: { resource: "knowledge", method: "search" },
43647
+ capability: "knowledge",
43648
+ description: "Search Slock Manual for Agents topics from the current server.",
43649
+ request: { query: agentApiKnowledgeSearchQuerySchema },
43650
+ response: { body: agentApiKnowledgeSearchResponseSchema }
43651
+ }),
43587
43652
  messageSend: route({
43588
43653
  key: "messageSend",
43589
43654
  method: "POST",
@@ -43661,7 +43726,7 @@ var agentApiContract = {
43661
43726
  client: { resource: "channels", method: "mute" },
43662
43727
  capability: "channels",
43663
43728
  description: "Mute ordinary activity delivery for a visible regular channel as the bound agent credential.",
43664
- request: { params: agentApiChannelMembershipParamsSchema },
43729
+ request: { params: agentApiChannelMembershipParamsSchema, body: agentApiChannelMuteBodySchema },
43665
43730
  response: { body: agentApiChannelMuteResponseSchema }
43666
43731
  }),
43667
43732
  channelUnmute: route({
@@ -44313,6 +44378,20 @@ var optionalQueryIntSchema = external_exports.union([external_exports.number().i
44313
44378
  var nullableNumberSchema2 = external_exports.number().finite().nullable();
44314
44379
  var passthroughObject2 = (shape) => external_exports.object(shape).passthrough();
44315
44380
  var daemonApiInboxFlagSchema = external_exports.enum(["mention", "thread", "dm", "task"]);
44381
+ var daemonApiAttentionHintSchema = passthroughObject2({
44382
+ schema: external_exports.literal(ATTENTION_HINT_SCHEMA),
44383
+ trigger: external_exports.enum(["M2", "M3"]),
44384
+ scope: external_exports.string().trim().min(1),
44385
+ suggested_command: external_exports.string().trim().min(1),
44386
+ copy: external_exports.string().trim().min(1),
44387
+ copy_version: external_exports.literal("attention-hint-copy-v1"),
44388
+ epoch_ms: external_exports.number().int().nonnegative(),
44389
+ thresholds: passthroughObject2({
44390
+ K: optionalNonNegativeIntSchema,
44391
+ k: optionalNonNegativeIntSchema,
44392
+ window_ms: external_exports.number().int().positive()
44393
+ })
44394
+ });
44316
44395
  var daemonApiInboxTargetRowSchema = passthroughObject2({
44317
44396
  target: external_exports.string().trim().min(1),
44318
44397
  channelId: optionalStringSchema2,
@@ -44323,8 +44402,9 @@ var daemonApiInboxTargetRowSchema = passthroughObject2({
44323
44402
  latestMsgId: optionalStringSchema2,
44324
44403
  latestSeq: optionalNonNegativeIntSchema,
44325
44404
  latestSenderName: optionalStringSchema2,
44326
- latestSenderType: external_exports.enum(["human", "agent", "system"]).optional(),
44327
- flags: external_exports.array(daemonApiInboxFlagSchema)
44405
+ latestSenderType: external_exports.enum(["human", "agent", "system", "third_party_app"]).optional(),
44406
+ flags: external_exports.array(daemonApiInboxFlagSchema),
44407
+ attentionHint: daemonApiAttentionHintSchema.optional()
44328
44408
  });
44329
44409
  var daemonApiInboxCheckResponseSchema = passthroughObject2({
44330
44410
  rows: external_exports.array(daemonApiInboxTargetRowSchema).optional()
@@ -44347,6 +44427,7 @@ var daemonApiWakeHintSchema = passthroughObject2({
44347
44427
  target_type: optionalStringSchema2,
44348
44428
  reason: optionalStringSchema2,
44349
44429
  wake_reason: optionalStringSchema2,
44430
+ attention_hint: daemonApiAttentionHintSchema.optional(),
44350
44431
  createdAt: optionalStringSchema2,
44351
44432
  created_at: optionalStringSchema2
44352
44433
  });
@@ -44702,6 +44783,7 @@ function formatAgentInboxRowDetails(row) {
44702
44783
  if (row.latestSenderName) parts.push(`latest sender @${row.latestSenderName}`);
44703
44784
  if (row.latestMsgId) parts.push(`latest msg=${shortMessageId(row.latestMsgId)}`);
44704
44785
  parts.push(...row.flags.map(formatAgentInboxFlag));
44786
+ if (row.attentionHint) parts.push(`attention_hint=${formatAttentionHintField(row.attentionHint)}`);
44705
44787
  return parts.join(" \xB7 ");
44706
44788
  }
44707
44789
  function formatAgentInboxFlag(flag) {
@@ -44711,6 +44793,18 @@ function formatAgentInboxFlag(flag) {
44711
44793
  function shortMessageId(value) {
44712
44794
  return value.slice(0, 8);
44713
44795
  }
44796
+ function formatAttentionHintField(hint) {
44797
+ return JSON.stringify({
44798
+ schema: hint.schema,
44799
+ trigger: hint.trigger,
44800
+ scope: hint.scope,
44801
+ suggested_command: hint.suggested_command,
44802
+ copy: hint.copy,
44803
+ copy_version: hint.copy_version,
44804
+ epoch_ms: hint.epoch_ms,
44805
+ thresholds: hint.thresholds
44806
+ });
44807
+ }
44714
44808
 
44715
44809
  // ../shared/src/externalAgentIntegration.ts
44716
44810
  init_esm_shims();
@@ -45018,6 +45112,15 @@ var SERVER_CAPABILITY_MATRIX = {
45018
45112
  })
45019
45113
  };
45020
45114
 
45115
+ // ../shared/src/tracing/traceFamilyRegistry.ts
45116
+ init_esm_shims();
45117
+
45118
+ // ../shared/src/tracing/stateTransitionTrace.ts
45119
+ init_esm_shims();
45120
+
45121
+ // ../shared/src/tracing/stateViolationTrace.ts
45122
+ init_esm_shims();
45123
+
45021
45124
  // ../shared/src/index.ts
45022
45125
  var BUILTIN_RUNTIME_PROVIDER_ENV_KEYS = PI_BUILTIN_PROVIDER_API_KEY_ENV_KEYS_GENERATED;
45023
45126
  var BUILTIN_RUNTIME_PROVIDERS = Object.entries(BUILTIN_RUNTIME_PROVIDER_ENV_KEYS).map(([id, envKey]) => ({ id, envKey }));
@@ -45098,9 +45201,9 @@ function isExternalAgentRuntime(runtime) {
45098
45201
  return runtime === EXTERNAL_AGENT_RUNTIME_ID;
45099
45202
  }
45100
45203
  var RUNTIMES = [
45101
- { id: "builtin", displayName: "Built-in", binary: "", supported: true },
45102
45204
  { id: "claude", displayName: "Claude Code", binary: "claude", supported: true },
45103
45205
  { id: "codex", displayName: "Codex CLI", binary: "codex", supported: true },
45206
+ { id: "builtin", displayName: "Builtin Pi", binary: "", supported: true },
45104
45207
  { id: "antigravity", displayName: "Antigravity CLI", binary: "agy", supported: true },
45105
45208
  // Kimi: prefer the in-process SDK (`kimi-sdk` → "Kimi Code") for new agents.
45106
45209
  // The legacy `kimi` (kimi-cli child-process) entry stays for backward compat
@@ -45460,7 +45563,8 @@ function createAgentApiSurfaceClient(client) {
45460
45563
  read: (query) => requestClientAsApiResponse(agentApi.history.read(query))
45461
45564
  },
45462
45565
  knowledge: {
45463
- get: (query) => requestClientAsApiResponse(agentApi.knowledge.get(query))
45566
+ get: (query) => requestClientAsApiResponse(agentApi.knowledge.get(query)),
45567
+ search: (query) => requestClientAsApiResponse(agentApi.knowledge.search(query))
45464
45568
  },
45465
45569
  tasks: {
45466
45570
  list: (query) => requestClientAsApiResponse(agentApi.tasks.list(query)),
@@ -45487,7 +45591,7 @@ function createAgentApiSurfaceClient(client) {
45487
45591
  channels: {
45488
45592
  join: (params) => requestClientAsApiResponse(agentApi.channels.join(params)),
45489
45593
  leave: (params) => requestClientAsApiResponse(agentApi.channels.leave(params)),
45490
- mute: (params) => requestClientAsApiResponse(agentApi.channels.mute(params)),
45594
+ mute: (params) => requestClientAsApiResponse(agentApi.channels.mute(params, {})),
45491
45595
  unmute: (params) => requestClientAsApiResponse(agentApi.channels.unmute(params)),
45492
45596
  members: (query) => requestClientAsApiResponse(agentApi.channels.members(query)),
45493
45597
  resolve: (body) => requestClientAsApiResponse(agentApi.channels.resolve(body))
@@ -46211,6 +46315,10 @@ function renderError(io, err) {
46211
46315
  `);
46212
46316
  io.stderr.write(`Code: ${err.code}
46213
46317
  `);
46318
+ if (err.draftSaved !== void 0) {
46319
+ io.stderr.write(`Draft saved: ${err.draftSaved ? "yes" : "no"}
46320
+ `);
46321
+ }
46214
46322
  if (err.suggestedNextAction) {
46215
46323
  io.stderr.write(`Next action: ${err.suggestedNextAction}
46216
46324
  `);
@@ -46234,8 +46342,16 @@ function registerCliCommand(parent, command, runtimeOptions = {}) {
46234
46342
  child.argument(arg);
46235
46343
  }
46236
46344
  for (const option of command.spec.options ?? []) {
46345
+ const commanderOption = option.hidden ? new Option(option.flags, option.description).hideHelp() : null;
46237
46346
  if (option.parse) {
46238
- child.option(option.flags, option.description, option.parse);
46347
+ if (commanderOption) {
46348
+ commanderOption.argParser(option.parse);
46349
+ child.addOption(commanderOption);
46350
+ } else {
46351
+ child.option(option.flags, option.description, option.parse);
46352
+ }
46353
+ } else if (commanderOption) {
46354
+ child.addOption(commanderOption);
46239
46355
  } else {
46240
46356
  child.option(option.flags, option.description);
46241
46357
  }
@@ -48575,6 +48691,156 @@ function formatServerInfo(data) {
48575
48691
  }
48576
48692
  return text;
48577
48693
  }
48694
+ function channelRef(name) {
48695
+ return name.startsWith("#") ? name : `#${name}`;
48696
+ }
48697
+ function channelVisibility(channel) {
48698
+ const type = channel.type?.trim();
48699
+ return type === "private" ? "private" : "public";
48700
+ }
48701
+ function channelMuted(channel) {
48702
+ if (typeof channel.muted === "boolean") return channel.muted;
48703
+ if (typeof channel.activityMuted === "boolean") return channel.activityMuted;
48704
+ return void 0;
48705
+ }
48706
+ function channelStatus(channel) {
48707
+ const parts = [
48708
+ channelVisibility(channel),
48709
+ channel.joined ? "joined" : "not joined"
48710
+ ];
48711
+ const muted = channelMuted(channel);
48712
+ if (muted !== void 0) parts.push(muted ? "muted" : "not muted");
48713
+ if (typeof channel.archived === "boolean") parts.push(channel.archived ? "archived" : "not archived");
48714
+ return parts.join(", ");
48715
+ }
48716
+ function formatPageFooter(page) {
48717
+ if (!page) return "";
48718
+ const start = page.total === 0 ? 0 : Math.min(page.offset + 1, page.total);
48719
+ const end = Math.min(page.offset + page.limit, page.total);
48720
+ const lines = [`
48721
+ Showing ${start}-${end} of ${page.total}.`];
48722
+ if (page.nextCommand && end < page.total) {
48723
+ lines.push(`More: ${page.nextCommand}`);
48724
+ }
48725
+ return `${lines.join("\n")}
48726
+ `;
48727
+ }
48728
+ function formatChannelInfo(channel, memberCounts) {
48729
+ const lines = ["## Channel", ""];
48730
+ lines.push(`Channel: ${channelRef(channel.name)}`);
48731
+ if (channel.id) lines.push(`ID: ${channel.id}`);
48732
+ lines.push(`Visibility: ${channelVisibility(channel)}`);
48733
+ lines.push(`Joined: ${channel.joined ? "yes" : "no"}`);
48734
+ const muted = channelMuted(channel);
48735
+ if (muted !== void 0) lines.push(`Muted: ${muted ? "yes" : "no"}`);
48736
+ if (typeof channel.archived === "boolean") lines.push(`Archived: ${channel.archived ? "yes" : "no"}`);
48737
+ lines.push(`Description: ${channel.description?.trim() || "(none)"}`);
48738
+ if (memberCounts) {
48739
+ const agents = memberCounts.agents ?? 0;
48740
+ const humans = memberCounts.humans ?? 0;
48741
+ lines.push(`Members: ${agents + humans} (${agents} agents, ${humans} humans)`);
48742
+ }
48743
+ lines.push("");
48744
+ lines.push(`More: raft channel members "${channelRef(channel.name)}"`);
48745
+ return `${lines.join("\n")}
48746
+ `;
48747
+ }
48748
+ function formatServerSummary(data) {
48749
+ const channels = data.channels ?? [];
48750
+ const agents = data.agents ?? [];
48751
+ const humans = data.humans ?? [];
48752
+ const joined = channels.filter((channel) => channel.joined).length;
48753
+ const lines = [
48754
+ "## Server",
48755
+ "",
48756
+ `Channels: ${channels.length} visible (${joined} joined)`,
48757
+ `Agents: ${agents.length}`,
48758
+ `Humans: ${humans.length}`,
48759
+ "",
48760
+ "Narrow queries:",
48761
+ "- raft server info --channels",
48762
+ "- raft server info --agents",
48763
+ "- raft server info --humans",
48764
+ "- raft channel info <name>",
48765
+ "- raft user info <name>",
48766
+ "",
48767
+ "Full dump: raft server info --full"
48768
+ ];
48769
+ return `${lines.join("\n")}
48770
+ `;
48771
+ }
48772
+ function formatServerChannels(channels, page) {
48773
+ const lines = [
48774
+ "## Server Channels",
48775
+ "",
48776
+ "Private channels are shown only when this agent is a member. Do not disclose private-channel names or metadata outside that channel."
48777
+ ];
48778
+ if (channels.length === 0) {
48779
+ lines.push("(none)");
48780
+ } else {
48781
+ for (const channel of channels) {
48782
+ const description = channel.description?.trim();
48783
+ lines.push(description ? `${channelRef(channel.name)} [${channelStatus(channel)}] \u2014 ${description}` : `${channelRef(channel.name)} [${channelStatus(channel)}]`);
48784
+ }
48785
+ }
48786
+ return `${lines.join("\n")}${formatPageFooter(page)}`;
48787
+ }
48788
+ function formatServerAgents(agents, page) {
48789
+ const lines = [
48790
+ "## Server Agents",
48791
+ "",
48792
+ "Role labels show server-level owner/admin authority; no role label means ordinary member."
48793
+ ];
48794
+ if (agents.length === 0) {
48795
+ lines.push("(none)");
48796
+ } else {
48797
+ for (const agent of agents) {
48798
+ const role = roleLabel(agent.role);
48799
+ const status = agentStatusLabel(agent);
48800
+ lines.push(agent.description ? `@${agent.name} (${status})${role} \u2014 ${agent.description}` : `@${agent.name} (${status})${role}`);
48801
+ }
48802
+ }
48803
+ return `${lines.join("\n")}${formatPageFooter(page)}`;
48804
+ }
48805
+ function formatServerHumans(humans, page) {
48806
+ const lines = [
48807
+ "## Server Humans",
48808
+ "",
48809
+ "Role labels show server-level owner/admin authority; no role label means ordinary member."
48810
+ ];
48811
+ if (humans.length === 0) {
48812
+ lines.push("(none)");
48813
+ } else {
48814
+ for (const human of humans) {
48815
+ const role = roleLabel(human.role);
48816
+ lines.push(human.description ? `@${human.name}${role} \u2014 ${human.description}` : `@${human.name}${role}`);
48817
+ }
48818
+ }
48819
+ return `${lines.join("\n")}${formatPageFooter(page)}`;
48820
+ }
48821
+ function formatUserInfo(user, memberships, page, skippedChannels = 0) {
48822
+ const name = user.value.name;
48823
+ const role = roleLabel(user.value.role);
48824
+ const lines = ["## User", ""];
48825
+ lines.push(`User: @${name}`);
48826
+ lines.push(`Kind: ${user.kind}`);
48827
+ if (user.kind === "agent") lines.push(`Status: ${agentStatusLabel(user.value)}`);
48828
+ if (role) lines.push(`Role: ${role.slice(2, -1)}`);
48829
+ if (user.value.description) lines.push(`Description: ${user.value.description}`);
48830
+ lines.push("");
48831
+ lines.push("### Visible Channel Memberships");
48832
+ if (memberships.length === 0) {
48833
+ lines.push("(none found in inspected visible channels)");
48834
+ } else {
48835
+ for (const channel of memberships) {
48836
+ lines.push(`${channelRef(channel.name)} [${channelStatus(channel)}]`);
48837
+ }
48838
+ }
48839
+ if (skippedChannels > 0) {
48840
+ lines.push(`Skipped ${skippedChannels} visible channel roster checks because the server rejected them.`);
48841
+ }
48842
+ return `${lines.join("\n")}${formatPageFooter(page)}`;
48843
+ }
48578
48844
  function formatChannelMembers(data) {
48579
48845
  let text = "## Channel Members\n\n";
48580
48846
  const ref = data.channel?.ref ?? "(unknown)";
@@ -48644,68 +48910,7 @@ function registerChannelMembersCommand(parent, runtimeOptions) {
48644
48910
  registerCliCommand(parent, channelMembersCommand, runtimeOptions);
48645
48911
  }
48646
48912
 
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
48913
+ // src/commands/channel/info.ts
48709
48914
  init_esm_shims();
48710
48915
 
48711
48916
  // src/commands/channel/leave.ts
@@ -48716,8 +48921,19 @@ function parseRegularChannelTarget(target) {
48716
48921
  const name = target.slice(1).trim();
48717
48922
  return name.length > 0 ? name : null;
48718
48923
  }
48719
- function formatLeaveChannelResult(target) {
48720
- return `Left ${target}. You can still inspect visible public channel history there, but you can no longer send or receive ordinary channel delivery until you join the public channel again or a human re-adds you to a private channel.`;
48924
+ function formatLeaveChannelResult(target, result2) {
48925
+ const lines = [
48926
+ `Left ${target}. You can still inspect visible public channel history there, but you can no longer send or receive ordinary channel delivery until you join the public channel again or a human re-adds you to a private channel.`
48927
+ ];
48928
+ if (result2?.attention?.ordinaryActivity) lines.push(result2.attention.ordinaryActivity);
48929
+ if (result2?.attention?.stillArrives?.length) {
48930
+ lines.push("Still arrives:");
48931
+ for (const item of result2.attention.stillArrives) lines.push(`- ${item}`);
48932
+ }
48933
+ if (result2?.attention?.threadBoundary) lines.push(result2.attention.threadBoundary);
48934
+ if (result2?.attention?.manageCommand) lines.push(`To stop a followed thread: ${result2.attention.manageCommand}`);
48935
+ if (result2?.attention?.manageApi) lines.push(`Agent API: ${result2.attention.manageApi}`);
48936
+ return lines.join("\n");
48721
48937
  }
48722
48938
  function formatAlreadyNotJoined(target) {
48723
48939
  return `Already not joined in ${target}.`;
@@ -48772,14 +48988,130 @@ var channelLeaveCommand = defineCommand(
48772
48988
  message: leaveRes.error ?? `HTTP ${leaveRes.status}`
48773
48989
  });
48774
48990
  }
48775
- writeText(ctx.io, formatLeaveChannelResult(target) + "\n");
48991
+ writeText(ctx.io, formatLeaveChannelResult(target, leaveRes.data ?? void 0) + "\n");
48776
48992
  }
48777
48993
  );
48778
48994
  function registerChannelLeaveCommand(parent, runtimeOptions) {
48779
48995
  registerCliCommand(parent, channelLeaveCommand, runtimeOptions);
48780
48996
  }
48781
48997
 
48998
+ // src/commands/channel/info.ts
48999
+ function normalizeChannelInfoTarget(target) {
49000
+ const input = target?.trim() ?? "";
49001
+ const normalized = input.startsWith("#") ? input : `#${input}`;
49002
+ const name = parseRegularChannelTarget(normalized);
49003
+ if (!name) {
49004
+ throw new CliError({
49005
+ code: "INVALID_TARGET",
49006
+ message: "Target must be a regular channel name, e.g. '#engineering' or 'engineering'. DMs and thread targets are not supported."
49007
+ });
49008
+ }
49009
+ return { input: normalized, name };
49010
+ }
49011
+ var channelInfoCommand = defineCommand(
49012
+ {
49013
+ name: "info",
49014
+ description: "Show narrow channel facts: existence, joined state, description, and member count when visible",
49015
+ arguments: ["<target>"]
49016
+ },
49017
+ async (ctx, target) => {
49018
+ const { input, name } = normalizeChannelInfoTarget(target);
49019
+ const agentContext = ctx.loadAgentContext();
49020
+ const client = ctx.createApiClient(agentContext);
49021
+ const agentApi = createAgentApiSurfaceClient(client);
49022
+ const infoRes = await agentApi.server.info();
49023
+ if (!infoRes.ok) {
49024
+ throw new CliError({
49025
+ code: infoRes.status >= 500 ? "SERVER_5XX" : "INFO_FAILED",
49026
+ message: infoRes.error ?? `HTTP ${infoRes.status}`
49027
+ });
49028
+ }
49029
+ const channel = (infoRes.data?.channels ?? []).find((candidate) => candidate.name === name);
49030
+ if (!channel) {
49031
+ throw new CliError({
49032
+ code: "NOT_FOUND",
49033
+ message: `Channel not found or not visible: ${input}`,
49034
+ suggestedNextAction: "Run `raft server info --channels --query <name>` to inspect visible channels, or ask a channel member to add you if this is private."
49035
+ });
49036
+ }
49037
+ let memberCounts = null;
49038
+ const membersRes = await agentApi.channels.members({ channel: `#${name}` });
49039
+ if (membersRes.ok) {
49040
+ memberCounts = {
49041
+ agents: membersRes.data?.agents?.length ?? 0,
49042
+ humans: membersRes.data?.humans?.length ?? 0
49043
+ };
49044
+ }
49045
+ writeText(ctx.io, formatChannelInfo(channel, memberCounts));
49046
+ }
49047
+ );
49048
+ function registerChannelInfoCommand(parent, runtimeOptions) {
49049
+ registerCliCommand(parent, channelInfoCommand, runtimeOptions);
49050
+ }
49051
+
49052
+ // src/commands/channel/create.ts
49053
+ init_esm_shims();
49054
+ function normalizeChannelName(raw) {
49055
+ return (raw ?? "").trim().replace(/^#/, "");
49056
+ }
49057
+ function formatCreateChannelResult(channel) {
49058
+ const target = `#${channel.name}`;
49059
+ const visibility = channel.type === "private" ? "private" : "public";
49060
+ return `Created ${target} (${visibility}). You are joined and can send messages there.`;
49061
+ }
49062
+ var channelCreateCommand = defineCommand(
49063
+ {
49064
+ name: "create",
49065
+ description: "Create a public or private channel when this agent has server admin authority",
49066
+ options: [
49067
+ {
49068
+ flags: "--name <name>",
49069
+ description: "Channel name, with or without a leading '#'"
49070
+ },
49071
+ {
49072
+ flags: "--description <description>",
49073
+ description: "Optional channel description"
49074
+ },
49075
+ {
49076
+ flags: "--private",
49077
+ description: "Create a private channel instead of a public channel"
49078
+ }
49079
+ ]
49080
+ },
49081
+ async (ctx, opts) => {
49082
+ const name = normalizeChannelName(opts.name);
49083
+ if (!name) {
49084
+ throw new CliError({
49085
+ code: "INVALID_ARG",
49086
+ message: "--name is required"
49087
+ });
49088
+ }
49089
+ const agentContext = ctx.loadAgentContext();
49090
+ const client = ctx.createApiClient(agentContext);
49091
+ const res = await client.request(
49092
+ "POST",
49093
+ `/internal/agent/${encodeURIComponent(agentContext.agentId)}/channels`,
49094
+ {
49095
+ name,
49096
+ description: opts.description,
49097
+ visibility: opts.private ? "private" : "public"
49098
+ }
49099
+ );
49100
+ if (!res.ok || !res.data) {
49101
+ throw new CliError({
49102
+ code: res.status >= 500 ? "SERVER_5XX" : "CREATE_FAILED",
49103
+ message: res.error ?? `HTTP ${res.status}`
49104
+ });
49105
+ }
49106
+ writeText(ctx.io, formatCreateChannelResult(res.data) + "\n");
49107
+ }
49108
+ );
49109
+ function registerChannelCreateCommand(parent, runtimeOptions) {
49110
+ registerCliCommand(parent, channelCreateCommand, runtimeOptions);
49111
+ }
49112
+
48782
49113
  // src/commands/channel/update.ts
49114
+ init_esm_shims();
48783
49115
  function normalizeChannelName2(raw) {
48784
49116
  return (raw ?? "").trim().replace(/^#/, "");
48785
49117
  }
@@ -48970,9 +49302,19 @@ init_esm_shims();
48970
49302
  function normalizeHandle2(raw) {
48971
49303
  return (raw ?? "").trim().replace(/^@/, "");
48972
49304
  }
48973
- function formatRemoveMemberResult(target, memberName, wasMember) {
49305
+ function formatRemoveMemberResult(target, memberName, wasMember, result2) {
48974
49306
  const member = `@${memberName}`;
48975
- return wasMember ? `Removed ${member} from ${target}.` : `${member} was not in ${target}.`;
49307
+ if (!wasMember) return `${member} was not in ${target}.`;
49308
+ const lines = [`Removed ${member} from ${target}.`];
49309
+ if (result2?.attention?.ordinaryActivity) lines.push(result2.attention.ordinaryActivity);
49310
+ if (result2?.attention?.stillArrives?.length) {
49311
+ lines.push("Still arrives:");
49312
+ for (const item of result2.attention.stillArrives) lines.push(`- ${item}`);
49313
+ }
49314
+ if (result2?.attention?.threadBoundary) lines.push(result2.attention.threadBoundary);
49315
+ if (result2?.attention?.manageCommand) lines.push(`To stop a followed thread: ${result2.attention.manageCommand}`);
49316
+ if (result2?.attention?.manageApi) lines.push(`Agent API: ${result2.attention.manageApi}`);
49317
+ return lines.join("\n");
48976
49318
  }
48977
49319
  var channelRemoveMemberCommand = defineCommand(
48978
49320
  {
@@ -49042,7 +49384,7 @@ var channelRemoveMemberCommand = defineCommand(
49042
49384
  });
49043
49385
  }
49044
49386
  const memberName = removeRes.data?.member?.name ?? (user || agent);
49045
- writeText(ctx.io, formatRemoveMemberResult(target, memberName, removeRes.data?.wasMember === true) + "\n");
49387
+ writeText(ctx.io, formatRemoveMemberResult(target, memberName, removeRes.data?.wasMember === true, removeRes.data ?? void 0) + "\n");
49046
49388
  }
49047
49389
  );
49048
49390
  function registerChannelRemoveMemberCommand(parent, runtimeOptions) {
@@ -49052,7 +49394,12 @@ function registerChannelRemoveMemberCommand(parent, runtimeOptions) {
49052
49394
  // src/commands/channel/join.ts
49053
49395
  init_esm_shims();
49054
49396
  function formatJoinChannelResult(target) {
49055
- return `Joined ${target}. You can now send messages there and receive ordinary channel delivery.`;
49397
+ return [
49398
+ `Joined ${target}. You can now send messages there and receive ordinary channel delivery.`,
49399
+ "Still arrives:",
49400
+ "- Personal @mentions still reach you even if you later mute ordinary channel updates.",
49401
+ "- Threads you started or follow stay followed even if you later mute this channel."
49402
+ ].join("\n");
49056
49403
  }
49057
49404
  function formatAlreadyJoined(target) {
49058
49405
  return `Already joined ${target}.`;
@@ -49208,12 +49555,90 @@ function registerChannelUnmuteCommand(parent, runtimeOptions) {
49208
49555
 
49209
49556
  // src/commands/server/info.ts
49210
49557
  init_esm_shims();
49211
- var serverInfoCommand = defineCommand(
49212
- {
49213
- name: "info",
49214
- description: "List channels, agents, and humans on the current server"
49558
+ function parseNonNegativeInt(raw, name, fallback) {
49559
+ if (raw === void 0) return fallback;
49560
+ if (!/^\d+$/.test(raw)) {
49561
+ throw new CliError({
49562
+ code: "INVALID_ARG",
49563
+ message: `${name} must be a non-negative integer`
49564
+ });
49565
+ }
49566
+ return Number(raw);
49567
+ }
49568
+ function parsePositiveInt2(raw, name, fallback) {
49569
+ const value = parseNonNegativeInt(raw, name, fallback);
49570
+ if (value <= 0) {
49571
+ throw new CliError({
49572
+ code: "INVALID_ARG",
49573
+ message: `${name} must be greater than 0`
49574
+ });
49575
+ }
49576
+ return value;
49577
+ }
49578
+ function selectedSections(opts) {
49579
+ const sections = [];
49580
+ if (opts.channels) sections.push("channels");
49581
+ if (opts.agents) sections.push("agents");
49582
+ if (opts.humans) sections.push("humans");
49583
+ return sections;
49584
+ }
49585
+ function hasListModifier(opts) {
49586
+ return Boolean(opts.joined || opts.query !== void 0 || opts.limit !== void 0 || opts.offset !== void 0);
49587
+ }
49588
+ function includesQuery(row, query) {
49589
+ const needle = query?.trim().toLowerCase();
49590
+ if (!needle) return true;
49591
+ const values = Object.values(row).filter((value) => typeof value === "string").map((value) => value.toLowerCase());
49592
+ return values.some((value) => value.includes(needle));
49593
+ }
49594
+ function pageRows(rows, offset, limit) {
49595
+ return rows.slice(offset, offset + limit);
49596
+ }
49597
+ function nextCommand(section, opts, offset, limit, total) {
49598
+ const nextOffset = offset + limit;
49599
+ if (nextOffset >= total) return void 0;
49600
+ const parts = ["raft server info", `--${section}`, `--offset ${nextOffset}`, `--limit ${limit}`];
49601
+ if (opts.query?.trim()) parts.push(`--query ${JSON.stringify(opts.query.trim())}`);
49602
+ if (opts.joined) parts.push("--joined");
49603
+ return parts.join(" ");
49604
+ }
49605
+ var serverInfoCommand = defineCommand(
49606
+ {
49607
+ name: "info",
49608
+ description: "Show bounded server facts; use --full for the legacy full inventory",
49609
+ options: [
49610
+ { flags: "--full", description: "Print the full channels, agents, humans, and runtime inventory" },
49611
+ { flags: "--channels", description: "List visible channels only" },
49612
+ { flags: "--agents", description: "List agents only" },
49613
+ { flags: "--humans", description: "List humans only" },
49614
+ { flags: "--joined", description: "With --channels, show only joined channels" },
49615
+ { flags: "--query <text>", description: "Filter the selected list by visible text" },
49616
+ { flags: "--limit <n>", description: "Maximum rows for list output (default: 50)" },
49617
+ { flags: "--offset <n>", description: "Rows to skip for list output (default: 0)" }
49618
+ ]
49215
49619
  },
49216
- async (ctx) => {
49620
+ async (ctx, opts = {}) => {
49621
+ const sections = selectedSections(opts);
49622
+ if (opts.full && sections.length > 0) {
49623
+ throw new CliError({
49624
+ code: "INVALID_ARG",
49625
+ message: "--full cannot be combined with --channels, --agents, or --humans"
49626
+ });
49627
+ }
49628
+ if (sections.length === 0 && hasListModifier(opts)) {
49629
+ throw new CliError({
49630
+ code: "INVALID_ARG",
49631
+ message: "--query, --limit, --offset, and --joined require --channels, --agents, or --humans"
49632
+ });
49633
+ }
49634
+ if (opts.joined && sections.some((section) => section !== "channels")) {
49635
+ throw new CliError({
49636
+ code: "INVALID_ARG",
49637
+ message: "--joined can only be used with --channels"
49638
+ });
49639
+ }
49640
+ const limit = parsePositiveInt2(opts.limit, "--limit", 50);
49641
+ const offset = parseNonNegativeInt(opts.offset, "--offset", 0);
49217
49642
  const agentContext = ctx.loadAgentContext();
49218
49643
  const client = ctx.createApiClient(agentContext);
49219
49644
  const res = await createAgentApiSurfaceClient(client).server.info();
@@ -49224,14 +49649,56 @@ var serverInfoCommand = defineCommand(
49224
49649
  message: res.error ?? `HTTP ${res.status}`
49225
49650
  });
49226
49651
  }
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
- };
49652
+ if (!res.data) {
49653
+ throw new CliError({
49654
+ code: "INVALID_JSON_RESPONSE",
49655
+ message: "Agent API serverInfo returned an empty response body"
49656
+ });
49657
+ }
49658
+ const data = {
49659
+ ...res.data,
49660
+ runtimeContext: {
49661
+ ...res.data.runtimeContext,
49662
+ workspacePath: res.data.runtimeContext.workspacePath ?? ctx.env.SLOCK_CURRENT_WORKSPACE_PATH ?? null
49663
+ }
49664
+ };
49665
+ if (opts.full) {
49666
+ writeText(ctx.io, formatServerInfo(data));
49667
+ return;
49668
+ }
49669
+ if (sections.length === 0) {
49670
+ writeText(ctx.io, formatServerSummary(data));
49671
+ return;
49233
49672
  }
49234
- writeText(ctx.io, formatServerInfo(data));
49673
+ const chunks = [];
49674
+ for (const section of sections) {
49675
+ if (section === "channels") {
49676
+ const rows = (data.channels ?? []).filter((channel) => !opts.joined || channel.joined).filter((channel) => includesQuery(channel, opts.query));
49677
+ chunks.push(formatServerChannels(pageRows(rows, offset, limit), {
49678
+ total: rows.length,
49679
+ offset,
49680
+ limit,
49681
+ nextCommand: nextCommand(section, opts, offset, limit, rows.length)
49682
+ }));
49683
+ } else if (section === "agents") {
49684
+ const rows = (data.agents ?? []).filter((agent) => includesQuery(agent, opts.query));
49685
+ chunks.push(formatServerAgents(pageRows(rows, offset, limit), {
49686
+ total: rows.length,
49687
+ offset,
49688
+ limit,
49689
+ nextCommand: nextCommand(section, opts, offset, limit, rows.length)
49690
+ }));
49691
+ } else {
49692
+ const rows = (data.humans ?? []).filter((human) => includesQuery(human, opts.query));
49693
+ chunks.push(formatServerHumans(pageRows(rows, offset, limit), {
49694
+ total: rows.length,
49695
+ offset,
49696
+ limit,
49697
+ nextCommand: nextCommand(section, opts, offset, limit, rows.length)
49698
+ }));
49699
+ }
49700
+ }
49701
+ writeText(ctx.io, chunks.join("\n"));
49235
49702
  }
49236
49703
  );
49237
49704
  function registerServerInfoCommand(parent, runtimeOptions) {
@@ -49571,6 +50038,100 @@ function registerServerUpdateCommand(parent, runtimeOptions) {
49571
50038
  registerCliCommand(parent, serverUpdateCommand, runtimeOptions);
49572
50039
  }
49573
50040
 
50041
+ // src/commands/user/info.ts
50042
+ init_esm_shims();
50043
+ function parseNonNegativeInt2(raw, name, fallback) {
50044
+ if (raw === void 0) return fallback;
50045
+ if (!/^\d+$/.test(raw)) {
50046
+ throw new CliError({
50047
+ code: "INVALID_ARG",
50048
+ message: `${name} must be a non-negative integer`
50049
+ });
50050
+ }
50051
+ return Number(raw);
50052
+ }
50053
+ function parsePositiveInt3(raw, name, fallback) {
50054
+ const value = parseNonNegativeInt2(raw, name, fallback);
50055
+ if (value <= 0) {
50056
+ throw new CliError({
50057
+ code: "INVALID_ARG",
50058
+ message: `${name} must be greater than 0`
50059
+ });
50060
+ }
50061
+ return value;
50062
+ }
50063
+ function normalizeUserName(target) {
50064
+ const trimmed = target?.trim() ?? "";
50065
+ const name = trimmed.startsWith("@") ? trimmed.slice(1) : trimmed;
50066
+ if (!name) {
50067
+ throw new CliError({
50068
+ code: "INVALID_ARG",
50069
+ message: "user name is required"
50070
+ });
50071
+ }
50072
+ return name;
50073
+ }
50074
+ var userInfoCommand = defineCommand(
50075
+ {
50076
+ name: "info",
50077
+ description: "Show narrow visible facts for a human or agent and its visible channel memberships",
50078
+ arguments: ["<name>"],
50079
+ options: [
50080
+ { flags: "--limit <n>", description: "Maximum visible channels to inspect (default: 50)" },
50081
+ { flags: "--offset <n>", description: "Visible channels to skip before inspection (default: 0)" }
50082
+ ]
50083
+ },
50084
+ async (ctx, target, opts = {}) => {
50085
+ const name = normalizeUserName(target);
50086
+ const limit = parsePositiveInt3(opts.limit, "--limit", 50);
50087
+ const offset = parseNonNegativeInt2(opts.offset, "--offset", 0);
50088
+ const agentContext = ctx.loadAgentContext();
50089
+ const client = ctx.createApiClient(agentContext);
50090
+ const agentApi = createAgentApiSurfaceClient(client);
50091
+ const infoRes = await agentApi.server.info();
50092
+ if (!infoRes.ok) {
50093
+ throw new CliError({
50094
+ code: infoRes.status >= 500 ? "SERVER_5XX" : "INFO_FAILED",
50095
+ message: infoRes.error ?? `HTTP ${infoRes.status}`
50096
+ });
50097
+ }
50098
+ const agent = (infoRes.data?.agents ?? []).find((candidate) => candidate.name === name);
50099
+ const human = (infoRes.data?.humans ?? []).find((candidate) => candidate.name === name);
50100
+ const user = agent ? { kind: "agent", value: agent } : human ? { kind: "human", value: human } : null;
50101
+ if (!user) {
50102
+ throw new CliError({
50103
+ code: "NOT_FOUND",
50104
+ message: `User not found or not visible: @${name}`,
50105
+ suggestedNextAction: "Run `raft server info --agents --query <name>` or `raft server info --humans --query <name>` to inspect visible users."
50106
+ });
50107
+ }
50108
+ const visibleChannels = infoRes.data?.channels ?? [];
50109
+ const inspectedChannels = visibleChannels.slice(offset, offset + limit);
50110
+ const memberships = [];
50111
+ let skippedChannels = 0;
50112
+ for (const channel of inspectedChannels) {
50113
+ const membersRes = await agentApi.channels.members({ channel: `#${channel.name}` });
50114
+ if (!membersRes.ok) {
50115
+ skippedChannels += 1;
50116
+ continue;
50117
+ }
50118
+ const agents = membersRes.data?.agents ?? [];
50119
+ const humans = membersRes.data?.humans ?? [];
50120
+ const found = user.kind === "agent" ? agents.some((candidate) => candidate.name === name) : humans.some((candidate) => candidate.name === name);
50121
+ if (found) memberships.push(channel);
50122
+ }
50123
+ writeText(ctx.io, formatUserInfo(user, memberships, {
50124
+ total: visibleChannels.length,
50125
+ offset,
50126
+ limit,
50127
+ nextCommand: offset + limit < visibleChannels.length ? `raft user info @${name} --offset ${offset + limit} --limit ${limit}` : void 0
50128
+ }, skippedChannels));
50129
+ }
50130
+ );
50131
+ function registerUserInfoCommand(parent, runtimeOptions) {
50132
+ registerCliCommand(parent, userInfoCommand, runtimeOptions);
50133
+ }
50134
+
49574
50135
  // src/commands/knowledge/get.ts
49575
50136
  init_esm_shims();
49576
50137
  function formatKnowledgeStdout(content) {
@@ -49607,11 +50168,13 @@ var knowledgeGetCommand = defineCommand(
49607
50168
  },
49608
50169
  {
49609
50170
  flags: "--turn-id <id>",
49610
- description: "Optional turn id for correlation in the knowledge event"
50171
+ description: "Diagnostic: override the turn id recorded on the knowledge event",
50172
+ hidden: true
49611
50173
  },
49612
50174
  {
49613
50175
  flags: "--trace-id <id>",
49614
- description: "Optional trace id for correlation in the knowledge event"
50176
+ description: "Diagnostic: override the trace id recorded on the knowledge event",
50177
+ hidden: true
49615
50178
  }
49616
50179
  ],
49617
50180
  helpAfter: "\nTopics:\n Run `raft manual get index` to list available manual topics.\n"
@@ -49646,6 +50209,93 @@ function registerKnowledgeGetCommand(parent, runtimeOptions) {
49646
50209
  registerCliCommand(parent, knowledgeGetCommand, runtimeOptions);
49647
50210
  }
49648
50211
 
50212
+ // src/commands/knowledge/search.ts
50213
+ init_esm_shims();
50214
+ function formatKnowledgeSearchResults(results) {
50215
+ return results.map((result2, index) => {
50216
+ const firstScreen = result2.firstScreen.trim();
50217
+ const body = firstScreen.split(/\r?\n/).filter(Boolean).map((line) => ` ${line}`).join("\n");
50218
+ return `${index + 1}. ${result2.slug} \u2014 ${result2.title}${body ? `
50219
+ ${body}` : ""}`;
50220
+ }).join("\n\n") + "\n";
50221
+ }
50222
+ function toKnowledgeSearchErrorCode(errorCode2, status) {
50223
+ switch (errorCode2) {
50224
+ case "INVALID_JSON_RESPONSE":
50225
+ case "SCOPE_DENIED":
50226
+ case "knowledge_agent_missing":
50227
+ case "knowledge_internal_error":
50228
+ case "knowledge_not_found":
50229
+ case "knowledge_query_invalid":
50230
+ case "knowledge_reason_invalid":
50231
+ case "knowledge_scope_invalid":
50232
+ case "knowledge_source_invalid":
50233
+ case "knowledge_trace_id_invalid":
50234
+ case "knowledge_turn_id_invalid":
50235
+ case "unsupported_capability":
50236
+ return errorCode2;
50237
+ default:
50238
+ return status >= 500 ? "SERVER_5XX" : "KNOWLEDGE_SEARCH_FAILED";
50239
+ }
50240
+ }
50241
+ var knowledgeSearchCommand = defineCommand(
50242
+ {
50243
+ name: "search",
50244
+ description: "Search Raft Manual for Agents topics from the current server",
50245
+ arguments: ["<keywords>"],
50246
+ options: [
50247
+ {
50248
+ flags: "--scope <scope>",
50249
+ description: "Optional search scope. Currently supports: recipes"
50250
+ },
50251
+ {
50252
+ flags: "--reason <text>",
50253
+ description: "Optional rationale for this search (>=12 chars when provided)"
50254
+ },
50255
+ {
50256
+ flags: "--turn-id <id>",
50257
+ description: "Diagnostic: override the turn id recorded on the knowledge event",
50258
+ hidden: true
50259
+ },
50260
+ {
50261
+ flags: "--trace-id <id>",
50262
+ description: "Diagnostic: override the trace id recorded on the knowledge event",
50263
+ hidden: true
50264
+ }
50265
+ ],
50266
+ helpAfter: '\nExamples:\n raft manual search "preview before merge" --scope recipes\n raft manual get recipes/technique/preview-env\n'
50267
+ },
50268
+ async (ctx, keywords, opts) => {
50269
+ const agentContext = ctx.loadAgentContext();
50270
+ const client = ctx.createApiClient(agentContext);
50271
+ const res = await createAgentApiSurfaceClient(client).knowledge.search({
50272
+ query: keywords,
50273
+ scope: opts.scope,
50274
+ reason: opts.reason,
50275
+ turn_id: opts.turnId,
50276
+ trace_id: opts.traceId
50277
+ });
50278
+ if (!res.ok) {
50279
+ throw new CliError({
50280
+ code: toKnowledgeSearchErrorCode(res.errorCode, res.status),
50281
+ message: res.error ?? `HTTP ${res.status}`,
50282
+ suggestedNextAction: res.suggestedNextAction ?? (res.errorCode === "knowledge_not_found" ? "Try different keywords, or run `raft manual get index` to browse available topics." : void 0)
50283
+ });
50284
+ }
50285
+ const data = res.data;
50286
+ if (!data || data.ok !== true || !Array.isArray(data.results)) {
50287
+ throw new CliError({
50288
+ code: "KNOWLEDGE_SEARCH_FAILED",
50289
+ message: "Server returned an unexpected response shape"
50290
+ });
50291
+ }
50292
+ writeText(ctx.io, formatKnowledgeSearchResults(data.results));
50293
+ }
50294
+ );
50295
+ function registerKnowledgeSearchCommand(parent, runtimeOptions) {
50296
+ registerCliCommand(parent, knowledgeSearchCommand, runtimeOptions);
50297
+ }
50298
+
49649
50299
  // src/commands/inbox/check.ts
49650
50300
  init_esm_shims();
49651
50301
 
@@ -49707,7 +50357,11 @@ function parseThreadTarget(target) {
49707
50357
  return null;
49708
50358
  }
49709
50359
  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.`;
50360
+ return [
50361
+ `Unfollowed ${target}. Ordinary delivery for this thread has stopped.`,
50362
+ "Still arrives: personal @mentions pierce as single messages \u2014 they do NOT re-follow you.",
50363
+ "Posting in this thread re-follows you automatically."
50364
+ ].join("\n");
49711
50365
  }
49712
50366
  var threadUnfollowCommand = defineCommand(
49713
50367
  {
@@ -50360,6 +51014,168 @@ You can also choose not to send anything.
50360
51014
  `
50361
51015
  });
50362
51016
  }
51017
+ function formatDriveByJoinedToPostTip(target, data) {
51018
+ const attention = data.attention?.driveByJoinedToPost;
51019
+ if (!attention) return "";
51020
+ const muteCommand = attention.muteCommand?.trim() || `raft channel mute "${target}"`;
51021
+ const stillArrives = attention.stillArrives?.[0]?.trim() || "@mentions still reach you, and threads you started stay followed.";
51022
+ return [
51023
+ "Tip: you joined this channel to post this message. If you don't need its ordinary updates:",
51024
+ ` ${muteCommand}`,
51025
+ stillArrives
51026
+ ].join("\n");
51027
+ }
51028
+ function markSendFailureDraftSaved(err, draftSaved) {
51029
+ if (err instanceof CliError) {
51030
+ if (err.draftSaved !== void 0) return err;
51031
+ return new CliError({
51032
+ code: err.code,
51033
+ message: err.message,
51034
+ exitCode: err.exitCode,
51035
+ cause: err.cause,
51036
+ suggestedNextAction: err.suggestedNextAction,
51037
+ draftSaved
51038
+ });
51039
+ }
51040
+ const message = err instanceof Error ? err.message : String(err);
51041
+ return new CliError({
51042
+ code: "INTERNAL_BUG",
51043
+ message: `Unexpected error: ${message}`,
51044
+ cause: err,
51045
+ draftSaved
51046
+ });
51047
+ }
51048
+ async function handleMessageSend(ctx, positionalContent, opts, setFailureDraftSaved) {
51049
+ const target = opts.target?.trim() ?? "";
51050
+ if (!target) {
51051
+ throw cliError("INVALID_ARG", "--target is required");
51052
+ }
51053
+ try {
51054
+ rejectArgContent(positionalContent, opts);
51055
+ } catch (err) {
51056
+ if (err instanceof SendContentError) throw cliError(err.code, err.message, { cause: err });
51057
+ throw err;
51058
+ }
51059
+ try {
51060
+ validateDraftSendFlags(opts);
51061
+ } catch (err) {
51062
+ if (err instanceof SendContentError) throw cliError(err.code, err.message, { cause: err });
51063
+ throw err;
51064
+ }
51065
+ let content;
51066
+ let outgoingContent = "";
51067
+ let outgoingAttachmentIds = [];
51068
+ let previousDraftReholdCount = 0;
51069
+ let seenUpToSeq;
51070
+ if (opts.sendDraft) {
51071
+ content = await resolveOptionalSendContent(ctx.io.stdin ?? process.stdin);
51072
+ try {
51073
+ rejectSendDraftStdin(content, opts.target);
51074
+ } catch (err) {
51075
+ if (err instanceof SendContentError) throw cliError(err.code, err.message, { cause: err });
51076
+ throw err;
51077
+ }
51078
+ } else {
51079
+ try {
51080
+ content = await resolveSendContent(ctx.io.stdin ?? process.stdin);
51081
+ } catch (err) {
51082
+ if (err instanceof SendContentError) throw cliError(err.code, err.message, { cause: err });
51083
+ throw err;
51084
+ }
51085
+ outgoingContent = content;
51086
+ outgoingAttachmentIds = opts.attachmentId && opts.attachmentId.length > 0 ? opts.attachmentId : [];
51087
+ }
51088
+ const agentContext = ctx.loadAgentContext();
51089
+ const client = ctx.createApiClient(agentContext);
51090
+ if (opts.sendDraft) {
51091
+ const savedDraft = getSavedDraft(agentContext.agentId, target);
51092
+ if (!savedDraft) {
51093
+ throw cliError(
51094
+ "SEND_DRAFT_NOT_FOUND",
51095
+ [
51096
+ "No saved draft exists for this target.",
51097
+ "To create or update a draft, send message content normally:",
51098
+ ` raft message send --target "${target}" <<'${MESSAGE_HEREDOC_DELIMITER}'`,
51099
+ " message body",
51100
+ ` ${MESSAGE_HEREDOC_DELIMITER}`
51101
+ ].join("\n")
51102
+ );
51103
+ }
51104
+ outgoingContent = savedDraft.content;
51105
+ outgoingAttachmentIds = savedDraft.attachmentIds;
51106
+ previousDraftReholdCount = savedDraft.reholdCount;
51107
+ seenUpToSeq = savedDraft.seenUpToSeq;
51108
+ setFailureDraftSaved(true);
51109
+ } else {
51110
+ const previousDraft = getSavedDraft(agentContext.agentId, target);
51111
+ previousDraftReholdCount = previousDraft?.reholdCount ?? 0;
51112
+ seenUpToSeq = previousDraft?.seenUpToSeq;
51113
+ }
51114
+ if (seenUpToSeq === void 0) {
51115
+ seenUpToSeq = getConsumedSeq(agentContext.agentId, target);
51116
+ }
51117
+ const body = {
51118
+ target,
51119
+ content: outgoingContent,
51120
+ draftReholdCount: previousDraftReholdCount
51121
+ };
51122
+ if (seenUpToSeq !== void 0) {
51123
+ body.seenUpToSeq = seenUpToSeq;
51124
+ }
51125
+ if (opts.sendDraft) {
51126
+ body.sendDraft = true;
51127
+ if (opts.anyway) body.continueAnyway = true;
51128
+ } else {
51129
+ body.draftReplacedExisting = previousDraftReholdCount > 0;
51130
+ }
51131
+ if (outgoingAttachmentIds.length > 0) {
51132
+ body.attachmentIds = outgoingAttachmentIds;
51133
+ }
51134
+ const agentApi = createAgentApiSurfaceClient(client);
51135
+ const res = await agentApi.messages.send(body);
51136
+ if (!res.ok) {
51137
+ const code = res.status >= 500 ? "SERVER_5XX" : "SEND_FAILED";
51138
+ throw cliError(code, res.error ?? `HTTP ${res.status}`);
51139
+ }
51140
+ const data = res.data;
51141
+ if (!data) {
51142
+ throw cliError("INVALID_JSON_RESPONSE", "Agent API messageSend returned an empty response body");
51143
+ }
51144
+ if (data.state === "held") {
51145
+ if (typeof data.seenUpToSeq === "number" && Number.isFinite(data.seenUpToSeq)) {
51146
+ recordConsumedSeqs(agentContext.agentId, { [target]: data.seenUpToSeq });
51147
+ }
51148
+ setSavedDraft(agentContext.agentId, target, {
51149
+ content: outgoingContent,
51150
+ attachmentIds: outgoingAttachmentIds,
51151
+ savedAt: Date.now(),
51152
+ reholdCount: previousDraftReholdCount + 1,
51153
+ seenUpToSeq: data.seenUpToSeq
51154
+ });
51155
+ writeText(ctx.io, formatHeldSendOutput(target, data));
51156
+ return;
51157
+ }
51158
+ clearSavedDraft(agentContext.agentId, target);
51159
+ const shortId = data.messageId ? data.messageId.slice(0, 8) : null;
51160
+ const replyHint = shortId ? ` (to reply in this message's thread, use target "${target.includes(":") ? target : target + ":" + shortId}")` : "";
51161
+ let unreadSection = "";
51162
+ if (data.recentUnread && data.recentUnread.length > 0) {
51163
+ unreadSection = `
51164
+
51165
+ --- New messages you may have missed ---
51166
+ ${formatMessages(data.recentUnread)}`;
51167
+ }
51168
+ const pendingMentionActions = normalizePendingMentionActions(data);
51169
+ const mentionSection = pendingMentionActions.length > 0 ? `
51170
+
51171
+ ${formatPendingMentionActions(pendingMentionActions, { source: "send" }).trimEnd()}` : "";
51172
+ const driveByTip = formatDriveByJoinedToPostTip(target, data);
51173
+ const driveBySection = driveByTip ? `
51174
+
51175
+ ${driveByTip}` : "";
51176
+ writeText(ctx.io, `Message sent to ${target}. Message ID: ${data.messageId}${replyHint}${driveBySection}${mentionSection}${unreadSection}
51177
+ `);
51178
+ }
50363
51179
  var messageSendCommand = defineCommand(
50364
51180
  {
50365
51181
  name: "send",
@@ -50378,131 +51194,14 @@ var messageSendCommand = defineCommand(
50378
51194
  ]
50379
51195
  },
50380
51196
  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
- }
51197
+ let failureDraftSaved = false;
50391
51198
  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
51199
+ await handleMessageSend(ctx, positionalContent, opts, (draftSaved) => {
51200
+ failureDraftSaved = draftSaved;
50486
51201
  });
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)}`;
51202
+ } catch (err) {
51203
+ throw markSendFailureDraftSaved(err, failureDraftSaved);
50499
51204
  }
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
51205
  }
50507
51206
  );
50508
51207
  function registerSendCommand(parent, runtimeOptions = {}) {
@@ -50614,7 +51313,7 @@ function requireTargetAlias(opts) {
50614
51313
  }
50615
51314
 
50616
51315
  // src/commands/message/read.ts
50617
- function parsePositiveInt2(name, raw) {
51316
+ function parsePositiveInt4(name, raw) {
50618
51317
  if (raw === void 0) return void 0;
50619
51318
  const n = Number(raw);
50620
51319
  if (!Number.isFinite(n) || !Number.isInteger(n) || n <= 0) {
@@ -50653,7 +51352,7 @@ function mapReadFailure(res) {
50653
51352
  }
50654
51353
  function validateReadOpts(opts) {
50655
51354
  const channel = requireTargetAlias(opts);
50656
- const limit = parsePositiveInt2("limit", opts.limit);
51355
+ const limit = parsePositiveInt4("limit", opts.limit);
50657
51356
  const before = opts.before?.trim();
50658
51357
  const after = opts.after?.trim();
50659
51358
  return {
@@ -50745,7 +51444,7 @@ function normalizeMemberHandleRef(raw) {
50745
51444
  }
50746
51445
  return handle;
50747
51446
  }
50748
- function parsePositiveInt3(name, raw) {
51447
+ function parsePositiveInt5(name, raw) {
50749
51448
  if (raw === void 0) return void 0;
50750
51449
  const n = Number(raw);
50751
51450
  if (!Number.isFinite(n) || !Number.isInteger(n) || n <= 0) {
@@ -50756,7 +51455,7 @@ function parsePositiveInt3(name, raw) {
50756
51455
  }
50757
51456
  return n;
50758
51457
  }
50759
- function parseNonNegativeInt(name, raw) {
51458
+ function parseNonNegativeInt3(name, raw) {
50760
51459
  if (raw === void 0) return void 0;
50761
51460
  const n = Number(raw);
50762
51461
  if (!Number.isFinite(n) || !Number.isInteger(n) || n < 0) {
@@ -50790,8 +51489,8 @@ function normalizeSearchOpts(opts) {
50790
51489
  message: "--sort relevance requires --query; filter-only search is sorted by recent"
50791
51490
  });
50792
51491
  }
50793
- const limit = parsePositiveInt3("limit", opts.limit);
50794
- const offset = parseNonNegativeInt("offset", opts.offset);
51492
+ const limit = parsePositiveInt5("limit", opts.limit);
51493
+ const offset = parseNonNegativeInt3("offset", opts.offset);
50795
51494
  const sort = opts.sort ?? (query ? void 0 : "recent");
50796
51495
  return {
50797
51496
  ...query ? { query } : {},
@@ -52825,6 +53524,15 @@ function safeUrl2(value, label) {
52825
53524
  }
52826
53525
  return url2;
52827
53526
  }
53527
+ function substituteEndpointPathParams(endpointPath, payload) {
53528
+ return endpointPath.replace(/\{([A-Za-z][A-Za-z0-9_]*)\}/g, (_match, name) => {
53529
+ const value = payload[name];
53530
+ if (value === void 0 || value === null || value === "") {
53531
+ throw cliError("INVALID_ARG", `missing path parameter ${name}`);
53532
+ }
53533
+ return encodeURIComponent(typeof value === "string" ? value : JSON.stringify(value));
53534
+ });
53535
+ }
52828
53536
  function resolveActionUrl(input) {
52829
53537
  const base = input.manifest.execution.base_url ?? input.manifest.app_origin ?? input.service.homepageUrl ?? (input.service.returnUrl ? safeUrl2(input.service.returnUrl, "service return URL").origin : null);
52830
53538
  if (!base) {
@@ -52834,7 +53542,7 @@ function resolveActionUrl(input) {
52834
53542
  );
52835
53543
  }
52836
53544
  const baseUrl = safeUrl2(base, "action base URL");
52837
- return new URL(input.action.endpoint.path, baseUrl);
53545
+ return new URL(substituteEndpointPathParams(input.action.endpoint.path, input.payload), baseUrl);
52838
53546
  }
52839
53547
  function appendPayloadAsQuery(url2, payload) {
52840
53548
  for (const [key, value] of Object.entries(payload)) {
@@ -52842,6 +53550,13 @@ function appendPayloadAsQuery(url2, payload) {
52842
53550
  url2.searchParams.set(key, typeof value === "string" ? value : JSON.stringify(value));
52843
53551
  }
52844
53552
  }
53553
+ function appendResourceLocatorQuery(input) {
53554
+ const { url: url2, action, payload } = input;
53555
+ if (/\{id\}/.test(action.endpoint.path)) return;
53556
+ const id = payload.id;
53557
+ if (id === void 0 || id === null || id === "" || url2.searchParams.has("id")) return;
53558
+ url2.searchParams.set("id", typeof id === "string" ? id : JSON.stringify(id));
53559
+ }
52845
53560
  async function invokeHttpAction(input) {
52846
53561
  const url2 = new URL(input.url);
52847
53562
  const cookie = cookieHeaderForUrl(input.cookies, url2);
@@ -52863,6 +53578,7 @@ async function invokeHttpAction(input) {
52863
53578
  if (input.action.endpoint.method === "GET") {
52864
53579
  appendPayloadAsQuery(url2, input.payload);
52865
53580
  } else {
53581
+ appendResourceLocatorQuery({ url: url2, action: input.action, payload: input.payload });
52866
53582
  headers["content-type"] = "application/json";
52867
53583
  init.body = JSON.stringify(input.payload);
52868
53584
  }
@@ -52919,6 +53635,9 @@ function formatActions(input) {
52919
53635
  lines.push(` endpoint: ${action.endpoint.method} ${action.endpoint.path}`);
52920
53636
  if (action.description) lines.push(` description: ${action.description}`);
52921
53637
  if (required2.length > 0) lines.push(` required params: ${required2.join(", ")}`);
53638
+ if (action.endpoint.method !== "GET" && Object.hasOwn(action.parameters ?? {}, "id") && !/\{id\}/.test(action.endpoint.path)) {
53639
+ lines.push(" note: id is treated as the resource locator and is also sent as query ?id=; JSON body is preserved");
53640
+ }
52922
53641
  }
52923
53642
  lines.push(`next: raft integration invoke --service ${JSON.stringify(input.service.clientId)} --action ${JSON.stringify(actions[0]?.name ?? "<name>")}`);
52924
53643
  return lines.join("\n");
@@ -53028,7 +53747,7 @@ var integrationInvokeCommand = defineCommand(
53028
53747
  { flags: "--list-actions", description: "List manifest actions instead of invoking one" },
53029
53748
  {
53030
53749
  flags: "--param <key=value>",
53031
- description: "Action parameter; repeatable. Use key=@file or key=@- to read text",
53750
+ description: "Action parameter; repeatable. Use key=@file or key=@- to read text. For non-GET actions, id is also sent as query ?id= when the manifest path has no {id}",
53032
53751
  parse: (value, previous = []) => {
53033
53752
  previous.push(value);
53034
53753
  return previous;
@@ -53156,7 +53875,7 @@ var integrationInvokeCommand = defineCommand(
53156
53875
  });
53157
53876
  cookies = session.cookies;
53158
53877
  }
53159
- const url2 = resolveActionUrl({ service, manifest, action });
53878
+ const url2 = resolveActionUrl({ service, manifest, action, payload });
53160
53879
  const result2 = await invokeHttpAction({ url: url2, action, payload, cookies, service });
53161
53880
  if (opts.json) {
53162
53881
  writeJson(cmdCtx.io, {
@@ -53755,6 +54474,7 @@ registerAgentLoginCommand(agentCmd);
53755
54474
  registerAgentListCommand(agentCmd);
53756
54475
  registerAgentBridgeCommand(agentCmd);
53757
54476
  var channelCmd = program2.command("channel").description("Channel membership and attention operations");
54477
+ registerChannelInfoCommand(channelCmd);
53758
54478
  registerChannelMembersCommand(channelCmd);
53759
54479
  registerChannelCreateCommand(channelCmd);
53760
54480
  registerChannelUpdateCommand(channelCmd);
@@ -53769,10 +54489,17 @@ registerThreadUnfollowCommand(threadCmd);
53769
54489
  var serverCmd = program2.command("server").description("Server / workspace introspection");
53770
54490
  registerServerInfoCommand(serverCmd);
53771
54491
  registerServerUpdateCommand(serverCmd);
53772
- var manualCmd = program2.command("manual").description("Raft Manual for Agents retrieval (canonical operating topics)");
54492
+ var userCmd = program2.command("user").description("User and agent introspection");
54493
+ registerUserInfoCommand(userCmd);
54494
+ var manualCmd = program2.command("manual").description("Look up Raft operating topics and agent recipes").addHelpText(
54495
+ "after",
54496
+ '\nCommon agent flows:\n raft manual get index\n raft manual get recipes/seeded\n raft manual get recipes/technique/preview-env\n raft manual search "preview before merge" --scope recipes\n\nUse `raft manual get --help` and `raft manual search --help` for options.\n'
54497
+ );
53773
54498
  registerKnowledgeGetCommand(manualCmd);
54499
+ registerKnowledgeSearchCommand(manualCmd);
53774
54500
  var knowledgeCmd = program2.command("knowledge").description("Legacy alias for `raft manual`");
53775
54501
  registerKnowledgeGetCommand(knowledgeCmd);
54502
+ registerKnowledgeSearchCommand(knowledgeCmd);
53776
54503
  var inboxCmd = program2.command("inbox").description("Inbox target summary operations");
53777
54504
  registerInboxCheckCommand(inboxCmd);
53778
54505
  var messageCmd = program2.command("message").description("Message operations");