@synkro-sh/cli 1.6.44 → 1.6.45

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/dist/bootstrap.js CHANGED
@@ -350,13 +350,13 @@ function installCursorHooks(hooksJsonPath, config) {
350
350
  });
351
351
  h.beforeShellExecution.push({
352
352
  command: cursorCcCmd(config.cwePrecheckScriptPath),
353
- timeout: 60,
353
+ timeout: 30,
354
354
  failClosed: false,
355
355
  [SYNKRO_MARKER2]: true
356
356
  });
357
357
  h.beforeShellExecution.push({
358
358
  command: bunRunCmd(config.bashJudgeScriptPath),
359
- timeout: 15,
359
+ timeout: 30,
360
360
  failClosed: false,
361
361
  [SYNKRO_MARKER2]: true
362
362
  });
@@ -371,36 +371,36 @@ function installCursorHooks(hooksJsonPath, config) {
371
371
  });
372
372
  h.preToolUse.push({
373
373
  command: cursorCcCmd(config.cwePrecheckScriptPath),
374
- timeout: 60,
374
+ timeout: 30,
375
375
  failClosed: false,
376
376
  matcher: "Shell|Bash|terminal|run_terminal_cmd|execute_command",
377
377
  [SYNKRO_MARKER2]: true
378
378
  });
379
379
  h.preToolUse.push({
380
380
  command: bunRunCmd(config.bashJudgeScriptPath),
381
- timeout: 15,
381
+ timeout: 30,
382
382
  failClosed: false,
383
383
  matcher: "Shell|Bash|Read|ReadFile|Grep|Glob|terminal|run_terminal_cmd|execute_command|read_file|grep_search|file_search|list_dir|codebase_search|delete_file",
384
384
  [SYNKRO_MARKER2]: true
385
385
  });
386
386
  pushCcHook(h, "preToolUse", config.editPrecheckScriptPath, {
387
- timeout: 15,
387
+ timeout: 30,
388
388
  matcher: "Write|Edit|StrReplace|MultiEdit|NotebookEdit|edit_file|reapply|edit_notebook|ApplyPatch|apply_patch"
389
389
  });
390
390
  pushCcHook(h, "preToolUse", config.cwePrecheckScriptPath, {
391
- timeout: 60,
391
+ timeout: 30,
392
392
  matcher: "Write|Edit|StrReplace|MultiEdit|NotebookEdit|edit_file|reapply|edit_notebook|ApplyPatch|apply_patch"
393
393
  });
394
394
  pushCcHook(h, "preToolUse", config.cvePrecheckScriptPath, {
395
- timeout: 20,
395
+ timeout: 10,
396
396
  matcher: "Write|Edit|StrReplace|MultiEdit|NotebookEdit|edit_file|reapply|edit_notebook|ApplyPatch|apply_patch"
397
397
  });
398
398
  pushCcHook(h, "preToolUse", config.agentJudgeScriptPath, {
399
- timeout: 15,
399
+ timeout: 30,
400
400
  matcher: "Agent|Task"
401
401
  });
402
402
  pushCcHook(h, "preToolUse", config.planJudgeScriptPath, {
403
- timeout: 20,
403
+ timeout: 45,
404
404
  matcher: "ExitPlanMode|SwitchMode|CreatePlan"
405
405
  });
406
406
  h.afterFileEdit = h.afterFileEdit ?? [];
@@ -3218,6 +3218,7 @@ export function isCursorInvokingCcHook(agentKind: string, model: string): boolea
3218
3218
  }
3219
3219
 
3220
3220
  let cursorHookExited = false;
3221
+ let hookFinalized = false;
3221
3222
 
