@botiverse/raft-daemon 0.58.1 → 0.59.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.
|
@@ -175,6 +175,7 @@ function emitCliTransportNormalizedError(attrs, env = process.env) {
|
|
|
175
175
|
function routeFamilyForPath(pathname) {
|
|
176
176
|
const normalized = pathname.split("?")[0] || "/";
|
|
177
177
|
if (normalized === "/internal/agent-api/send") return "agent-api/send";
|
|
178
|
+
if (normalized === "/internal/agent-api/activity") return "agent-api/activity";
|
|
178
179
|
if (normalized === "/internal/agent-api/events") return "agent-api/events";
|
|
179
180
|
if (normalized === "/internal/agent-api/inbox") return "agent-api/inbox";
|
|
180
181
|
if (normalized === "/internal/agent-api/receive-ack") return "agent-api/events";
|
|
@@ -332,6 +333,9 @@ var ApiClient = class {
|
|
|
332
333
|
if (suffix === "/reminders" || suffix.startsWith("/reminders?") || suffix.startsWith("/reminders/")) {
|
|
333
334
|
return `/internal/agent-api${suffix}`;
|
|
334
335
|
}
|
|
336
|
+
if (suffix === "/mention-actions/pending" || suffix === "/mention-actions/execute") {
|
|
337
|
+
return `/internal/agent-api${suffix}`;
|
|
338
|
+
}
|
|
335
339
|
if (suffix === "/receive" || suffix.startsWith("/receive?")) {
|
|
336
340
|
return "/internal/agent-api/events?since=latest";
|
|
337
341
|
}
|
|
@@ -15526,6 +15530,11 @@ var SERVER_CAPABILITY_MATRIX = {
|
|
|
15526
15530
|
joinPublicChannels: true
|
|
15527
15531
|
})
|
|
15528
15532
|
};
|
|
15533
|
+
var EXTERNAL_AGENT_ACTIVITY_EVENT_SCHEMA = "raft-activity.v1";
|
|
15534
|
+
var EXTERNAL_AGENT_ACTIVITY_DRAIN_SCHEMA = "raft-activity-drain.v1";
|
|
15535
|
+
var EXTERNAL_AGENT_ACTIVITY_INGEST_SCHEMA = "raft-agent-activity-ingest.v1";
|
|
15536
|
+
var EXTERNAL_AGENT_ACTIVITY_TEXT_LIMIT = 4096;
|
|
15537
|
+
var EXTERNAL_AGENT_ACTIVITY_TOOL_NAME_LIMIT = 120;
|
|
15529
15538
|
var EXTERNAL_AGENT_RUNTIME_ID = "external";
|
|
15530
15539
|
var EXTERNAL_AGENT_RUNTIME_MODEL = "external";
|
|
15531
15540
|
var EXTERNAL_AGENT_RUNTIME_DISPLAY_NAME = "External agent";
|
|
@@ -15820,6 +15829,15 @@ async function runAgentCommsBridgeOnce(input) {
|
|
|
15820
15829
|
}
|
|
15821
15830
|
const fetchedLastSeq = typeof fetched.last_seen_hint_seq === "number" ? fetched.last_seen_hint_seq : typeof fetched.last_hint_seq === "number" ? fetched.last_hint_seq : void 0;
|
|
15822
15831
|
if (typeof fetchedLastSeq === "number") lastSeenHintSeq = Math.max(lastSeenHintSeq ?? 0, fetchedLastSeq);
|
|
15832
|
+
if (input.activitySource && input.activitySink) {
|
|
15833
|
+
output.push(await drainAndForwardActivity({
|
|
15834
|
+
identity,
|
|
15835
|
+
source: input.activitySource,
|
|
15836
|
+
sink: input.activitySink,
|
|
15837
|
+
max: input.activityDrainLimit ?? input.limit ?? 50,
|
|
15838
|
+
now
|
|
15839
|
+
}));
|
|
15840
|
+
}
|
|
15823
15841
|
store.writeSession({
|
|
15824
15842
|
coreSessionId,
|
|
15825
15843
|
...typeof lastSeenHintSeq === "number" ? { lastSeenHintSeq } : {}
|
|
@@ -15827,6 +15845,126 @@ async function runAgentCommsBridgeOnce(input) {
|
|
|
15827
15845
|
output.push(lifecycle(identity, processedHintCount > 0 ? "handoff_pending" : "listening_idle", now));
|
|
15828
15846
|
return output;
|
|
15829
15847
|
}
|
|
15848
|
+
async function drainAndForwardActivity(input) {
|
|
15849
|
+
let drained;
|
|
15850
|
+
try {
|
|
15851
|
+
drained = await input.source.drainActivity({ max: input.max });
|
|
15852
|
+
} catch (err) {
|
|
15853
|
+
return activityDrainEvent(input.identity, input.now, {
|
|
15854
|
+
outcome: "failed",
|
|
15855
|
+
drainedCount: 0,
|
|
15856
|
+
forwardedCount: 0,
|
|
15857
|
+
rejectedCount: 0,
|
|
15858
|
+
droppedCount: 0,
|
|
15859
|
+
errorClass: err instanceof Error ? err.name : typeof err,
|
|
15860
|
+
errorMessage: errorMessage2(err)
|
|
15861
|
+
});
|
|
15862
|
+
}
|
|
15863
|
+
if (drained.schema !== EXTERNAL_AGENT_ACTIVITY_DRAIN_SCHEMA || !Array.isArray(drained.events)) {
|
|
15864
|
+
return activityDrainEvent(input.identity, input.now, {
|
|
15865
|
+
outcome: "failed",
|
|
15866
|
+
drainedCount: 0,
|
|
15867
|
+
forwardedCount: 0,
|
|
15868
|
+
rejectedCount: 0,
|
|
15869
|
+
droppedCount: normalizeNonNegativeInteger(drained.dropped),
|
|
15870
|
+
errorClass: "ProtocolError",
|
|
15871
|
+
errorMessage: "activity drain response did not match raft-activity-drain.v1"
|
|
15872
|
+
});
|
|
15873
|
+
}
|
|
15874
|
+
const sanitized = sanitizeExternalAgentActivityEvents(drained.events, input.now);
|
|
15875
|
+
if (sanitized.events.length === 0) {
|
|
15876
|
+
return activityDrainEvent(input.identity, input.now, {
|
|
15877
|
+
outcome: "no_events",
|
|
15878
|
+
drainedCount: drained.events.length,
|
|
15879
|
+
forwardedCount: 0,
|
|
15880
|
+
rejectedCount: sanitized.rejectedCount,
|
|
15881
|
+
droppedCount: normalizeNonNegativeInteger(drained.dropped)
|
|
15882
|
+
});
|
|
15883
|
+
}
|
|
15884
|
+
try {
|
|
15885
|
+
await input.sink.forwardActivity({
|
|
15886
|
+
schema: EXTERNAL_AGENT_ACTIVITY_INGEST_SCHEMA,
|
|
15887
|
+
coreSessionId: input.identity.coreSessionId,
|
|
15888
|
+
adapterInstance: input.identity.adapterInstance,
|
|
15889
|
+
events: sanitized.events,
|
|
15890
|
+
dropped: normalizeNonNegativeInteger(drained.dropped)
|
|
15891
|
+
});
|
|
15892
|
+
} catch (err) {
|
|
15893
|
+
return activityDrainEvent(input.identity, input.now, {
|
|
15894
|
+
outcome: "failed",
|
|
15895
|
+
drainedCount: drained.events.length,
|
|
15896
|
+
forwardedCount: 0,
|
|
15897
|
+
rejectedCount: sanitized.rejectedCount,
|
|
15898
|
+
droppedCount: normalizeNonNegativeInteger(drained.dropped),
|
|
15899
|
+
errorClass: err instanceof Error ? err.name : typeof err,
|
|
15900
|
+
errorMessage: errorMessage2(err)
|
|
15901
|
+
});
|
|
15902
|
+
}
|
|
15903
|
+
return activityDrainEvent(input.identity, input.now, {
|
|
15904
|
+
outcome: "forwarded",
|
|
15905
|
+
drainedCount: drained.events.length,
|
|
15906
|
+
forwardedCount: sanitized.events.length,
|
|
15907
|
+
rejectedCount: sanitized.rejectedCount,
|
|
15908
|
+
droppedCount: normalizeNonNegativeInteger(drained.dropped)
|
|
15909
|
+
});
|
|
15910
|
+
}
|
|
15911
|
+
function sanitizeExternalAgentActivityEvents(rawEvents, now = () => /* @__PURE__ */ new Date()) {
|
|
15912
|
+
const events = [];
|
|
15913
|
+
let rejectedCount = 0;
|
|
15914
|
+
for (const raw of rawEvents) {
|
|
15915
|
+
const hookEventName = stringField(raw.hookEventName ?? raw.hook_event_name, 80);
|
|
15916
|
+
if (!hookEventName) {
|
|
15917
|
+
rejectedCount += 1;
|
|
15918
|
+
continue;
|
|
15919
|
+
}
|
|
15920
|
+
const eventId = stringField(raw.eventId ?? raw.event_id, 160) ?? `event_${randomUUID()}`;
|
|
15921
|
+
const sessionId = stringField(raw.sessionId ?? raw.session_id, 200);
|
|
15922
|
+
const toolName = stringField(raw.toolName ?? raw.tool_name, EXTERNAL_AGENT_ACTIVITY_TOOL_NAME_LIMIT);
|
|
15923
|
+
const status = stringField(raw.status, 40);
|
|
15924
|
+
const errorClass = stringField(raw.errorClass ?? raw.error_class, 120);
|
|
15925
|
+
const occurredAt = validIsoDate(raw.occurredAt ?? raw.occurred_at) ?? now().toISOString();
|
|
15926
|
+
const durationMs = normalizeNonNegativeInteger(raw.durationMs ?? raw.duration_ms);
|
|
15927
|
+
const toolInput = truncateActivityText(
|
|
15928
|
+
raw.toolInput ?? raw.tool_input,
|
|
15929
|
+
raw.toolInputTruncated ?? raw.tool_input_truncated ?? raw.truncated
|
|
15930
|
+
);
|
|
15931
|
+
const toolOutput = truncateActivityText(
|
|
15932
|
+
raw.toolOutput ?? raw.tool_output,
|
|
15933
|
+
raw.toolOutputTruncated ?? raw.tool_output_truncated ?? raw.truncated
|
|
15934
|
+
);
|
|
15935
|
+
events.push({
|
|
15936
|
+
schema: EXTERNAL_AGENT_ACTIVITY_EVENT_SCHEMA,
|
|
15937
|
+
eventId,
|
|
15938
|
+
...sessionId ? { sessionId } : {},
|
|
15939
|
+
hookEventName,
|
|
15940
|
+
...toolName ? { toolName } : {},
|
|
15941
|
+
...status ? { status } : {},
|
|
15942
|
+
occurredAt,
|
|
15943
|
+
...durationMs > 0 ? { durationMs } : {},
|
|
15944
|
+
...errorClass ? { errorClass } : {},
|
|
15945
|
+
...toolInput.text !== void 0 ? { toolInput: toolInput.text, toolInputTruncated: toolInput.truncated } : {},
|
|
15946
|
+
...toolOutput.text !== void 0 ? { toolOutput: toolOutput.text, toolOutputTruncated: toolOutput.truncated } : {}
|
|
15947
|
+
});
|
|
15948
|
+
}
|
|
15949
|
+
return { events, rejectedCount };
|
|
15950
|
+
}
|
|
15951
|
+
function activityDrainEvent(identity, now, result2) {
|
|
15952
|
+
return {
|
|
15953
|
+
type: "agent_comms.activity_drain",
|
|
15954
|
+
eventId: `event_${randomUUID()}`,
|
|
15955
|
+
protocolVersion: AGENT_COMMS_PROTOCOL_VERSION,
|
|
15956
|
+
timestamp: now().toISOString(),
|
|
15957
|
+
coreSessionId: identity.coreSessionId,
|
|
15958
|
+
agentId: identity.agentId,
|
|
15959
|
+
profile: identity.profileSlug,
|
|
15960
|
+
profileSlug: identity.profileSlug,
|
|
15961
|
+
adapterInstance: identity.adapterInstance,
|
|
15962
|
+
runtimeSession: null,
|
|
15963
|
+
source: "slock-agent-bridge",
|
|
15964
|
+
provenance: commsCoreProvenance("comms_core"),
|
|
15965
|
+
...result2
|
|
15966
|
+
};
|
|
15967
|
+
}
|
|
15830
15968
|
var BRIDGE_LOG_MAX_BYTES = 5 * 1024 * 1024;
|
|
15831
15969
|
function rotateBridgeLogIfNeeded(logFile) {
|
|
15832
15970
|
try {
|
|
@@ -16156,6 +16294,46 @@ function stripContentFields(wakeHint) {
|
|
|
16156
16294
|
delete clone2.message;
|
|
16157
16295
|
return clone2;
|
|
16158
16296
|
}
|
|
16297
|
+
function stringField(value, maxLength) {
|
|
16298
|
+
if (typeof value !== "string") return void 0;
|
|
16299
|
+
const trimmed = value.replace(/\s+/g, " ").trim();
|
|
16300
|
+
if (!trimmed) return void 0;
|
|
16301
|
+
return trimmed.slice(0, maxLength);
|
|
16302
|
+
}
|
|
16303
|
+
function validIsoDate(value) {
|
|
16304
|
+
if (typeof value !== "string") return void 0;
|
|
16305
|
+
const parsed = Date.parse(value);
|
|
16306
|
+
if (Number.isNaN(parsed)) return void 0;
|
|
16307
|
+
return new Date(parsed).toISOString();
|
|
16308
|
+
}
|
|
16309
|
+
function normalizeNonNegativeInteger(value) {
|
|
16310
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) return 0;
|
|
16311
|
+
return Math.floor(value);
|
|
16312
|
+
}
|
|
16313
|
+
function truncateActivityText(value, alreadyTruncated) {
|
|
16314
|
+
if (value === void 0 || value === null) return { truncated: Boolean(alreadyTruncated) };
|
|
16315
|
+
let text;
|
|
16316
|
+
if (typeof value === "string") {
|
|
16317
|
+
text = value;
|
|
16318
|
+
} else {
|
|
16319
|
+
try {
|
|
16320
|
+
text = JSON.stringify(value);
|
|
16321
|
+
} catch {
|
|
16322
|
+
text = String(value);
|
|
16323
|
+
}
|
|
16324
|
+
}
|
|
16325
|
+
const marker = "\n[truncated]";
|
|
16326
|
+
if (text.length > EXTERNAL_AGENT_ACTIVITY_TEXT_LIMIT) {
|
|
16327
|
+
return {
|
|
16328
|
+
text: `${text.slice(0, Math.max(0, EXTERNAL_AGENT_ACTIVITY_TEXT_LIMIT - marker.length))}${marker}`,
|
|
16329
|
+
truncated: true
|
|
16330
|
+
};
|
|
16331
|
+
}
|
|
16332
|
+
return { text, truncated: Boolean(alreadyTruncated) };
|
|
16333
|
+
}
|
|
16334
|
+
function errorMessage2(err) {
|
|
16335
|
+
return (err instanceof Error ? err.message : String(err)).slice(0, 200);
|
|
16336
|
+
}
|
|
16159
16337
|
function safePathSegment(value) {
|
|
16160
16338
|
return value.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 120) || "unknown";
|
|
16161
16339
|
}
|
|
@@ -16309,7 +16487,10 @@ var agentBridgeCommand = defineCommand(
|
|
|
16309
16487
|
{ flags: "--wake-channel-endpoint <url>", description: "Localhost wake endpoint exposed by the runtime's Raft channel plugin (see docs/wake-endpoint-contract.md in raft-external-agents)." },
|
|
16310
16488
|
{ flags: "--wake-channel-token <token>", description: "Optional shared token for the Raft channel wake endpoint (env: RAFT_CHANNEL_TOKEN)." },
|
|
16311
16489
|
{ flags: "--runtime-session <id>", description: "Optional runtime session id when the adapter endpoint does not return one." },
|
|
16312
|
-
{ flags: "--reconcile-interval-ms <ms>", description: "Re-peek the full server-pending set every <ms> and re-wake hints that were injected but never consumed (0 disables; default 120000)." }
|
|
16490
|
+
{ flags: "--reconcile-interval-ms <ms>", description: "Re-peek the full server-pending set every <ms> and re-wake hints that were injected but never consumed (0 disables; default 120000)." },
|
|
16491
|
+
{ flags: "--activity-channel-endpoint <url>", description: "Localhost activity drain endpoint exposed by the runtime's Raft channel plugin. Defaults to /activity/drain derived from --wake-channel-endpoint." },
|
|
16492
|
+
{ flags: "--activity-channel-token <token>", description: "Optional shared token for the activity drain endpoint (env: RAFT_CHANNEL_TOKEN)." },
|
|
16493
|
+
{ flags: "--activity-drain-limit <n>", description: "Maximum plugin activity events to drain per bridge iteration." }
|
|
16313
16494
|
]
|
|
16314
16495
|
},
|
|
16315
16496
|
async (ctx, options) => {
|
|
@@ -16324,10 +16505,13 @@ var agentBridgeCommand = defineCommand(
|
|
|
16324
16505
|
const pollIntervalMs = parsePositiveInt(options.pollIntervalMs, 5e3, "poll-interval-ms");
|
|
16325
16506
|
const reconcileIntervalMs = options.reconcileIntervalMs === "0" ? 0 : parsePositiveInt(options.reconcileIntervalMs, 12e4, "reconcile-interval-ms");
|
|
16326
16507
|
const limit = parsePositiveInt(options.limit, 50, "limit");
|
|
16508
|
+
const activityDrainLimit = parsePositiveInt(options.activityDrainLimit, 50, "activity-drain-limit");
|
|
16327
16509
|
const client = ctx.createApiClient(agentContext);
|
|
16328
16510
|
const pollSource = createAgentApiWakeHintSource(client);
|
|
16329
16511
|
const streamSource = options.once ? null : createAgentApiWakeHintStreamSource(client, ctx.env);
|
|
16330
16512
|
const wakeAdapter = createWakeAdapter(options, ctx.env);
|
|
16513
|
+
const activitySource = createActivityDrainSource(options, ctx.env);
|
|
16514
|
+
const activitySink = activitySource ? createAgentApiActivitySink(client) : void 0;
|
|
16331
16515
|
let bridgeLock;
|
|
16332
16516
|
try {
|
|
16333
16517
|
bridgeLock = acquireAgentCommsBridgeLock({
|
|
@@ -16381,6 +16565,9 @@ var agentBridgeCommand = defineCommand(
|
|
|
16381
16565
|
replayPending,
|
|
16382
16566
|
wakeAdapter,
|
|
16383
16567
|
runtimeSession: options.runtimeSession ?? null,
|
|
16568
|
+
activitySource,
|
|
16569
|
+
activitySink,
|
|
16570
|
+
activityDrainLimit,
|
|
16384
16571
|
recentInjections
|
|
16385
16572
|
});
|
|
16386
16573
|
for (const event of events) emit(event);
|
|
@@ -16663,6 +16850,59 @@ function createWakeAdapter(options, env = process.env) {
|
|
|
16663
16850
|
token: options.wakeChannelToken ?? env.RAFT_CHANNEL_TOKEN
|
|
16664
16851
|
});
|
|
16665
16852
|
}
|
|
16853
|
+
function createActivityDrainSource(options, env = process.env) {
|
|
16854
|
+
const endpointUrl = options.activityChannelEndpoint ?? deriveActivityDrainEndpoint(options.wakeChannelEndpoint);
|
|
16855
|
+
if (!endpointUrl) return void 0;
|
|
16856
|
+
const token = options.activityChannelToken ?? options.wakeChannelToken ?? env.RAFT_CHANNEL_TOKEN;
|
|
16857
|
+
return {
|
|
16858
|
+
async drainActivity(input) {
|
|
16859
|
+
const url2 = new URL(endpointUrl);
|
|
16860
|
+
url2.searchParams.set("max", String(input.max));
|
|
16861
|
+
const signal = typeof AbortSignal.timeout === "function" ? AbortSignal.timeout(3e3) : void 0;
|
|
16862
|
+
const response = await fetch(url2, {
|
|
16863
|
+
method: "GET",
|
|
16864
|
+
signal,
|
|
16865
|
+
headers: {
|
|
16866
|
+
...token ? { "x-raft-bridge-token": token } : {}
|
|
16867
|
+
}
|
|
16868
|
+
});
|
|
16869
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
16870
|
+
const data = contentType.includes("application/json") ? await response.json() : {};
|
|
16871
|
+
if (!response.ok) {
|
|
16872
|
+
throw new CliError({
|
|
16873
|
+
code: response.status >= 500 ? "SERVER_5XX" : "BRIDGE_ACTIVITY_DRAIN_FAILED",
|
|
16874
|
+
message: typeof data?.error === "string" ? data.error : `HTTP ${response.status}`
|
|
16875
|
+
});
|
|
16876
|
+
}
|
|
16877
|
+
return data;
|
|
16878
|
+
}
|
|
16879
|
+
};
|
|
16880
|
+
}
|
|
16881
|
+
function createAgentApiActivitySink(client) {
|
|
16882
|
+
return {
|
|
16883
|
+
async forwardActivity(input) {
|
|
16884
|
+
const response = await client.request("POST", "/internal/agent-api/activity", input);
|
|
16885
|
+
if (!response.ok) {
|
|
16886
|
+
throw new CliError({
|
|
16887
|
+
code: response.status >= 500 ? "SERVER_5XX" : "BRIDGE_ACTIVITY_FORWARD_FAILED",
|
|
16888
|
+
message: response.error ?? `HTTP ${response.status}`
|
|
16889
|
+
});
|
|
16890
|
+
}
|
|
16891
|
+
}
|
|
16892
|
+
};
|
|
16893
|
+
}
|
|
16894
|
+
function deriveActivityDrainEndpoint(wakeChannelEndpoint) {
|
|
16895
|
+
if (!wakeChannelEndpoint) return void 0;
|
|
16896
|
+
try {
|
|
16897
|
+
const url2 = new URL(wakeChannelEndpoint);
|
|
16898
|
+
url2.pathname = "/activity/drain";
|
|
16899
|
+
url2.search = "";
|
|
16900
|
+
url2.hash = "";
|
|
16901
|
+
return url2.toString();
|
|
16902
|
+
} catch {
|
|
16903
|
+
return void 0;
|
|
16904
|
+
}
|
|
16905
|
+
}
|
|
16666
16906
|
function sleep(ms) {
|
|
16667
16907
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
16668
16908
|
}
|
|
@@ -17548,6 +17788,84 @@ ${opts.heldAction} Review the bounded context shown here, then choose one path.$
|
|
|
17548
17788
|
|
|
17549
17789
|
` + (opts.draftInstructions ?? "") + continueAnyway;
|
|
17550
17790
|
}
|
|
17791
|
+
function normalizeAction(action) {
|
|
17792
|
+
if (action === "notify" || action === "notify_only") return "notify";
|
|
17793
|
+
if (action === "invite" || action === "add") return "invite";
|
|
17794
|
+
return null;
|
|
17795
|
+
}
|
|
17796
|
+
function formatActionCommands(action) {
|
|
17797
|
+
const verbs = action.availableActions.map(normalizeAction).filter((verb) => verb !== null);
|
|
17798
|
+
return Array.from(new Set(verbs)).map((verb) => ` ${verb}: slock mention ${verb} ${action.resolutionId}`);
|
|
17799
|
+
}
|
|
17800
|
+
function normalizePendingMentionActions(data) {
|
|
17801
|
+
const value = data;
|
|
17802
|
+
const raw = Array.isArray(value?.pendingMentionActions) ? value.pendingMentionActions : Array.isArray(value?.actions) ? value.actions : Array.isArray(value?.results) ? value.results : [];
|
|
17803
|
+
return raw.filter((item) => Boolean(item && typeof item === "object")).map((item) => ({
|
|
17804
|
+
resolutionId: String(item.resolutionId ?? item.id ?? ""),
|
|
17805
|
+
messageId: String(item.messageId ?? ""),
|
|
17806
|
+
targetType: String(item.targetType ?? "unknown"),
|
|
17807
|
+
targetHandle: String(item.targetHandle ?? ""),
|
|
17808
|
+
reason: String(item.reason ?? "Mention target was not notified at send time."),
|
|
17809
|
+
availableActions: Array.isArray(item.availableActions) ? item.availableActions.map(String) : [],
|
|
17810
|
+
expiresAt: typeof item.expiresAt === "string" ? item.expiresAt : null
|
|
17811
|
+
})).filter((item) => item.resolutionId.length > 0);
|
|
17812
|
+
}
|
|
17813
|
+
function normalizeMentionActionResults(data) {
|
|
17814
|
+
const value = data;
|
|
17815
|
+
const raw = Array.isArray(value?.results) ? value.results : Array.isArray(value?.actionResults) ? value.actionResults : [];
|
|
17816
|
+
return raw.filter((item) => Boolean(item && typeof item === "object")).map((item) => ({
|
|
17817
|
+
resolutionId: String(item.resolutionId ?? item.id ?? ""),
|
|
17818
|
+
status: String(item.status ?? "not_found"),
|
|
17819
|
+
action: typeof item.action === "string" ? normalizeAction(item.action) : null,
|
|
17820
|
+
messageId: typeof item.messageId === "string" ? item.messageId : null,
|
|
17821
|
+
channelId: typeof item.channelId === "string" ? item.channelId : null,
|
|
17822
|
+
targetType: typeof item.targetType === "string" ? item.targetType : null,
|
|
17823
|
+
targetId: typeof item.targetId === "string" ? item.targetId : null,
|
|
17824
|
+
targetHandle: typeof item.targetHandle === "string" ? item.targetHandle : null,
|
|
17825
|
+
message: typeof item.message === "string" ? item.message : null,
|
|
17826
|
+
reason: typeof item.reason === "string" ? item.reason : null,
|
|
17827
|
+
dedupedResolutionIds: Array.isArray(item.dedupedResolutionIds) ? item.dedupedResolutionIds.filter((id) => typeof id === "string" && id.length > 0) : []
|
|
17828
|
+
})).filter((item) => item.resolutionId.length > 0);
|
|
17829
|
+
}
|
|
17830
|
+
function formatPendingMentionActions(actions, opts = {}) {
|
|
17831
|
+
if (actions.length === 0) {
|
|
17832
|
+
return opts.source === "pending" ? "Pending mention actions\n\nNo pending mention actions.\n" : "";
|
|
17833
|
+
}
|
|
17834
|
+
const lines = ["Pending mention actions", ""];
|
|
17835
|
+
for (const action of actions) {
|
|
17836
|
+
const target = action.targetHandle ? `${action.targetHandle} (${action.targetType})` : action.targetType;
|
|
17837
|
+
lines.push(`- ${action.resolutionId} \u2014 ${target}`);
|
|
17838
|
+
if (action.messageId) lines.push(` message: ${action.messageId}`);
|
|
17839
|
+
lines.push(` reason: ${action.reason}`);
|
|
17840
|
+
if (action.expiresAt) lines.push(` expires: ${action.expiresAt}`);
|
|
17841
|
+
const commands = formatActionCommands(action);
|
|
17842
|
+
if (commands.length > 0) {
|
|
17843
|
+
lines.push(" available commands:");
|
|
17844
|
+
lines.push(...commands);
|
|
17845
|
+
}
|
|
17846
|
+
}
|
|
17847
|
+
return `${lines.join("\n")}
|
|
17848
|
+
`;
|
|
17849
|
+
}
|
|
17850
|
+
function formatMentionActionResults(action, results) {
|
|
17851
|
+
const lines = [`Mention ${action} results`, ""];
|
|
17852
|
+
if (results.length === 0) {
|
|
17853
|
+
lines.push("No result rows returned.");
|
|
17854
|
+
return `${lines.join("\n")}
|
|
17855
|
+
`;
|
|
17856
|
+
}
|
|
17857
|
+
for (const result2 of results) {
|
|
17858
|
+
const target = result2.targetHandle ? ` ${result2.targetHandle}` : "";
|
|
17859
|
+
const detail = result2.message ?? result2.reason;
|
|
17860
|
+
const suffix = detail ? ` \u2014 ${detail}` : "";
|
|
17861
|
+
lines.push(`- ${result2.resolutionId}${target}: ${result2.status}${suffix}`);
|
|
17862
|
+
if (result2.dedupedResolutionIds && result2.dedupedResolutionIds.length > 1) {
|
|
17863
|
+
lines.push(` deduped: ${result2.dedupedResolutionIds.join(", ")}`);
|
|
17864
|
+
}
|
|
17865
|
+
}
|
|
17866
|
+
return `${lines.join("\n")}
|
|
17867
|
+
`;
|
|
17868
|
+
}
|
|
17551
17869
|
var DEFAULT_LOCAL_DRAFT_TTL_MS = 10 * 60 * 1e3;
|
|
17552
17870
|
function stateFilePath2(agentId) {
|
|
17553
17871
|
return path6.join(process.env.SLOCK_CLI_DRAFT_STATE_DIR ?? os3.tmpdir(), "slock-cli-attested-send", agentId, "continue-state.json");
|
|
@@ -17850,7 +18168,11 @@ var messageSendCommand = defineCommand(
|
|
|
17850
18168
|
--- New messages you may have missed ---
|
|
17851
18169
|
${formatMessages(data.recentUnread)}`;
|
|
17852
18170
|
}
|
|
17853
|
-
|
|
18171
|
+
const pendingMentionActions = normalizePendingMentionActions(data);
|
|
18172
|
+
const mentionSection = pendingMentionActions.length > 0 ? `
|
|
18173
|
+
|
|
18174
|
+
${formatPendingMentionActions(pendingMentionActions, { source: "send" }).trimEnd()}` : "";
|
|
18175
|
+
writeText(ctx.io, `Message sent to ${opts.target}. Message ID: ${data.messageId}${replyHint}${mentionSection}${unreadSection}
|
|
17854
18176
|
`);
|
|
17855
18177
|
}
|
|
17856
18178
|
);
|
|
@@ -18906,6 +19228,77 @@ var taskUpdateCommand = defineCommand(
|
|
|
18906
19228
|
function registerTaskUpdateCommand(parent, runtimeOptions) {
|
|
18907
19229
|
registerCliCommand(parent, taskUpdateCommand, runtimeOptions);
|
|
18908
19230
|
}
|
|
19231
|
+
function normalizeResolutionIds(rawIds) {
|
|
19232
|
+
const ids = (rawIds ?? []).map((id) => id.trim()).filter(Boolean);
|
|
19233
|
+
if (ids.length === 0) {
|
|
19234
|
+
throw cliError("INVALID_ARG", "At least one resolution id is required.");
|
|
19235
|
+
}
|
|
19236
|
+
return ids;
|
|
19237
|
+
}
|
|
19238
|
+
function buildMentionExecuteCommand(action) {
|
|
19239
|
+
return defineCommand(
|
|
19240
|
+
{
|
|
19241
|
+
name: action,
|
|
19242
|
+
description: `${action === "notify" ? "Notify" : "Invite"} unresolved mention targets by resolution id`,
|
|
19243
|
+
arguments: ["<resolutionIds...>"],
|
|
19244
|
+
options: [{ flags: "--json", description: "Emit machine-readable JSON" }]
|
|
19245
|
+
},
|
|
19246
|
+
async (ctx, resolutionIds, opts = {}) => {
|
|
19247
|
+
const ids = normalizeResolutionIds(resolutionIds);
|
|
19248
|
+
const agentContext = ctx.loadAgentContext();
|
|
19249
|
+
const client = ctx.createApiClient(agentContext);
|
|
19250
|
+
const res = await client.request(
|
|
19251
|
+
"POST",
|
|
19252
|
+
`/internal/agent/${encodeURIComponent(agentContext.agentId)}/mention-actions/execute`,
|
|
19253
|
+
{ action, resolutionIds: ids }
|
|
19254
|
+
);
|
|
19255
|
+
if (!res.ok || !res.data) {
|
|
19256
|
+
throw cliError(res.status >= 500 ? "SERVER_5XX" : "MENTION_ACTION_FAILED", res.error ?? `HTTP ${res.status}`);
|
|
19257
|
+
}
|
|
19258
|
+
const results = normalizeMentionActionResults(res.data);
|
|
19259
|
+
if (opts.json) {
|
|
19260
|
+
writeJson(ctx.io, { ok: true, action, results });
|
|
19261
|
+
return;
|
|
19262
|
+
}
|
|
19263
|
+
writeText(ctx.io, formatMentionActionResults(action, results));
|
|
19264
|
+
}
|
|
19265
|
+
);
|
|
19266
|
+
}
|
|
19267
|
+
function registerMentionExecuteCommands(parent, runtimeOptions = {}) {
|
|
19268
|
+
registerCliCommand(parent, buildMentionExecuteCommand("notify"), runtimeOptions);
|
|
19269
|
+
registerCliCommand(parent, buildMentionExecuteCommand("invite"), runtimeOptions);
|
|
19270
|
+
}
|
|
19271
|
+
var mentionPendingCommand = defineCommand(
|
|
19272
|
+
{
|
|
19273
|
+
name: "pending",
|
|
19274
|
+
description: "List sender-side pending mention actions",
|
|
19275
|
+
options: [{ flags: "--json", description: "Emit machine-readable JSON" }]
|
|
19276
|
+
},
|
|
19277
|
+
async (ctx, opts = {}) => {
|
|
19278
|
+
const agentContext = ctx.loadAgentContext();
|
|
19279
|
+
const client = ctx.createApiClient(agentContext);
|
|
19280
|
+
const res = await client.request(
|
|
19281
|
+
"GET",
|
|
19282
|
+
`/internal/agent/${encodeURIComponent(agentContext.agentId)}/mention-actions/pending`
|
|
19283
|
+
);
|
|
19284
|
+
if (!res.ok || !res.data) {
|
|
19285
|
+
throw cliError(res.status >= 500 ? "SERVER_5XX" : "MENTION_PENDING_FAILED", res.error ?? `HTTP ${res.status}`);
|
|
19286
|
+
}
|
|
19287
|
+
const actions = normalizePendingMentionActions(res.data);
|
|
19288
|
+
if (opts.json) {
|
|
19289
|
+
writeJson(ctx.io, { ok: true, pendingMentionActions: actions });
|
|
19290
|
+
return;
|
|
19291
|
+
}
|
|
19292
|
+
writeText(ctx.io, formatPendingMentionActions(actions, { source: "pending" }));
|
|
19293
|
+
}
|
|
19294
|
+
);
|
|
19295
|
+
function registerMentionPendingCommand(parent, runtimeOptions = {}) {
|
|
19296
|
+
registerCliCommand(parent, mentionPendingCommand, runtimeOptions);
|
|
19297
|
+
}
|
|
19298
|
+
function registerMentionCommands(parent, runtimeOptions = {}) {
|
|
19299
|
+
registerMentionPendingCommand(parent, runtimeOptions);
|
|
19300
|
+
registerMentionExecuteCommands(parent, runtimeOptions);
|
|
19301
|
+
}
|
|
18909
19302
|
function formatCreatedAgents(createdAgents) {
|
|
18910
19303
|
if (createdAgents.length === 0) {
|
|
18911
19304
|
return ["- Created Agents: none"];
|
|
@@ -20181,6 +20574,8 @@ registerTaskCreateCommand(taskCmd);
|
|
|
20181
20574
|
registerTaskClaimCommand(taskCmd);
|
|
20182
20575
|
registerTaskUnclaimCommand(taskCmd);
|
|
20183
20576
|
registerTaskUpdateCommand(taskCmd);
|
|
20577
|
+
var mentionCmd = program.command("mention").description("Sender-side mention action operations");
|
|
20578
|
+
registerMentionCommands(mentionCmd);
|
|
20184
20579
|
var profileCmd = program.command("profile").description("Profile operations");
|
|
20185
20580
|
registerProfileShowCommand(profileCmd);
|
|
20186
20581
|
registerProfileUpdateCommand(profileCmd);
|
package/dist/index.js
CHANGED