sentinelayer-cli 0.39.0 → 0.39.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sentinelayer-cli",
3
- "version": "0.39.0",
3
+ "version": "0.39.2",
4
4
  "description": "Scaffold Sentinelayer spec/prompt/guide artifacts with secure browser auth and token bootstrap.",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -100,6 +100,7 @@ import {
100
100
  listSessionMessageActions,
101
101
  listSessionsFromApi,
102
102
  probeSessionAccess,
103
+ pollHumanMessages,
103
104
  pollSessionEvents,
104
105
  pollSessionEventsBefore,
105
106
  searchSessionEvents,
@@ -237,6 +238,8 @@ const SESSION_SAY_LOCAL_ONLY_REASONS = new Set([
237
238
  "remote_sync_disabled_env",
238
239
  ]);
239
240
  const SESSION_READ_AUTO_VIEW_TIMEOUT_MS = 500;
241
+ const SESSION_RECAP_REMOTE_REQUEST_TIMEOUT_MS = 5_000;
242
+ const SESSION_RECAP_REMOTE_HYDRATE_MAX_PAGES = 1;
240
243
 
241
244
  function isLocalOnlySessionSayReason(reason) {
242
245
  return SESSION_SAY_LOCAL_ONLY_REASONS.has(normalizeString(reason));
@@ -5565,11 +5568,24 @@ export function registerSessionCommand(program) {
5565
5568
  hydration = await hydrateSessionFromRemote({
5566
5569
  sessionId: normalizedSessionId,
5567
5570
  targetPath,
5571
+ eventPageLimit: maxEvents,
5572
+ maxEventPages: SESSION_RECAP_REMOTE_HYDRATE_MAX_PAGES,
5573
+ _poll: (pollSessionId, pollOptions) =>
5574
+ pollHumanMessages(pollSessionId, {
5575
+ ...pollOptions,
5576
+ limit: maxEvents,
5577
+ timeoutMs: SESSION_RECAP_REMOTE_REQUEST_TIMEOUT_MS,
5578
+ }),
5579
+ _pollEvents: (pollSessionId, pollOptions) =>
5580
+ pollSessionEvents(pollSessionId, {
5581
+ ...pollOptions,
5582
+ timeoutMs: SESSION_RECAP_REMOTE_REQUEST_TIMEOUT_MS,
5583
+ }),
5568
5584
  });
5569
5585
  remoteTail = await pollSessionEventsBefore(normalizedSessionId, {
5570
5586
  targetPath,
5571
5587
  limit: maxEvents,
5572
- timeoutMs: 15_000,
5588
+ timeoutMs: SESSION_RECAP_REMOTE_REQUEST_TIMEOUT_MS,
5573
5589
  });
5574
5590
  if (remoteTail?.ok && Array.isArray(remoteTail.events) && remoteTail.events.length > 0) {
5575
5591
  remoteAppend = await appendMissingRemoteEvents(normalizedSessionId, remoteTail.events, {
@@ -296,6 +296,7 @@ export function buildEstimatedMessageLedgerEntry(
296
296
  billingTier = "estimated",
297
297
  includeHumanMessages = false,
298
298
  action = "estimated_agent_message",
299
+ estimatedMessageTokenBackend = null,
299
300
  } = {},
300
301
  ) {
301
302
  const kind = n(event?.event || event?.type);
@@ -322,6 +323,7 @@ export function buildEstimatedMessageLedgerEntry(
322
323
  const outputTokens = estimateTokens(text, {
323
324
  model,
324
325
  provider: n(agent.provider || payload.provider),
326
+ backend: estimatedMessageTokenBackend,
325
327
  });
326
328
  if (outputTokens <= 0) return null;
327
329
 
@@ -21,6 +21,7 @@ const DEFAULT_RECAP_ACTIVITY_THRESHOLD = 5;
21
21
  const DEFAULT_TASK_SUMMARY_LIMIT = 3;
22
22
  const DEFAULT_WORK_PLAN_SUMMARY_LIMIT = 5;
23
23
  const DEFAULT_ACTIVITY_SNIPPET_MAX_CHARS = 120;
24
+ const RECAP_ESTIMATED_USAGE_CHARS_PER_TOKEN = 4;
24
25
  const MAX_WORK_PLAN_BYTES = 128_000;
25
26
  const WORK_PLAN_RELATIVE_PATH = "tasks/todo.md";
26
27
  const ACTIVE_WORK_PLAN_FILE_PATTERN = /^reconciled-fix-plan-\d{4}-\d{2}-\d{2}\.md$/;
@@ -1027,8 +1028,19 @@ function roundCurrency(value) {
1027
1028
  return Math.round(normalized * 1_000_000) / 1_000_000;
1028
1029
  }
1029
1030
 
1031
+ function estimateRecapMessageTokens(text) {
1032
+ const normalized = normalizeString(text);
1033
+ if (!normalized) {
1034
+ return 0;
1035
+ }
1036
+ return Math.max(1, Math.ceil(normalized.length / RECAP_ESTIMATED_USAGE_CHARS_PER_TOKEN));
1037
+ }
1038
+
1030
1039
  function normalizeUsageSummary(events = []) {
1031
- const aggregate = aggregateSessionUsage(events, { includeEstimatedMessages: true });
1040
+ const aggregate = aggregateSessionUsage(events, {
1041
+ includeEstimatedMessages: true,
1042
+ estimatedMessageTokenBackend: estimateRecapMessageTokens,
1043
+ });
1032
1044
  const totals = {
1033
1045
  totalTokens: Number(aggregate.totals.totalTokens || 0),
1034
1046
  inputTokens: Number(aggregate.totals.inputTokens || 0),