3222
3223
  export function setupCursorHookSignals(): void {
3223
3224
  if (!isCursorHookFormat()) return;
@@ -3226,9 +3227,28 @@ export function setupCursorHookSignals(): void {
3226
3227
 
3227
3228
  function cursorHookExit(): never {
3228
3229
  cursorHookExited = true;
3230
+ hookFinalized = true;
3229
3231
  process.exit(0);
3230
3232
  }
3231
3233
 
3234
+ // Self-imposed deadline. CC/Cursor kill the hook process at the configured hook
3235
+ // timeout with a signal; if a grade fetch is still in flight when that happens,
3236
+ // the runtime dumps the in-flight request body (the grader prompt) to stderr and
3237
+ // exits non-zero \u2014 surfacing as a "hook error" toast with leaked prompt text.
3238
+ // To prevent that, each grading hook arms this watchdog a few seconds UNDER its
3239
+ // configured budget: when it fires we emit a clean empty result and exit 0
3240
+ // ourselves, so the harness never has to kill us. The timer is unref'd, so a
3241
+ // hook that finishes early exits normally and the watchdog never runs.
3242
+ export function installHookWatchdog(budgetMs: number): void {
3243
+ const t = setTimeout(() => {
3244
+ if (hookFinalized) return;
3245
+ hookFinalized = true;
3246
+ try { process.stdout.write('{}\\n'); } catch {}
3247
+ process.exit(0);
3248
+ }, budgetMs);
3249
+ if (typeof (t as any).unref === 'function') (t as any).unref();
3250
+ }
3251
+
3232
3252
  // \u2500\u2500\u2500 Grader-unavailable diagnostic log \u2500\u2500\u2500
3233
3253
  // Records every time a hook tried to call the local grader and fell open
3234
3254
  // because the call failed. JSONL at ~/.synkro/grader-unavailable.log so the
@@ -3308,6 +3328,8 @@ export function outputJson(obj: any): void {
3308
3328
  outputEmpty();
3309
3329
  return;
3310
3330
  }
3331
+ if (hookFinalized) return;
3332
+ hookFinalized = true;
3311
3333
  console.log(JSON.stringify(obj));
3312
3334
  }
3313
3335
 
@@ -3319,6 +3341,8 @@ export function outputEmpty(): void {
3319
3341
  }
3320
3342
  cursorHookExit();
3321
3343
  }
3344
+ if (hookFinalized) return;
3345
+ hookFinalized = true;
3322
3346
  console.log('{}');
3323
3347
  }
