sentinelayer-cli 0.46.4 → 0.48.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.
- package/README.md +63 -3
- package/package.json +12 -7
- package/skills/omar-gate-setup/SKILL.md +103 -0
- package/skills/senti-agent-identity/SKILL.md +80 -0
- package/skills/senti-judge/SKILL.md +139 -0
- package/skills/senti-room-notifications/SKILL.md +73 -0
- package/skills/senti-room-notifications/listen-wrapper.cjs +150 -0
- package/skills/senti-room-notifications/package.json +1 -0
- package/skills/senti-room-notifications/test-classifier.js +109 -0
- package/skills/senti-room-notifications/test-receipt.js +54 -0
- package/skills/sentinelayer-cli/SKILL.md +222 -0
- package/src/agents/devtestbot/runner.js +22 -11
- package/src/agents/devtestbot/tool.js +24 -11
- package/src/agents/jules/fix-cycle.js +7 -1
- package/src/agents/jules/tools/runtime-audit.js +17 -12
- package/src/agents/shared-tools/dispatch-core.js +10 -5
- package/src/ai/aidenid.js +4 -2
- package/src/ai/domain-target-store.js +11 -5
- package/src/ai/identity-store.js +11 -5
- package/src/ai/site-store.js +8 -4
- package/src/audit/orchestrator.js +21 -14
- package/src/audit/package.js +6 -4
- package/src/audit/persona-loop.js +7 -0
- package/src/audit/replay.js +4 -2
- package/src/auth/gate.js +46 -8
- package/src/auth/service.js +34 -15
- package/src/auth/session-store.js +105 -47
- package/src/board/evidence-resolvers.js +3 -4
- package/src/cli.js +23 -3
- package/src/commands/ai/identity-lifecycle.js +30 -26
- package/src/commands/ai/provision-governance.js +32 -24
- package/src/commands/ai/shared.js +6 -4
- package/src/commands/audit.js +14 -12
- package/src/commands/auth.js +24 -4
- package/src/commands/board.js +2 -2
- package/src/commands/chat.js +8 -6
- package/src/commands/judge.js +125 -0
- package/src/commands/legacy-args.js +1 -0
- package/src/commands/mcp.js +45 -52
- package/src/commands/omargate.js +2 -1
- package/src/commands/plugin.js +11 -3
- package/src/commands/review.js +9 -4
- package/src/commands/scan.js +7 -7
- package/src/commands/session.js +607 -57
- package/src/commands/skills.js +45 -0
- package/src/commands/watch.js +9 -7
- package/src/config/output-filesystem.js +156 -0
- package/src/config/schema.js +4 -2
- package/src/config/service.js +40 -4
- package/src/cost/history.js +15 -9
- package/src/daemon/artifact-lineage.js +15 -12
- package/src/daemon/assignment-ledger.js +31 -25
- package/src/daemon/ast-drift.js +7 -3
- package/src/daemon/budget-governor.js +26 -20
- package/src/daemon/error-worker.js +28 -22
- package/src/daemon/fix-cycle.js +5 -4
- package/src/daemon/hybrid-mapper.js +19 -16
- package/src/daemon/ingest-refresh.js +4 -0
- package/src/daemon/jira-lifecycle.js +21 -17
- package/src/daemon/operator-control.js +18 -15
- package/src/daemon/reliability-lane.js +18 -15
- package/src/daemon/scope-engine.js +12 -8
- package/src/daemon/watchdog.js +15 -12
- package/src/engram/build-state.js +24 -3
- package/src/engram/capability-index.js +367 -0
- package/src/engram/compile-graph.js +1063 -0
- package/src/engram/contracts/action-receipt.js +82 -0
- package/src/engram/contracts/capability-index.js +259 -0
- package/src/engram/contracts/capability.js +377 -0
- package/src/engram/contracts/content-hash.js +8 -0
- package/src/engram/contracts/evidence.js +258 -0
- package/src/engram/contracts/graph.js +594 -0
- package/src/engram/contracts/identity.js +8 -0
- package/src/engram/contracts/index.js +149 -0
- package/src/engram/contracts/media-asset.js +85 -0
- package/src/engram/contracts/money.js +249 -0
- package/src/engram/contracts/source-snapshot.js +57 -0
- package/src/engram/contracts/task-context-pack.js +114 -0
- package/src/engram/contracts/temporal-segment.js +72 -0
- package/src/engram/contracts/versions.js +96 -0
- package/src/engram/extract-html.js +692 -0
- package/src/engram/graph-store.js +877 -0
- package/src/engram/index.js +98 -14
- package/src/engram/ingest-site.js +132 -0
- package/src/engram/live-state.js +1180 -0
- package/src/engram/namespace.js +34 -1
- package/src/engram/retrieve-site.js +753 -0
- package/src/engram/safe-reader.js +597 -0
- package/src/engram/source-intake.js +251 -0
- package/src/engram/store.js +227 -9
- package/src/ingest/engine.js +21 -28
- package/src/judge/verdict.js +305 -0
- package/src/legacy-cli.js +96 -19
- package/src/mcp/bridge-inputs.js +28 -4
- package/src/mcp/cli-command-tools.js +70 -0
- package/src/mcp/registry.js +17 -13
- package/src/mcp/session-stdio-server.js +297 -19
- package/src/memory/blackboard.js +5 -4
- package/src/net/gh-api-path.js +35 -9
- package/src/net/test-egress-guard.js +16 -4
- package/src/plugin/manifest.js +12 -8
- package/src/review/ai-review.js +110 -10
- package/src/review/investor-dd-devtestbot.js +17 -6
- package/src/review/investor-dd-orchestrator.js +21 -13
- package/src/review/local-review.js +26 -16
- package/src/review/omargate-cache.js +5 -5
- package/src/review/omargate-orchestrator.js +89 -17
- package/src/review/replay.js +9 -4
- package/src/review/report.js +22 -13
- package/src/review/typesafe-severity.js +201 -0
- package/src/session/admission-auth.js +34 -7
- package/src/session/admission.js +322 -71
- package/src/session/agent-access.js +137 -0
- package/src/session/agent-registry.js +2 -1
- package/src/session/attachment-summary.js +77 -0
- package/src/session/edit-summary.js +19 -0
- package/src/session/invitations.js +65 -1
- package/src/session/mentions.js +17 -9
- package/src/session/message-edits.js +5 -4
- package/src/session/preview.js +10 -2
- package/src/session/recap.js +3 -2
- package/src/session/room-files.js +519 -0
- package/src/session/route-classes.js +22 -8
- package/src/session/setup-guides.js +4 -0
- package/src/session/standup.js +192 -0
- package/src/session/sync.js +229 -10
- package/src/session/tickets.js +41 -0
- package/src/session/transcript.js +2 -1
- package/src/session/wake/resolve-target.js +7 -3
- package/src/skills/listener-runtime.cjs +92 -0
- package/src/skills/service.js +207 -0
- package/src/swarm/factory.js +5 -5
- package/src/swarm/pentest.js +9 -9
- package/src/swarm/report.js +4 -4
- package/src/swarm/runtime.js +15 -12
- package/src/swarm/scenario-dsl.js +7 -5
- package/src/telemetry/ledger.js +16 -7
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// Display metadata only. The files command resolves pointers when asked to fetch.
|
|
2
|
+
import { containsSecret } from "./redact.js";
|
|
3
|
+
import { sessionMessageRoutingEvent } from "./message-edits.js";
|
|
4
|
+
|
|
5
|
+
const MAX_VISIBLE_ATTACHMENTS = 5;
|
|
6
|
+
|
|
7
|
+
function displayText(value, fallback = "") {
|
|
8
|
+
if (typeof value !== "string") return fallback;
|
|
9
|
+
const text = value.replace(/[\p{Cc}\p{Cf}]/gu, " ").replace(/\s+/g, " ").trim();
|
|
10
|
+
if (containsSecret(text) || /\w+:\/\/|\bbearer\s+\S+/i.test(text)) return fallback;
|
|
11
|
+
return Array.from(text.replace(/[\[\]`<>]/g, "")).slice(0, 255).join("") || fallback;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function commandId(value) {
|
|
15
|
+
return typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,119}$/.test(value)
|
|
16
|
+
&& !value.includes("..") && !containsSecret(value) ? value : "";
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function pointerAttachmentId(pointer, sessionId) {
|
|
20
|
+
if (typeof pointer !== "string" || !sessionId) return "";
|
|
21
|
+
const match = /^\/api\/v1\/sessions\/([^/]+)\/attachments\/([^/?#]+)$/.exec(pointer);
|
|
22
|
+
return match && match[1] === sessionId ? commandId(match[2]) : "";
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function fileSize(value) {
|
|
26
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) return "";
|
|
27
|
+
if (value < 1024) return `${value} B`;
|
|
28
|
+
const units = ["KB", "MB", "GB", "TB", "PB"];
|
|
29
|
+
let size = value / 1024;
|
|
30
|
+
let unit = 0;
|
|
31
|
+
while (size >= 1024 && unit < units.length - 1) {
|
|
32
|
+
size /= 1024;
|
|
33
|
+
unit += 1;
|
|
34
|
+
}
|
|
35
|
+
return `${size.toFixed(size < 10 ? 1 : 0)} ${units[unit]}`;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function formatAttachmentSummary(event = {}) {
|
|
39
|
+
const session = event?.sessionId || event?.session_id;
|
|
40
|
+
event = sessionMessageRoutingEvent(event);
|
|
41
|
+
const payload = event?.payload || {};
|
|
42
|
+
const attachments = Array.isArray(payload.attachments) ? payload.attachments : [];
|
|
43
|
+
const sourceSessionId = commandId(session || event?.sessionId || event?.session_id);
|
|
44
|
+
const sessionId = sourceSessionId || "<sessionId>";
|
|
45
|
+
const summaries = attachments.slice(0, MAX_VISIBLE_ATTACHMENTS).map((attachment) => {
|
|
46
|
+
const item = attachment && typeof attachment === "object" ? attachment : {};
|
|
47
|
+
const details = [`${displayText(item.kind, "file")} ${displayText(item.filename, "unnamed")}`];
|
|
48
|
+
const size = fileSize(item.sizeBytes ?? item.size_bytes);
|
|
49
|
+
if (size) details.push(size);
|
|
50
|
+
if (typeof item.sha256 === "string" && /^[a-f\d]{64}$/i.test(item.sha256)) {
|
|
51
|
+
details.push(`sha256 ${item.sha256.slice(0, 8).toLowerCase()}…`);
|
|
52
|
+
}
|
|
53
|
+
const status = item.removed === true ? "removed" : displayText(item.status);
|
|
54
|
+
if (status) details.push(`status ${status}`);
|
|
55
|
+
const marker = `[attachment: ${details.join(", ")}]`;
|
|
56
|
+
if (item.removed === true) return marker;
|
|
57
|
+
const attachmentId = commandId(item.attachmentId || item.attachment_id || item.id
|
|
58
|
+
|| pointerAttachmentId(item.pointer, sourceSessionId));
|
|
59
|
+
const fetch = attachmentId.length >= 8
|
|
60
|
+
? `sl session files get ${sessionId} ${attachmentId}`
|
|
61
|
+
: `sl session files ${sessionId}`;
|
|
62
|
+
return `${marker} (fetch: ${fetch})`;
|
|
63
|
+
});
|
|
64
|
+
if (attachments.length > MAX_VISIBLE_ATTACHMENTS) {
|
|
65
|
+
summaries.push(`+${attachments.length - MAX_VISIBLE_ATTACHMENTS} more`);
|
|
66
|
+
}
|
|
67
|
+
return summaries.join(" ");
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function appendAttachmentSummary(text, event) {
|
|
71
|
+
return [text, formatAttachmentSummary(event)].filter(Boolean).join(" ");
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function withAttachmentSummary(event) {
|
|
75
|
+
const attachmentSummary = formatAttachmentSummary(event);
|
|
76
|
+
return attachmentSummary ? { ...event, attachmentSummary } : event;
|
|
77
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export function sessionMessageEditText(event = {}) {
|
|
2
|
+
const payload = event.payload || {};
|
|
3
|
+
const text = payload.message ?? payload.reply?.note ?? payload.event?.payload?.message;
|
|
4
|
+
return typeof text === "string" ? text : "";
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function formatEditSummary(event = {}) {
|
|
8
|
+
if ((event.event || event.type) !== "session_message_edited") return "";
|
|
9
|
+
const payload = event.payload || {};
|
|
10
|
+
const sequence = Number(payload.targetSequenceId ?? payload.reply?.targetSequenceId ?? payload.event?.sequenceId);
|
|
11
|
+
const target = Number.isSafeInteger(sequence) && sequence > 0 ? sequence : "?";
|
|
12
|
+
const kind = payload.targetActionId || payload.reply ? "edited reply under" : "edited";
|
|
13
|
+
return [`[${kind} #${target}]`, sessionMessageEditText(event).trim()].filter(Boolean).join(" ");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function withEditSummary(event) {
|
|
17
|
+
const editSummary = formatEditSummary(event);
|
|
18
|
+
return editSummary ? { ...event, editSummary } : event;
|
|
19
|
+
}
|
|
@@ -4,7 +4,7 @@ import path from "node:path";
|
|
|
4
4
|
import process from "node:process";
|
|
5
5
|
|
|
6
6
|
import { checkedTransport, credentialFor, credentialHmac, isAuthenticated, isCredential } from "../auth/credential-destinations.js";
|
|
7
|
-
import { requestJsonMutation } from "../auth/http.js";
|
|
7
|
+
import { requestJson, requestJsonMutation } from "../auth/http.js";
|
|
8
8
|
import { resolveActiveAuthSession } from "../auth/service.js";
|
|
9
9
|
import { renderCoordinationBulletList } from "./coordination-guidance.js";
|
|
10
10
|
import { resolveSessionPaths } from "./paths.js";
|
|
@@ -12,8 +12,20 @@ import { urlPathSegment } from "../net/url-path.js";
|
|
|
12
12
|
|
|
13
13
|
export const SESSION_INVITATION_ACCEPT_ROUTE_ID =
|
|
14
14
|
"POST /api/v1/sessions/{session_id}/invitations/accept";
|
|
15
|
+
export const PENDING_INVITATION_ACCEPT_ROUTE_ID =
|
|
16
|
+
"POST /api/v1/sessions/invitations/{invitation_id}/accept";
|
|
15
17
|
export const SESSION_MUTATION_ORIGIN = "https://sentinelayer.com";
|
|
16
18
|
|
|
19
|
+
export function throwIfPendingSessionInvitation(payload, status) {
|
|
20
|
+
if ((status !== 403 && status !== 404) || payload?.error?.code !== "INVITATION_PENDING") return;
|
|
21
|
+
const error = new Error(
|
|
22
|
+
"An invitation to this room is waiting. Run `sl session invitations list --json`, then `sl session invitations accept <invitationId>` using its invitationId.",
|
|
23
|
+
);
|
|
24
|
+
error.code = "INVITATION_PENDING";
|
|
25
|
+
error.status = status;
|
|
26
|
+
throw error;
|
|
27
|
+
}
|
|
28
|
+
|
|
17
29
|
function normalizeString(value) {
|
|
18
30
|
return String(value || "").trim();
|
|
19
31
|
}
|
|
@@ -85,6 +97,58 @@ export function createSessionMutationIdempotencyKey(operationName = "invitation-
|
|
|
85
97
|
return `sl-cli-${operation}-${randomUUID()}`;
|
|
86
98
|
}
|
|
87
99
|
|
|
100
|
+
export async function listPendingSessionInvitations({
|
|
101
|
+
targetPath = process.cwd(),
|
|
102
|
+
resolveAuthSession = resolveActiveAuthSession,
|
|
103
|
+
request = requestJson,
|
|
104
|
+
} = {}) {
|
|
105
|
+
const auth = await resolveAuthSession({ cwd: targetPath, env: process.env, autoRotate: false });
|
|
106
|
+
if (!isAuthenticated(auth) || !auth?.apiUrl) {
|
|
107
|
+
throw new Error("Not authenticated. Run `sl auth login` first.");
|
|
108
|
+
}
|
|
109
|
+
const apiUrl = normalizeString(auth.apiUrl).replace(/\/+$/, "");
|
|
110
|
+
return checkedTransport(request)(`${apiUrl}/api/v1/sessions/invitations/pending`, {
|
|
111
|
+
method: "GET",
|
|
112
|
+
credential: await credentialFor(auth),
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export async function acceptPendingSessionInvitation(invitationId, {
|
|
117
|
+
targetPath = process.cwd(),
|
|
118
|
+
idempotencyKey = "",
|
|
119
|
+
origin = SESSION_MUTATION_ORIGIN,
|
|
120
|
+
resolveAuthSession = resolveActiveAuthSession,
|
|
121
|
+
requestMutation = requestJsonMutation,
|
|
122
|
+
} = {}) {
|
|
123
|
+
const normalizedInvitationId = typeof invitationId === "string" ? invitationId.trim() : "";
|
|
124
|
+
if (!normalizedInvitationId) throw new Error("invitation id is required.");
|
|
125
|
+
const invitationPath = `/api/v1/sessions/invitations/${urlPathSegment(normalizedInvitationId, { label: "invitationId" })}/accept`;
|
|
126
|
+
const auth = await resolveAuthSession({ cwd: targetPath, env: process.env, autoRotate: false });
|
|
127
|
+
if (!isAuthenticated(auth) || !auth?.apiUrl) {
|
|
128
|
+
throw new Error("Not authenticated. Run `sl auth login` first.");
|
|
129
|
+
}
|
|
130
|
+
const credential = await credentialFor(auth);
|
|
131
|
+
const resolvedIdempotencyKey = normalizeString(idempotencyKey)
|
|
132
|
+
|| createSessionMutationIdempotencyKey("session-invite-accept");
|
|
133
|
+
const apiUrl = normalizeString(auth.apiUrl).replace(/\/+$/, "");
|
|
134
|
+
return checkedTransport(requestMutation)(
|
|
135
|
+
`${apiUrl}${invitationPath}`,
|
|
136
|
+
{
|
|
137
|
+
method: "POST",
|
|
138
|
+
operationName: "session.invitation_accept_by_id",
|
|
139
|
+
idempotencyKey: resolvedIdempotencyKey,
|
|
140
|
+
credential,
|
|
141
|
+
headers: createSessionMutationHeaders({
|
|
142
|
+
credential,
|
|
143
|
+
routeId: PENDING_INVITATION_ACCEPT_ROUTE_ID,
|
|
144
|
+
idempotencyKey: resolvedIdempotencyKey,
|
|
145
|
+
origin,
|
|
146
|
+
}),
|
|
147
|
+
body: {},
|
|
148
|
+
},
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
|
|
88
152
|
export async function acceptSessionInvitation(
|
|
89
153
|
sessionId,
|
|
90
154
|
{
|
package/src/session/mentions.js
CHANGED
|
@@ -21,6 +21,8 @@
|
|
|
21
21
|
* punctuation + cap length)
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
|
+
import { sessionMessageEditText } from "./edit-summary.js";
|
|
25
|
+
|
|
24
26
|
// `@handle` is one or more identifier characters. We allow letters,
|
|
25
27
|
// digits, `._-` so `@codex-1`, `@human-mrrcarter`, `@claude.verifier`
|
|
26
28
|
// all work. Word boundary on the front avoids matching `you@example.com`.
|
|
@@ -97,20 +99,26 @@ export function enrichEventWithMentions(event) {
|
|
|
97
99
|
: null;
|
|
98
100
|
if (!payload) return event;
|
|
99
101
|
|
|
102
|
+
// An edit's immutable snapshot retains the original explicit audience.
|
|
103
|
+
const routingPayload = event.event === "session_message_edited"
|
|
104
|
+
? { ...payload.event?.payload, ...payload }
|
|
105
|
+
: payload;
|
|
100
106
|
// Already routed by an explicit caller — don't second-guess.
|
|
101
107
|
const hasExplicitTo =
|
|
102
|
-
Array.isArray(
|
|
103
|
-
Array.isArray(
|
|
104
|
-
typeof
|
|
105
|
-
typeof
|
|
106
|
-
typeof
|
|
108
|
+
Array.isArray(routingPayload.to) ||
|
|
109
|
+
Array.isArray(routingPayload.recipients) ||
|
|
110
|
+
typeof routingPayload.recipient === "string" ||
|
|
111
|
+
typeof routingPayload.targetAgent === "string" ||
|
|
112
|
+
typeof routingPayload.targetAgentId === "string";
|
|
107
113
|
|
|
108
114
|
// We pull text from the standard fields the renderer already uses,
|
|
109
115
|
// matching the priority in `Session.tsx:payloadText`.
|
|
110
|
-
const text =
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
116
|
+
const text = event.event === "session_message_edited"
|
|
117
|
+
? sessionMessageEditText(event)
|
|
118
|
+
: normalizeString(payload.message)
|
|
119
|
+
|| normalizeString(payload.text)
|
|
120
|
+
|| normalizeString(payload.detail)
|
|
121
|
+
|| normalizeString(payload.title);
|
|
114
122
|
if (!text) return event;
|
|
115
123
|
|
|
116
124
|
const parsed = parseMentions(text);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createAgentEvent } from "../events/schema.js";
|
|
2
2
|
import { enrichEventWithMentions } from "./mentions.js";
|
|
3
3
|
import { sessionEventIdentityKeys } from "./event-identity.js";
|
|
4
|
+
import { sessionMessageEditText } from "./edit-summary.js";
|
|
4
5
|
|
|
5
6
|
export function messageRevision(value = {}) {
|
|
6
7
|
const revision = Number(value.messageRevision ?? value.message_revision ?? 1);
|
|
@@ -79,11 +80,11 @@ export function sessionMessageRoutingEvent(event = {}) {
|
|
|
79
80
|
if (!snapshot) return event;
|
|
80
81
|
const parentPayload = event.payload?.event?.payload || {};
|
|
81
82
|
const payload = { ...parentPayload, ...snapshot.payload };
|
|
82
|
-
|
|
83
|
+
payload.message = sessionMessageEditText(event);
|
|
83
84
|
for (const key of ["to", "recipient", "recipients", "targetAgent", "targetAgentId", "broadcast", "mentions"]) {
|
|
84
85
|
if (event.payload[key] !== undefined) payload[key] = event.payload[key];
|
|
85
86
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
return
|
|
87
|
+
// Use the same recipient precedence as a new message. Broadcast mentions
|
|
88
|
+
// are metadata; only an explicit routing flag can widen the audience.
|
|
89
|
+
return enrichEventWithMentions({ ...snapshot, agent: event.agent || snapshot.agent, payload });
|
|
89
90
|
}
|
package/src/session/preview.js
CHANGED
|
@@ -7,9 +7,12 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { readStream } from "./stream.js";
|
|
10
|
+
import { appendAttachmentSummary, formatAttachmentSummary } from "./attachment-summary.js";
|
|
11
|
+
import { formatEditSummary } from "./edit-summary.js";
|
|
10
12
|
|
|
11
13
|
const PREVIEW_EVENTS = new Set([
|
|
12
14
|
"session_message",
|
|
15
|
+
"session_message_edited",
|
|
13
16
|
"session_say",
|
|
14
17
|
"agent_response",
|
|
15
18
|
"session_observation",
|
|
@@ -45,14 +48,16 @@ export function pickLatestPreview(events = []) {
|
|
|
45
48
|
const kind = String(event.event || event.type || "").trim();
|
|
46
49
|
if (!kind || !PREVIEW_EVENTS.has(kind)) continue;
|
|
47
50
|
const payload = event.payload && typeof event.payload === "object" ? event.payload : {};
|
|
51
|
+
const editSummary = formatEditSummary(event);
|
|
48
52
|
const text =
|
|
53
|
+
editSummary ||
|
|
49
54
|
payload.summary ||
|
|
50
55
|
payload.message ||
|
|
51
56
|
payload.response ||
|
|
52
57
|
payload.alert ||
|
|
53
58
|
payload.reason ||
|
|
54
59
|
payload.text;
|
|
55
|
-
if (!text) continue;
|
|
60
|
+
if (!text && !formatAttachmentSummary(event)) continue;
|
|
56
61
|
return {
|
|
57
62
|
ts: event.ts || event.timestamp || null,
|
|
58
63
|
agentId:
|
|
@@ -61,7 +66,10 @@ export function pickLatestPreview(events = []) {
|
|
|
61
66
|
payload.agentId ||
|
|
62
67
|
null,
|
|
63
68
|
kind,
|
|
64
|
-
message: trim(text),
|
|
69
|
+
message: appendAttachmentSummary(trim(text), event),
|
|
70
|
+
...(editSummary ? { editSummary, event } : {}),
|
|
71
|
+
...(Array.isArray(payload.attachments) && payload.attachments.length
|
|
72
|
+
? { attachments: payload.attachments } : {}),
|
|
65
73
|
};
|
|
66
74
|
}
|
|
67
75
|
return { ts: null, agentId: null, kind: null, message: null };
|
package/src/session/recap.js
CHANGED
|
@@ -7,6 +7,7 @@ import { createAgentEvent } from "../events/schema.js";
|
|
|
7
7
|
import { dedupeSessionEvents } from "./event-identity.js";
|
|
8
8
|
import { resolveSessionPaths } from "./paths.js";
|
|
9
9
|
import { readStream } from "./stream.js";
|
|
10
|
+
import { appendAttachmentSummary, formatAttachmentSummary } from "./attachment-summary.js";
|
|
10
11
|
import { getSession } from "./store.js";
|
|
11
12
|
import { aggregateSessionUsage } from "./usage.js";
|
|
12
13
|
|
|
@@ -381,11 +382,11 @@ function summarizeRecentActivity(events = [], { forAgentId = "", limit = 2 } = {
|
|
|
381
382
|
const message = normalizeString(
|
|
382
383
|
payload.message || payload.response || payload.recap || payload.alert || payload.reason
|
|
383
384
|
);
|
|
384
|
-
if (!message) {
|
|
385
|
+
if (!message && !formatAttachmentSummary(event)) {
|
|
385
386
|
continue;
|
|
386
387
|
}
|
|
387
388
|
snippets.push(
|
|
388
|
-
`${agentId}${formatSequenceMarker(event)}: ${shortActivitySnippetText(message)}`,
|
|
389
|
+
`${agentId}${formatSequenceMarker(event)}: ${appendAttachmentSummary(shortActivitySnippetText(message), event)}`,
|
|
389
390
|
);
|
|
390
391
|
if (snippets.length >= Math.max(1, limit)) {
|
|
391
392
|
break;
|