sentinelayer-cli 0.12.5 → 0.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -31,6 +31,7 @@ export async function recordCliLlmSessionUsage({
|
|
|
31
31
|
sourceCommand = "",
|
|
32
32
|
provider = "",
|
|
33
33
|
metadata = {},
|
|
34
|
+
syncRemote = true,
|
|
34
35
|
} = {}) {
|
|
35
36
|
const normalizedSessionId = normalizeString(sessionId);
|
|
36
37
|
const normalizedAgentId = normalizeString(agentId);
|
|
@@ -80,7 +81,7 @@ export async function recordCliLlmSessionUsage({
|
|
|
80
81
|
...metadata,
|
|
81
82
|
},
|
|
82
83
|
},
|
|
83
|
-
{ targetPath },
|
|
84
|
+
{ targetPath, syncRemote },
|
|
84
85
|
);
|
|
85
86
|
} catch (error) {
|
|
86
87
|
return {
|
package/src/commands/session.js
CHANGED
|
@@ -134,12 +134,12 @@ const SESSION_MESSAGE_ACTION_DESCRIPTIONS = Object.freeze([
|
|
|
134
134
|
{
|
|
135
135
|
type: "like",
|
|
136
136
|
command: "sl session react <id> like --target-sequence <n>",
|
|
137
|
-
description: "Positive lightweight feedback.",
|
|
137
|
+
description: "Positive lightweight feedback. Use --target-action-id <uuid> to react to a threaded reply.",
|
|
138
138
|
},
|
|
139
139
|
{
|
|
140
140
|
type: "dislike",
|
|
141
141
|
command: "sl session react <id> dislike --target-sequence <n>",
|
|
142
|
-
description: "Negative lightweight feedback.",
|
|
142
|
+
description: "Negative lightweight feedback. Use --target-action-id <uuid> to react to a threaded reply.",
|
|
143
143
|
},
|
|
144
144
|
{
|
|
145
145
|
type: "disregard",
|
|
@@ -190,6 +190,10 @@ function actionTargetCursor(action = {}) {
|
|
|
190
190
|
return normalizeString(action.targetCursor ?? action.target_cursor);
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
+
function actionTargetActionId(action = {}) {
|
|
194
|
+
return normalizeString(action.targetActionId ?? action.target_action_id);
|
|
195
|
+
}
|
|
196
|
+
|
|
193
197
|
function actionActorId(action = {}) {
|
|
194
198
|
return normalizeString(action.actorId ?? action.actor_id) || "unknown";
|
|
195
199
|
}
|
|
@@ -201,7 +205,11 @@ function actionCreatedAt(action = {}) {
|
|
|
201
205
|
function actionDisplayMessage(action = {}) {
|
|
202
206
|
const actionType = normalizeString(action.actionType ?? action.action_type).toLowerCase();
|
|
203
207
|
const targetSequence = actionTargetSequence(action);
|
|
204
|
-
const
|
|
208
|
+
const targetActionId = actionTargetActionId(action);
|
|
209
|
+
const parentLabel = targetSequence ? `#${targetSequence}` : actionTargetCursor(action) || "";
|
|
210
|
+
const targetLabel = targetActionId
|
|
211
|
+
? `action:${targetActionId}${parentLabel ? ` (${parentLabel})` : ""}`
|
|
212
|
+
: parentLabel || "target";
|
|
205
213
|
const note = normalizeString(action.note);
|
|
206
214
|
if (note) return `${actionType} ${targetLabel}: ${note}`;
|
|
207
215
|
return `${actionType} ${targetLabel}`;
|
|
@@ -217,6 +225,7 @@ function buildSessionActionEvent(sessionId, action = {}) {
|
|
|
217
225
|
actionType,
|
|
218
226
|
targetSequenceId: actionTargetSequence(action),
|
|
219
227
|
targetCursor: actionTargetCursor(action),
|
|
228
|
+
targetActionId: actionTargetActionId(action),
|
|
220
229
|
actorId: actionActorId(action),
|
|
221
230
|
note: normalizeString(action.note),
|
|
222
231
|
createdAt: actionCreatedAt(action),
|
|
@@ -237,6 +246,7 @@ function buildSessionActionEvent(sessionId, action = {}) {
|
|
|
237
246
|
actionType,
|
|
238
247
|
targetSequenceId: actionTargetSequence(action),
|
|
239
248
|
targetCursor: actionTargetCursor(action) || null,
|
|
249
|
+
targetActionId: actionTargetActionId(action) || null,
|
|
240
250
|
note: normalizeString(action.note) || null,
|
|
241
251
|
message: actionDisplayMessage(action),
|
|
242
252
|
source: "session_action",
|
|
@@ -304,10 +314,15 @@ function defaultActionIdempotencyKey({
|
|
|
304
314
|
actionType,
|
|
305
315
|
targetSequenceId,
|
|
306
316
|
targetCursor,
|
|
317
|
+
targetActionId,
|
|
307
318
|
note,
|
|
308
319
|
agentId,
|
|
309
320
|
} = {}) {
|
|
310
|
-
const target =
|
|
321
|
+
const target = normalizeString(targetActionId)
|
|
322
|
+
? `action:${normalizeString(targetActionId)}`
|
|
323
|
+
: targetSequenceId
|
|
324
|
+
? `seq:${targetSequenceId}`
|
|
325
|
+
: `cursor:${normalizeString(targetCursor)}`;
|
|
311
326
|
const noteHash = note ? shortSha256(note) : "none";
|
|
312
327
|
const actor = normalizeString(agentId) || "user";
|
|
313
328
|
return `cli:${normalizeString(actionType).toLowerCase()}:${target}:${actor}:${noteHash}`;
|
|
@@ -1813,6 +1828,7 @@ export function registerSessionCommand(program) {
|
|
|
1813
1828
|
commandName = "session action",
|
|
1814
1829
|
targetSequenceId: targetSequenceIdOverride = null,
|
|
1815
1830
|
targetCursor: targetCursorOverride = "",
|
|
1831
|
+
targetActionId: targetActionIdOverride = "",
|
|
1816
1832
|
note: noteOverride = "",
|
|
1817
1833
|
} = {}) {
|
|
1818
1834
|
const normalizedSessionId = normalizeString(sessionId);
|
|
@@ -1825,8 +1841,9 @@ export function registerSessionCommand(program) {
|
|
|
1825
1841
|
targetSequenceIdOverride ||
|
|
1826
1842
|
parseOptionalPositiveInteger(options.targetSequence, "target-sequence");
|
|
1827
1843
|
const targetCursor = normalizeString(targetCursorOverride) || normalizeString(options.targetCursor);
|
|
1828
|
-
|
|
1829
|
-
|
|
1844
|
+
const targetActionId = normalizeString(targetActionIdOverride) || normalizeString(options.targetActionId);
|
|
1845
|
+
if (!targetSequenceId && !targetCursor && !targetActionId) {
|
|
1846
|
+
throw new Error("Provide --target-sequence, --target-cursor, or --target-action-id.");
|
|
1830
1847
|
}
|
|
1831
1848
|
await ensureLocalSessionForRemoteCommand(normalizedSessionId, { targetPath });
|
|
1832
1849
|
const note = normalizeString(noteOverride) || normalizeString(options.note);
|
|
@@ -1837,6 +1854,7 @@ export function registerSessionCommand(program) {
|
|
|
1837
1854
|
actionType: normalizedActionType,
|
|
1838
1855
|
targetSequenceId,
|
|
1839
1856
|
targetCursor,
|
|
1857
|
+
targetActionId,
|
|
1840
1858
|
note,
|
|
1841
1859
|
agentId,
|
|
1842
1860
|
});
|
|
@@ -1846,6 +1864,7 @@ export function registerSessionCommand(program) {
|
|
|
1846
1864
|
targetPath,
|
|
1847
1865
|
targetSequenceId,
|
|
1848
1866
|
targetCursor,
|
|
1867
|
+
targetActionId,
|
|
1849
1868
|
note,
|
|
1850
1869
|
metadata: {
|
|
1851
1870
|
source: "cli",
|
|
@@ -1912,6 +1931,7 @@ export function registerSessionCommand(program) {
|
|
|
1912
1931
|
)
|
|
1913
1932
|
.option("--target-sequence <n>", "Target event sequence id")
|
|
1914
1933
|
.option("--target-cursor <cursor>", "Target event cursor")
|
|
1934
|
+
.option("--target-action-id <uuid>", "Target a threaded reply/action by action UUID")
|
|
1915
1935
|
.option("--note <text>", "Optional action note or reply body")
|
|
1916
1936
|
.option("--agent <id>", "Agent id for local idempotency metadata", "cli-user")
|
|
1917
1937
|
.option("--idempotency-key <key>", "Explicit idempotency key")
|
|
@@ -1926,6 +1946,7 @@ export function registerSessionCommand(program) {
|
|
|
1926
1946
|
.description("React to or acknowledge a target session event with ack, like, or dislike")
|
|
1927
1947
|
.option("--target-sequence <n>", "Target event sequence id")
|
|
1928
1948
|
.option("--target-cursor <cursor>", "Target event cursor")
|
|
1949
|
+
.option("--target-action-id <uuid>", "Target a threaded reply/action by action UUID")
|
|
1929
1950
|
.option("--agent <id>", "Agent id for local idempotency metadata", "cli-user")
|
|
1930
1951
|
.option("--idempotency-key <key>", "Explicit idempotency key")
|
|
1931
1952
|
.option("--path <path>", "Workspace path for the session", ".")
|
|
@@ -55,6 +55,14 @@ export function sessionEventIdentityKeys(event = {}) {
|
|
|
55
55
|
if (messageId) {
|
|
56
56
|
keys.push(`message:${messageId}`);
|
|
57
57
|
}
|
|
58
|
+
const actionId = typeof payload.actionId === "string"
|
|
59
|
+
? payload.actionId.trim()
|
|
60
|
+
: typeof payload.action_id === "string"
|
|
61
|
+
? payload.action_id.trim()
|
|
62
|
+
: "";
|
|
63
|
+
if (actionId) {
|
|
64
|
+
keys.push(`action:${actionId}`);
|
|
65
|
+
}
|
|
58
66
|
const timestamp = timestampKey(event.ts, event.timestamp, event.at);
|
|
59
67
|
const hasPayloadSignal = Object.keys(payload).length > 0;
|
|
60
68
|
const hasFingerprintSignal =
|
package/src/session/sync.js
CHANGED
|
@@ -1245,6 +1245,7 @@ export async function listSessionMessageActions(
|
|
|
1245
1245
|
{
|
|
1246
1246
|
targetPath = process.cwd(),
|
|
1247
1247
|
targetSequenceId = null,
|
|
1248
|
+
targetActionId = "",
|
|
1248
1249
|
limit = SESSION_ACTION_FETCH_LIMIT,
|
|
1249
1250
|
timeoutMs = DEFAULT_SYNC_TIMEOUT_MS,
|
|
1250
1251
|
forceCircuitProbe = false,
|
|
@@ -1294,6 +1295,10 @@ export async function listSessionMessageActions(
|
|
|
1294
1295
|
if (Number.isFinite(normalizedTargetSequence) && normalizedTargetSequence > 0) {
|
|
1295
1296
|
query.set("targetSequenceId", String(Math.floor(normalizedTargetSequence)));
|
|
1296
1297
|
}
|
|
1298
|
+
const normalizedTargetActionId = normalizeString(targetActionId);
|
|
1299
|
+
if (normalizedTargetActionId) {
|
|
1300
|
+
query.set("targetActionId", normalizedTargetActionId);
|
|
1301
|
+
}
|
|
1297
1302
|
query.set(
|
|
1298
1303
|
"limit",
|
|
1299
1304
|
String(Math.max(1, Math.min(SESSION_ACTION_FETCH_LIMIT, normalizePositiveInteger(limit, 200))))
|
|
@@ -1351,6 +1356,7 @@ export async function createSessionMessageAction(
|
|
|
1351
1356
|
targetPath = process.cwd(),
|
|
1352
1357
|
targetSequenceId = null,
|
|
1353
1358
|
targetCursor = "",
|
|
1359
|
+
targetActionId = "",
|
|
1354
1360
|
note = "",
|
|
1355
1361
|
metadata = {},
|
|
1356
1362
|
idempotencyKey = "",
|
|
@@ -1402,6 +1408,10 @@ export async function createSessionMessageAction(
|
|
|
1402
1408
|
if (normalizedTargetCursor) {
|
|
1403
1409
|
body.targetCursor = normalizedTargetCursor;
|
|
1404
1410
|
}
|
|
1411
|
+
const normalizedTargetActionId = normalizeString(targetActionId);
|
|
1412
|
+
if (normalizedTargetActionId) {
|
|
1413
|
+
body.targetActionId = normalizedTargetActionId;
|
|
1414
|
+
}
|
|
1405
1415
|
const normalizedNote = normalizeString(note);
|
|
1406
1416
|
if (normalizedNote) {
|
|
1407
1417
|
body.note = normalizedNote;
|
|
@@ -155,7 +155,63 @@ function eventTimestamp(event) {
|
|
|
155
155
|
return normalize(event?.ts || event?.timestamp);
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
+
function actionTargetLabel(payload = {}) {
|
|
159
|
+
const targetActionId = normalize(payload.targetActionId || payload.target_action_id);
|
|
160
|
+
const targetSequence = Number(payload.targetSequenceId || payload.target_sequence_id || 0);
|
|
161
|
+
const targetCursor = normalize(payload.targetCursor || payload.target_cursor);
|
|
162
|
+
const parent =
|
|
163
|
+
Number.isFinite(targetSequence) && targetSequence > 0
|
|
164
|
+
? `#${Math.floor(targetSequence)}`
|
|
165
|
+
: targetCursor
|
|
166
|
+
? `cursor ${targetCursor}`
|
|
167
|
+
: "";
|
|
168
|
+
if (targetActionId) {
|
|
169
|
+
return parent ? `reply action ${targetActionId} under ${parent}` : `reply action ${targetActionId}`;
|
|
170
|
+
}
|
|
171
|
+
return parent || "target";
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function actionBody(event) {
|
|
175
|
+
const payload = event && typeof event.payload === "object" ? event.payload : {};
|
|
176
|
+
const kind = normalize(event?.event || event?.type);
|
|
177
|
+
const actionType = normalize(payload.actionType || payload.action_type || kind.replace(/^session_/, ""));
|
|
178
|
+
const target = actionTargetLabel(payload);
|
|
179
|
+
const actionId = normalize(payload.actionId || payload.action_id);
|
|
180
|
+
const note = normalize(payload.note);
|
|
181
|
+
const metadata = [];
|
|
182
|
+
if (actionId) metadata.push(`Action ID: \`${actionId}\``);
|
|
183
|
+
if (actionType) metadata.push(`Action: \`${actionType}\``);
|
|
184
|
+
if (kind === "session_reply") {
|
|
185
|
+
return [
|
|
186
|
+
`**Reply to:** \`${target}\``,
|
|
187
|
+
...metadata,
|
|
188
|
+
note ? "" : null,
|
|
189
|
+
note || normalize(payload.message),
|
|
190
|
+
].filter((line) => line !== null && line !== "").join("\n");
|
|
191
|
+
}
|
|
192
|
+
if (kind === "session_reaction") {
|
|
193
|
+
return [
|
|
194
|
+
`**Reaction:** \`${actionType || "reaction"}\` on \`${target}\``,
|
|
195
|
+
...metadata,
|
|
196
|
+
note ? `Note: ${note}` : null,
|
|
197
|
+
].filter(Boolean).join("\n");
|
|
198
|
+
}
|
|
199
|
+
if (kind === "session_action") {
|
|
200
|
+
return [
|
|
201
|
+
`**Session action:** \`${actionType || "action"}\` on \`${target}\``,
|
|
202
|
+
...metadata,
|
|
203
|
+
note ? "" : null,
|
|
204
|
+
note,
|
|
205
|
+
].filter((line) => line !== null && line !== "").join("\n");
|
|
206
|
+
}
|
|
207
|
+
return "";
|
|
208
|
+
}
|
|
209
|
+
|
|
158
210
|
function eventBody(event) {
|
|
211
|
+
const kind = normalize(event?.event || event?.type);
|
|
212
|
+
if (kind === "session_action" || kind === "session_reply" || kind === "session_reaction") {
|
|
213
|
+
return actionBody(event);
|
|
214
|
+
}
|
|
159
215
|
const payload = event && typeof event.payload === "object" ? event.payload : {};
|
|
160
216
|
// session_usage carries the response inside payload.response.text
|
|
161
217
|
const responseText =
|