@openscout/scout 0.2.49 → 0.2.50

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/main.mjs CHANGED
@@ -7505,7 +7505,9 @@ var init_paths = __esm(() => {
7505
7505
  endpoints: "/v1/endpoints",
7506
7506
  conversations: "/v1/conversations",
7507
7507
  invocations: "/v1/invocations",
7508
- activity: "/v1/activity"
7508
+ activity: "/v1/activity",
7509
+ collaborationRecords: "/v1/collaboration/records",
7510
+ collaborationEvents: "/v1/collaboration/events"
7509
7511
  }
7510
7512
  };
7511
7513
  });
@@ -7776,7 +7778,9 @@ async function resolveMentionTargets(snapshot, text, currentDirectory) {
7776
7778
  const unresolved = [...mentions.unparsed];
7777
7779
  const ambiguous = [];
7778
7780
  const candidateMap = new Map;
7779
- const endpointBackedAgentIds = [...new Set(Object.values(snapshot.endpoints).map((endpoint) => endpoint.agentId).filter((agentId) => agentId && agentId !== OPERATOR_ID))];
7781
+ const endpointBackedAgentIds = [
7782
+ ...new Set(Object.values(snapshot.endpoints).map((endpoint) => endpoint.agentId).filter((agentId) => agentId && agentId !== OPERATOR_ID))
7783
+ ];
7780
7784
  for (const agent of Object.values(snapshot.agents)) {
7781
7785
  if (isSupersededBrokerAgent(snapshot, agent.id)) {
7782
7786
  continue;
@@ -7786,14 +7790,19 @@ async function resolveMentionTargets(snapshot, text, currentDirectory) {
7786
7790
  for (const selector of selectors) {
7787
7791
  if (selector.definitionId === "system")
7788
7792
  continue;
7789
- const discovered = await resolveRelayAgentConfig(selector, { currentDirectory });
7793
+ const discovered = await resolveRelayAgentConfig(selector, {
7794
+ currentDirectory
7795
+ });
7790
7796
  if (discovered && !candidateMap.has(discovered.agentId)) {
7791
7797
  candidateMap.set(discovered.agentId, {
7792
7798
  agentId: discovered.agentId,
7793
7799
  definitionId: discovered.definitionId,
7794
7800
  nodeQualifier: discovered.instance.nodeQualifier,
7795
7801
  workspaceQualifier: discovered.instance.workspaceQualifier,
7796
- aliases: [discovered.instance.selector, discovered.instance.defaultSelector]
7802
+ aliases: [
7803
+ discovered.instance.selector,
7804
+ discovered.instance.defaultSelector
7805
+ ]
7797
7806
  });
7798
7807
  }
7799
7808
  const candidates = Array.from(candidateMap.values());
@@ -8033,8 +8042,12 @@ async function ensureTargetRelayAgentRegistered(baseUrl, snapshot, nodeId, agent
8033
8042
  }
8034
8043
  function conversationDefinition(snapshot, nodeId, channel, senderId, targetParticipantIds = []) {
8035
8044
  const normalizedChannel = channel?.trim() || "shared";
8036
- const sharedParticipants = [...new Set([OPERATOR_ID, senderId, ...Object.keys(snapshot.agents)])].sort();
8037
- const scopedParticipants = [...new Set([OPERATOR_ID, senderId, ...targetParticipantIds])].sort();
8045
+ const sharedParticipants = [
8046
+ ...new Set([OPERATOR_ID, senderId, ...Object.keys(snapshot.agents)])
8047
+ ].sort();
8048
+ const scopedParticipants = [
8049
+ ...new Set([OPERATOR_ID, senderId, ...targetParticipantIds])
8050
+ ].sort();
8038
8051
  if (normalizedChannel === "voice") {
8039
8052
  return {
8040
8053
  id: BROKER_VOICE_CHANNEL_ID,
@@ -8085,7 +8098,12 @@ function conversationDefinition(snapshot, nodeId, channel, senderId, targetParti
8085
8098
  async function ensureBrokerConversation(baseUrl, snapshot, nodeId, channel, senderId, targetParticipantIds = []) {
8086
8099
  const definition = conversationDefinition(snapshot, nodeId, channel, senderId, targetParticipantIds);
8087
8100
  const existing = snapshot.conversations[definition.id];
8088
- const nextParticipants = [...new Set([...existing?.participantIds ?? [], ...definition.participantIds])].sort();
8101
+ const nextParticipants = [
8102
+ ...new Set([
8103
+ ...existing?.participantIds ?? [],
8104
+ ...definition.participantIds
8105
+ ])
8106
+ ].sort();
8089
8107
  if (!existing || existing.kind !== definition.kind || existing.visibility !== definition.visibility || existing.shareMode !== definition.shareMode || nextParticipants.length !== existing.participantIds.length) {
8090
8108
  const nextConversation = {
8091
8109
  ...definition,
@@ -8107,6 +8125,221 @@ function directConversationIdForActors(sourceId, targetId) {
8107
8125
  }
8108
8126
  return `dm.${[sourceId, targetId].sort().join(".")}`;
8109
8127
  }
8128
+ function relayChannelMetadata(conversation, explicitChannel) {
8129
+ const normalized = explicitChannel?.trim();
8130
+ if (normalized) {
8131
+ return normalized;
8132
+ }
8133
+ return conversation.kind === "direct" ? "dm" : "shared";
8134
+ }
8135
+ function relayAudienceReason(conversation) {
8136
+ return conversation.kind === "direct" ? "direct_message" : "mention";
8137
+ }
8138
+ function buildScoutEntityId(prefix, createdAtMs) {
8139
+ return `${prefix}-${createdAtMs.toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
8140
+ }
8141
+ function createTrackedWorkItemSummary(record) {
8142
+ if (record.kind !== "work_item") {
8143
+ throw new Error(`expected work_item collaboration record, received ${record.kind}`);
8144
+ }
8145
+ return {
8146
+ id: record.id,
8147
+ title: record.title,
8148
+ summary: record.summary ?? null,
8149
+ state: record.state,
8150
+ acceptanceState: record.acceptanceState,
8151
+ ownerId: record.ownerId ?? null,
8152
+ nextMoveOwnerId: record.nextMoveOwnerId ?? null,
8153
+ conversationId: record.conversationId ?? null,
8154
+ priority: record.priority ?? null
8155
+ };
8156
+ }
8157
+ async function createScoutTrackedWorkItem(input) {
8158
+ const recordId = buildScoutEntityId("work", input.createdAtMs);
8159
+ const record = {
8160
+ id: recordId,
8161
+ kind: "work_item",
8162
+ state: "open",
8163
+ acceptanceState: input.workItem.acceptanceState ?? "pending",
8164
+ title: input.workItem.title.trim(),
8165
+ summary: input.workItem.summary?.trim() || undefined,
8166
+ createdById: input.senderId,
8167
+ ownerId: input.targetAgentId,
8168
+ nextMoveOwnerId: input.targetAgentId,
8169
+ conversationId: input.conversationId,
8170
+ parentId: input.workItem.parentId?.trim() || undefined,
8171
+ priority: input.workItem.priority,
8172
+ labels: input.workItem.labels?.map((label) => label.trim()).filter(Boolean),
8173
+ createdAt: input.createdAtMs,
8174
+ updatedAt: input.createdAtMs,
8175
+ requestedById: input.senderId,
8176
+ metadata: {
8177
+ source: input.source,
8178
+ ...input.workItem.metadata ?? {}
8179
+ }
8180
+ };
8181
+ await brokerPostJson(input.baseUrl, scoutBrokerPaths.v1.collaborationRecords, record);
8182
+ const event = {
8183
+ id: buildScoutEntityId("evt", input.createdAtMs),
8184
+ recordId,
8185
+ recordKind: "work_item",
8186
+ kind: "created",
8187
+ actorId: input.senderId,
8188
+ at: input.createdAtMs,
8189
+ summary: input.workItem.summary?.trim() || input.workItem.title.trim(),
8190
+ metadata: {
8191
+ source: input.source
8192
+ }
8193
+ };
8194
+ await brokerPostJson(input.baseUrl, scoutBrokerPaths.v1.collaborationEvents, event);
8195
+ return createTrackedWorkItemSummary(record);
8196
+ }
8197
+ function normalizeOptionalString2(value) {
8198
+ if (value === null || value === undefined) {
8199
+ return;
8200
+ }
8201
+ const trimmed = value.trim();
8202
+ return trimmed.length > 0 ? trimmed : undefined;
8203
+ }
8204
+ function normalizeWorkItemLabels(labels) {
8205
+ if (!labels) {
8206
+ return;
8207
+ }
8208
+ const normalized = labels.map((label) => label.trim()).filter(Boolean);
8209
+ return normalized.length > 0 ? normalized : undefined;
8210
+ }
8211
+ function normalizeWorkItemProgress(progress) {
8212
+ if (!progress) {
8213
+ return;
8214
+ }
8215
+ const normalized = {};
8216
+ if (typeof progress.completedSteps === "number") {
8217
+ normalized.completedSteps = progress.completedSteps;
8218
+ }
8219
+ if (typeof progress.totalSteps === "number") {
8220
+ normalized.totalSteps = progress.totalSteps;
8221
+ }
8222
+ if (typeof progress.percent === "number") {
8223
+ normalized.percent = progress.percent;
8224
+ }
8225
+ if (typeof progress.checkpoint === "string" && progress.checkpoint.trim()) {
8226
+ normalized.checkpoint = progress.checkpoint.trim();
8227
+ }
8228
+ if (typeof progress.summary === "string" && progress.summary.trim()) {
8229
+ normalized.summary = progress.summary.trim();
8230
+ }
8231
+ return Object.keys(normalized).length > 0 ? normalized : undefined;
8232
+ }
8233
+ function normalizeWorkItemWaitingOn(waitingOn) {
8234
+ if (!waitingOn) {
8235
+ return;
8236
+ }
8237
+ const label = waitingOn.label.trim();
8238
+ if (!label) {
8239
+ return;
8240
+ }
8241
+ return {
8242
+ ...waitingOn,
8243
+ label,
8244
+ targetId: normalizeOptionalString2(waitingOn.targetId)
8245
+ };
8246
+ }
8247
+ function deriveWorkItemEventKind(previous, next) {
8248
+ if (next.acceptanceState !== previous.acceptanceState) {
8249
+ if (next.acceptanceState === "accepted") {
8250
+ return "accepted";
8251
+ }
8252
+ if (next.acceptanceState === "reopened") {
8253
+ return "reopened";
8254
+ }
8255
+ }
8256
+ if (next.state !== previous.state) {
8257
+ switch (next.state) {
8258
+ case "waiting":
8259
+ return "waiting";
8260
+ case "review":
8261
+ return "review_requested";
8262
+ case "done":
8263
+ return "done";
8264
+ case "cancelled":
8265
+ return "cancelled";
8266
+ case "working":
8267
+ return previous.state === "open" ? "claimed" : "progressed";
8268
+ case "open":
8269
+ default:
8270
+ return "progressed";
8271
+ }
8272
+ }
8273
+ if (next.ownerId !== previous.ownerId || next.nextMoveOwnerId !== previous.nextMoveOwnerId) {
8274
+ return "handoff";
8275
+ }
8276
+ return "progressed";
8277
+ }
8278
+ function summarizeWorkItemUpdate(record) {
8279
+ if (record.progress?.summary?.trim()) {
8280
+ return record.progress.summary.trim();
8281
+ }
8282
+ if (record.summary?.trim()) {
8283
+ return record.summary.trim();
8284
+ }
8285
+ return record.title.trim();
8286
+ }
8287
+ function brokerSnapshotWorkItem(snapshot, workId) {
8288
+ const record = snapshot.collaborationRecords[workId];
8289
+ return record?.kind === "work_item" ? record : null;
8290
+ }
8291
+ async function updateScoutWorkItem(input) {
8292
+ const broker = await loadScoutBrokerContext();
8293
+ if (!broker) {
8294
+ return null;
8295
+ }
8296
+ const current = brokerSnapshotWorkItem(broker.snapshot, input.workId.trim());
8297
+ if (!current) {
8298
+ throw new Error(`unknown work item: ${input.workId}`);
8299
+ }
8300
+ const updatedAtMs = input.updatedAtMs ?? Date.now();
8301
+ const nextState = input.state ?? current.state;
8302
+ const nextSummary = input.summary === undefined ? current.summary : normalizeOptionalString2(input.summary) ?? undefined;
8303
+ const nextOwnerId = input.ownerId === undefined ? current.ownerId : normalizeOptionalString2(input.ownerId);
8304
+ const nextMoveOwnerId = input.nextMoveOwnerId === undefined ? current.nextMoveOwnerId : normalizeOptionalString2(input.nextMoveOwnerId);
8305
+ const nextPriority = input.priority === undefined ? current.priority : input.priority ?? undefined;
8306
+ const nextLabels = input.labels === undefined ? current.labels : normalizeWorkItemLabels(input.labels);
8307
+ const nextProgress = input.progress === undefined ? current.progress : normalizeWorkItemProgress(input.progress);
8308
+ const waitingOn = input.waitingOn === undefined ? nextState === "waiting" ? current.waitingOn : undefined : normalizeWorkItemWaitingOn(input.waitingOn);
8309
+ const updated = {
8310
+ ...current,
8311
+ title: normalizeOptionalString2(input.title) ?? current.title,
8312
+ summary: nextSummary,
8313
+ state: nextState,
8314
+ acceptanceState: input.acceptanceState ?? current.acceptanceState,
8315
+ ownerId: nextOwnerId,
8316
+ nextMoveOwnerId,
8317
+ priority: nextPriority,
8318
+ labels: nextLabels,
8319
+ waitingOn,
8320
+ progress: nextProgress,
8321
+ updatedAt: updatedAtMs,
8322
+ startedAt: current.startedAt ?? (nextState === "working" ? updatedAtMs : current.startedAt),
8323
+ reviewRequestedAt: nextState === "review" ? current.reviewRequestedAt ?? updatedAtMs : current.reviewRequestedAt,
8324
+ completedAt: nextState === "done" || nextState === "cancelled" ? current.completedAt ?? updatedAtMs : current.completedAt,
8325
+ metadata: input.metadata ? { ...current.metadata ?? {}, ...input.metadata } : current.metadata
8326
+ };
8327
+ await brokerPostJson(broker.baseUrl, scoutBrokerPaths.v1.collaborationRecords, updated);
8328
+ const event = {
8329
+ id: buildScoutEntityId("evt", updatedAtMs),
8330
+ recordId: updated.id,
8331
+ recordKind: "work_item",
8332
+ kind: deriveWorkItemEventKind(current, updated),
8333
+ actorId: input.actorId,
8334
+ at: updatedAtMs,
8335
+ summary: normalizeOptionalString2(input.eventSummary) ?? summarizeWorkItemUpdate(updated),
8336
+ metadata: {
8337
+ source: input.source?.trim() || "scout-mcp"
8338
+ }
8339
+ };
8340
+ await brokerPostJson(broker.baseUrl, scoutBrokerPaths.v1.collaborationEvents, event);
8341
+ return createTrackedWorkItemSummary(updated);
8342
+ }
8110
8343
  async function ensureBrokerDirectConversationBetween(baseUrl, snapshot, nodeId, sourceId, targetId) {
8111
8344
  const conversationId = targetId === SCOUT_AGENT_ID && sourceId === OPERATOR_ID ? BROKER_SHARED_CHANNEL_ID : directConversationIdForActors(sourceId, targetId);
8112
8345
  const participantIds = [...new Set([sourceId, targetId])].sort();
@@ -8154,7 +8387,9 @@ async function sendScoutMessage(input) {
8154
8387
  const mentionResolution = await resolveMentionTargets(broker.snapshot, input.body, currentDirectory);
8155
8388
  const senderId = await resolveConversationActorId(broker.baseUrl, broker.snapshot, broker.node.id, input.senderId, currentDirectory);
8156
8389
  const availableTargets = (await Promise.all(mentionResolution.resolved.map(async (target) => await ensureTargetRelayAgentRegistered(broker.baseUrl, broker.snapshot, broker.node.id, target.agentId, currentDirectory) ? target : null))).filter((target) => Boolean(target));
8157
- const validTargets = [...new Set(availableTargets.map((target) => target.agentId).filter((target) => target !== senderId && Boolean(broker.snapshot.agents[target])))].sort();
8390
+ const validTargets = [
8391
+ ...new Set(availableTargets.map((target) => target.agentId).filter((target) => target !== senderId && Boolean(broker.snapshot.agents[target])))
8392
+ ].sort();
8158
8393
  const unresolvedTargets = mentionResolution.resolved.filter((target) => !validTargets.includes(target.agentId)).map((target) => target.label).concat(mentionResolution.unresolved).concat(mentionResolution.ambiguous.map((entry) => entry.label));
8159
8394
  if (unresolvedTargets.length > 0) {
8160
8395
  return { usedBroker: true, invokedTargets: [], unresolvedTargets };
@@ -8181,18 +8416,25 @@ async function sendScoutMessage(input) {
8181
8416
  body: input.body,
8182
8417
  mentions: mentionResolution.resolved.filter((target) => validTargets.includes(target.agentId)).map((target) => ({ actorId: target.agentId, label: target.label })),
8183
8418
  speech: speechText ? { text: speechText } : undefined,
8184
- audience: validTargets.length > 0 ? { notify: validTargets, reason: "mention" } : undefined,
8419
+ audience: validTargets.length > 0 ? { notify: validTargets, reason: relayAudienceReason(conversation) } : undefined,
8185
8420
  visibility: conversation.visibility,
8186
8421
  policy: "durable",
8187
8422
  createdAt: createdAtMs,
8188
8423
  metadata: {
8189
8424
  source: "scout-cli",
8190
- relayChannel: input.channel ?? "shared",
8425
+ relayChannel: relayChannelMetadata(conversation, input.channel),
8426
+ relayTargetIds: validTargets,
8191
8427
  relayMessageId: messageId,
8192
8428
  returnAddress
8193
8429
  }
8194
8430
  });
8195
- return { usedBroker: true, invokedTargets: validTargets, unresolvedTargets };
8431
+ return {
8432
+ usedBroker: true,
8433
+ conversationId: conversation.id,
8434
+ messageId,
8435
+ invokedTargets: validTargets,
8436
+ unresolvedTargets
8437
+ };
8196
8438
  }
8197
8439
  async function sendScoutMessageToAgentIds(input) {
8198
8440
  const broker = await loadScoutBrokerContext();
@@ -8207,7 +8449,9 @@ async function sendScoutMessageToAgentIds(input) {
8207
8449
  const createdAtMs = input.createdAtMs ?? Date.now();
8208
8450
  const source = input.source?.trim() || "scout-mcp";
8209
8451
  const senderId = await resolveConversationActorId(broker.baseUrl, broker.snapshot, broker.node.id, input.senderId, currentDirectory);
8210
- const requestedTargetIds = [...new Set(input.targetAgentIds.map((targetId) => targetId.trim()).filter(Boolean).filter((targetId) => targetId !== senderId))];
8452
+ const requestedTargetIds = [
8453
+ ...new Set(input.targetAgentIds.map((targetId) => targetId.trim()).filter(Boolean).filter((targetId) => targetId !== senderId))
8454
+ ];
8211
8455
  const availableTargets = (await Promise.all(requestedTargetIds.map(async (targetId) => await ensureTargetRelayAgentRegistered(broker.baseUrl, broker.snapshot, broker.node.id, targetId, currentDirectory) ? targetId : null))).filter((targetId) => Boolean(targetId && broker.snapshot.agents[targetId]));
8212
8456
  const unresolvedTargetIds = requestedTargetIds.filter((targetId) => !availableTargets.includes(targetId));
8213
8457
  if (unresolvedTargetIds.length > 0) {
@@ -8244,14 +8488,14 @@ async function sendScoutMessageToAgentIds(input) {
8244
8488
  speech: speechText ? { text: speechText } : undefined,
8245
8489
  audience: availableTargets.length > 0 ? {
8246
8490
  notify: availableTargets,
8247
- reason: conversation.kind === "direct" ? "direct_message" : "mention"
8491
+ reason: relayAudienceReason(conversation)
8248
8492
  } : undefined,
8249
8493
  visibility: conversation.visibility,
8250
8494
  policy: "durable",
8251
8495
  createdAt: createdAtMs,
8252
8496
  metadata: {
8253
8497
  source,
8254
- relayChannel: input.channel ?? (conversation.kind === "direct" ? "dm" : "shared"),
8498
+ relayChannel: relayChannelMetadata(conversation, input.channel),
8255
8499
  relayTargetIds: availableTargets,
8256
8500
  relayMessageId: messageId,
8257
8501
  returnAddress
@@ -8375,8 +8619,12 @@ async function askScoutAgentById(input) {
8375
8619
  raw: targetLabel.replace(/^@/, ""),
8376
8620
  label: targetLabel,
8377
8621
  definitionId: broker.snapshot.agents[targetAgentId]?.definitionId ?? metadataString2(broker.snapshot.agents[targetAgentId]?.metadata, "definitionId") ?? targetAgentId,
8378
- ...broker.snapshot.agents[targetAgentId]?.workspaceQualifier ? { workspaceQualifier: broker.snapshot.agents[targetAgentId]?.workspaceQualifier } : {},
8379
- ...broker.snapshot.agents[targetAgentId]?.nodeQualifier ? { nodeQualifier: broker.snapshot.agents[targetAgentId]?.nodeQualifier } : {}
8622
+ ...broker.snapshot.agents[targetAgentId]?.workspaceQualifier ? {
8623
+ workspaceQualifier: broker.snapshot.agents[targetAgentId]?.workspaceQualifier
8624
+ } : {},
8625
+ ...broker.snapshot.agents[targetAgentId]?.nodeQualifier ? {
8626
+ nodeQualifier: broker.snapshot.agents[targetAgentId]?.nodeQualifier
8627
+ } : {}
8380
8628
  }
8381
8629
  };
8382
8630
  const targetReady = await ensureTargetRelayAgentRegistered(broker.baseUrl, broker.snapshot, broker.node.id, targetAgentId, currentDirectory);
@@ -8400,6 +8648,15 @@ async function askScoutAgentById(input) {
8400
8648
  conversationId: conversation.id,
8401
8649
  replyToMessageId: messageId
8402
8650
  });
8651
+ const workItem = input.workItem ? await createScoutTrackedWorkItem({
8652
+ baseUrl: broker.baseUrl,
8653
+ senderId,
8654
+ targetAgentId,
8655
+ conversationId: conversation.id,
8656
+ createdAtMs,
8657
+ source,
8658
+ workItem: input.workItem
8659
+ }) : undefined;
8403
8660
  await brokerPostJson(broker.baseUrl, scoutBrokerPaths.v1.messages, {
8404
8661
  id: messageId,
8405
8662
  conversationId: conversation.id,
@@ -8411,15 +8668,16 @@ async function askScoutAgentById(input) {
8411
8668
  speech: speechText ? { text: speechText } : undefined,
8412
8669
  audience: {
8413
8670
  notify: [targetAgentId],
8414
- reason: conversation.kind === "direct" ? "direct_message" : "mention"
8671
+ reason: relayAudienceReason(conversation)
8415
8672
  },
8416
8673
  visibility: conversation.visibility,
8417
8674
  policy: "durable",
8418
8675
  createdAt: createdAtMs,
8419
8676
  metadata: {
8420
8677
  source,
8421
- relayChannel: input.channel ?? (conversation.kind === "direct" ? "dm" : "shared"),
8678
+ relayChannel: relayChannelMetadata(conversation, input.channel),
8422
8679
  relayTarget: targetAgentId,
8680
+ collaborationRecordId: workItem?.id,
8423
8681
  returnAddress
8424
8682
  }
8425
8683
  });
@@ -8430,6 +8688,7 @@ async function askScoutAgentById(input) {
8430
8688
  targetAgentId,
8431
8689
  action: "consult",
8432
8690
  task: input.body.trim(),
8691
+ collaborationRecordId: workItem?.id,
8433
8692
  conversationId: conversation.id,
8434
8693
  messageId,
8435
8694
  execution: input.executionHarness ? { harness: input.executionHarness } : undefined,
@@ -8438,8 +8697,9 @@ async function askScoutAgentById(input) {
8438
8697
  createdAt: createdAtMs,
8439
8698
  metadata: {
8440
8699
  source,
8441
- relayChannel: input.channel ?? (conversation.kind === "direct" ? "dm" : "shared"),
8700
+ relayChannel: relayChannelMetadata(conversation, input.channel),
8442
8701
  relayTarget: targetAgentId,
8702
+ collaborationRecordId: workItem?.id,
8443
8703
  returnAddress
8444
8704
  }
8445
8705
  });
@@ -8447,7 +8707,8 @@ async function askScoutAgentById(input) {
8447
8707
  usedBroker: true,
8448
8708
  flight: invocationResponse.flight,
8449
8709
  conversationId: conversation.id,
8450
- messageId
8710
+ messageId,
8711
+ workItem
8451
8712
  };
8452
8713
  }
8453
8714
  async function askScoutQuestion(input) {
@@ -8490,10 +8751,20 @@ async function askScoutQuestion(input) {
8490
8751
  const messageId = `m-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`;
8491
8752
  const messageBody = input.body.trim().startsWith(target.label) ? input.body.trim() : `${target.label} ${input.body.trim()}`;
8492
8753
  const speechText = input.shouldSpeak ? stripScoutAgentSelectorLabels(messageBody) : "";
8754
+ const createdAt = input.createdAtMs ?? Date.now();
8493
8755
  const returnAddress = buildScoutReturnAddress(broker.snapshot, senderId, {
8494
8756
  conversationId: conversation.id,
8495
8757
  replyToMessageId: messageId
8496
8758
  });
8759
+ const workItem = input.workItem ? await createScoutTrackedWorkItem({
8760
+ baseUrl: broker.baseUrl,
8761
+ senderId,
8762
+ targetAgentId: target.agentId,
8763
+ conversationId: conversation.id,
8764
+ createdAtMs: createdAt,
8765
+ source: "scout-cli",
8766
+ workItem: input.workItem
8767
+ }) : undefined;
8497
8768
  await brokerPostJson(broker.baseUrl, scoutBrokerPaths.v1.messages, {
8498
8769
  id: messageId,
8499
8770
  conversationId: conversation.id,
@@ -8503,14 +8774,18 @@ async function askScoutQuestion(input) {
8503
8774
  body: messageBody,
8504
8775
  mentions: [{ actorId: target.agentId, label: target.label }],
8505
8776
  speech: speechText ? { text: speechText } : undefined,
8506
- audience: { notify: [target.agentId], reason: "mention" },
8777
+ audience: {
8778
+ notify: [target.agentId],
8779
+ reason: relayAudienceReason(conversation)
8780
+ },
8507
8781
  visibility: conversation.visibility,
8508
8782
  policy: "durable",
8509
- createdAt: input.createdAtMs ?? Date.now(),
8783
+ createdAt,
8510
8784
  metadata: {
8511
8785
  source: "scout-cli",
8512
- relayChannel: input.channel ?? (conversation.kind === "direct" ? "dm" : "shared"),
8786
+ relayChannel: relayChannelMetadata(conversation, input.channel),
8513
8787
  relayTarget: target.agentId,
8788
+ collaborationRecordId: workItem?.id,
8514
8789
  returnAddress
8515
8790
  }
8516
8791
  });
@@ -8521,16 +8796,18 @@ async function askScoutQuestion(input) {
8521
8796
  targetAgentId: target.agentId,
8522
8797
  action: "consult",
8523
8798
  task: messageBody,
8799
+ collaborationRecordId: workItem?.id,
8524
8800
  conversationId: conversation.id,
8525
8801
  messageId,
8526
8802
  execution: input.executionHarness ? { harness: input.executionHarness } : undefined,
8527
8803
  ensureAwake: true,
8528
8804
  stream: false,
8529
- createdAt: Date.now(),
8805
+ createdAt,
8530
8806
  metadata: {
8531
8807
  source: "scout-cli",
8532
- relayChannel: input.channel ?? (conversation.kind === "direct" ? "dm" : "shared"),
8808
+ relayChannel: relayChannelMetadata(conversation, input.channel),
8533
8809
  relayTarget: target.agentId,
8810
+ collaborationRecordId: workItem?.id,
8534
8811
  returnAddress
8535
8812
  }
8536
8813
  });
@@ -8538,7 +8815,8 @@ async function askScoutQuestion(input) {
8538
8815
  usedBroker: true,
8539
8816
  flight: invocationResponse.flight,
8540
8817
  conversationId: conversation.id,
8541
- messageId
8818
+ messageId,
8819
+ workItem
8542
8820
  };
8543
8821
  }
8544
8822
  async function loadBrokerFlight(baseUrl, flightId) {
@@ -8734,17 +9012,25 @@ async function listScoutAgents(options = {}) {
8734
9012
  continue;
8735
9013
  if (isSupersededBrokerAgent(broker.snapshot, message.actorId))
8736
9014
  continue;
8737
- const current = messageStats.get(message.actorId) ?? { messages: 0, lastSeen: null };
9015
+ const current = messageStats.get(message.actorId) ?? {
9016
+ messages: 0,
9017
+ lastSeen: null
9018
+ };
8738
9019
  current.messages += 1;
8739
- current.lastSeen = maxDefined([current.lastSeen, normalizeUnixTimestamp(message.createdAt)]);
9020
+ current.lastSeen = maxDefined([
9021
+ current.lastSeen,
9022
+ normalizeUnixTimestamp(message.createdAt)
9023
+ ]);
8740
9024
  messageStats.set(message.actorId, current);
8741
9025
  }
8742
- return [...new Set([
8743
- ...Object.keys(broker.snapshot.agents ?? {}),
8744
- ...Array.from(endpointsByAgent.keys()),
8745
- ...Array.from(messageStats.keys()),
8746
- ...Array.from(configuredAgentIds.values())
8747
- ])].filter((agentId) => agentId && agentId !== OPERATOR_ID).filter((agentId) => !isSupersededBrokerAgent(broker.snapshot, agentId)).map((agentId) => {
9026
+ return [
9027
+ ...new Set([
9028
+ ...Object.keys(broker.snapshot.agents ?? {}),
9029
+ ...Array.from(endpointsByAgent.keys()),
9030
+ ...Array.from(messageStats.keys()),
9031
+ ...Array.from(configuredAgentIds.values())
9032
+ ])
9033
+ ].filter((agentId) => agentId && agentId !== OPERATOR_ID).filter((agentId) => !isSupersededBrokerAgent(broker.snapshot, agentId)).map((agentId) => {
8748
9034
  const endpoints = endpointsByAgent.get(agentId) ?? [];
8749
9035
  const brokerMessages = messageStats.get(agentId);
8750
9036
  const registrationKind = configuredAgentIds.has(agentId) ? "configured" : "broker";
@@ -8911,6 +9197,12 @@ function renderAmbiguousCandidate(label) {
8911
9197
  return "";
8912
9198
  return trimmed.startsWith("@") ? trimmed : `@${trimmed}`;
8913
9199
  }
9200
+ function renderConversationRoute(conversationId) {
9201
+ if (!conversationId) {
9202
+ return "conversation";
9203
+ }
9204
+ return conversationId.startsWith("dm.") ? `DM ${conversationId}` : `conversation ${conversationId}`;
9205
+ }
8914
9206
  function formatScoutAskRoutingError(result, targetLabel) {
8915
9207
  const renderedTarget = renderScoutTargetLabel(targetLabel);
8916
9208
  const diagnostic = result.targetDiagnostic;
@@ -8956,12 +9248,15 @@ async function runAskWithOptions(context, options) {
8956
9248
  if (!result.flight) {
8957
9249
  throw new Error(formatScoutAskRoutingError(result, options.targetLabel));
8958
9250
  }
8959
- context.stderr(`asking ${result.flight.targetAgentId}... (flight ${result.flight.id})`);
9251
+ context.stderr(`asking ${result.flight.targetAgentId} as ${senderId} via ${renderConversationRoute(result.conversationId)}... (flight ${result.flight.id})`);
8960
9252
  const completed = await waitForScoutFlight(resolveScoutBrokerUrl(), result.flight.id, {
8961
9253
  timeoutSeconds: options.timeoutSeconds,
8962
9254
  onUpdate: (_flight, detail) => context.stderr(detail)
8963
9255
  });
8964
9256
  context.output.writeValue({
9257
+ senderId,
9258
+ conversationId: result.conversationId ?? null,
9259
+ messageId: result.messageId ?? null,
8965
9260
  flight: completed,
8966
9261
  output: completed.output ?? completed.summary ?? ""
8967
9262
  }, (value) => value.output);
@@ -9018,6 +9313,13 @@ function renderScoutAgentList(entries) {
9018
9313
  }
9019
9314
  function renderScoutMessagePostResult(result) {
9020
9315
  const lines = [result.message];
9316
+ if (result.senderId) {
9317
+ lines.push(`From: ${result.senderId}`);
9318
+ }
9319
+ if (result.conversationId) {
9320
+ const route = result.conversationId.startsWith("dm.") ? "DM" : "Conversation";
9321
+ lines.push(`${route}: ${result.conversationId}`);
9322
+ }
9021
9323
  if (result.invokedTargets.length > 0) {
9022
9324
  lines.push(`Routed to: ${result.invokedTargets.join(", ")}`);
9023
9325
  }
@@ -9136,6 +9438,8 @@ async function runSendCommand(context, args) {
9136
9438
  throw new Error(formatScoutSendRoutingError(result.unresolvedTargets));
9137
9439
  }
9138
9440
  context.output.writeValue({
9441
+ senderId,
9442
+ conversationId: result.conversationId,
9139
9443
  message: options.message,
9140
9444
  invokedTargets: result.invokedTargets,
9141
9445
  unresolvedTargets: result.unresolvedTargets
@@ -39549,11 +39853,7 @@ function buildIdentityCandidate(entry) {
39549
39853
  ...entry.workspace ? { workspaceQualifier: entry.workspace } : {},
39550
39854
  ...entry.node ? { nodeQualifier: entry.node } : {},
39551
39855
  ...entry.harness ? { harness: entry.harness } : {},
39552
- aliases: [
39553
- entry.selector,
39554
- entry.defaultSelector,
39555
- entry.handle
39556
- ].filter((value) => Boolean(value && value.trim().length > 0))
39856
+ aliases: [entry.selector, entry.defaultSelector, entry.handle].filter((value) => Boolean(value && value.trim().length > 0))
39557
39857
  };
39558
39858
  }
39559
39859
  function decorateAgentLabels(entries) {
@@ -39756,7 +40056,11 @@ async function resolveScoutAgentForMcp(input) {
39756
40056
  const diagnosis = diagnoseAgentIdentity(selector, identityCandidates);
39757
40057
  if (diagnosis.kind === "resolved") {
39758
40058
  const match = candidates.find((candidate) => candidate.agentId === diagnosis.match.agentId) ?? null;
39759
- return { kind: match ? "resolved" : "unresolved", candidate: match, candidates: [] };
40059
+ return {
40060
+ kind: match ? "resolved" : "unresolved",
40061
+ candidate: match,
40062
+ candidates: []
40063
+ };
39760
40064
  }
39761
40065
  if (diagnosis.kind === "ambiguous") {
39762
40066
  const ambiguous = diagnosis.candidates.map((candidate) => candidates.find((entry) => entry.agentId === candidate.agentId)).filter((candidate) => Boolean(candidate));
@@ -39770,8 +40074,22 @@ function defaultScoutMcpDependencies(env) {
39770
40074
  resolveBrokerUrl: () => env.OPENSCOUT_BROKER_URL?.trim() || resolveScoutBrokerUrl(),
39771
40075
  searchAgents: ({ query, currentDirectory, limit }) => searchScoutAgentsForMcp({ query, currentDirectory, limit }),
39772
40076
  resolveAgent: ({ label, currentDirectory }) => resolveScoutAgentForMcp({ label, currentDirectory }),
39773
- sendMessage: ({ senderId, body, channel, shouldSpeak, currentDirectory }) => sendScoutMessage({ senderId, body, channel, shouldSpeak, currentDirectory }),
39774
- sendMessageToAgentIds: ({ senderId, body, targetAgentIds, channel, shouldSpeak, currentDirectory, source }) => sendScoutMessageToAgentIds({
40077
+ sendMessage: ({ senderId, body, channel, shouldSpeak, currentDirectory }) => sendScoutMessage({
40078
+ senderId,
40079
+ body,
40080
+ channel,
40081
+ shouldSpeak,
40082
+ currentDirectory
40083
+ }),
40084
+ sendMessageToAgentIds: ({
40085
+ senderId,
40086
+ body,
40087
+ targetAgentIds,
40088
+ channel,
40089
+ shouldSpeak,
40090
+ currentDirectory,
40091
+ source
40092
+ }) => sendScoutMessageToAgentIds({
39775
40093
  senderId,
39776
40094
  body,
39777
40095
  targetAgentIds,
@@ -39780,23 +40098,43 @@ function defaultScoutMcpDependencies(env) {
39780
40098
  currentDirectory,
39781
40099
  source
39782
40100
  }),
39783
- askQuestion: ({ senderId, targetLabel, body, channel, shouldSpeak, currentDirectory }) => askScoutQuestion({
40101
+ askQuestion: ({
39784
40102
  senderId,
39785
40103
  targetLabel,
39786
40104
  body,
40105
+ workItem,
40106
+ channel,
40107
+ shouldSpeak,
40108
+ currentDirectory
40109
+ }) => askScoutQuestion({
40110
+ senderId,
40111
+ targetLabel,
40112
+ body,
40113
+ workItem,
39787
40114
  channel,
39788
40115
  shouldSpeak,
39789
40116
  currentDirectory
39790
40117
  }),
39791
- askAgentById: ({ senderId, targetAgentId, body, channel, shouldSpeak, currentDirectory, source }) => askScoutAgentById({
40118
+ askAgentById: ({
40119
+ senderId,
40120
+ targetAgentId,
40121
+ body,
40122
+ workItem,
40123
+ channel,
40124
+ shouldSpeak,
40125
+ currentDirectory,
40126
+ source
40127
+ }) => askScoutAgentById({
39792
40128
  senderId,
39793
40129
  targetAgentId,
39794
40130
  body,
40131
+ workItem,
39795
40132
  channel,
39796
40133
  shouldSpeak,
39797
40134
  currentDirectory,
39798
40135
  source
39799
40136
  }),
40137
+ updateWorkItem: (input) => updateScoutWorkItem(input),
39800
40138
  waitForFlight: (baseUrl, flightId, options) => waitForScoutFlight(baseUrl, flightId, options)
39801
40139
  };
39802
40140
  }
@@ -39923,10 +40261,19 @@ function createScoutMcpServer(options) {
39923
40261
  destructiveHint: false,
39924
40262
  openWorldHint: false
39925
40263
  }
39926
- }, async ({ body, currentDirectory, senderId, channel, shouldSpeak, mentionAgentIds }) => {
40264
+ }, async ({
40265
+ body,
40266
+ currentDirectory,
40267
+ senderId,
40268
+ channel,
40269
+ shouldSpeak,
40270
+ mentionAgentIds
40271
+ }) => {
39927
40272
  const resolvedCurrentDirectory = resolveToolCurrentDirectory(currentDirectory, options.defaultCurrentDirectory);
39928
40273
  const resolvedSenderId = await deps.resolveSenderId(senderId, resolvedCurrentDirectory, env);
39929
- const explicitTargetIds = [...new Set((mentionAgentIds ?? []).map((value) => value.trim()).filter(Boolean))];
40274
+ const explicitTargetIds = [
40275
+ ...new Set((mentionAgentIds ?? []).map((value) => value.trim()).filter(Boolean))
40276
+ ];
39930
40277
  if (explicitTargetIds.length > 0) {
39931
40278
  const result2 = await deps.sendMessageToAgentIds({
39932
40279
  senderId: resolvedSenderId,
@@ -39964,8 +40311,8 @@ function createScoutMcpServer(options) {
39964
40311
  senderId: resolvedSenderId,
39965
40312
  mode: "body_mentions",
39966
40313
  usedBroker: result.usedBroker,
39967
- conversationId: null,
39968
- messageId: null,
40314
+ conversationId: result.conversationId ?? null,
40315
+ messageId: result.messageId ?? null,
39969
40316
  invokedTargetIds: result.invokedTargets,
39970
40317
  unresolvedTargetIds: result.unresolvedTargets
39971
40318
  };
@@ -39976,13 +40323,14 @@ function createScoutMcpServer(options) {
39976
40323
  });
39977
40324
  server.registerTool("invocations_ask", {
39978
40325
  title: "Ask Scout Agent",
39979
- description: "Create a broker-backed Scout invocation. Prefer targetAgentId when the host already resolved an @mention.",
40326
+ description: "Create a broker-backed Scout invocation. Provide workItem to mint a durable workId beyond the message and flight ids.",
39980
40327
  inputSchema: object2({
39981
40328
  body: string2().min(1),
39982
40329
  currentDirectory: string2().optional(),
39983
40330
  senderId: string2().optional(),
39984
40331
  targetAgentId: string2().optional(),
39985
40332
  targetLabel: string2().optional(),
40333
+ workItem: workItemInputSchema.optional(),
39986
40334
  channel: string2().optional(),
39987
40335
  shouldSpeak: boolean2().optional(),
39988
40336
  awaitReply: boolean2().optional(),
@@ -39998,7 +40346,18 @@ function createScoutMcpServer(options) {
39998
40346
  destructiveHint: false,
39999
40347
  openWorldHint: false
40000
40348
  }
40001
- }, async ({ body, currentDirectory, senderId, targetAgentId, targetLabel, channel, shouldSpeak, awaitReply, timeoutSeconds }) => {
40349
+ }, async ({
40350
+ body,
40351
+ currentDirectory,
40352
+ senderId,
40353
+ targetAgentId,
40354
+ targetLabel,
40355
+ workItem,
40356
+ channel,
40357
+ shouldSpeak,
40358
+ awaitReply,
40359
+ timeoutSeconds
40360
+ }) => {
40002
40361
  const resolvedCurrentDirectory = resolveToolCurrentDirectory(currentDirectory, options.defaultCurrentDirectory);
40003
40362
  const resolvedSenderId = await deps.resolveSenderId(senderId, resolvedCurrentDirectory, env);
40004
40363
  const shouldAwait = Boolean(awaitReply);
@@ -40007,6 +40366,7 @@ function createScoutMcpServer(options) {
40007
40366
  senderId: resolvedSenderId,
40008
40367
  targetAgentId: targetAgentId.trim(),
40009
40368
  body,
40369
+ workItem,
40010
40370
  channel,
40011
40371
  shouldSpeak,
40012
40372
  currentDirectory: resolvedCurrentDirectory,
@@ -40023,9 +40383,13 @@ function createScoutMcpServer(options) {
40023
40383
  conversationId: result2.conversationId ?? null,
40024
40384
  messageId: result2.messageId ?? null,
40025
40385
  flight: completedFlight2 ?? result2.flight ?? null,
40386
+ flightId: completedFlight2?.id ?? result2.flight?.id ?? null,
40026
40387
  output: completedFlight2?.output ?? completedFlight2?.summary ?? null,
40027
40388
  unresolvedTargetId: result2.unresolvedTargetId ?? null,
40028
40389
  unresolvedTargetLabel: null,
40390
+ workItem: result2.workItem ?? null,
40391
+ workId: result2.workItem?.id ?? null,
40392
+ workUrl: result2.workItem ? `/api/work/${encodeURIComponent(result2.workItem.id)}` : null,
40029
40393
  targetDiagnostic: result2.targetDiagnostic ?? null
40030
40394
  };
40031
40395
  return {
@@ -40037,6 +40401,7 @@ function createScoutMcpServer(options) {
40037
40401
  senderId: resolvedSenderId,
40038
40402
  targetLabel: targetLabel.trim(),
40039
40403
  body,
40404
+ workItem,
40040
40405
  channel,
40041
40406
  shouldSpeak,
40042
40407
  currentDirectory: resolvedCurrentDirectory
@@ -40052,9 +40417,13 @@ function createScoutMcpServer(options) {
40052
40417
  conversationId: result.conversationId ?? null,
40053
40418
  messageId: result.messageId ?? null,
40054
40419
  flight: completedFlight ?? result.flight ?? null,
40420
+ flightId: completedFlight?.id ?? result.flight?.id ?? null,
40055
40421
  output: completedFlight?.output ?? completedFlight?.summary ?? null,
40056
40422
  unresolvedTargetId: null,
40057
40423
  unresolvedTargetLabel: result.unresolvedTarget ?? null,
40424
+ workItem: result.workItem ?? null,
40425
+ workId: result.workItem?.id ?? null,
40426
+ workUrl: result.workItem ? `/api/work/${encodeURIComponent(result.workItem.id)}` : null,
40058
40427
  targetDiagnostic: result.targetDiagnostic ?? null
40059
40428
  };
40060
40429
  return {
@@ -40062,6 +40431,42 @@ function createScoutMcpServer(options) {
40062
40431
  structuredContent
40063
40432
  };
40064
40433
  });
40434
+ server.registerTool("work_update", {
40435
+ title: "Update Scout Work",
40436
+ description: "Update a durable Scout work item and append a matching collaboration event.",
40437
+ inputSchema: object2({
40438
+ currentDirectory: string2().optional(),
40439
+ senderId: string2().optional(),
40440
+ work: workItemUpdateSchema
40441
+ }),
40442
+ outputSchema: workUpdateResultSchema,
40443
+ annotations: {
40444
+ readOnlyHint: false,
40445
+ idempotentHint: false,
40446
+ destructiveHint: false,
40447
+ openWorldHint: false
40448
+ }
40449
+ }, async ({ currentDirectory, senderId, work }) => {
40450
+ const resolvedCurrentDirectory = resolveToolCurrentDirectory(currentDirectory, options.defaultCurrentDirectory);
40451
+ const resolvedSenderId = await deps.resolveSenderId(senderId, resolvedCurrentDirectory, env);
40452
+ const workItem = await deps.updateWorkItem({
40453
+ ...work,
40454
+ actorId: resolvedSenderId,
40455
+ source: "scout-mcp"
40456
+ });
40457
+ const structuredContent = {
40458
+ currentDirectory: resolvedCurrentDirectory,
40459
+ senderId: resolvedSenderId,
40460
+ usedBroker: workItem !== null,
40461
+ workItem,
40462
+ workId: workItem?.id ?? null,
40463
+ workUrl: workItem ? `/api/work/${encodeURIComponent(workItem.id)}` : null
40464
+ };
40465
+ return {
40466
+ content: createTextContent(structuredContent),
40467
+ structuredContent
40468
+ };
40469
+ });
40065
40470
  return server;
40066
40471
  }
40067
40472
  async function runScoutMcpServer(options) {
@@ -40072,7 +40477,7 @@ async function runScoutMcpServer(options) {
40072
40477
  const transport = new StdioServerTransport;
40073
40478
  await server.connect(transport);
40074
40479
  }
40075
- var AGENT_STATE_VALUES, REGISTRATION_KIND_VALUES, RESOLVE_KIND_VALUES, flightSchema, agentCandidateSchema, whoAmISchema, searchResultSchema, resolveResultSchema, sendResultSchema, askResultSchema;
40480
+ var AGENT_STATE_VALUES, REGISTRATION_KIND_VALUES, RESOLVE_KIND_VALUES, flightSchema, trackedWorkItemSchema, workItemInputSchema, waitingOnSchema, progressSchema, workItemUpdateSchema, agentCandidateSchema, whoAmISchema, searchResultSchema, resolveResultSchema, sendResultSchema, askResultSchema, workUpdateResultSchema;
40076
40481
  var init_scout_mcp = __esm(async () => {
40077
40482
  init_mcp();
40078
40483
  init_stdio2();
@@ -40081,8 +40486,18 @@ var init_scout_mcp = __esm(async () => {
40081
40486
  init_v4();
40082
40487
  init_product();
40083
40488
  await init_service();
40084
- AGENT_STATE_VALUES = ["offline", "idle", "active", "waiting", "discovered"];
40085
- REGISTRATION_KIND_VALUES = ["broker", "configured", "discovered"];
40489
+ AGENT_STATE_VALUES = [
40490
+ "offline",
40491
+ "idle",
40492
+ "active",
40493
+ "waiting",
40494
+ "discovered"
40495
+ ];
40496
+ REGISTRATION_KIND_VALUES = [
40497
+ "broker",
40498
+ "configured",
40499
+ "discovered"
40500
+ ];
40086
40501
  RESOLVE_KIND_VALUES = ["resolved", "ambiguous", "unresolved"];
40087
40502
  flightSchema = object2({
40088
40503
  id: string2(),
@@ -40097,6 +40512,61 @@ var init_scout_mcp = __esm(async () => {
40097
40512
  completedAt: number2().optional(),
40098
40513
  metadata: record(string2(), unknown()).optional()
40099
40514
  });
40515
+ trackedWorkItemSchema = object2({
40516
+ id: string2(),
40517
+ title: string2(),
40518
+ summary: string2().nullable(),
40519
+ state: _enum2(["open", "working", "waiting", "review", "done", "cancelled"]),
40520
+ acceptanceState: _enum2(["none", "pending", "accepted", "reopened"]),
40521
+ ownerId: string2().nullable(),
40522
+ nextMoveOwnerId: string2().nullable(),
40523
+ conversationId: string2().nullable(),
40524
+ priority: _enum2(["low", "normal", "high", "urgent"]).nullable()
40525
+ });
40526
+ workItemInputSchema = object2({
40527
+ title: string2().min(1),
40528
+ summary: string2().optional(),
40529
+ priority: _enum2(["low", "normal", "high", "urgent"]).optional(),
40530
+ labels: array(string2()).optional(),
40531
+ parentId: string2().optional(),
40532
+ acceptanceState: _enum2(["none", "pending", "accepted", "reopened"]).optional(),
40533
+ metadata: record(string2(), unknown()).optional()
40534
+ });
40535
+ waitingOnSchema = object2({
40536
+ kind: _enum2([
40537
+ "actor",
40538
+ "question",
40539
+ "work_item",
40540
+ "approval",
40541
+ "artifact",
40542
+ "condition"
40543
+ ]),
40544
+ label: string2().min(1),
40545
+ targetId: string2().optional(),
40546
+ metadata: record(string2(), unknown()).optional()
40547
+ });
40548
+ progressSchema = object2({
40549
+ completedSteps: number2().optional(),
40550
+ totalSteps: number2().optional(),
40551
+ checkpoint: string2().optional(),
40552
+ summary: string2().optional(),
40553
+ percent: number2().optional()
40554
+ });
40555
+ workItemUpdateSchema = object2({
40556
+ workId: string2().min(1),
40557
+ title: string2().optional(),
40558
+ summary: string2().nullable().optional(),
40559
+ state: _enum2(["open", "working", "waiting", "review", "done", "cancelled"]).optional(),
40560
+ acceptanceState: _enum2(["none", "pending", "accepted", "reopened"]).optional(),
40561
+ ownerId: string2().nullable().optional(),
40562
+ nextMoveOwnerId: string2().nullable().optional(),
40563
+ priority: _enum2(["low", "normal", "high", "urgent"]).nullable().optional(),
40564
+ labels: array(string2()).optional(),
40565
+ waitingOn: waitingOnSchema.nullable().optional(),
40566
+ progress: progressSchema.nullable().optional(),
40567
+ metadata: record(string2(), unknown()).optional(),
40568
+ eventSummary: string2().optional()
40569
+ });
40100
40570
  agentCandidateSchema = object2({
40101
40571
  agentId: string2(),
40102
40572
  label: string2(),
@@ -40151,11 +40621,23 @@ var init_scout_mcp = __esm(async () => {
40151
40621
  conversationId: string2().nullable(),
40152
40622
  messageId: string2().nullable(),
40153
40623
  flight: flightSchema.nullable(),
40624
+ flightId: string2().nullable(),
40154
40625
  output: string2().nullable(),
40155
40626
  unresolvedTargetId: string2().nullable(),
40156
40627
  unresolvedTargetLabel: string2().nullable(),
40628
+ workItem: trackedWorkItemSchema.nullable(),
40629
+ workId: string2().nullable(),
40630
+ workUrl: string2().nullable(),
40157
40631
  targetDiagnostic: object2({}).catchall(unknown()).nullable()
40158
40632
  });
40633
+ workUpdateResultSchema = object2({
40634
+ currentDirectory: string2(),
40635
+ senderId: string2(),
40636
+ usedBroker: boolean2(),
40637
+ workItem: trackedWorkItemSchema.nullable(),
40638
+ workId: string2().nullable(),
40639
+ workUrl: string2().nullable()
40640
+ });
40159
40641
  });
40160
40642
 
40161
40643
  // ../../apps/desktop/src/cli/commands/mcp.ts
@@ -55989,46 +56471,30 @@ import { dirname as dirname12, join as join26, resolve as resolve10 } from "path
55989
56471
  import { fileURLToPath as fileURLToPath8 } from "url";
55990
56472
  function renderServerCommandHelp() {
55991
56473
  return [
55992
- "scout server \u2014 desktop web UI (Bun runtime)",
56474
+ "scout server \u2014 Scout web UI (Bun runtime)",
55993
56475
  "",
55994
56476
  "Usage:",
55995
56477
  " scout server start [options]",
55996
56478
  " scout server open [options]",
55997
- " scout server control-plane start [options]",
55998
- " scout server control-plane open [options]",
55999
56479
  "",
56000
56480
  "Subcommands:",
56001
- " start Full desktop web API + UI assets (default stack).",
56002
- " open Open the full web UI and start it on demand if needed.",
56003
- " control-plane start Pairing + relay/shell activity only (`@openscout/web` surface).",
56004
- " control-plane open Open the control-plane UI and start it on demand if needed.",
56481
+ " start Start the Scout web UI server.",
56482
+ " open Open the Scout web UI (starts server on demand if needed).",
56005
56483
  "",
56006
56484
  "Options:",
56007
- " --port <n> Listen port (default 3200; env SCOUT_WEB_PORT)",
56008
- " --static Serve built UI from disk (sets SCOUT_STATIC=1)",
56009
- " --static-root DIR Static client root (env SCOUT_STATIC_ROOT)",
56010
- " --vite-url URL Dev proxy target for non-API routes (env SCOUT_VITE_URL)",
56485
+ " --port <n> Listen port (default 3200; env OPENSCOUT_WEB_PORT)",
56486
+ " --static Serve built UI from disk",
56487
+ " --static-root DIR Static client root (env OPENSCOUT_WEB_STATIC_ROOT)",
56488
+ " --vite-url URL Dev proxy target for non-API routes (env OPENSCOUT_WEB_VITE_URL)",
56011
56489
  " --cwd DIR Workspace / setup root (env OPENSCOUT_SETUP_CWD)",
56012
56490
  " --path PATH Browser path for `open` (default /)",
56013
56491
  "",
56014
- "Requires `bun` on PATH.",
56015
- "Published installs include dist/client for the full web UI and dist/control-plane-client",
56016
- "for the minimal control-plane UI; if present and you do not pass --vite-url, the matching",
56017
- "static assets are used by default."
56492
+ "Requires `bun` on PATH."
56018
56493
  ].join(`
56019
56494
  `);
56020
56495
  }
56021
56496
  function resolveScoutWebServerEntry() {
56022
- const mainDir = dirname12(fileURLToPath8(import.meta.url));
56023
- const bundled = join26(mainDir, "scout-web-server.mjs");
56024
- if (existsSync18(bundled)) {
56025
- return bundled;
56026
- }
56027
- const source = fileURLToPath8(new URL("../../server/index.ts", import.meta.url));
56028
- if (existsSync18(source)) {
56029
- return source;
56030
- }
56031
- throw new ScoutCliError("Could not find Scout web server entry. Rebuild @openscout/scout or run from the OpenScout repository.");
56497
+ return resolveScoutControlPlaneWebServerEntry();
56032
56498
  }
56033
56499
  function resolveScoutControlPlaneWebServerEntry() {
56034
56500
  const mainDir = dirname12(fileURLToPath8(import.meta.url));
@@ -56051,25 +56517,25 @@ function parseServerFlags(args) {
56051
56517
  const v = args[++i];
56052
56518
  if (!v)
56053
56519
  throw new ScoutCliError("--port requires a value");
56054
- env.SCOUT_WEB_PORT = v;
56520
+ env.OPENSCOUT_WEB_PORT = v;
56055
56521
  continue;
56056
56522
  }
56057
56523
  if (a === "--static") {
56058
- env.SCOUT_STATIC = "1";
56524
+ env.NODE_ENV = "production";
56059
56525
  continue;
56060
56526
  }
56061
56527
  if (a === "--static-root") {
56062
56528
  const v = args[++i];
56063
56529
  if (!v)
56064
56530
  throw new ScoutCliError("--static-root requires a value");
56065
- env.SCOUT_STATIC_ROOT = v;
56531
+ env.OPENSCOUT_WEB_STATIC_ROOT = v;
56066
56532
  continue;
56067
56533
  }
56068
56534
  if (a === "--vite-url") {
56069
56535
  const v = args[++i];
56070
56536
  if (!v)
56071
56537
  throw new ScoutCliError("--vite-url requires a value");
56072
- env.SCOUT_VITE_URL = v;
56538
+ env.OPENSCOUT_WEB_VITE_URL = v;
56073
56539
  continue;
56074
56540
  }
56075
56541
  if (a === "--cwd") {
@@ -56087,15 +56553,15 @@ function parseServerFlags(args) {
56087
56553
  continue;
56088
56554
  }
56089
56555
  if (a.startsWith("--port=")) {
56090
- env.SCOUT_WEB_PORT = a.slice("--port=".length);
56556
+ env.OPENSCOUT_WEB_PORT = a.slice("--port=".length);
56091
56557
  continue;
56092
56558
  }
56093
56559
  if (a.startsWith("--static-root=")) {
56094
- env.SCOUT_STATIC_ROOT = a.slice("--static-root=".length);
56560
+ env.OPENSCOUT_WEB_STATIC_ROOT = a.slice("--static-root=".length);
56095
56561
  continue;
56096
56562
  }
56097
56563
  if (a.startsWith("--vite-url=")) {
56098
- env.SCOUT_VITE_URL = a.slice("--vite-url=".length);
56564
+ env.OPENSCOUT_WEB_VITE_URL = a.slice("--vite-url=".length);
56099
56565
  continue;
56100
56566
  }
56101
56567
  if (a.startsWith("--cwd=")) {
@@ -56110,9 +56576,9 @@ function parseServerFlags(args) {
56110
56576
  }
56111
56577
  return { env, openPath };
56112
56578
  }
56113
- function resolveBundledStaticClientRoot(entry, mode) {
56579
+ function resolveBundledStaticClientRoot(entry, _mode) {
56114
56580
  const entryDir = dirname12(entry);
56115
- const clientDirectory = mode === "control-plane" ? join26(entryDir, "control-plane-client") : join26(entryDir, "client");
56581
+ const clientDirectory = join26(entryDir, "client");
56116
56582
  const indexPath = join26(clientDirectory, "index.html");
56117
56583
  return existsSync18(indexPath) ? clientDirectory : null;
56118
56584
  }
@@ -56120,12 +56586,18 @@ function buildMergedServerEnv(entry, mode, flagEnv) {
56120
56586
  const bundledStaticClientRoot = resolveBundledStaticClientRoot(entry, mode);
56121
56587
  const autoEnv = {};
56122
56588
  if (bundledStaticClientRoot) {
56123
- const wantsVite = Boolean(flagEnv.SCOUT_VITE_URL ?? process.env.SCOUT_VITE_URL);
56589
+ const wantsVite = Boolean(flagEnv.OPENSCOUT_WEB_VITE_URL ?? process.env.OPENSCOUT_WEB_VITE_URL);
56124
56590
  if (!wantsVite) {
56125
- autoEnv.SCOUT_STATIC = "1";
56126
- autoEnv.SCOUT_STATIC_ROOT = bundledStaticClientRoot;
56591
+ autoEnv.NODE_ENV = "production";
56592
+ autoEnv.OPENSCOUT_WEB_STATIC_ROOT = bundledStaticClientRoot;
56127
56593
  }
56128
56594
  }
56595
+ if (flagEnv.SCOUT_WEB_PORT) {
56596
+ autoEnv.OPENSCOUT_WEB_PORT = flagEnv.SCOUT_WEB_PORT;
56597
+ }
56598
+ if (flagEnv.OPENSCOUT_SETUP_CWD) {
56599
+ autoEnv.OPENSCOUT_SETUP_CWD = flagEnv.OPENSCOUT_SETUP_CWD;
56600
+ }
56129
56601
  return { ...process.env, ...autoEnv, ...flagEnv };
56130
56602
  }
56131
56603
  function parseServerSelection(args) {
@@ -56133,7 +56605,7 @@ function parseServerSelection(args) {
56133
56605
  return {
56134
56606
  action: "start",
56135
56607
  flagArgs: args.slice(1),
56136
- entry: resolveScoutWebServerEntry(),
56608
+ entry: resolveScoutControlPlaneWebServerEntry(),
56137
56609
  mode: "full"
56138
56610
  };
56139
56611
  }
@@ -56141,16 +56613,14 @@ function parseServerSelection(args) {
56141
56613
  return {
56142
56614
  action: "open",
56143
56615
  flagArgs: args.slice(1),
56144
- entry: resolveScoutWebServerEntry(),
56616
+ entry: resolveScoutControlPlaneWebServerEntry(),
56145
56617
  mode: "full"
56146
56618
  };
56147
56619
  }
56148
56620
  if (args[0] === "control-plane") {
56149
- if (args[1] !== "start" && args[1] !== "open") {
56150
- throw new ScoutCliError("expected: scout server control-plane <start|open>");
56151
- }
56621
+ const sub = args[1] === "start" || args[1] === "open" ? args[1] : "start";
56152
56622
  return {
56153
- action: args[1],
56623
+ action: sub,
56154
56624
  flagArgs: args.slice(2),
56155
56625
  entry: resolveScoutControlPlaneWebServerEntry(),
56156
56626
  mode: "control-plane"
@@ -56172,7 +56642,7 @@ function normalizeServerOpenPath(value) {
56172
56642
  return `/${trimmed}`;
56173
56643
  }
56174
56644
  function resolveServerPort(env) {
56175
- const envValue = env.SCOUT_WEB_PORT?.trim();
56645
+ const envValue = (env.OPENSCOUT_WEB_PORT ?? env.SCOUT_WEB_PORT)?.trim();
56176
56646
  if (envValue) {
56177
56647
  const port = Number.parseInt(envValue, 10);
56178
56648
  if (!Number.isFinite(port) || port <= 0) {
@@ -118141,11 +118611,7 @@ function renderScoutHelp(version2 = "0.2.18") {
118141
118611
  "",
118142
118612
  "Commands:",
118143
118613
  commandLines,
118144
- ...deprecatedLines ? [
118145
- "",
118146
- "Deprecated aliases:",
118147
- deprecatedLines
118148
- ] : [],
118614
+ ...deprecatedLines ? ["", "Deprecated aliases:", deprecatedLines] : [],
118149
118615
  "",
118150
118616
  "Global flags:",
118151
118617
  ' --json Structured JSON (doctor: NDJSON stream; last object has phase "complete")',
@@ -118162,6 +118628,10 @@ function renderScoutHelp(version2 = "0.2.18") {
118162
118628
  " scout menu",
118163
118629
  " scout server open",
118164
118630
  "",
118631
+ "One-to-one delegation:",
118632
+ ' scout ask --to hudson "review the parser" # DM by default',
118633
+ ' scout ask --as premotion.master.mini --to hudson "build the editor"',
118634
+ "",
118165
118635
  "Addressing:",
118166
118636
  " @name short form; requires exactly one live match",
118167
118637
  " @name.harness:<codex|claude|...> pin a specific harness (alias: runtime:)",