sentinelayer-cli 0.34.0 → 0.34.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.34.0",
3
+ "version": "0.34.2",
4
4
  "description": "Scaffold Sentinelayer spec/prompt/guide artifacts with secure browser auth and token bootstrap.",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -755,6 +755,14 @@ function formatHumanAskLine(event = {}) {
755
755
  return `${sequenceLabel} ${humanAskAgentId(event)}${ts ? ` ${ts}` : ""}${suffix}`;
756
756
  }
757
757
 
758
+ function formatRemoteHydrateAppendWarning(result = {}) {
759
+ const count = Number(result?.appendFailureCount || 0);
760
+ if (!Number.isFinite(count) || count <= 0) return "";
761
+ const reason = normalizeString(result.appendFailureReason) || "local_append_failed";
762
+ const noun = count === 1 ? "event" : "events";
763
+ return `Remote hydrate could not persist ${count} ${noun} locally (${reason}); affected cursors were not advanced.`;
764
+ }
765
+
758
766
  function eventTimestampMs(event = {}) {
759
767
  for (const key of ["ts", "timestamp", "createdAt", "at"]) {
760
768
  const epoch = Date.parse(normalizeString(event?.[key]));
@@ -5481,6 +5489,10 @@ export function registerSessionCommand(program) {
5481
5489
  ),
5482
5490
  );
5483
5491
  }
