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
@@ -14,6 +14,10 @@ import {
14
14
  } from "../auth/service.js";
15
15
  import { resolveCredentialsFilePath } from "../auth/session-store.js";
16
16
  import { CLI_VERSION } from "../legacy-cli.js";
17
+ import { authLoginHint } from "../ui/command-hints.js";
18
+
19
+ const AUTH_DEBUG_ENV = "SENTINELAYER_DEBUG_ERRORS";
20
+ const AUTH_UNMASK_REQUEST_IDS_ENV = "SENTINELAYER_UNMASK_REQUEST_IDS";
17
21
 
18
22
  function shouldEmitJson(options, command) {
19
23
  const local = Boolean(options && options.json);
@@ -53,12 +57,39 @@ function formatApiError(error) {
53
57
  if (!(error instanceof SentinelayerApiError)) {
54
58
  return error instanceof Error ? error.message : String(error || "Unknown error");
55
59
  }
56
- const requestId = error.requestId ? ` request_id=${error.requestId}` : "";
60
+ const requestIdValue = error.requestId
61
+ ? (shouldExposeSensitiveAuthInfo() ? error.requestId : maskIdentifier(error.requestId))
62
+ : "";
63
+ const requestId = requestIdValue ? ` request_id=${requestIdValue}` : "";
57
64
  return `${error.message} [${error.code}] status=${error.status}${requestId}`;
58
65
  }
59
66
 
67
+ function shouldExposeSensitiveAuthInfo() {
68
+ const normalized = String(process.env[AUTH_DEBUG_ENV] || "").trim().toLowerCase();
69
+ const unmask = String(process.env[AUTH_UNMASK_REQUEST_IDS_ENV] || "").trim().toLowerCase();
70
+ const isTty = Boolean(process.stdout && process.stdout.isTTY);
71
+ const nodeEnv = String(process.env.NODE_ENV || "").trim().toLowerCase();
72
+ const isDev = nodeEnv === "development";
73
+ const debugEnabled = normalized === "true" || normalized === "1" || normalized === "yes";
74
+ const unmaskEnabled = unmask === "true" || unmask === "1" || unmask === "yes";
75
+ return debugEnabled && unmaskEnabled && isTty && isDev;
76
+ }
77
+
78
+ function shouldRevealTokenIdentifiers() {
79
+ return shouldExposeSensitiveAuthInfo();
80
+ }
81
+
82
+ function maskIdentifier(value) {
83
+ const raw = String(value || "").trim();
84
+ if (!raw) return "";
85
+ if (raw.length <= 6) {
86
+ return `${raw.slice(0, 2)}…`;
87
+ }
88
+ return `${raw.slice(0, 4)}…${raw.slice(-2)}`;
89
+ }
90
+
60
91
  function printAuthHint() {
61
- console.log(pc.gray("Run `sl auth login` to create a persistent CLI session."));
92
+ console.log(pc.gray(`Run \`${authLoginHint()}\` to create a persistent CLI session.`));
62
93
  }
63
94
 
64
95
  export function registerAuthCommand(program) {
@@ -192,10 +223,16 @@ export function registerAuthCommand(program) {
192
223
  const displayUser = status.remoteUser || status.user || {};
193
224
  console.log(pc.green(`Authenticated as ${renderUserSummary(displayUser)}`));
194
225
 
195
- if (status.aidenid && status.aidenid.orgId) {
196
- console.log(pc.green(`AIdenID: provisioned (org: ${status.aidenid.orgId}, project: ${status.aidenid.projectId || "unknown"})`));
197
- if (status.aidenid.apiKeyPrefix) {
198
- console.log(pc.gray(` API key prefix: ${status.aidenid.apiKeyPrefix}`));
226
+ if (status.aidenid && (status.aidenid.orgId || status.aidenid.projectId)) {
227
+ if (shouldExposeSensitiveAuthInfo()) {
228
+ const orgDisplay = status.aidenid.orgId ? maskIdentifier(status.aidenid.orgId) : "unknown";
229
+ const projectDisplay = status.aidenid.projectId ? maskIdentifier(status.aidenid.projectId) : "unknown";
230
+ console.log(pc.green(`AIdenID: provisioned (org: ${orgDisplay}, project: ${projectDisplay})`));
231
+ if (status.aidenid.apiKeyPrefix) {
232
+ console.log(pc.gray(` API key prefix: ${maskIdentifier(status.aidenid.apiKeyPrefix)}`));
233
+ }
234
+ } else {
235
+ console.log(pc.green("AIdenID: provisioned"));
199
236
  }
200
237
  } else {
201
238
  console.log(pc.gray("AIdenID: not provisioned (will provision on next login)"));
@@ -205,10 +242,15 @@ export function registerAuthCommand(program) {
205
242
 
206
243
  if (status.remoteError) {
207
244
  console.log(pc.red(`Remote validation failed: ${status.remoteError.message}`));
245
+ const requestIdValue = status.remoteError.requestId
246
+ ? (shouldExposeSensitiveAuthInfo()
247
+ ? status.remoteError.requestId
248
+ : maskIdentifier(status.remoteError.requestId))
249
+ : "";
208
250
  console.log(
209
251
  pc.gray(
210
252
  `Error code: ${status.remoteError.code} status=${status.remoteError.status}${
211
- status.remoteError.requestId ? ` request_id=${status.remoteError.requestId}` : ""
253
+ requestIdValue ? ` request_id=${requestIdValue}` : ""
212
254
  }`
213
255
  )
214
256
  );
@@ -260,7 +302,8 @@ export function registerAuthCommand(program) {
260
302
  `${renderUserSummary(session.user)} | source=${session.source} | storage=${session.storage || "unknown"}`
261
303
  );
262
304
  if (session.tokenId) {
263
- console.log(pc.gray(` token_id: ${session.tokenId}`));
305
+ const tokenDisplay = shouldRevealTokenIdentifiers() ? session.tokenId : maskIdentifier(session.tokenId);
306
+ console.log(pc.gray(` token_id: ${tokenDisplay}`));
264
307
  }
265
308
  if (session.tokenExpiresAt) {
266
309
  console.log(pc.gray(` expires_at: ${session.tokenExpiresAt}`));
@@ -303,7 +346,8 @@ export function registerAuthCommand(program) {
303
346
  return;
304
347
  }
305
348
 
306
- console.log(pc.green(`Revoked token: ${result.tokenId}`));
349
+ const tokenDisplay = shouldRevealTokenIdentifiers() ? result.tokenId : maskIdentifier(result.tokenId);
350
+ console.log(pc.green(`Revoked token: ${tokenDisplay}`));
307
351
  console.log(pc.gray(`API: ${result.apiUrl}`));
308
352
  if (result.matchedStoredSession) {
309
353
  console.log(
@@ -3,13 +3,21 @@ import { buildLegacyArgs } from "./legacy-args.js";
3
3
  export function registerOmarGateCommand(program, invokeLegacy) {
4
4
  const omargate = program
5
5
  .command("omargate")
6
- .description("Run local Omar Gate checks");
6
+ .description("Run local Omar Gate security analysis (deterministic + AI persona swarm)");
7
7
 
8
8
  omargate
9
9
  .command("deep")
10
- .description("Run local credential/policy scan")
10
+ .description("Run full Omar Gate deep scan with 22-rule deterministic + multi-persona AI analysis")
11
11
  .option("--path <path>", "Target repository path")
12
12
  .option("--output-dir <path>", "Artifact root for report output")
13
+ .option("--no-ai", "Skip AI review layer (deterministic only)")
14
+ .option("--ai-dry-run", "Run AI layer in dry-run mode (no LLM call)")
15
+ .option("--scan-mode <mode>", "Scan depth: baseline (1 persona), deep (6), full-depth (13)")
16
+ .option("--max-parallel <n>", "Max concurrent persona calls (default: 4)")
17
+ .option("--model <id>", "LLM model override (default: gpt-5.3-codex)")
18
+ .option("--provider <name>", "LLM provider: sentinelayer, openai, anthropic, google")
19
+ .option("--max-cost <usd>", "Maximum AI layer cost in USD (default: 5.0)")
20
+ .option("--stream", "Emit NDJSON events to stdout as personas run")
13
21
  .option("--json", "Emit machine-readable output")
14
22
  .action(async (options, command) => {
15
23
  const legacyArgs = buildLegacyArgs(["/omargate", "deep"], {
@@ -30,7 +30,8 @@ import {
30
30
  } from "../scan/generator.js";
31
31
  import { detectRepoSlug, setupSecrets } from "../scan/gh-secrets.js";
32
32
  import { appendRunEvent, deriveStopClassFromBudget } from "../telemetry/ledger.js";
33
- import { readStoredSession } from "../auth/session-store.js";
33
+ import { resolveActiveAuthSession } from "../auth/service.js";
34
+ import { authLoginHint } from "../ui/command-hints.js";
34
35
 
35
36
  const LEGACY_SCAN_WORKFLOW_PATH = ".github/workflows/security-review.yml";
36
37
 
@@ -832,16 +833,21 @@ export function registerScanCommand(program) {
832
833
 
833
834
  let tokenValue = "";
834
835
  try {
835
- const session = await readStoredSession();
836
+ const session = await resolveActiveAuthSession({
837
+ cwd: targetPath,
838
+ env: process.env,
839
+ autoRotate: false,
840
+ });
836
841
  if (session && session.token) {
837
842
  tokenValue = session.token;
838
843
  }
839
844
  } catch {
840
- /* no stored session */
845
+ /* no active auth session */
841
846
  }
842
847
 
843
848
  if (!tokenValue) {
844
- const msg = "No SentinelLayer token found. Run 'sl auth login' first, or use --dry-run for instructions.";
849
+ const msg =
850
+ `No SentinelLayer token found. Run '${authLoginHint()}', set SENTINELAYER_TOKEN, or use --dry-run for instructions.`;
845
851
  if (emitJson) {
846
852
  console.log(JSON.stringify({ command: "scan setup-secrets", ok: false, reason: msg }, null, 2));
847
853
  } else {