sentinelayer-cli 0.4.5 → 0.8.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.
Files changed (72) hide show
  1. package/README.md +16 -18
  2. package/package.json +7 -6
  3. package/src/agents/jules/config/definition.js +13 -62
  4. package/src/agents/jules/config/system-prompt.js +8 -1
  5. package/src/agents/jules/fix-cycle.js +12 -372
  6. package/src/agents/jules/loop.js +116 -26
  7. package/src/agents/jules/pulse.js +10 -327
  8. package/src/agents/jules/stream.js +13 -12
  9. package/src/agents/jules/swarm/orchestrator.js +3 -3
  10. package/src/agents/jules/swarm/sub-agent.js +6 -3
  11. package/src/agents/jules/tools/aidenid-email.js +189 -0
  12. package/src/agents/jules/tools/auth-audit.js +1187 -45
  13. package/src/agents/jules/tools/dispatch.js +25 -12
  14. package/src/agents/jules/tools/file-edit.js +2 -180
  15. package/src/agents/jules/tools/file-read.js +2 -100
  16. package/src/agents/jules/tools/glob.js +2 -168
  17. package/src/agents/jules/tools/grep.js +2 -228
  18. package/src/agents/jules/tools/path-guards.js +2 -161
  19. package/src/agents/jules/tools/runtime-audit.js +6 -2
  20. package/src/agents/jules/tools/shell.js +2 -383
  21. package/src/agents/persona-visuals.js +64 -0
  22. package/src/agents/shared-tools/dispatch-core.js +320 -0
  23. package/src/agents/shared-tools/file-edit.js +180 -0
  24. package/src/agents/shared-tools/file-read.js +100 -0
  25. package/src/agents/shared-tools/glob.js +168 -0
  26. package/src/agents/shared-tools/grep.js +228 -0
  27. package/src/agents/shared-tools/index.js +46 -0
  28. package/src/agents/shared-tools/path-guards.js +161 -0
  29. package/src/agents/shared-tools/shell.js +383 -0
  30. package/src/ai/aidenid.js +56 -7
  31. package/src/ai/client.js +45 -0
  32. package/src/ai/proxy.js +137 -0
  33. package/src/auth/gate.js +290 -16
  34. package/src/auth/http.js +450 -39
  35. package/src/auth/service.js +262 -47
  36. package/src/auth/session-store.js +475 -21
  37. package/src/cli.js +5 -0
  38. package/src/commands/audit.js +13 -8
  39. package/src/commands/auth.js +53 -9
  40. package/src/commands/omargate.js +10 -2
  41. package/src/commands/scan.js +10 -4
  42. package/src/commands/session.js +590 -0
  43. package/src/commands/spec.js +62 -0
  44. package/src/commands/watch.js +3 -2
  45. package/src/daemon/assignment-ledger.js +196 -0
  46. package/src/daemon/error-worker.js +599 -16
  47. package/src/daemon/fix-cycle.js +384 -0
  48. package/src/daemon/ingest-refresh.js +10 -9
  49. package/src/daemon/jira-lifecycle.js +135 -0
  50. package/src/daemon/pulse.js +327 -0
  51. package/src/daemon/scope-engine.js +1068 -0
  52. package/src/events/schema.js +190 -0
  53. package/src/interactive/index.js +18 -16
  54. package/src/legacy-cli.js +606 -37
  55. package/src/prompt/generator.js +19 -1
  56. package/src/review/ai-review.js +11 -1
  57. package/src/review/local-review.js +75 -19
  58. package/src/review/omargate-interactive.js +68 -0
  59. package/src/review/omargate-orchestrator.js +404 -0
  60. package/src/review/persona-prompts.js +296 -0
  61. package/src/review/scan-modes.js +48 -0
  62. package/src/scan/generator.js +1 -1
  63. package/src/session/agent-registry.js +352 -0
  64. package/src/session/daemon.js +801 -0
  65. package/src/session/paths.js +33 -0
  66. package/src/session/runtime-bridge.js +739 -0
  67. package/src/session/store.js +388 -0
  68. package/src/session/stream.js +325 -0
  69. package/src/spec/generator.js +100 -0
  70. package/src/telemetry/session-tracker.js +148 -32
  71. package/src/telemetry/sync.js +6 -2
  72. package/src/ui/command-hints.js +13 -0