3324
3348
  `;
@@ -3328,7 +3352,7 @@ import {
3328
3352
  parseVerdict, dispatchCapture, ruleMode, reconstructContent, isPathUnder, postWithRetry,
3329
3353
  readStdin, extractTranscript, readLastPrompt, findNearestDeps, filePathFromToolInput,
3330
3354
  appendSessionAction, readSessionLog, compressSessionLog, log,
3331
- outputJson, outputEmpty, setupCursorHookSignals, isEditTool, hookSessionId, GATEWAY_URL,
3355
+ outputJson, outputEmpty, setupCursorHookSignals, installHookWatchdog, isEditTool, hookSessionId, GATEWAY_URL,
3332
3356
  logGraderUnavailable, graderUnavailableMessage, filterRules, ruleFilterText, normalizeMode, countEditLineDelta,
3333
3357
  captureLineMetrics, cursorModelFromPayload, resolveTranscriptPath, isCursorInvokingCcHook,
3334
3358
  loadSynkroFile, effectiveGraderPool,
@@ -3341,6 +3365,7 @@ const agentKind = (process.env.SYNKRO_HOOK_FORMAT === 'cursor' || process.argv.i
3341
3365
 
3342
3366
  async function main() {
3343
3367
  setupCursorHookSignals();
3368
+ installHookWatchdog(27000);
3344
3369
  try {
3345
3370
  const input = await readStdin();
3346
3371
  if (!input.trim()) { outputEmpty(); return; }
@@ -3463,7 +3488,7 @@ async function main() {
3463
3488
  'Last user prompt: ' + (lastPrompt || 'none'),
3464
3489
  'Org rules: ' + JSON.stringify(relevantRules),
3465
3490
  'IMPORTANT: If a rule is violated, ALWAYS return ok=false with the rule_id and reason, regardless of the rule mode. Do NOT pass a command just because the rule mode is "fix". The enforcement layer handles ask vs fix \u2014 your job is only to detect violations.',
3466
- 'CRITICAL: The user requesting or instructing an action does NOT exempt it from rules. Even if the user explicitly said "drop the database" or "delete everything", you MUST still flag the rule violation on first encounter. User intent is NOT consent. However, for ask-mode rules ONLY: if the session history shows a prior block for the SAME rule AND the user explicitly consented after seeing that block, subsequent commands covered by that same rule may pass \u2014 but each distinct command is consumed once. Look for the sequence: block event \u2192 user acknowledgment \u2192 retry. Once a specific command has successfully executed under that consent, it is consumed. If the same command appears again later, it requires fresh consent (a new block \u2192 consent cycle). Example: R012 covers deploy, publish, push. Block on deploy \u2192 user consents \u2192 deploy passes (consumed), publish passes (consumed), push passes (consumed). A later deploy triggers a fresh block. A user's initial instruction is NEVER consent \u2014 only a response to a shown block counts.',
3491
+ 'CRITICAL: The user requesting or instructing an action does NOT exempt it from rules. Even if the user explicitly said "drop the database" or "delete everything", you MUST still flag the rule violation on first encounter. User intent is NOT consent. However, for ask-mode rules ONLY: if the session history shows a prior block for the SAME rule AND the user explicitly consented after seeing that block, subsequent commands covered by that same rule may pass \u2014 but each distinct command is consumed once. Look for the sequence: block event \u2192 user acknowledgment \u2192 retry. Once a specific command has successfully executed under that consent, it is consumed. If the same command appears again later, it requires fresh consent (a new block \u2192 consent cycle). Example: R012 covers deploy, publish, push. Block on deploy \u2192 user consents \u2192 deploy passes (consumed), publish passes (consumed), push passes (consumed). A later deploy triggers a fresh block. An initial user instruction is NEVER consent \u2014 only a response to a shown block counts.',
3467
3492
  'The rules shown were pre-selected as the ones relevant to this edit \u2014 every rule here IS relevant, do not label any "not relevant". When passing (ok=true), give a terse, specific reason each rule passes. Format: "R003: no hardcoded secrets in file. R005: in-repo path only." Cover every rule shown.',
3468
3493
  ].join('\\n');
3469
3494
 
@@ -3585,7 +3610,7 @@ main();
3585
3610
  import {
3586
3611
  loadJwt, ensureFreshJwt, detectRepo, loadConfig, cweRoute, tag,
3587
3612
  localGradeCwe, parseVerdict, reconstructContent, readStdin, log,
3588
- outputJson, outputEmpty, setupCursorHookSignals, isEditTool, isShellTool, isCursorHookFormat,
3613
+ outputJson, outputEmpty, setupCursorHookSignals, installHookWatchdog, isEditTool, isShellTool, isCursorHookFormat,
3589
3614
  extractShellCodeWrites, hookSessionId, filePathFromToolInput, emitBlockScanFindings, dispatchFinding, dispatchCapture, GATEWAY_URL,
3590
3615
  logGraderUnavailable, graderUnavailableMessage, resolveTranscriptPath, isCursorInvokingCcHook,
3591
3616
  loadSynkroFile, effectiveGraderPool,
@@ -3725,6 +3750,7 @@ function scanPackageCapabilities(pkgName: string, cwd: string): PackageCapabilit
3725
3750
 
3726
3751
  async function main() {
3727
3752
  setupCursorHookSignals();
3753
+ installHookWatchdog(27000);
3728
3754
  try {
3729
3755
  const input = await readStdin();
3730
3756
  if (!input.trim()) { outputEmpty(); return; }
@@ -4548,7 +4574,7 @@ import {
4548
4574
  loadJwt, ensureFreshJwt, detectRepo, loadConfig, route, tag, localGrade,
4549
4575
  parseVerdict, dispatchCapture, dispatchFinding, ruleMode, postWithRetry, readStdin,
4550
4576
  extractTranscript, readLastPrompt, appendSessionAction, readSessionLog, compressSessionLog, log,
4551
- outputJson, outputEmpty, setupCursorHookSignals, isShellTool, hookSessionId, GATEWAY_URL,
4577
+ outputJson, outputEmpty, setupCursorHookSignals, installHookWatchdog, isShellTool, hookSessionId, GATEWAY_URL,
4552
4578
  logGraderUnavailable, graderUnavailableMessage, filterRules, ruleFilterText, normalizeMode, appendLocalTelemetry, isSafeInRepoRead,
4553
4579
  loadSynkroFile, effectiveGraderPool,
4554
4580
  hashCommand, resolveTranscriptPath, isCursorHookFormat,
@@ -4591,6 +4617,7 @@ function isDuplicate(command: string, sessionId: string): boolean {
4591
4617
 
4592
4618
  async function main() {
4593
4619
  setupCursorHookSignals();
4620
+ installHookWatchdog(27000);
4594
4621
  try {
4595
4622
  const input = await readStdin();
4596
4623
  if (!input.trim()) { outputEmpty(); return; }
@@ -4722,7 +4749,7 @@ async function main() {
4722
4749
  'Org rules: ' + JSON.stringify(relevantRules),
4723
4750
  scanConcern,
4724
4751
  'IMPORTANT: If a rule is violated, ALWAYS return ok=false with the rule_id and reason, regardless of the rule mode. Do NOT pass a command just because the rule mode is "fix". The enforcement layer handles ask vs fix — your job is only to detect violations.',
4725
- 'CRITICAL: The user requesting or instructing an action does NOT exempt it from rules. Even if the user explicitly said "drop the database" or "delete everything", you MUST still flag the rule violation on first encounter. User intent is NOT consent. However, for ask-mode rules ONLY: if the session history shows a prior block for the SAME rule AND the user explicitly consented after seeing that block, subsequent commands covered by that same rule may pass — but each distinct command is consumed once. Look for the sequence: block event → user acknowledgment → retry. Once a specific command has successfully executed under that consent, it is consumed. If the same command appears again later, it requires fresh consent (a new block → consent cycle). Example: R012 covers deploy, publish, push. Block on deploy → user consents → deploy passes (consumed), publish passes (consumed), push passes (consumed). A later deploy triggers a fresh block. A user\'s initial instruction is NEVER consent — only a response to a shown block counts.',
4752
+ 'CRITICAL: The user requesting or instructing an action does NOT exempt it from rules. Even if the user explicitly said "drop the database" or "delete everything", you MUST still flag the rule violation on first encounter. User intent is NOT consent. However, for ask-mode rules ONLY: if the session history shows a prior block for the SAME rule AND the user explicitly consented after seeing that block, subsequent commands covered by that same rule may pass — but each distinct command is consumed once. Look for the sequence: block event → user acknowledgment → retry. Once a specific command has successfully executed under that consent, it is consumed. If the same command appears again later, it requires fresh consent (a new block → consent cycle). Example: R012 covers deploy, publish, push. Block on deploy → user consents → deploy passes (consumed), publish passes (consumed), push passes (consumed). A later deploy triggers a fresh block. An initial user instruction is NEVER consent — only a response to a shown block counts.',
4726
4753
  'The rules shown were pre-selected as the ones relevant to this command — every rule here IS relevant, do not label any "not relevant". When passing (ok=true), give a terse, specific reason each rule passes. Format: "R003: no secrets in grep args. R005: in-repo path only." Cover every rule shown.',
4727
4754
  'Rules with preconditions (e.g. "run X before Y") are CONSUMED after the protected action completes. Use the session history timestamps to determine ordering: a precondition satisfied before the last occurrence of the protected action does NOT satisfy the next occurrence. Each new protected action needs its precondition re-satisfied.',
4728
4755
  ].filter(Boolean).join('\\n');
@@ -4845,7 +4872,7 @@ import {
4845
4872
  loadJwt, ensureFreshJwt, detectRepo, loadConfig, route, tag, localGrade,
4846
4873
  parseVerdict, dispatchCapture, ruleMode, postWithRetry, readStdin,
4847
4874
  extractTranscript, readLastPrompt, appendSessionAction, readSessionLog, compressSessionLog, log,
4848
- outputJson, outputEmpty, setupCursorHookSignals, isAgentTool, hookSessionId, GATEWAY_URL,
4875
+ outputJson, outputEmpty, setupCursorHookSignals, installHookWatchdog, isAgentTool, hookSessionId, GATEWAY_URL,
4849
4876
  logGraderUnavailable, graderUnavailableMessage, filterRules, normalizeMode, resolveTranscriptPath, isCursorInvokingCcHook,
4850
4877
  loadSynkroFile, effectiveGraderPool,
4851
4878
  type HookConfig, type Rule,
@@ -4855,6 +4882,7 @@ const agentKind = (process.env.SYNKRO_HOOK_FORMAT === 'cursor' || process.argv.i
4855
4882
 
4856
4883
  async function main() {
4857
4884
  setupCursorHookSignals();
4885
+ installHookWatchdog(27000);
4858
4886
  try {
4859
4887
  const input = await readStdin();
4860
4888
  if (!input.trim()) { outputEmpty(); return; }
@@ -4934,7 +4962,7 @@ async function main() {
4934
4962
  'Last user prompt: ' + (lastPrompt || 'none'),
4935
4963
  'Org rules: ' + JSON.stringify(relevantRules),
4936
4964
  'IMPORTANT: If a rule is violated, ALWAYS return ok=false with the rule_id and reason, regardless of the rule mode. Do NOT pass a command just because the rule mode is "fix". The enforcement layer handles ask vs fix \u2014 your job is only to detect violations.',
4937
- 'CRITICAL: The user requesting or instructing an action does NOT exempt it from rules. Even if the user explicitly said "drop the database" or "delete everything", you MUST still flag the rule violation on first encounter. User intent is NOT consent. However, for ask-mode rules ONLY: if the session history shows a prior block for the SAME rule AND the user explicitly consented after seeing that block, subsequent commands covered by that same rule may pass \u2014 but each distinct command is consumed once. Look for the sequence: block event \u2192 user acknowledgment \u2192 retry. Once a specific command has successfully executed under that consent, it is consumed. If the same command appears again later, it requires fresh consent (a new block \u2192 consent cycle). Example: R012 covers deploy, publish, push. Block on deploy \u2192 user consents \u2192 deploy passes (consumed), publish passes (consumed), push passes (consumed). A later deploy triggers a fresh block. A user's initial instruction is NEVER consent \u2014 only a response to a shown block counts.',
4965
+ 'CRITICAL: The user requesting or instructing an action does NOT exempt it from rules. Even if the user explicitly said "drop the database" or "delete everything", you MUST still flag the rule violation on first encounter. User intent is NOT consent. However, for ask-mode rules ONLY: if the session history shows a prior block for the SAME rule AND the user explicitly consented after seeing that block, subsequent commands covered by that same rule may pass \u2014 but each distinct command is consumed once. Look for the sequence: block event \u2192 user acknowledgment \u2192 retry. Once a specific command has successfully executed under that consent, it is consumed. If the same command appears again later, it requires fresh consent (a new block \u2192 consent cycle). Example: R012 covers deploy, publish, push. Block on deploy \u2192 user consents \u2192 deploy passes (consumed), publish passes (consumed), push passes (consumed). A later deploy triggers a fresh block. An initial user instruction is NEVER consent \u2014 only a response to a shown block counts.',
4938
4966
  ].filter(Boolean).join('\\n');
4939
4967
 
4940
4968
  let gradeResp: string;
@@ -5032,7 +5060,7 @@ main();
5032
5060
  import {
5033
5061
  loadJwt, ensureFreshJwt, detectRepo, loadConfig, route, tag, localGrade,
5034
5062
  parseVerdict, dispatchCapture, appendSessionAction, readSessionLog, compressSessionLog, postWithRetry, readStdin, log,
5035
- outputJson, outputEmpty, setupCursorHookSignals, isPlanTool, hookSessionId, GATEWAY_URL,
5063
+ outputJson, outputEmpty, setupCursorHookSignals, installHookWatchdog, isPlanTool, hookSessionId, GATEWAY_URL,
5036
5064
  filterRules, graderUnavailableMessage, resolveTranscriptPath, isCursorInvokingCcHook,
5037
5065
  loadSynkroFile, effectiveGraderPool,
5038
5066
  } from './_synkro-common.ts';
@@ -5084,6 +5112,7 @@ function appendReviewToPlan(planFile: string, verdict: string): void {
5084
5112
 
5085
5113
  async function main() {
5086
5114
  setupCursorHookSignals();
5115
+ installHookWatchdog(42000);
5087
5116
  try {
5088
5117
  const input = await readStdin();
5089
5118
  if (!input.trim()) { outputEmpty(); return; }
@@ -5590,8 +5619,10 @@ function isDuplicate(command: string, sessionId: string): boolean {
5590
5619
  return false;
5591
5620
  }
5592
5621
 
5593
- // Cursor beforeShellExecution timeout is 15s; stay under it (JWT refresh + grade).
5594
- const CURSOR_GRADE_TIMEOUT_MS = 12000;
5622
+ // Cursor hook timeouts now match CC (30s for bash/edit/agent), so use the same
5623
+ // 24s internal grade budget as the CC path \u2014 stays under the 30s hook timeout
5624
+ // (JWT refresh + grade) and fails open cleanly via the caller's catch.
5625
+ const CURSOR_GRADE_TIMEOUT_MS = 24000;
5595
5626
  const CURSOR_CLOUD_TIMEOUT_MS = 9000;
5596
5627
 
5597
5628
  let hookDone = false;
@@ -5733,7 +5764,7 @@ async function main() {
5733
5764
  'Org rules: ' + JSON.stringify(relevantRules),
5734
5765
  scanConcern,
5735
5766
  'IMPORTANT: If a rule is violated, ALWAYS return ok=false with the rule_id and reason, regardless of the rule mode. Do NOT pass a command just because the rule mode is "fix". The enforcement layer handles ask vs fix \u2014 your job is only to detect violations.',
5736
- 'CRITICAL: The user requesting or instructing an action does NOT exempt it from rules. Even if the user explicitly said "drop the database" or "delete everything", you MUST still flag the rule violation on first encounter. User intent is NOT consent. However, for ask-mode rules ONLY: if the session history shows a prior block for the SAME rule AND the user explicitly consented after seeing that block, subsequent commands covered by that same rule may pass \u2014 but each distinct command is consumed once. Look for the sequence: block event \u2192 user acknowledgment \u2192 retry. Once a specific command has successfully executed under that consent, it is consumed. If the same command appears again later, it requires fresh consent (a new block \u2192 consent cycle). Example: R012 covers deploy, publish, push. Block on deploy \u2192 user consents \u2192 deploy passes (consumed), publish passes (consumed), push passes (consumed). A later deploy triggers a fresh block. A user's initial instruction is NEVER consent \u2014 only a response to a shown block counts.',
5767
+ 'CRITICAL: The user requesting or instructing an action does NOT exempt it from rules. Even if the user explicitly said "drop the database" or "delete everything", you MUST still flag the rule violation on first encounter. User intent is NOT consent. However, for ask-mode rules ONLY: if the session history shows a prior block for the SAME rule AND the user explicitly consented after seeing that block, subsequent commands covered by that same rule may pass \u2014 but each distinct command is consumed once. Look for the sequence: block event \u2192 user acknowledgment \u2192 retry. Once a specific command has successfully executed under that consent, it is consumed. If the same command appears again later, it requires fresh consent (a new block \u2192 consent cycle). Example: R012 covers deploy, publish, push. Block on deploy \u2192 user consents \u2192 deploy passes (consumed), publish passes (consumed), push passes (consumed). A later deploy triggers a fresh block. An initial user instruction is NEVER consent \u2014 only a response to a shown block counts.',
5737
5768
  'The rules shown were pre-selected as the ones relevant to this command \u2014 every rule here IS relevant, do not label any "not relevant". When passing (ok=true), give a terse, specific reason each rule passes. Format: "R003: no secrets in grep args. R005: in-repo path only." Cover every rule shown.',
5738
5769
  'Rules with preconditions (e.g. "run X before Y") are CONSUMED after the protected action completes. Use the session history timestamps to determine ordering: a precondition satisfied before the last occurrence of the protected action does NOT satisfy the next occurrence. Each new protected action needs its precondition re-satisfied.',
5739
5770
  ].filter(Boolean).join('\\n');
@@ -8270,7 +8301,7 @@ function writeConfigEnv(opts) {
8270
8301
  `SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
8271
8302
  `SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
8272
8303
  `SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
8273
- `SYNKRO_VERSION=${shellQuoteSingle("1.6.44")}`
8304
+ `SYNKRO_VERSION=${shellQuoteSingle("1.6.45")}`
8274
8305
  ];
8275
8306
  if (safeSynkroBin) lines.push(`SYNKRO_CLI_BIN=${shellQuoteSingle(safeSynkroBin)}`);
8276
8307
  if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
@@ -11355,7 +11386,7 @@ var args = process.argv.slice(2);
11355
11386
  var cmd = args[0] || "";
11356
11387
  var subArgs = args.slice(1);
11357
11388
  function printVersion() {
11358
- console.log("1.6.44");
11389
+ console.log("1.6.45");
11359
11390
  }
11360
11391
  function printHelp2() {
11361
11392
  console.log(`Synkro CLI \u2014 runtime safety for AI coding agents