5492
+ const appendWarning = formatRemoteHydrateAppendWarning(hydration);
5493
+ if (appendWarning) {
5494
+ console.log(pc.yellow(appendWarning));
5495
+ }
5484
5496
  } else {
5485
5497
  console.log(
5486
5498
  pc.yellow(
@@ -5847,6 +5859,8 @@ export function registerSessionCommand(program) {
5847
5859
  eventsCursor: result.eventsCursor,
5848
5860
  materializedLocalSession: result.materializedLocalSession,
5849
5861
  localAppendComplete: result.localAppendComplete,
5862
+ appendFailureCount: result.appendFailureCount,
5863
+ appendFailureReason: result.appendFailureReason,
5850
5864
  access: access || undefined,
5851
5865
  };
5852
5866
  if (shouldEmitJson(options, command)) {
@@ -5857,6 +5871,10 @@ export function registerSessionCommand(program) {
5857
5871
  console.log(
5858
5872
  `Hydrated session ${normalizedSessionId}: relayed=${result.relayed} dropped=${result.dropped}.`,
5859
5873
  );
5874
+ const appendWarning = formatRemoteHydrateAppendWarning(result);
5875
+ if (appendWarning) {
5876
+ console.log(pc.yellow(appendWarning));
5877
+ }
5860
5878
  if (access && !access.accessible) {
5861
5879
  if (access.reason === "session_not_found") {
5862
5880
  console.log(
package/src/legacy-cli.js CHANGED
@@ -2521,14 +2521,14 @@ jobs:
2521
2521
  with:
2522
2522
  github_token: \${{ github.token }}
2523
2523
  sentinelayer_token: \${{ secrets.${normalizedSecret} }}${specIdBindingLine}
2524
- sentinelayer_managed_llm: "false"
2525
- openai_api_key: \${{ secrets.OPENAI_API_KEY }}
2526
- google_api_key: \${{ secrets.GOOGLE_API_KEY }}
2524
+ sentinelayer_managed_llm: "true"
2527
2525
  scan_mode: \${{ github.event_name == 'workflow_dispatch' && inputs.scan_mode || 'deep' }}
2528
2526
  severity_gate: \${{ github.event_name == 'workflow_dispatch' && inputs.severity_gate || 'P1' }}
2529
2527
  model: gpt-5.3-codex
2530
2528
  codex_model: gpt-5.3-codex
2531
- model_fallback: gemini-2.5-flash
2529
+ model_fallback: gpt-4.1-mini
2530
+ use_codex: "true"
2531
+ codex_only: "false"
2532
2532
  llm_failure_policy: block
2533
2533
  - name: Enforce Omar reviewer merge thresholds
2534
2534
  shell: bash
@@ -2612,7 +2612,7 @@ jobs:
2612
2612
  "scan": {
2613
2613
  "mode": env("OMAR_SCAN_MODE", "deep"),
2614
2614
  "action_ref": "mrrCarter/sentinelayer-v1-action@03d7369cba7de2e9f15b959275c982111f0ee493",
2615
- "managed_llm": False,
2615
+ "managed_llm": True,
2616
2616
  "llm_failure_policy": "block",
2617
2617
  },
2618
2618
  "github": {
@@ -227,14 +227,14 @@ export function buildSecurityReviewWorkflow({ secretName = DEFAULT_SCAN_SECRET_N
227
227
  with: {
228
228
  github_token: "${{ github.token }}",
229
229
  sentinelayer_token: `\${{ secrets.${normalizedSecret} }}`,
230
- sentinelayer_managed_llm: "false",
231
- openai_api_key: "${{ secrets.OPENAI_API_KEY }}",
232
- google_api_key: "${{ secrets.GOOGLE_API_KEY }}",
230
+ sentinelayer_managed_llm: "true",
233
231
  scan_mode: profile.scanMode || "deep",
234
232
  severity_gate: profile.severityGate || "P1",
235
233
  model: "gpt-5.3-codex",
236
234
  codex_model: "gpt-5.3-codex",
237
- model_fallback: "gemini-2.5-flash",
235
+ model_fallback: "gpt-4.1-mini",
236
+ use_codex: "true",
237
+ codex_only: "false",
238
238
  llm_failure_policy: "block",
239
239
  playwright_mode: profile.playwrightMode || "off",
240
240
  sbom_mode: profile.sbomMode || "off",
@@ -326,7 +326,7 @@ export function buildSecurityReviewWorkflow({ secretName = DEFAULT_SCAN_SECRET_N
326
326
  " 'scan': {",
327
327
  " 'mode': env('OMAR_SCAN_MODE', 'deep'),",
328
328
  ` 'action_ref': '${SENTINELAYER_ACTION_REF}',`,
329
- " 'managed_llm': False,",
329
+ " 'managed_llm': True,",
330
330
  " 'llm_failure_policy': 'block',",
331
331
  " },",
332
332
  " 'github': {",
@@ -38,6 +38,7 @@ import { isSessionControlEvent } from "./control-events.js";
38
38
  const EVENTS_CURSOR_SUFFIX = "events";
39
39
  const DEFAULT_EVENT_PAGE_LIMIT = 200;
40
40
  const DEFAULT_MAX_EVENT_PAGES = 25;
41
+ const MAX_APPEND_FAILURE_REASON_LENGTH = 160;
41
42
 
42
43
  function indexRelayEventIdentityKeys(indexByKey, eventList = [], event = {}, index = -1) {
43
44
  if (!indexByKey || !Array.isArray(eventList) || index < 0) return;
@@ -163,6 +164,28 @@ function normalizePositiveInteger(value, fallbackValue) {
163
164
  return Math.floor(normalized);
164
165
  }
165
166
 
167
+ function localAppendFailureReason(error) {
168
+ const message = error?.message || String(error || "");
169
+ let reason = String(message).trim();
170
+ if (!reason) return "local_append_failed";
171
+ reason = reason.replace(
172
+ /(["'])(?:[A-Za-z]:\\|\/(?:Users|home|tmp|var|private|mnt|workspace)\/).*?\1/g,
173
+ "$1[path]$1",
174
+ );
175
+ reason = reason.replace(/[A-Za-z]:\\[^,;\r\n)]+/g, "[path]");
176
+ reason = reason.replace(/(^|[\s"'(])\/(?:Users|home|tmp|var|private|mnt|workspace)\/[^\s,;)"']+/g, "$1[path]");
177
+ reason = reason.replace(/\bBearer\s+[A-Za-z0-9._~+/=-]+/gi, "Bearer [REDACTED]");
178
+ reason = reason.replace(
179
+ /\b([A-Za-z0-9_-]*(?:api[_-]?key|authorization|password|secret|token)[A-Za-z0-9_-]*)\s*[:=]\s*(?:"[^"]+"|'[^']+'|[^\s,;]+)/gi,
180
+ "$1=[REDACTED]",
181
+ );
182
+ reason = reason.replace(/\b[A-Za-z0-9._~+/=-]{32,}\b/g, "[REDACTED]");
183
+ if (reason.length > MAX_APPEND_FAILURE_REASON_LENGTH) {
184
+ reason = `${reason.slice(0, MAX_APPEND_FAILURE_REASON_LENGTH - 3)}...`;
185
+ }
186
+ return reason || "local_append_failed";
187
+ }
188
+
166
189
  async function pollSessionEventPages({
167
190
  sessionId,
168
191
  targetPath,
@@ -436,6 +459,8 @@ export async function hydrateSessionFromRemote({
436
459
  mergeExisting: eventsNeedingMerge.has(event),
437
460
  }));
438
461
  const failedRelayKeys = new Set();
462
+ let appendFailureCount = 0;
463
+ let appendFailureReason = "";
439
464
  for (const { event, mergeExisting } of appendEvents) {
440
465
  try {
441
466
  const persisted = await _append(sessionId, event, {
@@ -453,7 +478,11 @@ export async function hydrateSessionFromRemote({
453
478
  persistedEvent,
454
479
  existingRelayEvents.length - 1,
455
480
  );
456
- } catch {
481
+ } catch (error) {
482
+ appendFailureCount += 1;
483
+ if (!appendFailureReason) {
484
+ appendFailureReason = localAppendFailureReason(error);
485
+ }
457
486
  addSessionEventIdentityKeys(failedRelayKeys, event);
458
487
  // Append errors are observable via the stream but should not
459
488
  // abort the rest of the batch — partial relay is still progress.
@@ -492,6 +521,8 @@ export async function hydrateSessionFromRemote({
492
521
  eventsBackfillReason: eventsResult?.complete === false ? eventsResult?.reason || "" : "",
493
522
  materializedLocalSession,
494
523
  localAppendComplete: humanCursorSafe && eventsCursorSafe,
524
+ appendFailureCount,
525
+ appendFailureReason,
495
526
  remoteStatus: remoteStatus || null,
496
527
  };
497
528
  }