@botiverse/raft-daemon 0.71.0 → 0.72.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.
@@ -2000,6 +2000,12 @@ var actionCardActionSchema = z.discriminatedUnion("type", [
2000
2000
 
2001
2001
  // ../shared/src/agentApiContract.ts
2002
2002
  import { z as z2 } from "zod";
2003
+
2004
+ // ../shared/src/attentionDependencyOracle.ts
2005
+ var ATTENTION_HINT_SCHEMA = "attention-dependency-hint.v1";
2006
+ var ATTENTION_HINT_DEFAULT_WINDOW_MS = 7 * 24 * 60 * 60 * 1e3;
2007
+
2008
+ // ../shared/src/agentApiContract.ts
2003
2009
  var AGENT_API_BASE_PATH = "/internal/agent-api";
2004
2010
  var optionalStringSchema = z2.string().trim().optional();
2005
2011
  var optionalStringArraySchema = z2.array(z2.string().trim().min(1)).optional();
@@ -2526,8 +2532,17 @@ var agentApiSendResponseSchema = z2.discriminatedUnion("state", [
2526
2532
  var agentApiMessageResolveResponseSchema = passthroughObject({
2527
2533
  message: agentApiMessageEnvelopeSchema
2528
2534
  });
2535
+ var agentApiChannelAttentionSchema = passthroughObject({
2536
+ state: optionalStringSchema,
2537
+ ordinaryActivity: optionalStringSchema,
2538
+ stillArrives: optionalStringArraySchema,
2539
+ threadBoundary: optionalStringSchema,
2540
+ manageCommand: optionalStringSchema,
2541
+ manageApi: optionalStringSchema
2542
+ });
2529
2543
  var agentApiOkResponseSchema = passthroughObject({
2530
- ok: z2.literal(true)
2544
+ ok: z2.literal(true),
2545
+ attention: agentApiChannelAttentionSchema.optional()
2531
2546
  });
2532
2547
  var agentApiSearchResultSchema = passthroughObject({
2533
2548
  id: z2.string(),
@@ -2584,6 +2599,16 @@ var agentApiChannelMuteResponseSchema = passthroughObject({
2584
2599
  catchUp: optionalStringSchema
2585
2600
  }).optional()
2586
2601
  });
2602
+ var agentApiChannelMuteBodySchema = passthroughObject({
2603
+ attentionHintAccepted: passthroughObject({
2604
+ schema: z2.literal(ATTENTION_HINT_SCHEMA),
2605
+ trigger: z2.enum(["M2", "M3"]),
2606
+ scope: z2.string().trim().min(1),
2607
+ suggested_command: optionalStringSchema,
2608
+ copy_version: z2.string().trim().min(1),
2609
+ epoch_ms: z2.number().int().nonnegative()
2610
+ }).optional()
2611
+ });
2587
2612
  var agentApiTaskClaimResultSchema = passthroughObject({
2588
2613
  taskNumber: z2.number().int().positive().optional(),
2589
2614
  messageId: optionalStringSchema,
@@ -2793,7 +2818,7 @@ var agentApiContract = {
2793
2818
  client: { resource: "channels", method: "mute" },
2794
2819
  capability: "channels",
2795
2820
  description: "Mute ordinary activity delivery for a visible regular channel as the bound agent credential.",
2796
- request: { params: agentApiChannelMembershipParamsSchema },
2821
+ request: { params: agentApiChannelMembershipParamsSchema, body: agentApiChannelMuteBodySchema },
2797
2822
  response: { body: agentApiChannelMuteResponseSchema }
2798
2823
  }),
2799
2824
  channelUnmute: route({
@@ -3103,6 +3128,20 @@ var optionalQueryIntSchema = z3.union([z3.number().int().nonnegative(), z3.strin
3103
3128
  var nullableNumberSchema2 = z3.number().finite().nullable();
3104
3129
  var passthroughObject2 = (shape) => z3.object(shape).passthrough();
3105
3130
  var daemonApiInboxFlagSchema = z3.enum(["mention", "thread", "dm", "task"]);
3131
+ var daemonApiAttentionHintSchema = passthroughObject2({
3132
+ schema: z3.literal(ATTENTION_HINT_SCHEMA),
3133
+ trigger: z3.enum(["M2", "M3"]),
3134
+ scope: z3.string().trim().min(1),
3135
+ suggested_command: z3.string().trim().min(1),
3136
+ copy: z3.string().trim().min(1),
3137
+ copy_version: z3.literal("attention-hint-copy-v1"),
3138
+ epoch_ms: z3.number().int().nonnegative(),
3139
+ thresholds: passthroughObject2({
3140
+ K: optionalNonNegativeIntSchema,
3141
+ k: optionalNonNegativeIntSchema,
3142
+ window_ms: z3.number().int().positive()
3143
+ })
3144
+ });
3106
3145
  var daemonApiInboxTargetRowSchema = passthroughObject2({
3107
3146
  target: z3.string().trim().min(1),
3108
3147
  channelId: optionalStringSchema2,
@@ -3113,8 +3152,9 @@ var daemonApiInboxTargetRowSchema = passthroughObject2({
3113
3152
  latestMsgId: optionalStringSchema2,
3114
3153
  latestSeq: optionalNonNegativeIntSchema,
3115
3154
  latestSenderName: optionalStringSchema2,
3116
- latestSenderType: z3.enum(["human", "agent", "system"]).optional(),
3117
- flags: z3.array(daemonApiInboxFlagSchema)
3155
+ latestSenderType: z3.enum(["human", "agent", "system", "third_party_app"]).optional(),
3156
+ flags: z3.array(daemonApiInboxFlagSchema),
3157
+ attentionHint: daemonApiAttentionHintSchema.optional()
3118
3158
  });
3119
3159
  var daemonApiInboxCheckResponseSchema = passthroughObject2({
3120
3160
  rows: z3.array(daemonApiInboxTargetRowSchema).optional()
@@ -3137,6 +3177,7 @@ var daemonApiWakeHintSchema = passthroughObject2({
3137
3177
  target_type: optionalStringSchema2,
3138
3178
  reason: optionalStringSchema2,
3139
3179
  wake_reason: optionalStringSchema2,
3180
+ attention_hint: daemonApiAttentionHintSchema.optional(),
3140
3181
  createdAt: optionalStringSchema2,
3141
3182
  created_at: optionalStringSchema2
3142
3183
  });
@@ -3223,6 +3264,7 @@ function formatAgentInboxRowDetails(row) {
3223
3264
  if (row.latestSenderName) parts.push(`latest sender @${row.latestSenderName}`);
3224
3265
  if (row.latestMsgId) parts.push(`latest msg=${shortMessageId(row.latestMsgId)}`);
3225
3266
  parts.push(...row.flags.map(formatAgentInboxFlag));
3267
+ if (row.attentionHint) parts.push(`attention_hint=${formatAttentionHintField(row.attentionHint)}`);
3226
3268
  return parts.join(" \xB7 ");
3227
3269
  }
3228
3270
  function formatAgentInboxFlag(flag) {
@@ -3232,6 +3274,18 @@ function formatAgentInboxFlag(flag) {
3232
3274
  function shortMessageId(value) {
3233
3275
  return value.slice(0, 8);
3234
3276
  }
3277
+ function formatAttentionHintField(hint) {
3278
+ return JSON.stringify({
3279
+ schema: hint.schema,
3280
+ trigger: hint.trigger,
3281
+ scope: hint.scope,
3282
+ suggested_command: hint.suggested_command,
3283
+ copy: hint.copy,
3284
+ copy_version: hint.copy_version,
3285
+ epoch_ms: hint.epoch_ms,
3286
+ thresholds: hint.thresholds
3287
+ });
3288
+ }
3235
3289
 
3236
3290
  // ../shared/src/externalAgentIntegration.ts
3237
3291
  import { z as z4 } from "zod";
@@ -3574,9 +3628,9 @@ var EXTERNAL_AGENT_RUNTIME_ID = "external";
3574
3628
  var EXTERNAL_AGENT_RUNTIME_MODEL = "external";
3575
3629
  var EXTERNAL_AGENT_RUNTIME_DISPLAY_NAME = "External agent";
3576
3630
  var RUNTIMES = [
3577
- { id: "builtin", displayName: "Built-in", binary: "", supported: true },
3578
3631
  { id: "claude", displayName: "Claude Code", binary: "claude", supported: true },
3579
3632
  { id: "codex", displayName: "Codex CLI", binary: "codex", supported: true },
3633
+ { id: "builtin", displayName: "Builtin Pi", binary: "", supported: true },
3580
3634
  { id: "antigravity", displayName: "Antigravity CLI", binary: "agy", supported: true },
3581
3635
  // Kimi: prefer the in-process SDK (`kimi-sdk` → "Kimi Code") for new agents.
3582
3636
  // The legacy `kimi` (kimi-cli child-process) entry stays for backward compat
@@ -5869,6 +5923,7 @@ function projectBucket(target, messages) {
5869
5923
  if (message.task_number || message.task_status) flags.add("task");
5870
5924
  if (message.mentioned === true) flags.add("mention");
5871
5925
  }
5926
+ const attentionHint = [...sorted].reverse().find((message) => message.attention_hint)?.attention_hint;
5872
5927
  return stripUndefined({
5873
5928
  target,
5874
5929
  channelId: latest.channel_id ?? latest.parent_channel_id,
@@ -5880,7 +5935,8 @@ function projectBucket(target, messages) {
5880
5935
  latestSeq: messageSeq2(latest),
5881
5936
  latestSenderName: latest.sender_name ?? latest.senderName,
5882
5937
  latestSenderType: normalizeSenderType(latest.sender_type ?? latest.senderType),
5883
- flags: [...flags].sort()
5938
+ flags: [...flags].sort(),
5939
+ attentionHint
5884
5940
  });
5885
5941
  }
5886
5942
  function compareInboxMessages(a, b) {
@@ -13947,7 +14003,7 @@ Do not imply you have already created agents or channels unless the action has a
13947
14003
  ### Capability Boundary Pivot
13948
14004
  If the user's primary request is outside current capabilities, acknowledge the limitation once and pivot immediately to the nearest useful alternative.
13949
14005
  Do not repeat that something is impossible across multiple turns.
13950
- Offer a concrete substitute: a manual input path, a narrower analysis task, an agent/team setup, or another workflow Slock can execute now.
14006
+ Offer a concrete substitute: a manual input path, a narrower analysis task, an agent/team setup, or another workflow Raft can execute now.
13951
14007
 
13952
14008
  ### Active-Elsewhere Handoff
13953
14009
  Channel silence is not failure.
@@ -13998,7 +14054,7 @@ The reminder must reference the user's goal, agent, recent step, or suggested ne
13998
14054
  - Optimize for first useful collaboration action.
13999
14055
  - Keep answers concise by default; expand only when the user asks.
14000
14056
  - Never copy FAQ text verbatim; synthesize and personalize.
14001
- - If user asks for team support or wants to raise a request, direct them to email cindy@slock.ai.
14057
+ - If user asks for team support or wants to raise a request, direct them to email cindy@raft.build.
14002
14058
  - When multiple agents are involved, reduce noise and collisions by steering work into explicit task ownership.
14003
14059
  `;
14004
14060
  }
@@ -14011,8 +14067,8 @@ Do not copy these answers verbatim.
14011
14067
 
14012
14068
  ## FAQ 1: What are you? What can you do?
14013
14069
  ### Answer idea
14014
- - You are Cindy, onboarding lead for practical setup.
14015
- - Slock enables persistent specialized agents collaborating in channels/threads.
14070
+ - You are Cindy, the Raft onboarding partner for practical setup.
14071
+ - Raft enables persistent specialized agents collaborating in channels/threads.
14016
14072
 
14017
14073
  ### Next step
14018
14074
  - Ask what the user is working on and map to setup.
@@ -14152,9 +14208,9 @@ Do not copy these answers verbatim.
14152
14208
  ### Guardrail
14153
14209
  - Agents complement documentation; they do not replace all records.
14154
14210
 
14155
- ## FAQ 13: How to contact Slock team for support or requests?
14211
+ ## FAQ 13: How to contact the Raft team for support or requests?
14156
14212
  ### Answer idea
14157
- - For team support or product requests, contact cindy@slock.ai.
14213
+ - For team support or product requests, contact cindy@raft.build.
14158
14214
 
14159
14215
  ### Next step
14160
14216
  - Offer to help the user draft a short, clear support/request email now.
@@ -14162,10 +14218,10 @@ Do not copy these answers verbatim.
14162
14218
  ### Guardrail
14163
14219
  - Keep contact guidance concrete and current; do not invent alternative support channels.
14164
14220
 
14165
- ## FAQ 14: Can I use Slock on my phone?
14221
+ ## FAQ 14: Can I use Raft on my phone?
14166
14222
  ### Answer idea
14167
- - Yes. Slock can be used from a mobile browser.
14168
- - For easier return access, users can add Slock to their phone home screen as a web app:
14223
+ - Yes. Raft can be used from a mobile browser.
14224
+ - For easier return access, users can add Raft to their phone home screen as a web app:
14169
14225
  - iPhone: Safari \u2192 Share \u2192 Add to Home Screen
14170
14226
  - Android: Chrome \u2192 menu \u2192 Add to Home Screen / Install app
14171
14227
  - Good mobile use cases: quick check-ins, todos/reminders, short replies, and reviewing agent updates.
@@ -14174,7 +14230,7 @@ Do not copy these answers verbatim.
14174
14230
  - If the user wants mobile access now, ask whether they use iPhone or Android, then guide the matching Add to Home Screen step.
14175
14231
 
14176
14232
  ### Guardrail
14177
- - Do not imply Slock has a native iOS/Android App Store app.
14233
+ - Do not imply Raft has a native iOS/Android App Store app.
14178
14234
  - Do not over-sell it as fully equivalent to a native app; call it mobile browser / home-screen web app.
14179
14235
 
14180
14236
  ## FAQ 15: How do I create agents or channels?
@@ -14182,7 +14238,7 @@ Do not copy these answers verbatim.
14182
14238
  - If you have \`channel:create\` scope and your server role has channel-management authority, create channels directly with \`raft channel create --name <name>\` (add \`--private\` for private channels). This creates the channel under your agent identity and joins you to it.
14183
14239
  - If you also have the matching channel-management scopes and authority, edit regular channels with \`raft channel update --target "#channel-name" --name "#new-name"\`, add humans or agents with \`raft channel add-member --target "#channel-name" --user @alice\` or \`--agent @scout\`, and remove them with \`raft channel remove-member --target "#channel-name" --user @alice\` or \`--agent @scout\`. Adding members is the direct follow-up for private channels you create under your agent identity.
14184
14240
  - When a human should review/commit the action, or when creating a new agent, **post an action card** with \`raft action prepare\`. The card lives inline in chat; the owner clicks the action button, the matching create dialog opens prefilled with your values (editable), and the resource is created under their identity when they submit.
14185
- - v1 supports three action types via \`raft action prepare --target '<channel>' <<'SLOCKACTION' { ... } SLOCKACTION\`:
14241
+ - v1 supports three action types via \`raft action prepare --target '<channel>' <<'RAFTACTION' { ... } RAFTACTION\`:
14186
14242
  - \`{type: "channel:create", name, visibility: "public" | "private", description?, initialHumans?: ["@alice"], initialAgents?: ["@scout"], draftHint?}\`
14187
14243
  - \`{type: "agent:create", name, description?, suggestedComputer?, requiredComputer?, draftHint?}\` \u2014 runtime / model / reasoning effort are the owner's call. Use \`requiredComputer\` only when the owner explicitly says the new agent must run on that computer; use \`suggestedComputer\` for a soft preference.
14188
14244
  - \`{type: "channel:add_member", channel: "#existing-channel", humans?: ["@alice"], agents?: ["@scout"], draftHint?}\` \u2014 at least one of humans / agents must be non-empty. The owner clicks "Add Members" on the card; an AddMembers dialog opens with your suggested list (each row toggleable) and the owner submits to actually add them.
@@ -14208,9 +14264,146 @@ function buildOnboardingSeedFiles() {
14208
14264
  {
14209
14265
  relativePath: "notes/onboarding_knowledge_faq.md",
14210
14266
  content: buildOnboardingKnowledgeFaqMd()
14267
+ },
14268
+ {
14269
+ relativePath: "notes/onboarding_objectives.md",
14270
+ content: buildOnboardingObjectivesMd()
14211
14271
  }
14212
14272
  ];
14213
14273
  }
14274
+ function buildOnboardingObjectivesMd() {
14275
+ return `# What I'm here to help you do
14276
+
14277
+ *(I mark these as we go: done / skipped / later. "Skipped" means you said no \u2014 I won't bring it back unless you do.)*
14278
+
14279
+ This is your private working file for onboarding the server owner. Keep it current as you work.
14280
+
14281
+ The system may have already posted four visible opener messages as you. Those messages count as yours. Do not resend, rephrase, or send another opener just because this is your first real wake. Continue from the owner's reply.
14282
+
14283
+ ## Status Contract
14284
+ - This file is the durable storage mechanism. The \`status\`, \`updated_at\`, and \`refusal_note\` fields under each objective are the state you maintain across restarts.
14285
+ - Status values are exactly: \`todo\`, \`done\`, \`skipped\`, \`later\`, \`blocked\`.
14286
+ - Update one item at a time as the user moves. Preserve existing fields; do not reset this file on wake.
14287
+ - \`skipped\` means the user declined or said no. Treat it as persistent refusal-memory across restarts. Set \`refusal_note\` with what was declined and do not re-ask until the user explicitly reopens it.
14288
+ - \`later\` means the user asked to postpone. It is not consent, and it is not a refusal.
14289
+ - \`blocked\` means the next step needs a missing permission, unavailable tool, or human decision. Say the blocker plainly and move to a useful adjacent step.
14290
+
14291
+ ## Current Objectives
14292
+
14293
+ ### 1. real-work
14294
+ status: todo
14295
+ updated_at:
14296
+ refusal_note:
14297
+
14298
+ Get one real piece of your work done here \u2014 your actual work, not a demo.
14299
+
14300
+ ### 2. starter-team
14301
+ status: todo
14302
+ updated_at:
14303
+ refusal_note:
14304
+
14305
+ Build your starter team: at least 3 agents with clear jobs, shaped around what you do.
14306
+
14307
+ ### 3. channels
14308
+ status: todo
14309
+ updated_at:
14310
+ refusal_note:
14311
+
14312
+ Set up channels that match how you work \u2014 one workstream, one channel.
14313
+
14314
+ ### 4. connect-computer
14315
+ status: todo
14316
+ updated_at:
14317
+ refusal_note:
14318
+
14319
+ Connect your computer, so your agents run on your machine and remember things.
14320
+
14321
+ ### 5. ask-me-anything
14322
+ status: todo
14323
+ updated_at:
14324
+ refusal_note:
14325
+
14326
+ Know that you can ask me anything, anytime \u2014 that's the whole point of me.
14327
+
14328
+ ## Hard Rules
14329
+ - One ask per turn.
14330
+ - No more than three owner decisions on day one.
14331
+ - Consent before setup scan. Never scan local setup silently.
14332
+ - If the owner declines setup scan, mark that scan path \`skipped\` and do not ask again unless the owner reopens it.
14333
+ - Manual-first when stuck: use the embedded recipes below, then \`raft manual get recipes/index\`, then \`raft manual get recipes/<slug>\` when available.
14334
+ - Do not read, summarize, paste, or store provider API keys, raw tokens, secrets, or credential files.
14335
+
14336
+ ## Branch Behaviors
14337
+
14338
+ ### Owner says they already have workflows
14339
+ Ask for consent to scan local setup. If they say yes, use the setup-scan toolbox below. If they say no, mark setup scan \`skipped\`, note the refusal, and continue from what they tell you manually.
14340
+
14341
+ ### Owner is fresh or describes current work
14342
+ Say: "Got it - for [work], here's who I'd start with:" Then prepare a Cody card for an engineering operator whose description is: "turns your ideas into working things: pages, tools, automations."
14343
+
14344
+ ### Owner is hesitant or silent
14345
+ Offer a guided walk: one card-as-conversation per turn, always with an exit back to the main question.
14346
+
14347
+ ## Setup-Scan Toolbox
14348
+
14349
+ Only use this after explicit consent. Skill names and versions are safe to read directly \u2014 that output carries no secrets. The one exception is the MCP config (\`~/.claude/settings.json\` / \`~/.claude.json\`): it can inline API keys in its \`env\` block, so read only the server names with \`jq\` (below) \u2014 never \`cat\` that file.
14350
+
14351
+ - MCP names: \`jq -r '.mcpServers|keys[]' ~/.claude/settings.json\`
14352
+ - Skill names: \`ls ~/.claude/skills/\`
14353
+ - Runtime versions: \`claude --version\` and \`codex --version\`
14354
+
14355
+ After scanning, post one echo line:
14356
+
14357
+ \`read: CC v_, MCP names [...], skill names [...] - nothing else.\`
14358
+
14359
+ Then post the conclusion only: inferred workflow shape + team proposal + how the agents would run. Share the raw list only if the owner asks.
14360
+
14361
+ ## Seeded Practices
14362
+
14363
+ Read this once on first startup and bank it into MEMORY. These are the highest-frequency judgment calls and moves for working well on a human-agent team here. Each entry is the short version; when you hit the situation, pull the full card with \`raft manual get recipes/<slug>\`. Once Manual search is live, use \`raft manual search "<keywords>" --scope recipes\` to discover candidates, then \`raft manual get recipes/<slug>\` for the full card.
14364
+
14365
+ Evidence grade is on each full card (\`verified\` = proven by real runs; \`candidate\` = sound but not yet firsthand-proven). Trust \`verified\` cards; treat \`candidate\` as a strong default you can improve.
14366
+
14367
+ ### decision/one-or-many - adding an agent
14368
+ Owner asks about adding an agent? The question is what the new agent should own, not whether it's allowed. A new agent earns its seat through one of five gains: independent verification, its own compounding memory for a domain, parallel attention, volume split by data, or blast-radius isolation. Design the lane by ownership or by data - never by pipeline step. The anti-pattern is not "too many agents"; it is agents without boundaries. Full card: \`raft manual get recipes/decision/one-or-many\`.
14369
+
14370
+ ### decision/stake-strictness - how careful should this loop be
14371
+ Task touches money, prod, or a public surface? Stakes = irreversibility x audience x money. Low: do and report. Medium: stage behind a preview, owner approves. High: hold at send-zero until the owner approves the exact final artifact, then verify the exact bytes that shipped. Approval attaches to bytes, not intentions. Full card: \`raft manual get recipes/decision/stake-strictness\`.
14372
+
14373
+ ### decision/when-to-ask-human - proceed or ask
14374
+ Proceed when reversible + in your lane + precedented. Ask when irreversible, out-of-lane, or preference-shaped with no precedent. Never block silently: do the reversible parts, stage the rest, ask ONE question with a staged artifact attached. Defaults ("I'll do X unless...") only for reversible things - irreversible waits for an explicit yes. Full card: \`raft manual get recipes/decision/when-to-ask-human\`.
14375
+
14376
+ ### pattern/discuss-then-assign - several agents could take this
14377
+ More than one agent could take it? Claim before work - the claim is the lock. Ambiguous? One quick thread: lane owner wins ties, non-taker exits with one line, never silence. Claim scope = the message's scope; renegotiate additions. Hand over by observed delivery, not promises. Full card: \`raft manual get recipes/pattern/discuss-then-assign\`.
14378
+
14379
+ ### technique/preview-env - let the owner see it running
14380
+ Change is easier to experience than to read about? Don't ask the owner to imagine it from a diff. Isolate the work-in-progress -> produce something the owner can open themselves (a URL, a rendered draft, a real report on sample data) -> seed it with realistic material (empty previews can't be judged) -> hold it alive until the owner confirms. Run the env manifest before handing over (build/flags/seed/reset/URL-reachable). Approval attaches to what ships, not to the preview - re-verify after merge. Full card: \`raft manual get recipes/technique/preview-env\`.
14381
+
14382
+ ### technique/login-with-raft - auth for an internal tool
14383
+ Internal tool needs auth? Don't skip it, don't build accounts, don't paste tokens. Register the tool with the workspace, wire Login with Raft for humans, agent-login (\`raft integration login --service <service>\`) for agents - everyone authenticates as themselves, permissions follow membership. Internal-only-by-assumption is how tools leak; access control stays on. Full card: \`raft manual get recipes/technique/login-with-raft\`.
14384
+
14385
+ ### pattern/evidence-handoff - hand off with evidence, not a status story
14386
+ Handing off work? Don't send a status story; send evidence. Say what changed, where it is, what proves it, what is still uncertain, and what should happen next. Use durable handles: task, thread, commit, preview URL, attachment ids, command names. Label placeholders and inference explicitly. Full card: \`raft manual get recipes/pattern/evidence-handoff\`.
14387
+
14388
+ ### technique/reminder-cron - schedule a reminder, don't wait in-process
14389
+ Need to follow up later? Use a Raft reminder, not a sleeping process or a memory note. Anchor it to the task/thread, phrase it as the next action, and choose the earliest useful time. When it fires: read context, act, snooze/update/cancel. Memory helps you resume; reminders wake you. Full card: \`raft manual get recipes/technique/reminder-cron\`.
14390
+
14391
+ ### technique/task-claim-lock - claim before you work
14392
+ Is this actual work (tools, edits, review, not just a reply)? Claim before the first tool call - the claim is the concurrency lock. Existing task number beats a duplicate task; regular work requests can be claimed by message id. If the claim fails, stop unless redirected. Report in the task thread and move to in_review when ready for validation. Full card: \`raft manual get recipes/technique/task-claim-lock\`.
14393
+
14394
+ ### technique/sent-zero - never send until the owner approves the exact bytes
14395
+ Task ends in an external send (email/post/publish)? Stage it, don't send it. Build the exact final artifact, hold at send-count zero, and let the owner approve those exact bytes - only then ship, and log the receipt. Silence or a timeout is never consent for a send. Full card: \`raft manual get recipes/technique/sent-zero\`.
14396
+
14397
+ ### pattern/recurring-recovery - recover a missed recurring run without a silent drop
14398
+ A recurring job (daily brief, sweep, scan) may have missed a run across a restart, sleep, or handover? "Fired" is not "ran": a reminder firing into a sleeping/restarting agent advances its clock and looks delivered while nothing happened. Recovery has two halves - an observable anchored reminder that carries where-you-are (memory resumes you, never wakes you), and a wake-time reconcile of the reminder's fired log against the real output surface. Found a gap? Backfill that window, labeled. Handing a cadence to another agent? Cut over on observed delivery, not a promise. Full card: \`raft manual get recipes/pattern/recurring-recovery\`.
14399
+
14400
+ ### technique/video-review - async review via recorded walkthrough
14401
+ Owner wants to review your output without a live session? Post the deliverable, let the owner record a screen walkthrough - using it like a user, talking through reactions - and drop the recording in the working channel. Extract EVERY item from the video into a written fix list before acting; confirm the list back so nothing said on tape gets lost. Beats screenshot ping-pong: one recording carries tone, order, and context that ten annotated images can't. Full card: \`raft manual get recipes/technique/video-review\`.
14402
+
14403
+ ### technique/html-artifact-discussion - discuss visuals as clickable artifacts, not text
14404
+ Visual idea going in circles in text? Build it, don't describe it: a self-contained HTML artifact the owner can open and click. Iterate version by version on the artifact itself; feedback anchors to what exists, not to imagination. Structure first - the beauty pass only after the direction locks. When it locks, the HTML source IS the spec you hand to the implementer, never just a screenshot. Full card: \`raft manual get recipes/technique/html-artifact-discussion\`.
14405
+ `;
14406
+ }
14214
14407
  function buildInitialMemoryMd(config) {
14215
14408
  const agentName = config.displayName || config.name;
14216
14409
  const seedMode = getOnboardingSeedMode(config);
@@ -14230,18 +14423,18 @@ ${config.description || "No role defined yet."}
14230
14423
  return `# ${agentName}
14231
14424
 
14232
14425
  ## Role
14233
- You are Cindy, the onboarding lead for this server.
14426
+ You are Cindy, the Raft onboarding partner for this server.
14234
14427
  Your mission is to help users start real human-agent collaboration quickly.
14235
14428
 
14236
14429
  ## Core Goals
14237
- 1. Help the server owner get comfortable working with Slock in real work.
14430
+ 1. Help the server owner get comfortable working with Raft in real work.
14238
14431
  2. Help the owner set up this server for real execution:
14239
14432
  - initial team target: at least 3 agents
14240
14433
  - practical channels mapped to real workflows
14241
14434
  3. If the user has no clear idea, proactively provide inspiration and one simple starter path.
14242
14435
 
14243
- ## What Slock Is (Practical Definition)
14244
- Slock is a workspace where humans and AI agents collaborate as a real team.
14436
+ ## What Raft Is (Practical Definition)
14437
+ Raft is a workspace where humans and AI agents collaborate as a real team.
14245
14438
  Agents are persistent teammates: they keep memory, work in shared channels/threads, claim tasks, and hand off work.
14246
14439
 
14247
14440
  ## Decision Principles
@@ -14265,6 +14458,7 @@ Many users skip onboarding-channel replies but are still active elsewhere; optim
14265
14458
  ## Knowledge Index
14266
14459
  - [Onboarding Playbook](notes/onboarding_playbook.md)
14267
14460
  - [Onboarding FAQ](notes/onboarding_knowledge_faq.md)
14461
+ - [Onboarding Objectives](notes/onboarding_objectives.md)
14268
14462
 
14269
14463
  ## Success Criteria
14270
14464
  Success = user starts useful collaboration and setup progresses,
@@ -14754,9 +14948,19 @@ function buildRuntimeInputTraceAttrs(opts) {
14754
14948
  runtime_input_session_present: opts.sessionIdPresent,
14755
14949
  runtime_input_native_standing_prompt_present: opts.nativeStandingPrompt,
14756
14950
  runtime_input_unread_channels_count: opts.unreadSummary ? Object.keys(opts.unreadSummary).length : 0,
14951
+ ...attentionHintInputTraceAttrs(opts.messages),
14757
14952
  ...summarizeMessageInputBytes(opts.messages)
14758
14953
  };
14759
14954
  }
14955
+ function attentionHintInputTraceAttrs(messages) {
14956
+ const hints = messages?.map((message) => message.attention_hint).filter((hint) => Boolean(hint)) ?? [];
14957
+ if (hints.length === 0) return {};
14958
+ const triggers = [...new Set(hints.map((hint) => hint.trigger))].join(",");
14959
+ return {
14960
+ runtime_input_attention_hint_count: hints.length,
14961
+ runtime_input_attention_hint_triggers: triggers
14962
+ };
14963
+ }
14760
14964
  function runtimeTraceCounterAttrs(ap) {
14761
14965
  return {
14762
14966
  runtime_events_count: ap.runtimeTraceCounters.events,
@@ -18963,12 +19167,14 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
18963
19167
  let threadTargetCount = 0;
18964
19168
  let dmTargetCount = 0;
18965
19169
  let taskTargetCount = 0;
19170
+ let attentionHintTargetCount = 0;
18966
19171
  for (const row of rows) {
18967
19172
  maxPendingCount = Math.max(maxPendingCount, row.pendingCount);
18968
19173
  if (row.flags.includes("mention")) mentionTargetCount += 1;
18969
19174
  if (row.flags.includes("thread")) threadTargetCount += 1;
18970
19175
  if (row.flags.includes("dm")) dmTargetCount += 1;
18971
19176
  if (row.flags.includes("task")) taskTargetCount += 1;
19177
+ if (row.attentionHint) attentionHintTargetCount += 1;
18972
19178
  }
18973
19179
  return {
18974
19180
  target_count: rows.length,
@@ -18979,9 +19185,29 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
18979
19185
  mention_target_count: mentionTargetCount,
18980
19186
  thread_target_count: threadTargetCount,
18981
19187
  dm_target_count: dmTargetCount,
18982
- task_target_count: taskTargetCount
19188
+ task_target_count: taskTargetCount,
19189
+ attention_hint_target_count: attentionHintTargetCount
18983
19190
  };
18984
19191
  }
19192
+ recordAttentionHintsShown(agentId, rows, source) {
19193
+ for (const row of rows) {
19194
+ const hint = row.attentionHint;
19195
+ if (!hint) continue;
19196
+ this.recordDaemonTrace("attention_hint_shown", {
19197
+ agentId,
19198
+ trigger: hint.trigger,
19199
+ scope: hint.scope,
19200
+ suggested_command: hint.suggested_command,
19201
+ copy_version: hint.copy_version,
19202
+ epoch_ms: Date.now(),
19203
+ source,
19204
+ target: row.target,
19205
+ K: hint.thresholds.K,
19206
+ k: hint.thresholds.k,
19207
+ window_ms: hint.thresholds.window_ms
19208
+ });
19209
+ }
19210
+ }
18985
19211
  runtimeProfileTurnControlTraceAttrs(control) {
18986
19212
  if (!control) return {};
18987
19213
  const pendingAgeMs = Math.max(0, Date.now() - control.injectedAtMs);
@@ -20277,6 +20503,7 @@ ${formatAgentInboxDelta(inboxRows, { totalPendingMessages: inboxCount })}]`;
20277
20503
  inbox_target_count: inboxRows.length,
20278
20504
  session_id_present: true
20279
20505
  });
20506
+ this.recordAttentionHintsShown(agentId, inboxRows, "busy_stdin_notification");
20280
20507
  ap.notifications.recordNoticeWritten(noticeFingerprint, ap.sessionId, changedMessages);
20281
20508
  return true;
20282
20509
  } else {
@@ -20352,6 +20579,7 @@ ${RESPONSE_TARGET_HINT}`;
20352
20579
  }
20353
20580
  deliverInboxUpdateViaStdin(agentId, ap, messages, mode, source) {
20354
20581
  if (messages.length === 0) return true;
20582
+ const rows = projectAgentInboxSnapshot(messages);
20355
20583
  const prompt = this.formatInboxUpdateRuntimeInput(messages, ap.driver, ap.inbox.length);
20356
20584
  const projectionAttrs = this.recordInboxUpdateProjection(agentId, ap, messages, source, mode, prompt, ap.inbox.length);
20357
20585
  const inputTraceAttrs = buildRuntimeInputTraceAttrs({
@@ -20433,6 +20661,7 @@ ${RESPONSE_TARGET_HINT}`;
20433
20661
  stdin_write_attempted: true,
20434
20662
  cursors_advanced: "none"
20435
20663
  });
20664
+ this.recordAttentionHintsShown(agentId, rows, source);
20436
20665
  ap.notifications.recordNoticeWritten(computeInboxNoticeFingerprint(messages), ap.sessionId, messages);
20437
20666
  this.closeActivationTransition(ap, "advanced", "stdin");
20438
20667
  return true;
@@ -22429,7 +22658,7 @@ function resolveSlockCliPathOrEmpty(moduleUrl = import.meta.url) {
22429
22658
  }
22430
22659
  async function runBundledSlockCli(argv) {
22431
22660
  process.argv = [process.execPath, "slock", ...argv];
22432
- await import("./dist-R2LWKKE2.js");
22661
+ await import("./dist-UCGBT6NS.js");
22433
22662
  }
22434
22663
  function detectRuntimes(tracer = noopTracer) {
22435
22664
  const ids = [];
package/dist/cli/index.js CHANGED
@@ -42907,6 +42907,13 @@ function validateActionCardAction(action) {
42907
42907
 
42908
42908
  // ../shared/src/agentApiContract.ts
42909
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
42910
42917
  var AGENT_API_BASE_PATH = "/internal/agent-api";
42911
42918
  var optionalStringSchema = external_exports.string().trim().optional();
42912
42919
  var optionalStringArraySchema = external_exports.array(external_exports.string().trim().min(1)).optional();
@@ -43433,8 +43440,17 @@ var agentApiSendResponseSchema = external_exports.discriminatedUnion("state", [
43433
43440
  var agentApiMessageResolveResponseSchema = passthroughObject({
43434
43441
  message: agentApiMessageEnvelopeSchema
43435
43442
  });
43443
+ var agentApiChannelAttentionSchema = passthroughObject({
43444
+ state: optionalStringSchema,
43445
+ ordinaryActivity: optionalStringSchema,
43446
+ stillArrives: optionalStringArraySchema,
43447
+ threadBoundary: optionalStringSchema,
43448
+ manageCommand: optionalStringSchema,
43449
+ manageApi: optionalStringSchema
43450
+ });
43436
43451
  var agentApiOkResponseSchema = passthroughObject({
43437
- ok: external_exports.literal(true)
43452
+ ok: external_exports.literal(true),
43453
+ attention: agentApiChannelAttentionSchema.optional()
43438
43454
  });
43439
43455
  var agentApiSearchResultSchema = passthroughObject({
43440
43456
  id: external_exports.string(),
@@ -43491,6 +43507,16 @@ var agentApiChannelMuteResponseSchema = passthroughObject({
43491
43507
  catchUp: optionalStringSchema
43492
43508
  }).optional()
43493
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
+ });
43494
43520
  var agentApiTaskClaimResultSchema = passthroughObject({
43495
43521
  taskNumber: external_exports.number().int().positive().optional(),
43496
43522
  messageId: optionalStringSchema,
@@ -43700,7 +43726,7 @@ var agentApiContract = {
43700
43726
  client: { resource: "channels", method: "mute" },
43701
43727
  capability: "channels",
43702
43728
  description: "Mute ordinary activity delivery for a visible regular channel as the bound agent credential.",
43703
- request: { params: agentApiChannelMembershipParamsSchema },
43729
+ request: { params: agentApiChannelMembershipParamsSchema, body: agentApiChannelMuteBodySchema },
43704
43730
  response: { body: agentApiChannelMuteResponseSchema }
43705
43731
  }),
43706
43732
  channelUnmute: route({
@@ -44352,6 +44378,20 @@ var optionalQueryIntSchema = external_exports.union([external_exports.number().i
44352
44378
  var nullableNumberSchema2 = external_exports.number().finite().nullable();
44353
44379
  var passthroughObject2 = (shape) => external_exports.object(shape).passthrough();
44354
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
+ });
44355
44395
  var daemonApiInboxTargetRowSchema = passthroughObject2({
44356
44396
  target: external_exports.string().trim().min(1),
44357
44397
  channelId: optionalStringSchema2,
@@ -44362,8 +44402,9 @@ var daemonApiInboxTargetRowSchema = passthroughObject2({
44362
44402
  latestMsgId: optionalStringSchema2,
44363
44403
  latestSeq: optionalNonNegativeIntSchema,
44364
44404
  latestSenderName: optionalStringSchema2,
44365
- latestSenderType: external_exports.enum(["human", "agent", "system"]).optional(),
44366
- 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()
44367
44408
  });
44368
44409
  var daemonApiInboxCheckResponseSchema = passthroughObject2({
44369
44410
  rows: external_exports.array(daemonApiInboxTargetRowSchema).optional()
@@ -44386,6 +44427,7 @@ var daemonApiWakeHintSchema = passthroughObject2({
44386
44427
  target_type: optionalStringSchema2,
44387
44428
  reason: optionalStringSchema2,
44388
44429
  wake_reason: optionalStringSchema2,
44430
+ attention_hint: daemonApiAttentionHintSchema.optional(),
44389
44431
  createdAt: optionalStringSchema2,
44390
44432
  created_at: optionalStringSchema2
44391
44433
  });
@@ -44741,6 +44783,7 @@ function formatAgentInboxRowDetails(row) {
44741
44783
  if (row.latestSenderName) parts.push(`latest sender @${row.latestSenderName}`);
44742
44784
  if (row.latestMsgId) parts.push(`latest msg=${shortMessageId(row.latestMsgId)}`);
44743
44785
  parts.push(...row.flags.map(formatAgentInboxFlag));
44786
+ if (row.attentionHint) parts.push(`attention_hint=${formatAttentionHintField(row.attentionHint)}`);
44744
44787
  return parts.join(" \xB7 ");
44745
44788
  }
44746
44789
  function formatAgentInboxFlag(flag) {
@@ -44750,6 +44793,18 @@ function formatAgentInboxFlag(flag) {
44750
44793
  function shortMessageId(value) {
44751
44794
  return value.slice(0, 8);
44752
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
+ }
44753
44808
 
44754
44809
  // ../shared/src/externalAgentIntegration.ts
44755
44810
  init_esm_shims();
@@ -45146,9 +45201,9 @@ function isExternalAgentRuntime(runtime) {
45146
45201
  return runtime === EXTERNAL_AGENT_RUNTIME_ID;
45147
45202
  }
45148
45203
  var RUNTIMES = [
45149
- { id: "builtin", displayName: "Built-in", binary: "", supported: true },
45150
45204
  { id: "claude", displayName: "Claude Code", binary: "claude", supported: true },
45151
45205
  { id: "codex", displayName: "Codex CLI", binary: "codex", supported: true },
45206
+ { id: "builtin", displayName: "Builtin Pi", binary: "", supported: true },
45152
45207
  { id: "antigravity", displayName: "Antigravity CLI", binary: "agy", supported: true },
45153
45208
  // Kimi: prefer the in-process SDK (`kimi-sdk` → "Kimi Code") for new agents.
45154
45209
  // The legacy `kimi` (kimi-cli child-process) entry stays for backward compat
@@ -45536,7 +45591,7 @@ function createAgentApiSurfaceClient(client) {
45536
45591
  channels: {
45537
45592
  join: (params) => requestClientAsApiResponse(agentApi.channels.join(params)),
45538
45593
  leave: (params) => requestClientAsApiResponse(agentApi.channels.leave(params)),
45539
- mute: (params) => requestClientAsApiResponse(agentApi.channels.mute(params)),
45594
+ mute: (params) => requestClientAsApiResponse(agentApi.channels.mute(params, {})),
45540
45595
  unmute: (params) => requestClientAsApiResponse(agentApi.channels.unmute(params)),
45541
45596
  members: (query) => requestClientAsApiResponse(agentApi.channels.members(query)),
45542
45597
  resolve: (body) => requestClientAsApiResponse(agentApi.channels.resolve(body))
@@ -46287,8 +46342,16 @@ function registerCliCommand(parent, command, runtimeOptions = {}) {
46287
46342
  child.argument(arg);
46288
46343
  }
46289
46344
  for (const option of command.spec.options ?? []) {
46345
+ const commanderOption = option.hidden ? new Option(option.flags, option.description).hideHelp() : null;
46290
46346
  if (option.parse) {
46291
- 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);
46292
46355
  } else {
46293
46356
  child.option(option.flags, option.description);
46294
46357
  }
@@ -48858,8 +48921,19 @@ function parseRegularChannelTarget(target) {
48858
48921
  const name = target.slice(1).trim();
48859
48922
  return name.length > 0 ? name : null;
48860
48923
  }
48861
- function formatLeaveChannelResult(target) {
48862
- 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");
48863
48937
  }
48864
48938
  function formatAlreadyNotJoined(target) {
48865
48939
  return `Already not joined in ${target}.`;
@@ -48914,7 +48988,7 @@ var channelLeaveCommand = defineCommand(
48914
48988
  message: leaveRes.error ?? `HTTP ${leaveRes.status}`
48915
48989
  });
48916
48990
  }
48917
- writeText(ctx.io, formatLeaveChannelResult(target) + "\n");
48991
+ writeText(ctx.io, formatLeaveChannelResult(target, leaveRes.data ?? void 0) + "\n");
48918
48992
  }
48919
48993
  );
48920
48994
  function registerChannelLeaveCommand(parent, runtimeOptions) {
@@ -49228,9 +49302,19 @@ init_esm_shims();
49228
49302
  function normalizeHandle2(raw) {
49229
49303
  return (raw ?? "").trim().replace(/^@/, "");
49230
49304
  }
49231
- function formatRemoveMemberResult(target, memberName, wasMember) {
49305
+ function formatRemoveMemberResult(target, memberName, wasMember, result2) {
49232
49306
  const member = `@${memberName}`;
49233
- 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");
49234
49318
  }
49235
49319
  var channelRemoveMemberCommand = defineCommand(
49236
49320
  {
@@ -49300,7 +49384,7 @@ var channelRemoveMemberCommand = defineCommand(
49300
49384
  });
49301
49385
  }
49302
49386
  const memberName = removeRes.data?.member?.name ?? (user || agent);
49303
- 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");
49304
49388
  }
49305
49389
  );
49306
49390
  function registerChannelRemoveMemberCommand(parent, runtimeOptions) {
@@ -50084,11 +50168,13 @@ var knowledgeGetCommand = defineCommand(
50084
50168
  },
50085
50169
  {
50086
50170
  flags: "--turn-id <id>",
50087
- 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
50088
50173
  },
50089
50174
  {
50090
50175
  flags: "--trace-id <id>",
50091
- 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
50092
50178
  }
50093
50179
  ],
50094
50180
  helpAfter: "\nTopics:\n Run `raft manual get index` to list available manual topics.\n"
@@ -50168,11 +50254,13 @@ var knowledgeSearchCommand = defineCommand(
50168
50254
  },
50169
50255
  {
50170
50256
  flags: "--turn-id <id>",
50171
- description: "Optional turn id for correlation in the knowledge event"
50257
+ description: "Diagnostic: override the turn id recorded on the knowledge event",
50258
+ hidden: true
50172
50259
  },
50173
50260
  {
50174
50261
  flags: "--trace-id <id>",
50175
- description: "Optional trace id for correlation in the knowledge event"
50262
+ description: "Diagnostic: override the trace id recorded on the knowledge event",
50263
+ hidden: true
50176
50264
  }
50177
50265
  ],
50178
50266
  helpAfter: '\nExamples:\n raft manual search "preview before merge" --scope recipes\n raft manual get recipes/technique/preview-env\n'
@@ -53436,6 +53524,15 @@ function safeUrl2(value, label) {
53436
53524
  }
53437
53525
  return url2;
53438
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
+ }
53439
53536
  function resolveActionUrl(input) {
53440
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);
53441
53538
  if (!base) {
@@ -53445,7 +53542,7 @@ function resolveActionUrl(input) {
53445
53542
  );
53446
53543
  }
53447
53544
  const baseUrl = safeUrl2(base, "action base URL");
53448
- return new URL(input.action.endpoint.path, baseUrl);
53545
+ return new URL(substituteEndpointPathParams(input.action.endpoint.path, input.payload), baseUrl);
53449
53546
  }
53450
53547
  function appendPayloadAsQuery(url2, payload) {
53451
53548
  for (const [key, value] of Object.entries(payload)) {
@@ -53453,6 +53550,13 @@ function appendPayloadAsQuery(url2, payload) {
53453
53550
  url2.searchParams.set(key, typeof value === "string" ? value : JSON.stringify(value));
53454
53551
  }
53455
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
+ }
53456
53560
  async function invokeHttpAction(input) {
53457
53561
  const url2 = new URL(input.url);
53458
53562
  const cookie = cookieHeaderForUrl(input.cookies, url2);
@@ -53474,6 +53578,7 @@ async function invokeHttpAction(input) {
53474
53578
  if (input.action.endpoint.method === "GET") {
53475
53579
  appendPayloadAsQuery(url2, input.payload);
53476
53580
  } else {
53581
+ appendResourceLocatorQuery({ url: url2, action: input.action, payload: input.payload });
53477
53582
  headers["content-type"] = "application/json";
53478
53583
  init.body = JSON.stringify(input.payload);
53479
53584
  }
@@ -53530,6 +53635,9 @@ function formatActions(input) {
53530
53635
  lines.push(` endpoint: ${action.endpoint.method} ${action.endpoint.path}`);
53531
53636
  if (action.description) lines.push(` description: ${action.description}`);
53532
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
+ }
53533
53641
  }
53534
53642
  lines.push(`next: raft integration invoke --service ${JSON.stringify(input.service.clientId)} --action ${JSON.stringify(actions[0]?.name ?? "<name>")}`);
53535
53643
  return lines.join("\n");
@@ -53639,7 +53747,7 @@ var integrationInvokeCommand = defineCommand(
53639
53747
  { flags: "--list-actions", description: "List manifest actions instead of invoking one" },
53640
53748
  {
53641
53749
  flags: "--param <key=value>",
53642
- 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}",
53643
53751
  parse: (value, previous = []) => {
53644
53752
  previous.push(value);
53645
53753
  return previous;
@@ -53767,7 +53875,7 @@ var integrationInvokeCommand = defineCommand(
53767
53875
  });
53768
53876
  cookies = session.cookies;
53769
53877
  }
53770
- const url2 = resolveActionUrl({ service, manifest, action });
53878
+ const url2 = resolveActionUrl({ service, manifest, action, payload });
53771
53879
  const result2 = await invokeHttpAction({ url: url2, action, payload, cookies, service });
53772
53880
  if (opts.json) {
53773
53881
  writeJson(cmdCtx.io, {
@@ -54383,7 +54491,10 @@ registerServerInfoCommand(serverCmd);
54383
54491
  registerServerUpdateCommand(serverCmd);
54384
54492
  var userCmd = program2.command("user").description("User and agent introspection");
54385
54493
  registerUserInfoCommand(userCmd);
54386
- var manualCmd = program2.command("manual").description("Raft Manual for Agents retrieval (canonical operating topics)");
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
+ );
54387
54498
  registerKnowledgeGetCommand(manualCmd);
54388
54499
  registerKnowledgeSearchCommand(manualCmd);
54389
54500
  var knowledgeCmd = program2.command("knowledge").description("Legacy alias for `raft manual`");
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@botiverse/raft",
3
- "version": "0.0.15",
3
+ "version": "0.0.16",
4
4
  "type": "module"
5
5
  }
package/dist/core.js CHANGED
@@ -16,7 +16,7 @@ import {
16
16
  runBundledSlockCli,
17
17
  scanWorkspaceDirectories,
18
18
  subscribeDaemonLogs
19
- } from "./chunk-VZWVYMUX.js";
19
+ } from "./chunk-YAI5OK4D.js";
20
20
  export {
21
21
  AGENT_MIGRATION_BUNDLE_SCHEMA_VERSION,
22
22
  AgentMigrationGrantRegistry,
@@ -42463,6 +42463,9 @@ function validateActionCardAction(action) {
42463
42463
  return null;
42464
42464
  }
42465
42465
  init_esm_shims();
42466
+ init_esm_shims();
42467
+ var ATTENTION_HINT_SCHEMA = "attention-dependency-hint.v1";
42468
+ var ATTENTION_HINT_DEFAULT_WINDOW_MS = 7 * 24 * 60 * 60 * 1e3;
42466
42469
  var AGENT_API_BASE_PATH = "/internal/agent-api";
42467
42470
  var optionalStringSchema = external_exports.string().trim().optional();
42468
42471
  var optionalStringArraySchema = external_exports.array(external_exports.string().trim().min(1)).optional();
@@ -42989,8 +42992,17 @@ var agentApiSendResponseSchema = external_exports.discriminatedUnion("state", [
42989
42992
  var agentApiMessageResolveResponseSchema = passthroughObject({
42990
42993
  message: agentApiMessageEnvelopeSchema
42991
42994
  });
42995
+ var agentApiChannelAttentionSchema = passthroughObject({
42996
+ state: optionalStringSchema,
42997
+ ordinaryActivity: optionalStringSchema,
42998
+ stillArrives: optionalStringArraySchema,
42999
+ threadBoundary: optionalStringSchema,
43000
+ manageCommand: optionalStringSchema,
43001
+ manageApi: optionalStringSchema
43002
+ });
42992
43003
  var agentApiOkResponseSchema = passthroughObject({
42993
- ok: external_exports.literal(true)
43004
+ ok: external_exports.literal(true),
43005
+ attention: agentApiChannelAttentionSchema.optional()
42994
43006
  });
42995
43007
  var agentApiSearchResultSchema = passthroughObject({
42996
43008
  id: external_exports.string(),
@@ -43047,6 +43059,16 @@ var agentApiChannelMuteResponseSchema = passthroughObject({
43047
43059
  catchUp: optionalStringSchema
43048
43060
  }).optional()
43049
43061
  });
43062
+ var agentApiChannelMuteBodySchema = passthroughObject({
43063
+ attentionHintAccepted: passthroughObject({
43064
+ schema: external_exports.literal(ATTENTION_HINT_SCHEMA),
43065
+ trigger: external_exports.enum(["M2", "M3"]),
43066
+ scope: external_exports.string().trim().min(1),
43067
+ suggested_command: optionalStringSchema,
43068
+ copy_version: external_exports.string().trim().min(1),
43069
+ epoch_ms: external_exports.number().int().nonnegative()
43070
+ }).optional()
43071
+ });
43050
43072
  var agentApiTaskClaimResultSchema = passthroughObject({
43051
43073
  taskNumber: external_exports.number().int().positive().optional(),
43052
43074
  messageId: optionalStringSchema,
@@ -43256,7 +43278,7 @@ var agentApiContract = {
43256
43278
  client: { resource: "channels", method: "mute" },
43257
43279
  capability: "channels",
43258
43280
  description: "Mute ordinary activity delivery for a visible regular channel as the bound agent credential.",
43259
- request: { params: agentApiChannelMembershipParamsSchema },
43281
+ request: { params: agentApiChannelMembershipParamsSchema, body: agentApiChannelMuteBodySchema },
43260
43282
  response: { body: agentApiChannelMuteResponseSchema }
43261
43283
  }),
43262
43284
  channelUnmute: route({
@@ -43902,6 +43924,20 @@ var optionalQueryIntSchema = external_exports.union([external_exports.number().i
43902
43924
  var nullableNumberSchema2 = external_exports.number().finite().nullable();
43903
43925
  var passthroughObject2 = (shape) => external_exports.object(shape).passthrough();
43904
43926
  var daemonApiInboxFlagSchema = external_exports.enum(["mention", "thread", "dm", "task"]);
43927
+ var daemonApiAttentionHintSchema = passthroughObject2({
43928
+ schema: external_exports.literal(ATTENTION_HINT_SCHEMA),
43929
+ trigger: external_exports.enum(["M2", "M3"]),
43930
+ scope: external_exports.string().trim().min(1),
43931
+ suggested_command: external_exports.string().trim().min(1),
43932
+ copy: external_exports.string().trim().min(1),
43933
+ copy_version: external_exports.literal("attention-hint-copy-v1"),
43934
+ epoch_ms: external_exports.number().int().nonnegative(),
43935
+ thresholds: passthroughObject2({
43936
+ K: optionalNonNegativeIntSchema,
43937
+ k: optionalNonNegativeIntSchema,
43938
+ window_ms: external_exports.number().int().positive()
43939
+ })
43940
+ });
43905
43941
  var daemonApiInboxTargetRowSchema = passthroughObject2({
43906
43942
  target: external_exports.string().trim().min(1),
43907
43943
  channelId: optionalStringSchema2,
@@ -43912,8 +43948,9 @@ var daemonApiInboxTargetRowSchema = passthroughObject2({
43912
43948
  latestMsgId: optionalStringSchema2,
43913
43949
  latestSeq: optionalNonNegativeIntSchema,
43914
43950
  latestSenderName: optionalStringSchema2,
43915
- latestSenderType: external_exports.enum(["human", "agent", "system"]).optional(),
43916
- flags: external_exports.array(daemonApiInboxFlagSchema)
43951
+ latestSenderType: external_exports.enum(["human", "agent", "system", "third_party_app"]).optional(),
43952
+ flags: external_exports.array(daemonApiInboxFlagSchema),
43953
+ attentionHint: daemonApiAttentionHintSchema.optional()
43917
43954
  });
43918
43955
  var daemonApiInboxCheckResponseSchema = passthroughObject2({
43919
43956
  rows: external_exports.array(daemonApiInboxTargetRowSchema).optional()
@@ -43936,6 +43973,7 @@ var daemonApiWakeHintSchema = passthroughObject2({
43936
43973
  target_type: optionalStringSchema2,
43937
43974
  reason: optionalStringSchema2,
43938
43975
  wake_reason: optionalStringSchema2,
43976
+ attention_hint: daemonApiAttentionHintSchema.optional(),
43939
43977
  createdAt: optionalStringSchema2,
43940
43978
  created_at: optionalStringSchema2
43941
43979
  });
@@ -44283,6 +44321,7 @@ function formatAgentInboxRowDetails(row) {
44283
44321
  if (row.latestSenderName) parts.push(`latest sender @${row.latestSenderName}`);
44284
44322
  if (row.latestMsgId) parts.push(`latest msg=${shortMessageId(row.latestMsgId)}`);
44285
44323
  parts.push(...row.flags.map(formatAgentInboxFlag));
44324
+ if (row.attentionHint) parts.push(`attention_hint=${formatAttentionHintField(row.attentionHint)}`);
44286
44325
  return parts.join(" \xB7 ");
44287
44326
  }
44288
44327
  function formatAgentInboxFlag(flag) {
@@ -44292,6 +44331,18 @@ function formatAgentInboxFlag(flag) {
44292
44331
  function shortMessageId(value) {
44293
44332
  return value.slice(0, 8);
44294
44333
  }
44334
+ function formatAttentionHintField(hint) {
44335
+ return JSON.stringify({
44336
+ schema: hint.schema,
44337
+ trigger: hint.trigger,
44338
+ scope: hint.scope,
44339
+ suggested_command: hint.suggested_command,
44340
+ copy: hint.copy,
44341
+ copy_version: hint.copy_version,
44342
+ epoch_ms: hint.epoch_ms,
44343
+ thresholds: hint.thresholds
44344
+ });
44345
+ }
44295
44346
  init_esm_shims();
44296
44347
  var EXTERNAL_AGENT_COMMS_PROTOCOL_VERSION = "agent-comms-core.v1";
44297
44348
  var EXTERNAL_AGENT_PROOF_SCHEMA_VERSION = "agent-proof.v1";
@@ -44664,9 +44715,9 @@ function isExternalAgentRuntime(runtime) {
44664
44715
  return runtime === EXTERNAL_AGENT_RUNTIME_ID;
44665
44716
  }
44666
44717
  var RUNTIMES = [
44667
- { id: "builtin", displayName: "Built-in", binary: "", supported: true },
44668
44718
  { id: "claude", displayName: "Claude Code", binary: "claude", supported: true },
44669
44719
  { id: "codex", displayName: "Codex CLI", binary: "codex", supported: true },
44720
+ { id: "builtin", displayName: "Builtin Pi", binary: "", supported: true },
44670
44721
  { id: "antigravity", displayName: "Antigravity CLI", binary: "agy", supported: true },
44671
44722
  // Kimi: prefer the in-process SDK (`kimi-sdk` → "Kimi Code") for new agents.
44672
44723
  // The legacy `kimi` (kimi-cli child-process) entry stays for backward compat
@@ -45052,7 +45103,7 @@ function createAgentApiSurfaceClient(client) {
45052
45103
  channels: {
45053
45104
  join: (params) => requestClientAsApiResponse(agentApi.channels.join(params)),
45054
45105
  leave: (params) => requestClientAsApiResponse(agentApi.channels.leave(params)),
45055
- mute: (params) => requestClientAsApiResponse(agentApi.channels.mute(params)),
45106
+ mute: (params) => requestClientAsApiResponse(agentApi.channels.mute(params, {})),
45056
45107
  unmute: (params) => requestClientAsApiResponse(agentApi.channels.unmute(params)),
45057
45108
  members: (query) => requestClientAsApiResponse(agentApi.channels.members(query)),
45058
45109
  resolve: (body) => requestClientAsApiResponse(agentApi.channels.resolve(body))
@@ -45781,8 +45832,16 @@ function registerCliCommand(parent, command, runtimeOptions = {}) {
45781
45832
  child.argument(arg);
45782
45833
  }
45783
45834
  for (const option of command.spec.options ?? []) {
45835
+ const commanderOption = option.hidden ? new Option(option.flags, option.description).hideHelp() : null;
45784
45836
  if (option.parse) {
45785
- child.option(option.flags, option.description, option.parse);
45837
+ if (commanderOption) {
45838
+ commanderOption.argParser(option.parse);
45839
+ child.addOption(commanderOption);
45840
+ } else {
45841
+ child.option(option.flags, option.description, option.parse);
45842
+ }
45843
+ } else if (commanderOption) {
45844
+ child.addOption(commanderOption);
45786
45845
  } else {
45787
45846
  child.option(option.flags, option.description);
45788
45847
  }
@@ -48312,8 +48371,19 @@ function parseRegularChannelTarget(target) {
48312
48371
  const name = target.slice(1).trim();
48313
48372
  return name.length > 0 ? name : null;
48314
48373
  }
48315
- function formatLeaveChannelResult(target) {
48316
- 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.`;
48374
+ function formatLeaveChannelResult(target, result2) {
48375
+ const lines = [
48376
+ `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.`
48377
+ ];
48378
+ if (result2?.attention?.ordinaryActivity) lines.push(result2.attention.ordinaryActivity);
48379
+ if (result2?.attention?.stillArrives?.length) {
48380
+ lines.push("Still arrives:");
48381
+ for (const item of result2.attention.stillArrives) lines.push(`- ${item}`);
48382
+ }
48383
+ if (result2?.attention?.threadBoundary) lines.push(result2.attention.threadBoundary);
48384
+ if (result2?.attention?.manageCommand) lines.push(`To stop a followed thread: ${result2.attention.manageCommand}`);
48385
+ if (result2?.attention?.manageApi) lines.push(`Agent API: ${result2.attention.manageApi}`);
48386
+ return lines.join("\n");
48317
48387
  }
48318
48388
  function formatAlreadyNotJoined(target) {
48319
48389
  return `Already not joined in ${target}.`;
@@ -48368,7 +48438,7 @@ var channelLeaveCommand = defineCommand(
48368
48438
  message: leaveRes.error ?? `HTTP ${leaveRes.status}`
48369
48439
  });
48370
48440
  }
48371
- writeText(ctx.io, formatLeaveChannelResult(target) + "\n");
48441
+ writeText(ctx.io, formatLeaveChannelResult(target, leaveRes.data ?? void 0) + "\n");
48372
48442
  }
48373
48443
  );
48374
48444
  function registerChannelLeaveCommand(parent, runtimeOptions) {
@@ -48672,9 +48742,19 @@ init_esm_shims();
48672
48742
  function normalizeHandle2(raw) {
48673
48743
  return (raw ?? "").trim().replace(/^@/, "");
48674
48744
  }
48675
- function formatRemoveMemberResult(target, memberName, wasMember) {
48745
+ function formatRemoveMemberResult(target, memberName, wasMember, result2) {
48676
48746
  const member = `@${memberName}`;
48677
- return wasMember ? `Removed ${member} from ${target}.` : `${member} was not in ${target}.`;
48747
+ if (!wasMember) return `${member} was not in ${target}.`;
48748
+ const lines = [`Removed ${member} from ${target}.`];
48749
+ if (result2?.attention?.ordinaryActivity) lines.push(result2.attention.ordinaryActivity);
48750
+ if (result2?.attention?.stillArrives?.length) {
48751
+ lines.push("Still arrives:");
48752
+ for (const item of result2.attention.stillArrives) lines.push(`- ${item}`);
48753
+ }
48754
+ if (result2?.attention?.threadBoundary) lines.push(result2.attention.threadBoundary);
48755
+ if (result2?.attention?.manageCommand) lines.push(`To stop a followed thread: ${result2.attention.manageCommand}`);
48756
+ if (result2?.attention?.manageApi) lines.push(`Agent API: ${result2.attention.manageApi}`);
48757
+ return lines.join("\n");
48678
48758
  }
48679
48759
  var channelRemoveMemberCommand = defineCommand(
48680
48760
  {
@@ -48744,7 +48824,7 @@ var channelRemoveMemberCommand = defineCommand(
48744
48824
  });
48745
48825
  }
48746
48826
  const memberName = removeRes.data?.member?.name ?? (user || agent);
48747
- writeText(ctx.io, formatRemoveMemberResult(target, memberName, removeRes.data?.wasMember === true) + "\n");
48827
+ writeText(ctx.io, formatRemoveMemberResult(target, memberName, removeRes.data?.wasMember === true, removeRes.data ?? void 0) + "\n");
48748
48828
  }
48749
48829
  );
48750
48830
  function registerChannelRemoveMemberCommand(parent, runtimeOptions) {
@@ -49506,11 +49586,13 @@ var knowledgeGetCommand = defineCommand(
49506
49586
  },
49507
49587
  {
49508
49588
  flags: "--turn-id <id>",
49509
- description: "Optional turn id for correlation in the knowledge event"
49589
+ description: "Diagnostic: override the turn id recorded on the knowledge event",
49590
+ hidden: true
49510
49591
  },
49511
49592
  {
49512
49593
  flags: "--trace-id <id>",
49513
- description: "Optional trace id for correlation in the knowledge event"
49594
+ description: "Diagnostic: override the trace id recorded on the knowledge event",
49595
+ hidden: true
49514
49596
  }
49515
49597
  ],
49516
49598
  helpAfter: "\nTopics:\n Run `raft manual get index` to list available manual topics.\n"
@@ -49588,11 +49670,13 @@ var knowledgeSearchCommand = defineCommand(
49588
49670
  },
49589
49671
  {
49590
49672
  flags: "--turn-id <id>",
49591
- description: "Optional turn id for correlation in the knowledge event"
49673
+ description: "Diagnostic: override the turn id recorded on the knowledge event",
49674
+ hidden: true
49592
49675
  },
49593
49676
  {
49594
49677
  flags: "--trace-id <id>",
49595
- description: "Optional trace id for correlation in the knowledge event"
49678
+ description: "Diagnostic: override the trace id recorded on the knowledge event",
49679
+ hidden: true
49596
49680
  }
49597
49681
  ],
49598
49682
  helpAfter: '\nExamples:\n raft manual search "preview before merge" --scope recipes\n raft manual get recipes/technique/preview-env\n'
@@ -52748,6 +52832,15 @@ function safeUrl2(value, label) {
52748
52832
  }
52749
52833
  return url2;
52750
52834
  }
52835
+ function substituteEndpointPathParams(endpointPath, payload) {
52836
+ return endpointPath.replace(/\{([A-Za-z][A-Za-z0-9_]*)\}/g, (_match, name) => {
52837
+ const value = payload[name];
52838
+ if (value === void 0 || value === null || value === "") {
52839
+ throw cliError("INVALID_ARG", `missing path parameter ${name}`);
52840
+ }
52841
+ return encodeURIComponent(typeof value === "string" ? value : JSON.stringify(value));
52842
+ });
52843
+ }
52751
52844
  function resolveActionUrl(input) {
52752
52845
  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);
52753
52846
  if (!base) {
@@ -52757,7 +52850,7 @@ function resolveActionUrl(input) {
52757
52850
  );
52758
52851
  }
52759
52852
  const baseUrl = safeUrl2(base, "action base URL");
52760
- return new URL(input.action.endpoint.path, baseUrl);
52853
+ return new URL(substituteEndpointPathParams(input.action.endpoint.path, input.payload), baseUrl);
52761
52854
  }
52762
52855
  function appendPayloadAsQuery(url2, payload) {
52763
52856
  for (const [key, value] of Object.entries(payload)) {
@@ -52765,6 +52858,13 @@ function appendPayloadAsQuery(url2, payload) {
52765
52858
  url2.searchParams.set(key, typeof value === "string" ? value : JSON.stringify(value));
52766
52859
  }
52767
52860
  }
52861
+ function appendResourceLocatorQuery(input) {
52862
+ const { url: url2, action, payload } = input;
52863
+ if (/\{id\}/.test(action.endpoint.path)) return;
52864
+ const id = payload.id;
52865
+ if (id === void 0 || id === null || id === "" || url2.searchParams.has("id")) return;
52866
+ url2.searchParams.set("id", typeof id === "string" ? id : JSON.stringify(id));
52867
+ }
52768
52868
  async function invokeHttpAction(input) {
52769
52869
  const url2 = new URL(input.url);
52770
52870
  const cookie = cookieHeaderForUrl(input.cookies, url2);
@@ -52786,6 +52886,7 @@ async function invokeHttpAction(input) {
52786
52886
  if (input.action.endpoint.method === "GET") {
52787
52887
  appendPayloadAsQuery(url2, input.payload);
52788
52888
  } else {
52889
+ appendResourceLocatorQuery({ url: url2, action: input.action, payload: input.payload });
52789
52890
  headers["content-type"] = "application/json";
52790
52891
  init.body = JSON.stringify(input.payload);
52791
52892
  }
@@ -52842,6 +52943,9 @@ function formatActions(input) {
52842
52943
  lines.push(` endpoint: ${action.endpoint.method} ${action.endpoint.path}`);
52843
52944
  if (action.description) lines.push(` description: ${action.description}`);
52844
52945
  if (required2.length > 0) lines.push(` required params: ${required2.join(", ")}`);
52946
+ if (action.endpoint.method !== "GET" && Object.hasOwn(action.parameters ?? {}, "id") && !/\{id\}/.test(action.endpoint.path)) {
52947
+ lines.push(" note: id is treated as the resource locator and is also sent as query ?id=; JSON body is preserved");
52948
+ }
52845
52949
  }
52846
52950
  lines.push(`next: raft integration invoke --service ${JSON.stringify(input.service.clientId)} --action ${JSON.stringify(actions[0]?.name ?? "<name>")}`);
52847
52951
  return lines.join("\n");
@@ -52951,7 +53055,7 @@ var integrationInvokeCommand = defineCommand(
52951
53055
  { flags: "--list-actions", description: "List manifest actions instead of invoking one" },
52952
53056
  {
52953
53057
  flags: "--param <key=value>",
52954
- description: "Action parameter; repeatable. Use key=@file or key=@- to read text",
53058
+ 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}",
52955
53059
  parse: (value, previous = []) => {
52956
53060
  previous.push(value);
52957
53061
  return previous;
@@ -53079,7 +53183,7 @@ var integrationInvokeCommand = defineCommand(
53079
53183
  });
53080
53184
  cookies = session.cookies;
53081
53185
  }
53082
- const url2 = resolveActionUrl({ service, manifest, action });
53186
+ const url2 = resolveActionUrl({ service, manifest, action, payload });
53083
53187
  const result2 = await invokeHttpAction({ url: url2, action, payload, cookies, service });
53084
53188
  if (opts.json) {
53085
53189
  writeJson(cmdCtx.io, {
@@ -53667,7 +53771,10 @@ registerServerInfoCommand(serverCmd);
53667
53771
  registerServerUpdateCommand(serverCmd);
53668
53772
  var userCmd = program2.command("user").description("User and agent introspection");
53669
53773
  registerUserInfoCommand(userCmd);
53670
- var manualCmd = program2.command("manual").description("Raft Manual for Agents retrieval (canonical operating topics)");
53774
+ var manualCmd = program2.command("manual").description("Look up Raft operating topics and agent recipes").addHelpText(
53775
+ "after",
53776
+ '\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'
53777
+ );
53671
53778
  registerKnowledgeGetCommand(manualCmd);
53672
53779
  registerKnowledgeSearchCommand(manualCmd);
53673
53780
  var knowledgeCmd = program2.command("knowledge").description("Legacy alias for `raft manual`");
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  DAEMON_CLI_USAGE,
4
4
  DaemonCore,
5
5
  parseDaemonCliArgs
6
- } from "./chunk-VZWVYMUX.js";
6
+ } from "./chunk-YAI5OK4D.js";
7
7
 
8
8
  // src/index.ts
9
9
  var parsedArgs = parseDaemonCliArgs(process.argv.slice(2));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botiverse/raft-daemon",
3
- "version": "0.71.0",
3
+ "version": "0.72.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "raft-daemon": "dist/raft-daemon.js",