sentinelayer-cli 0.10.1 → 0.11.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/package.json +1 -1
- package/src/commands/session.js +8 -3
- package/src/legacy-cli.js +1 -1
- package/src/scan/generator.js +1 -1
- package/src/session/sync.js +79 -32
package/package.json
CHANGED
package/src/commands/session.js
CHANGED
|
@@ -2474,7 +2474,8 @@ export function registerSessionCommand(program) {
|
|
|
2474
2474
|
const remote = await listSessionsFromApi({
|
|
2475
2475
|
targetPath,
|
|
2476
2476
|
includeArchived,
|
|
2477
|
-
limit,
|
|
2477
|
+
limit: emitJson ? 200 : limit,
|
|
2478
|
+
fetchAll: emitJson,
|
|
2478
2479
|
});
|
|
2479
2480
|
const trimmed = emitJson ? remote.sessions : remote.sessions.slice(0, limit);
|
|
2480
2481
|
const payload = {
|
|
@@ -2485,6 +2486,8 @@ export function registerSessionCommand(program) {
|
|
|
2485
2486
|
ok: remote.ok,
|
|
2486
2487
|
reason: remote.reason || "",
|
|
2487
2488
|
count: remote.count,
|
|
2489
|
+
nextCursor: remote.nextCursor || null,
|
|
2490
|
+
hasMore: Boolean(remote.hasMore),
|
|
2488
2491
|
sessions: trimmed,
|
|
2489
2492
|
};
|
|
2490
2493
|
if (emitJson) {
|
|
@@ -2519,10 +2522,12 @@ export function registerSessionCommand(program) {
|
|
|
2519
2522
|
`${item.sessionId} status=${item.status}${archive} created=${created}${lastActivity}`,
|
|
2520
2523
|
);
|
|
2521
2524
|
}
|
|
2522
|
-
if (remote.count > trimmed.length) {
|
|
2525
|
+
if (remote.count > trimmed.length || remote.hasMore) {
|
|
2523
2526
|
console.log(
|
|
2524
2527
|
pc.gray(
|
|
2525
|
-
|
|
2528
|
+
remote.hasMore
|
|
2529
|
+
? "… more sessions are available (raise --limit or use --json)."
|
|
2530
|
+
: `… ${remote.count - trimmed.length} more (raise --limit or use --json).`,
|
|
2526
2531
|
),
|
|
2527
2532
|
);
|
|
2528
2533
|
}
|
package/src/legacy-cli.js
CHANGED
|
@@ -2316,7 +2316,7 @@ jobs:
|
|
|
2316
2316
|
fi
|
|
2317
2317
|
- name: Run Omar Gate
|
|
2318
2318
|
id: omar
|
|
2319
|
-
uses: mrrCarter/sentinelayer-v1-action@
|
|
2319
|
+
uses: mrrCarter/sentinelayer-v1-action@4cb3063e04e3b899981b25f6918b26f70d35a8d4
|
|
2320
2320
|
with:
|
|
2321
2321
|
sentinelayer_token: \${{ secrets.${normalizedSecret} }}${specIdBindingLine}
|
|
2322
2322
|
scan_mode: \${{ github.event_name == 'workflow_dispatch' && inputs.scan_mode || 'deep' }}
|
package/src/scan/generator.js
CHANGED
|
@@ -2,7 +2,7 @@ import YAML from "yaml";
|
|
|
2
2
|
|
|
3
3
|
export const DEFAULT_SCAN_WORKFLOW_PATH = ".github/workflows/omar-gate.yml";
|
|
4
4
|
export const DEFAULT_SCAN_SECRET_NAME = "SENTINELAYER_TOKEN";
|
|
5
|
-
export const SENTINELAYER_ACTION_REF = "mrrCarter/sentinelayer-v1-action@
|
|
5
|
+
export const SENTINELAYER_ACTION_REF = "mrrCarter/sentinelayer-v1-action@4cb3063e04e3b899981b25f6918b26f70d35a8d4";
|
|
6
6
|
export const SUPPORTED_E2E_HINTS = Object.freeze(["auto", "yes", "no"]);
|
|
7
7
|
export const SUPPORTED_PLAYWRIGHT_MODES = Object.freeze(["auto", "off", "baseline", "audit"]);
|
|
8
8
|
|
package/src/session/sync.js
CHANGED
|
@@ -1243,21 +1243,27 @@ export async function pollSessionEventsBefore(
|
|
|
1243
1243
|
*
|
|
1244
1244
|
* Mirrors the failure shape of `pollHumanMessages` so callers can render
|
|
1245
1245
|
* a single error path: `{ ok, reason, sessions, count }`. Sessions are
|
|
1246
|
-
* returned in API order (
|
|
1246
|
+
* returned in API order (most-recently-active first per the server's contract); the
|
|
1247
1247
|
* caller is responsible for any further sort or filter.
|
|
1248
1248
|
*
|
|
1249
1249
|
* @param {object} [options]
|
|
1250
1250
|
* @param {string} [options.targetPath]
|
|
1251
1251
|
* @param {boolean} [options.includeArchived]
|
|
1252
1252
|
* @param {number} [options.limit]
|
|
1253
|
+
* @param {string|null} [options.cursor]
|
|
1254
|
+
* @param {boolean} [options.fetchAll]
|
|
1255
|
+
* @param {number} [options.maxPages]
|
|
1253
1256
|
* @param {Function} [options.resolveAuthSession]
|
|
1254
1257
|
* @param {Function} [options.fetchImpl]
|
|
1255
|
-
* @returns {Promise<{ok: boolean, reason: string, sessions: Array<object>, count: number}>}
|
|
1258
|
+
* @returns {Promise<{ok: boolean, reason: string, sessions: Array<object>, count: number, nextCursor: string|null, hasMore: boolean}>}
|
|
1256
1259
|
*/
|
|
1257
1260
|
export async function listSessionsFromApi({
|
|
1258
1261
|
targetPath = process.cwd(),
|
|
1259
1262
|
includeArchived = false,
|
|
1260
1263
|
limit = 50,
|
|
1264
|
+
cursor = null,
|
|
1265
|
+
fetchAll = false,
|
|
1266
|
+
maxPages = 50,
|
|
1261
1267
|
resolveAuthSession = resolveActiveAuthSession,
|
|
1262
1268
|
fetchImpl = fetchWithTimeout,
|
|
1263
1269
|
timeoutMs = DEFAULT_SYNC_TIMEOUT_MS,
|
|
@@ -1270,52 +1276,93 @@ export async function listSessionsFromApi({
|
|
|
1270
1276
|
autoRotate: false,
|
|
1271
1277
|
});
|
|
1272
1278
|
} catch {
|
|
1273
|
-
return { ok: false, reason: "no_session", sessions: [], count: 0 };
|
|
1274
|
-
}
|
|
1275
|
-
if (!session || !session.token) {
|
|
1276
|
-
return { ok: false, reason: "not_authenticated", sessions: [], count: 0 };
|
|
1277
|
-
}
|
|
1278
|
-
|
|
1279
|
-
const apiBaseUrl = resolveApiBaseUrl(session);
|
|
1280
|
-
const query = new URLSearchParams();
|
|
1281
|
-
if (includeArchived) query.set("include_archived", "true");
|
|
1282
|
-
const normalizedLimit = Math.max(1, Math.min(200, normalizePositiveInteger(limit, 50)));
|
|
1283
|
-
query.set("limit", String(normalizedLimit));
|
|
1284
|
-
const endpoint = `${apiBaseUrl}/api/v1/sessions?${query.toString()}`;
|
|
1285
|
-
|
|
1286
|
-
let response;
|
|
1287
|
-
try {
|
|
1288
|
-
response = await fetchImpl(
|
|
1289
|
-
endpoint,
|
|
1290
|
-
{
|
|
1291
|
-
method: "GET",
|
|
1292
|
-
headers: { Authorization: `Bearer ${session.token}` },
|
|
1293
|
-
},
|
|
1294
|
-
normalizePositiveInteger(timeoutMs, DEFAULT_SYNC_TIMEOUT_MS),
|
|
1295
|
-
);
|
|
1296
|
-
} catch (err) {
|
|
1297
1279
|
return {
|
|
1298
1280
|
ok: false,
|
|
1299
|
-
reason:
|
|
1281
|
+
reason: "no_session",
|
|
1300
1282
|
sessions: [],
|
|
1301
1283
|
count: 0,
|
|
1284
|
+
nextCursor: null,
|
|
1285
|
+
hasMore: false,
|
|
1302
1286
|
};
|
|
1303
1287
|
}
|
|
1304
|
-
if (!
|
|
1288
|
+
if (!session || !session.token) {
|
|
1305
1289
|
return {
|
|
1306
1290
|
ok: false,
|
|
1307
|
-
reason:
|
|
1291
|
+
reason: "not_authenticated",
|
|
1308
1292
|
sessions: [],
|
|
1309
1293
|
count: 0,
|
|
1294
|
+
nextCursor: null,
|
|
1295
|
+
hasMore: false,
|
|
1310
1296
|
};
|
|
1311
1297
|
}
|
|
1312
|
-
|
|
1313
|
-
const
|
|
1298
|
+
|
|
1299
|
+
const apiBaseUrl = resolveApiBaseUrl(session);
|
|
1300
|
+
const normalizedLimit = Math.max(1, Math.min(200, normalizePositiveInteger(limit, 50)));
|
|
1301
|
+
const normalizedMaxPages = Math.max(1, Math.min(100, normalizePositiveInteger(maxPages, 50)));
|
|
1302
|
+
let nextCursor = normalizeString(cursor) || null;
|
|
1303
|
+
let hasMore = false;
|
|
1304
|
+
const sessions = [];
|
|
1305
|
+
const seenSessionIds = new Set();
|
|
1306
|
+
let count = 0;
|
|
1307
|
+
|
|
1308
|
+
for (let page = 0; page < normalizedMaxPages; page += 1) {
|
|
1309
|
+
const query = new URLSearchParams();
|
|
1310
|
+
if (includeArchived) query.set("include_archived", "true");
|
|
1311
|
+
query.set("limit", String(normalizedLimit));
|
|
1312
|
+
if (nextCursor) query.set("cursor", nextCursor);
|
|
1313
|
+
const endpoint = `${apiBaseUrl}/api/v1/sessions?${query.toString()}`;
|
|
1314
|
+
|
|
1315
|
+
let response;
|
|
1316
|
+
try {
|
|
1317
|
+
response = await fetchImpl(
|
|
1318
|
+
endpoint,
|
|
1319
|
+
{
|
|
1320
|
+
method: "GET",
|
|
1321
|
+
headers: { Authorization: `Bearer ${session.token}` },
|
|
1322
|
+
},
|
|
1323
|
+
normalizePositiveInteger(timeoutMs, DEFAULT_SYNC_TIMEOUT_MS),
|
|
1324
|
+
);
|
|
1325
|
+
} catch (err) {
|
|
1326
|
+
return {
|
|
1327
|
+
ok: false,
|
|
1328
|
+
reason: normalizeString(err?.message) || "list_failed",
|
|
1329
|
+
sessions: [],
|
|
1330
|
+
count: 0,
|
|
1331
|
+
nextCursor: null,
|
|
1332
|
+
hasMore: false,
|
|
1333
|
+
};
|
|
1334
|
+
}
|
|
1335
|
+
if (!response || !response.ok) {
|
|
1336
|
+
return {
|
|
1337
|
+
ok: false,
|
|
1338
|
+
reason: `api_${response ? response.status : "no_response"}`,
|
|
1339
|
+
sessions: [],
|
|
1340
|
+
count: 0,
|
|
1341
|
+
nextCursor: null,
|
|
1342
|
+
hasMore: false,
|
|
1343
|
+
};
|
|
1344
|
+
}
|
|
1345
|
+
const payload = await response.json().catch(() => ({}));
|
|
1346
|
+
const pageSessions = Array.isArray(payload?.sessions) ? payload.sessions : [];
|
|
1347
|
+
for (const item of pageSessions) {
|
|
1348
|
+
const sessionId = normalizeString(item?.sessionId || item?.id);
|
|
1349
|
+
if (sessionId && seenSessionIds.has(sessionId)) continue;
|
|
1350
|
+
if (sessionId) seenSessionIds.add(sessionId);
|
|
1351
|
+
sessions.push(item);
|
|
1352
|
+
}
|
|
1353
|
+
count = sessions.length;
|
|
1354
|
+
nextCursor = normalizeString(payload?.next_cursor || payload?.nextCursor);
|
|
1355
|
+
hasMore = Boolean(payload?.has_more && nextCursor);
|
|
1356
|
+
if (!fetchAll || !hasMore) break;
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1314
1359
|
return {
|
|
1315
1360
|
ok: true,
|
|
1316
1361
|
reason: "",
|
|
1317
1362
|
sessions,
|
|
1318
|
-
count
|
|
1363
|
+
count,
|
|
1364
|
+
nextCursor: nextCursor || null,
|
|
1365
|
+
hasMore,
|
|
1319
1366
|
};
|
|
1320
1367
|
}
|
|
1321
1368
|
|