sentinelayer-cli 0.46.0 → 0.46.2

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.
Files changed (38) hide show
  1. package/bin/create-sentinelayer.js +2 -2
  2. package/bin/sentinelayer-cli.js +2 -2
  3. package/bin/sl.js +2 -2
  4. package/package.json +1 -1
  5. package/src/agents/agent-id-path.js +57 -0
  6. package/src/agents/jules/tools/runtime-audit.js +2 -1
  7. package/src/ai/aidenid.js +11 -10
  8. package/src/ai/client.js +2 -1
  9. package/src/audit/orchestrator.js +7 -1
  10. package/src/audit/registry.js +9 -1
  11. package/src/auth/credential-destinations.js +57 -13
  12. package/src/auth/http.js +4 -0
  13. package/src/auth/service.js +4 -3
  14. package/src/board/evidence-resolvers.js +15 -3
  15. package/src/cli-bootstrap.js +20 -0
  16. package/src/cli.js +3 -1
  17. package/src/commands/ai/identity-lifecycle.js +4 -3
  18. package/src/commands/chat.js +4 -1
  19. package/src/commands/session.js +51 -17
  20. package/src/legacy-cli.js +4 -11
  21. package/src/mcp/session-stdio-server.js +13 -9
  22. package/src/net/gh-api-path.js +68 -0
  23. package/src/net/url-path.js +41 -0
  24. package/src/review/dd-report-email-client.js +2 -3
  25. package/src/scan/gh-secrets.js +4 -1
  26. package/src/session/admission-access.js +17 -8
  27. package/src/session/admission.js +12 -5
  28. package/src/session/agent-registry.js +4 -5
  29. package/src/session/checkpoints.js +4 -3
  30. package/src/session/file-locks.js +8 -6
  31. package/src/session/invitations.js +2 -1
  32. package/src/session/listener-process.js +118 -32
  33. package/src/session/live-source.js +2 -3
  34. package/src/session/paths.js +51 -2
  35. package/src/session/store.js +3 -3
  36. package/src/session/sync.js +34 -26
  37. package/src/session/tickets.js +13 -6
  38. package/src/session/title-sync.js +2 -1
@@ -11,6 +11,7 @@ import { isSessionControlEvent } from "./control-events.js";
11
11
  import { createSessionMutationHeaders } from "./invitations.js";
12
12
  import { messageRevision } from "./message-edits.js";
13
13
  import { installTestEgressGuard } from "../net/test-egress-guard.js";
14
+ import { isUrlPathSegment, urlPathSegment } from "../net/url-path.js";
14
15
 
15
16
  // No-op outside tests; inside a test process (or a child it spawned) every fetch
16
17
  // to a non-loopback host is refused before a socket opens.
@@ -1023,7 +1024,7 @@ export async function syncSessionEventToApi(
1023
1024
  }
1024
1025
 
1025
1026
  const apiBaseUrl = resolveApiBaseUrl(session);