@@ -109,6 +109,7 @@ function createInitialQueue(nowIso = new Date().toISOString()) {
109
109
  function normalizeAssignmentRecord(record = {}, nowIso = new Date().toISOString()) {
110
110
  const updatedAt = normalizeIsoTimestamp(record.updatedAt, nowIso);
111
111
  return {
112
+ sessionId: normalizeString(record.sessionId) || null,
112
113
  workItemId: normalizeString(record.workItemId),
113
114
  assignedAgentIdentity: normalizeString(record.assignedAgentIdentity) || null,
114
115
  leasedAt: record.leasedAt ? normalizeIsoTimestamp(record.leasedAt, updatedAt) : null,
@@ -285,6 +286,33 @@ function requireAgentIdentity(value, fieldName = "agentIdentity") {
285
286
  return normalized;
286
287
  }
287
288
 
289
+ function normalizeSessionId(value) {
290
+ const normalized = normalizeString(value);
291
+ return normalized || null;
292
+ }
293
+
294
+ function requireSessionId(value, fieldName = "sessionId") {
295
+ const normalized = normalizeString(value);
296
+ if (!normalized) {
297
+ throw new Error(`${fieldName} is required.`);
298
+ }
299
+ return normalized;
300
+ }
301
+
302
+ function assertSessionBinding(existingAssignment, expectedSessionId, workItemId) {
303
+ const normalizedExpected = normalizeSessionId(expectedSessionId);
304
+ if (!normalizedExpected) {
305
+ return;
306
+ }
307
+ const normalizedExisting = normalizeSessionId(existingAssignment?.sessionId);
308
+ if (!normalizedExisting || normalizedExisting === normalizedExpected) {
309
+ return;
310
+ }
311
+ throw new Error(
312
+ `Work item '${normalizeString(workItemId)}' is bound to session '${normalizedExisting}', not '${normalizedExpected}'.`
313
+ );
314
+ }
315
+
288
316
  function normalizeReleaseTargetStatus(value) {
289
317
  const normalized = normalizeString(value).toUpperCase();
290
318
  if (!RELEASE_TARGET_STATUSES.has(normalized)) {
@@ -313,6 +341,7 @@ export async function resolveAssignmentLedgerStorage({
313
341
  export async function claimAssignment({
314
342
  targetPath = ".",
315
343
  outputDir = "",
344
+ sessionId = "",
316
345
  workItemId,
317
346
  agentIdentity,
318
347
  leaseTtlSeconds = 1800,
@@ -329,6 +358,7 @@ export async function claimAssignment({
329
358
  if (!normalizedWorkItemId) {
330
359
  throw new Error("workItemId is required.");
331
360
  }
361
+ const normalizedSessionId = normalizeSessionId(sessionId);
332
362
  const normalizedAgentIdentity = requireAgentIdentity(agentIdentity);
333
363
  const normalizedTtl = normalizePositiveInteger(leaseTtlSeconds, 1800);
334
364
  const storage = await resolveAssignmentLedgerStorage({
@@ -346,6 +376,7 @@ export async function claimAssignment({
346
376
 
347
377
  const assignmentIndex = findAssignmentIndex(ledger, normalizedWorkItemId);
348
378
  const existingAssignment = assignmentIndex >= 0 ? ledger.assignments[assignmentIndex] : null;
379
+ assertSessionBinding(existingAssignment, normalizedSessionId, normalizedWorkItemId);
349
380
  if (
350
381
  existingAssignment &&
351
382
  ACTIVE_ASSIGNMENT_STATUSES.has(existingAssignment.status) &&
@@ -361,6 +392,7 @@ export async function claimAssignment({
361
392
  const nextRecord = normalizeAssignmentRecord(
362
393
  {
363
394
  workItemId: normalizedWorkItemId,
395
+ sessionId: normalizedSessionId || normalizeSessionId(existingAssignment?.sessionId),
364
396
  assignedAgentIdentity: normalizedAgentIdentity,
365
397
  leasedAt: normalizedNow,
366
398
  leaseTtlSeconds: normalizedTtl,
@@ -402,6 +434,7 @@ export async function claimAssignment({
402
434
  await appendEvent(storage.eventsPath, {
403
435
  timestamp: normalizedNow,
404
436
  eventType: "claim",
437
+ sessionId: nextRecord.sessionId,
405
438
  workItemId: normalizedWorkItemId,
406
439
  agentIdentity: normalizedAgentIdentity,
407
440
  leaseTtlSeconds: normalizedTtl,
@@ -422,6 +455,7 @@ export async function claimAssignment({
422
455
  export async function heartbeatAssignment({
423
456
  targetPath = ".",
424
457
  outputDir = "",
458
+ sessionId = "",
425
459
  workItemId,
426
460
  agentIdentity,
427
461
  leaseTtlSeconds = 1800,
@@ -438,6 +472,7 @@ export async function heartbeatAssignment({
438
472
  if (!normalizedWorkItemId) {
439
473
  throw new Error("workItemId is required.");
440
474
  }
475
+ const normalizedSessionId = normalizeSessionId(sessionId);
441
476
  const normalizedAgentIdentity = requireAgentIdentity(agentIdentity);
442
477
  const normalizedTtl = normalizePositiveInteger(leaseTtlSeconds, 1800);
443
478
  const storage = await resolveAssignmentLedgerStorage({
@@ -458,11 +493,13 @@ export async function heartbeatAssignment({
458
493
  `Work item '${normalizedWorkItemId}' is assigned to '${existing.assignedAgentIdentity}', not '${normalizedAgentIdentity}'.`
459
494
  );
460
495
  }
496
+ assertSessionBinding(existing, normalizedSessionId, normalizedWorkItemId);
461
497
 
462
498
  const leaseExpiresAt = toIsoAfterSeconds(normalizedNow, normalizedTtl);
463
499
  const next = normalizeAssignmentRecord(
464
500
  {
465
501
  ...existing,
502
+ sessionId: normalizedSessionId || normalizeSessionId(existing.sessionId),
466
503
  status: "IN_PROGRESS",
467
504
  leaseTtlSeconds: normalizedTtl,
468
505
  leaseExpiresAt,
@@ -498,6 +535,7 @@ export async function heartbeatAssignment({
498
535
  await appendEvent(storage.eventsPath, {
499
536
  timestamp: normalizedNow,
500
537
  eventType: "heartbeat",
538
+ sessionId: next.sessionId,
501
539
  workItemId: normalizedWorkItemId,
502
540
  agentIdentity: normalizedAgentIdentity,
503
541
  stage: next.stage,
@@ -515,6 +553,7 @@ export async function heartbeatAssignment({
515
553
  export async function releaseAssignment({
516
554
  targetPath = ".",
517
555
  outputDir = "",
556
+ sessionId = "",
518
557
  workItemId,
519
558
  agentIdentity = "",
520
559
  status = "QUEUED",
@@ -534,6 +573,7 @@ export async function releaseAssignment({
534
573
  }
535
574
  const normalizedStatus = normalizeReleaseTargetStatus(status);
536
575
  const normalizedAgentIdentity = normalizeString(agentIdentity) || null;
576
+ const normalizedSessionId = normalizeSessionId(sessionId);
537
577
  const storage = await resolveAssignmentLedgerStorage({
538
578
  targetPath,
539
579
  outputDir,
@@ -547,6 +587,7 @@ export async function releaseAssignment({
547
587
  throw new Error(`No assignment exists for work item '${normalizedWorkItemId}'.`);
548
588
  }
549
589
  const existing = ledger.assignments[assignmentIndex];
590
+ assertSessionBinding(existing, normalizedSessionId, normalizedWorkItemId);
550
591
  if (
551
592
  normalizedAgentIdentity &&
552
593
  normalizeString(existing.assignedAgentIdentity) &&
@@ -560,6 +601,7 @@ export async function releaseAssignment({
560
601
  const next = normalizeAssignmentRecord(
561
602
  {
562
603
  ...existing,
604
+ sessionId: normalizedSessionId || normalizeSessionId(existing.sessionId),
563
605
  status: normalizedStatus,
564
606
  stage: normalizeString(stage) || existing.stage,
565
607
  runId: normalizeString(runId) || existing.runId,
@@ -594,6 +636,7 @@ export async function releaseAssignment({
594
636
  await appendEvent(storage.eventsPath, {
595
637
  timestamp: normalizedNow,
596
638
  eventType: "release",
639
+ sessionId: next.sessionId,
597
640
  workItemId: normalizedWorkItemId,
598
641
  agentIdentity: next.assignedAgentIdentity,
599
642
  status: normalizedStatus,
@@ -611,6 +654,7 @@ export async function releaseAssignment({
611
654
  export async function reassignAssignment({
612
655
  targetPath = ".",
613
656
  outputDir = "",
657
+ sessionId = "",
614
658
  workItemId,
615
659
  fromAgentIdentity = "",
616
660
  toAgentIdentity,
@@ -628,6 +672,7 @@ export async function reassignAssignment({
628
672
  if (!normalizedWorkItemId) {
629
673
  throw new Error("workItemId is required.");
630
674
  }
675
+ const normalizedSessionId = normalizeSessionId(sessionId);
631
676
  const normalizedToAgent = requireAgentIdentity(toAgentIdentity, "toAgentIdentity");
632
677
  const normalizedFromAgent = normalizeString(fromAgentIdentity) || null;
633
678
  const normalizedTtl = normalizePositiveInteger(leaseTtlSeconds, 1800);
@@ -644,6 +689,7 @@ export async function reassignAssignment({
644
689
  throw new Error(`No assignment exists for work item '${normalizedWorkItemId}'.`);
645
690
  }
646
691
  const existing = ledger.assignments[assignmentIndex];
692
+ assertSessionBinding(existing, normalizedSessionId, normalizedWorkItemId);
647
693
  if (
648
694
  normalizedFromAgent &&
649
695
  normalizeString(existing.assignedAgentIdentity) &&
@@ -658,6 +704,7 @@ export async function reassignAssignment({
658
704
  const next = normalizeAssignmentRecord(
659
705
  {
660
706
  ...existing,
707
+ sessionId: normalizedSessionId || normalizeSessionId(existing.sessionId),
661
708
  assignedAgentIdentity: normalizedToAgent,
662
709
  leasedAt: normalizedNow,
663
710
  leaseTtlSeconds: normalizedTtl,
@@ -697,6 +744,7 @@ export async function reassignAssignment({
697
744
  await appendEvent(storage.eventsPath, {
698
745
  timestamp: normalizedNow,
699
746
  eventType: "reassign",
747
+ sessionId: next.sessionId,
700
748
  workItemId: normalizedWorkItemId,
701
749
  fromAgentIdentity: existing.assignedAgentIdentity,
702
750
  toAgentIdentity: normalizedToAgent,
@@ -716,6 +764,7 @@ export async function reassignAssignment({
716
764
  export async function listAssignments({
717
765
  targetPath = ".",
718
766
  outputDir = "",
767
+ sessionId = "",
719
768
  statuses = [],
720
769
  agentIdentity = "",
721
770
  includeExpired = true,
@@ -727,6 +776,7 @@ export async function listAssignments({
727
776
  const normalizedNow = normalizeIsoTimestamp(nowIso, new Date().toISOString());
728
777
  const normalizedLimit = normalizePositiveInteger(limit, 50);
729
778
  const normalizedAgent = normalizeString(agentIdentity);
779
+ const normalizedSessionId = normalizeSessionId(sessionId);
730
780
  const statusFilter = parseStatusList(statuses);
731
781
  const storage = await resolveAssignmentLedgerStorage({
732
782
  targetPath,
@@ -750,6 +800,9 @@ export async function listAssignments({
750
800
  if (normalizedAgent && record.assignedAgentIdentity !== normalizedAgent) {
751
801
  return false;
752
802
  }
803
+ if (normalizedSessionId && record.sessionId !== normalizedSessionId) {
804
+ return false;
805
+ }
753
806
  if (!includeExpired && record.expired) {
754
807
  return false;
755
808
  }
@@ -768,3 +821,146 @@ export async function listAssignments({
768
821
  assignments: records.slice(0, normalizedLimit),
769
822
  };
770
823
  }
824
+
825
+ function normalizeLeaseTtlMs(value, fallbackValue = 1_800_000) {
826
+ return normalizePositiveInteger(value, fallbackValue);
827
+ }
828
+
829
+ export async function leaseWorkItem({
830
+ targetPath = ".",
831
+ outputDir = "",
832
+ sessionId,
833
+ workItemId,
834
+ agentIdentity,
835
+ leaseTtlMs = 1_800_000,
836
+ stage = "triage",
837
+ runId = "",
838
+ jiraIssueKey = "",
839
+ budgetSnapshot = {},
840
+ env,
841
+ homeDir,
842
+ nowIso = new Date().toISOString(),
843
+ } = {}) {
844
+ const normalizedSessionId = requireSessionId(sessionId);
845
+ const leaseTtlSeconds = Math.max(1, Math.ceil(normalizeLeaseTtlMs(leaseTtlMs) / 1000));
846
+ return claimAssignment({
847
+ targetPath,
848
+ outputDir,
849
+ sessionId: normalizedSessionId,
850
+ workItemId,
851
+ agentIdentity,
852
+ leaseTtlSeconds,
853
+ stage,
854
+ runId,
855
+ jiraIssueKey,
856
+ budgetSnapshot,
857
+ env,
858
+ homeDir,
859
+ nowIso,
860
+ });
861
+ }
862
+
863
+ export async function heartbeatLease({
864
+ targetPath = ".",
865
+ outputDir = "",
866
+ sessionId,
867
+ workItemId,
868
+ agentIdentity,
869
+ leaseTtlMs = 1_800_000,
870
+ stage = "",
871
+ runId = "",
872
+ jiraIssueKey = "",
873
+ budgetSnapshot = {},
874
+ env,
875
+ homeDir,
876
+ nowIso = new Date().toISOString(),
877
+ } = {}) {
878
+ const normalizedSessionId = requireSessionId(sessionId);
879
+ const leaseTtlSeconds = Math.max(1, Math.ceil(normalizeLeaseTtlMs(leaseTtlMs) / 1000));
880
+ return heartbeatAssignment({
881
+ targetPath,
882
+ outputDir,
883
+ sessionId: normalizedSessionId,
884
+ workItemId,
885
+ agentIdentity,
886
+ leaseTtlSeconds,
887
+ stage,
888
+ runId,
889
+ jiraIssueKey,
890
+ budgetSnapshot,
891
+ env,
892
+ homeDir,
893
+ nowIso,
894
+ });
895
+ }
896
+
897
+ export async function releaseLease({
898
+ targetPath = ".",
899
+ outputDir = "",
900
+ sessionId,
901
+ workItemId,
902
+ agentIdentity = "",
903
+ status = "QUEUED",
904
+ stage = "",
905
+ runId = "",
906
+ jiraIssueKey = "",
907
+ reason = "",
908
+ budgetSnapshot = {},
909
+ env,
910
+ homeDir,
911
+ nowIso = new Date().toISOString(),
912
+ } = {}) {
913
+ const normalizedSessionId = requireSessionId(sessionId);
914
+ return releaseAssignment({
915
+ targetPath,
916
+ outputDir,
917
+ sessionId: normalizedSessionId,
918
+ workItemId,
919
+ agentIdentity,
920
+ status,
921
+ stage,
922
+ runId,
923
+ jiraIssueKey,
924
+ reason,
925
+ budgetSnapshot,
926
+ env,
927
+ homeDir,
928
+ nowIso,
929
+ });
930
+ }
931
+
932
+ export async function reassignLease({
933
+ targetPath = ".",
934
+ outputDir = "",
935
+ sessionId,
936
+ workItemId,
937
+ from = "",
938
+ to,
939
+ leaseTtlMs = 1_800_000,
940
+ stage = "triage",
941
+ runId = "",
942
+ jiraIssueKey = "",
943
+ budgetSnapshot = {},
944
+ env,
945
+ homeDir,
946
+ nowIso = new Date().toISOString(),
947
+ } = {}) {
948
+ const normalizedSessionId = requireSessionId(sessionId);
949
+ const leaseTtlSeconds = Math.max(1, Math.ceil(normalizeLeaseTtlMs(leaseTtlMs) / 1000));
950
+ return reassignAssignment({
951
+ targetPath,
952
+ outputDir,
953
+ sessionId: normalizedSessionId,
954
+ workItemId,
955
+ fromAgentIdentity: from,
956
+ toAgentIdentity: to,
957
+ leaseTtlSeconds,
958
+ stage,
959
+ runId,
960
+ jiraIssueKey,
961
+ budgetSnapshot,
962
+ env,
963
+ homeDir,
964
+ nowIso,
965
+ });
966
+ }