1026
- const endpoint = `${apiBaseUrl}/api/v1/sessions/${encodeURIComponent(normalizedSessionId)}/events`;
1027
+ const endpoint = `${apiBaseUrl}/api/v1/sessions/${urlPathSegment(normalizedSessionId, { label: "sessionId" })}/events`;
1027
1028
  const requestBody = JSON.stringify({
1028
1029
  event,
1029
1030
  source: "cli",
@@ -1221,7 +1222,7 @@ async function syncSessionAuxPayload(
1221
1222
  }
1222
1223
 
1223
1224
  const apiBaseUrl = resolveApiBaseUrl(session);
1224
- const endpoint = `${apiBaseUrl}/api/v1/sessions/${encodeURIComponent(normalizedSessionId)}${pathSuffix}`;
1225
+ const endpoint = `${apiBaseUrl}/api/v1/sessions/${urlPathSegment(normalizedSessionId, { label: "sessionId" })}${pathSuffix}`;
1225
1226
  try {
1226
1227
  const { response } = await fetchJsonWithFullTimeout(
1227
1228
  endpoint,
@@ -1351,7 +1352,7 @@ export async function pollHumanMessages(
1351
1352
  query.set("since", normalizedSince);
1352
1353
  }
1353
1354
  query.set("limit", String(Math.max(1, Math.min(HUMAN_MESSAGE_FETCH_LIMIT, normalizePositiveInteger(limit, HUMAN_MESSAGE_FETCH_LIMIT)))));
1354
- const endpoint = `${apiBaseUrl}/api/v1/sessions/${encodeURIComponent(normalizedSessionId)}/human-messages?${query.toString()}`;
1355
+ const endpoint = `${apiBaseUrl}/api/v1/sessions/${urlPathSegment(normalizedSessionId, { label: "sessionId" })}/human-messages?${query.toString()}`;
1355
1356
 
1356
1357
  try {
1357
1358
  const { response, payload } = await fetchJsonWithFullTimeout(
@@ -1526,7 +1527,7 @@ export async function pollSessionEvents(
1526
1527
  "limit",
1527
1528
  String(Math.max(1, Math.min(SESSION_EVENT_FETCH_LIMIT, normalizePositiveInteger(limit, SESSION_EVENT_FETCH_LIMIT))))
1528
1529
  );
1529
- const endpoint = `${apiBaseUrl}/api/v1/sessions/${encodeURIComponent(normalizedSessionId)}/events?${query.toString()}`;
1530
+ const endpoint = `${apiBaseUrl}/api/v1/sessions/${urlPathSegment(normalizedSessionId, { label: "sessionId" })}/events?${query.toString()}`;
1530
1531
 
1531
1532
  try {
1532
1533
  const { response, payload } = await fetchJsonWithFullTimeout(
@@ -1681,7 +1682,7 @@ export async function fetchSessionPresence(
1681
1682
  }
1682
1683
 
1683
1684
  const apiBaseUrl = resolveApiBaseUrl(session);
1684
- const endpoint = `${apiBaseUrl}/api/v1/sessions/${encodeURIComponent(normalizedSessionId)}/presence`;
1685
+ const endpoint = `${apiBaseUrl}/api/v1/sessions/${urlPathSegment(normalizedSessionId, { label: "sessionId" })}/presence`;
1685
1686
  try {
1686
1687
  const { response, payload } = await fetchJsonWithFullTimeout(
1687
1688
  endpoint,
@@ -1832,7 +1833,7 @@ export async function renewSessionPresence(
1832
1833
  }
1833
1834
 
1834
1835
  const apiBaseUrl = resolveApiBaseUrl(session);
1835
- const endpoint = `${apiBaseUrl}/api/v1/sessions/${encodeURIComponent(normalizedSessionId)}/presence`;
1836
+ const endpoint = `${apiBaseUrl}/api/v1/sessions/${urlPathSegment(normalizedSessionId, { label: "sessionId" })}/presence`;
1836
1837
  const body = {
1837
1838
  agentId: normalizedAgentId,
1838
1839
  state: normalizeString(state).toLowerCase() || "idle",
@@ -1955,7 +1956,7 @@ export async function requestSessionListenerStop(
1955
1956
  const normalizedIdempotencyKey =
1956
1957
  normalizeString(idempotencyKey) || `sl-listener-stop-${randomUUID()}`;
1957
1958
  const apiBaseUrl = resolveApiBaseUrl(session);
1958
- const endpoint = `${apiBaseUrl}/api/v1/sessions/${encodeURIComponent(normalizedSessionId)}/listener-controls/stop`;
1959
+ const endpoint = `${apiBaseUrl}/api/v1/sessions/${urlPathSegment(normalizedSessionId, { label: "sessionId" })}/listener-controls/stop`;
1959
1960
  const body = normalizedTargetAgentId
1960
1961
  ? { targetAgentId: normalizedTargetAgentId }
1961
1962
  : { broadcast: true };
@@ -2080,7 +2081,7 @@ export async function updateSessionReadCursor(
2080
2081
  }
2081
2082
 
2082
2083
  const apiBaseUrl = resolveApiBaseUrl(session);
2083
- const endpoint = `${apiBaseUrl}/api/v1/sessions/${encodeURIComponent(normalizedSessionId)}/read-cursor`;
2084
+ const endpoint = `${apiBaseUrl}/api/v1/sessions/${urlPathSegment(normalizedSessionId, { label: "sessionId" })}/read-cursor`;
2084
2085
  const body = {
2085
2086
  targetSequenceId:
2086
2087
  Number.isFinite(normalizedTargetSequence) && normalizedTargetSequence > 0
@@ -2225,7 +2226,7 @@ export async function streamSessionEvents(
2225
2226
  query.set("after", normalizedSince);
2226
2227
  }
2227
2228
  const suffix = query.toString() ? `?${query.toString()}` : "";
2228
- const endpoint = `${apiBaseUrl}/api/v1/sessions/${encodeURIComponent(normalizedSessionId)}/stream${suffix}`;
2229
+ const endpoint = `${apiBaseUrl}/api/v1/sessions/${urlPathSegment(normalizedSessionId, { label: "sessionId" })}/stream${suffix}`;
2229
2230
  const controller = new AbortController();
2230
2231
  const normalizedTimeoutMs = normalizePositiveInteger(timeoutMs, DEFAULT_SYNC_TIMEOUT_MS);
2231
2232
  const normalizedIdleTimeoutMs = normalizePositiveInteger(idleTimeoutMs, 0);
@@ -2450,7 +2451,7 @@ export async function pollSessionEventsBefore(
2450
2451
  "limit",
2451
2452
  String(Math.max(1, Math.min(SESSION_EVENT_FETCH_LIMIT, normalizePositiveInteger(limit, 50))))
2452
2453
  );
2453
- const endpoint = `${apiBaseUrl}/api/v1/sessions/${encodeURIComponent(normalizedSessionId)}/events/before?${query.toString()}`;
2454
+ const endpoint = `${apiBaseUrl}/api/v1/sessions/${urlPathSegment(normalizedSessionId, { label: "sessionId" })}/events/before?${query.toString()}`;
2454
2455
 
2455
2456
  try {
2456
2457
  const { response, payload } = await fetchJsonWithFullTimeout(
@@ -2571,7 +2572,7 @@ export async function listSessionMessageActions(
2571
2572
  "limit",
2572
2573
  String(Math.max(1, Math.min(SESSION_ACTION_FETCH_LIMIT, normalizePositiveInteger(limit, 200))))
2573
2574
  );
2574
- const endpoint = `${apiBaseUrl}/api/v1/sessions/${encodeURIComponent(normalizedSessionId)}/actions?${query.toString()}`;
2575
+ const endpoint = `${apiBaseUrl}/api/v1/sessions/${urlPathSegment(normalizedSessionId, { label: "sessionId" })}/actions?${query.toString()}`;
2575
2576
 
2576
2577
  try {
2577
2578
  const { response, payload } = await fetchJsonWithFullTimeout(
@@ -2668,7 +2669,7 @@ export async function fetchSessionUsageLedger(
2668
2669
  "limit",
2669
2670
  String(Math.max(1, Math.min(500, normalizePositiveInteger(limit, 500))))
2670
2671
  );
2671
- const endpoint = `${apiBaseUrl}/api/v1/sessions/${encodeURIComponent(normalizedSessionId)}/usage?${query.toString()}`;
2672
+ const endpoint = `${apiBaseUrl}/api/v1/sessions/${urlPathSegment(normalizedSessionId, { label: "sessionId" })}/usage?${query.toString()}`;
2672
2673
 
2673
2674
  try {
2674
2675
  const { response, payload } = await fetchJsonWithFullTimeout(
@@ -2847,7 +2848,10 @@ export async function editSessionMessage(sessionId, {
2847
2848
  let revision = expectedRevision === null || expectedRevision === undefined ? null : Number(expectedRevision);
2848
2849
  const validSequence = Number.isSafeInteger(sequence) && sequence > 0;
2849
2850
  const mutationKey = normalizeString(idempotencyKey) || `sl-message-edit-${randomUUID()}`;
2850
- if (!sid || typeof text !== "string" || !text.trim() || (!replyId && !messageId && !validSequence) ||
2851
+ // Every id is checked here, before the request try below: an id that is not one URL path
2852
+ // segment sends nothing and is never counted against the outbound breaker.
2853
+ const idsAreSegments = isUrlPathSegment(sid) && [replyId, messageId].every((id) => !id || isUrlPathSegment(id));
2854
+ if (!idsAreSegments || typeof text !== "string" || !text.trim() || (!replyId && !messageId && !validSequence) ||
2851
2855
  (revision !== null && (!Number.isSafeInteger(revision) || revision <= 0)) || mutationKey.length > 128) {
2852
2856
  return { ok: false, reason: "invalid_input" };
2853
2857
  }
@@ -2858,7 +2862,11 @@ export async function editSessionMessage(sessionId, {
2858
2862
  try { auth = await resolveAuthSession({ cwd: targetPath, env: process.env, autoRotate: false }); }
2859
2863
  catch { return { ok: false, reason: "no_session" }; }
2860
2864
  if (!isAuthenticated(auth)) return { ok: false, reason: "not_authenticated" };
2861
- const base = `${resolveApiBaseUrl(auth)}/api/v1/sessions/${encodeURIComponent(sid)}`;
2865
+ const base = `${resolveApiBaseUrl(auth)}/api/v1/sessions/${urlPathSegment(sid, { label: "sessionId" })}`;
2866
+ // The edit target: a reply by its id, or a message by its id (checked above, or from the lookup).
2867
+ const targetUrl = (id) => (replyId
2868
+ ? `${base}/replies/${urlPathSegment(replyId, { label: "replyId" })}`
2869
+ : `${base}/messages/${urlPathSegment(id, { label: "messageId" })}`);
2862
2870
  const credential = await credentialFor(auth);
2863
2871
  const failure = (response, payload) => {
2864
2872
  const code = normalizeString(payload?.detail?.code || payload?.error?.code || payload?.code);
@@ -2869,21 +2877,23 @@ export async function editSessionMessage(sessionId, {
2869
2877
  try {
2870
2878
  // Sequence resolution and omitted-revision lookup are one authenticated GET.
2871
2879
  if ((!replyId && !messageId) || revision === null) {
2872
- const resource = replyId ? `replies/${encodeURIComponent(replyId)}` : messageId
2873
- ? `messages/${encodeURIComponent(messageId)}` : `messages/by-sequence/${sequence}`;
2880
+ const lookupUrl = replyId || messageId
2881
+ ? targetUrl(messageId)
2882
+ : `${base}/messages/by-sequence/${urlPathSegment(sequence, { label: "targetSequenceId" })}`;
2874
2883
  const authorQuery = normalizeString(agentId) ? `?agentId=${encodeURIComponent(normalizeString(agentId))}` : "";
2875
- const { response, payload } = await fetchJsonWithFullTimeout(`${base}/${resource}${authorQuery}`, { method: "GET", credential, signal }, timeoutMs, fetchImpl, { readErrorBody: true });
2884
+ const { response, payload } = await fetchJsonWithFullTimeout(`${lookupUrl}${authorQuery}`, { method: "GET", credential, signal }, timeoutMs, fetchImpl, { readErrorBody: true });
2876
2885
  if (!response?.ok || payload?.ok === false) return failure(response, payload);
2877
2886
  const current = replyId ? payload?.reply : payload?.event;
2878
2887
  const fetchedRevision = Number(current?.messageRevision ?? 1);
2879
- if (!current?.id || (replyId && current.id !== replyId) || !Number.isSafeInteger(fetchedRevision) || fetchedRevision <= 0) return { ok: false, reason: "invalid_edit_target" };
2888
+ // A message id from the lookup is held to the same rule before it is used in a URL.
2889
+ if (!current?.id || (replyId ? current.id !== replyId : !isUrlPathSegment(current.id)) ||
2890
+ !Number.isSafeInteger(fetchedRevision) || fetchedRevision <= 0) return { ok: false, reason: "invalid_edit_target" };
2880
2891
  if (current.canEdit === false) return { ok: false, reason: "MESSAGE_EDIT_FORBIDDEN", status: 403 };
2881
2892
  if (!replyId) messageId = current.id;
2882
2893
  if (revision === null) revision = fetchedRevision;
2883
2894
  }
2884
- const resource = replyId ? `replies/${encodeURIComponent(replyId)}` : `messages/${encodeURIComponent(messageId)}`;
2885
2895
  const body = { text, expectedRevision: revision, ...(normalizeString(agentId) ? { agentId: normalizeString(agentId) } : {}) };
2886
- const { response, payload } = await fetchJsonWithFullTimeout(`${base}/${resource}`, {
2896
+ const { response, payload } = await fetchJsonWithFullTimeout(targetUrl(messageId), {
2887
2897
  method: "PATCH",
2888
2898
  headers: {
2889
2899
  ...createSessionMutationHeaders({ credential, sessionId: sid, routeId: replyId
@@ -2985,7 +2995,7 @@ export async function createSessionMessageAction(
2985
2995
  }
2986
2996
 
2987
2997
  const apiBaseUrl = resolveApiBaseUrl(session);
2988
- const endpoint = `${apiBaseUrl}/api/v1/sessions/${encodeURIComponent(normalizedSessionId)}/actions`;
2998
+ const endpoint = `${apiBaseUrl}/api/v1/sessions/${urlPathSegment(normalizedSessionId, { label: "sessionId" })}/actions`;
2989
2999
  const body = {
2990
3000
  actionType: normalizedActionType,
2991
3001
  metadata: metadata && typeof metadata === "object" && !Array.isArray(metadata) ? metadata : {},
@@ -3143,7 +3153,7 @@ export async function searchSessionEvents(
3143
3153
  "limit",
3144
3154
  String(Math.max(1, Math.min(SESSION_SEARCH_FETCH_LIMIT, normalizePositiveInteger(limit, 20))))
3145
3155
  );
3146
- const endpoint = `${apiBaseUrl}/api/v1/sessions/${encodeURIComponent(normalizedSessionId)}/events/search?${queryParams.toString()}`;
3156
+ const endpoint = `${apiBaseUrl}/api/v1/sessions/${urlPathSegment(normalizedSessionId, { label: "sessionId" })}/events/search?${queryParams.toString()}`;
3147
3157
 
3148
3158
  try {
3149
3159
  const { response, payload } = await fetchJsonWithFullTimeout(
@@ -3389,7 +3399,7 @@ export async function fetchSessionFromApi(
3389
3399
  }
3390
3400
 
3391
3401
  const apiBaseUrl = resolveApiBaseUrl(session);
3392
- const endpoint = `${apiBaseUrl}/api/v1/sessions/${encodeURIComponent(normalizedSessionId)}`;
3402
+ const endpoint = `${apiBaseUrl}/api/v1/sessions/${urlPathSegment(normalizedSessionId, { label: "sessionId" })}`;
3393
3403
 
3394
3404
  let response;
3395
3405
  let body;
@@ -3468,9 +3478,7 @@ export async function probeSessionAccess(
3468
3478
  }
3469
3479
 
3470
3480
  const apiBaseUrl = resolveApiBaseUrl(session);
3471
- const endpoint = `${apiBaseUrl}/api/v1/sessions/${encodeURIComponent(
3472
- normalizedSessionId,
3473
- )}/events?limit=1`;
3481
+ const endpoint = `${apiBaseUrl}/api/v1/sessions/${urlPathSegment(normalizedSessionId, { label: "sessionId" })}/events?limit=1`;
3474
3482
 
3475
3483
  let response;
3476
3484
  try {
@@ -22,6 +22,7 @@ import process from "node:process";
22
22
  import { checkedTransport, credentialFor, isAuthenticated } from "../auth/credential-destinations.js";
23
23
  import { requestJson, requestJsonMutation } from "../auth/http.js";
24
24
  import { resolveActiveAuthSession } from "../auth/service.js";
25
+ import { urlPathSegment } from "../net/url-path.js";
25
26
 
26
27
  function normalizeString(value) {
27
28
  return String(value ?? "").trim();
@@ -75,8 +76,14 @@ async function auth(targetPath, resolveAuthSession) {
75
76
  return { credential: await credentialFor(session), apiUrl: normalizeString(session.apiUrl).replace(/\/+$/, "") };
76
77
  }
77
78
 
78
- function ticketsUrl(apiUrl, sessionId, suffix = "") {
79
- return `${apiUrl}/api/v1/sessions/${encodeURIComponent(sessionId)}/tickets${suffix}`;
79
+ /** The room's tickets URL; `route` is a fixed collection route ("/events"). */
80
+ function ticketsUrl(apiUrl, sessionId, route = "") {
81
+ return `${apiUrl}/api/v1/sessions/${urlPathSegment(sessionId, { label: "sessionId" })}/tickets${route}`;
82
+ }
83
+
84
+ /** One ticket's URL: the raw ticket id is encoded here; `route` is a fixed route ("/claim"). */
85
+ function ticketUrl(apiUrl, sessionId, ticketId, route) {
86
+ return `${ticketsUrl(apiUrl, sessionId)}/${urlPathSegment(ticketId, { label: "ticketId" })}${route}`;
80
87
  }
81
88
 
82
89
  /** The Idempotency-Key for this logical write: reused until its response is stored. */
@@ -226,7 +233,7 @@ export async function claimTicket(
226
233
  const statePath = ticketLeasePath(sessionId, ticketId, identity, { homeDir });
227
234
  const { credential, apiUrl } = await auth(targetPath, resolveAuthSession);
228
235
  const { key } = await operationKey(statePath, "claim", String(expectedVersion ?? "any"));
229
- const response = await mutate(ticketsUrl(apiUrl, sessionId, `/${encodeURIComponent(ticketId)}/claim`), {
236
+ const response = await mutate(ticketUrl(apiUrl, sessionId, ticketId, "/claim"), {
230
237
  credential, key, operation: "claim", requestMutation,
231
238
  body: expectedVersion == null ? {} : { expectedVersion: Number(expectedVersion) },
232
239
  });
@@ -262,7 +269,7 @@ export async function renewTicketLease(
262
269
  const held = await heldLease(statePath);
263
270
  const { credential, apiUrl } = await auth(targetPath, resolveAuthSession);
264
271
  const { key } = await operationKey(statePath, "renew", `${held.leaseId}:${held.fence}:${held.ticketVersion}`);
265
- const response = await mutate(ticketsUrl(apiUrl, sessionId, `/${encodeURIComponent(ticketId)}/lease/renew`), {
272
+ const response = await mutate(ticketUrl(apiUrl, sessionId, ticketId, "/lease/renew"), {
266
273
  credential, key, operation: "renew", requestMutation, body: { leaseId: held.leaseId, fence: held.fence },
267
274
  });
268
275
  await writeState(statePath, leaseState(response));
@@ -278,7 +285,7 @@ export async function releaseTicketLease(
278
285
  const held = await heldLease(statePath);
279
286
  const { credential, apiUrl } = await auth(targetPath, resolveAuthSession);
280
287
  const { key } = await operationKey(statePath, "release", `${held.leaseId}:${held.fence}:${held.ticketVersion}`);
281
- const response = await mutate(ticketsUrl(apiUrl, sessionId, `/${encodeURIComponent(ticketId)}/lease/release`), {
288
+ const response = await mutate(ticketUrl(apiUrl, sessionId, ticketId, "/lease/release"), {
282
289
  credential, key, operation: "release", requestMutation,
283
290
  body: { leaseId: held.leaseId, fence: held.fence, expectedVersion: held.ticketVersion, ...(reason ? { reason } : {}) },
284
291
  });
@@ -303,7 +310,7 @@ export async function submitTicket(
303
310
  const held = await heldLease(statePath);
304
311
  const { credential, apiUrl } = await auth(targetPath, resolveAuthSession);
305
312
  const { key } = await operationKey(statePath, "submit", `${held.leaseId}:${held.fence}:${held.ticketVersion}`);
306
- const response = await mutate(ticketsUrl(apiUrl, sessionId, `/${encodeURIComponent(ticketId)}/submit`), {
313
+ const response = await mutate(ticketUrl(apiUrl, sessionId, ticketId, "/submit"), {
307
314
  credential, key, operation: "submit", requestMutation,
308
315
  body: {
309
316
  leaseId: held.leaseId,
@@ -4,6 +4,7 @@ import { checkedTransport, credentialFor, isAuthenticated } from "../auth/creden
4
4
  import { SentinelayerApiError, requestJsonMutation } from "../auth/http.js";
5
5
  import { resolveActiveAuthSession } from "../auth/service.js";
6
6
  import { recordSessionRemoteTitleSync } from "./store.js";
7
+ import { urlPathSegment } from "../net/url-path.js";
7
8
 
8
9
  const DEFAULT_TITLE_SYNC_TIMEOUT_MS = 2_000;
9
10
  const DEFAULT_TITLE_SYNC_RETRY_DELAY_MS = 200;
@@ -78,7 +79,7 @@ export async function pushSessionTitleToApi(
78
79
  }
79
80
  const apiUrl = String(session.apiUrl).replace(/\/+$/, "");
80
81
  const result = await checkedTransport(requestMutation)(
81
- `${apiUrl}/api/v1/sessions/${encodeURIComponent(normalizedSessionId)}/title`,
82
+ `${apiUrl}/api/v1/sessions/${urlPathSegment(normalizedSessionId, { label: "sessionId" })}/title`,
82
83
  {
83
84
  method: "POST",
84
85
  operationName: "session.set_title",