@synkro-sh/cli 1.6.17 → 1.6.19

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
@@ -1641,6 +1641,10 @@ export function dispatchCapture(
1641
1641
  const body: Record<string, any> = {
1642
1642
  capture_type: 'local_verdict',
1643
1643
  event_id: eventId,
1644
+ // Source-time of the action. The ingest handler uses this for created_at
1645
+ // \u2014 without it, the spool drain stamps every event with NOW() and a batch
1646
+ // of actions taken minutes apart all collapse to the drain instant.
1647
+ _ts: new Date().toISOString(),
1644
1648
  hook_type: hookType,
1645
1649
  verdict: verdictStr,
1646
1650
  severity,
@@ -3172,13 +3176,14 @@ async function main() {
3172
3176
  if (!input.trim()) { outputEmpty(); return; }
3173
3177
 
3174
3178
  const payload = JSON.parse(input);
3175
- const toolName = payload.tool_name || '';
3176
- if (!isShellTool(toolName)) { outputEmpty(); return; }
3177
-
3178
3179
  const toolInput = payload.tool_input || {};
3179
3180
  const command = typeof payload.command === 'string' ? payload.command : (toolInput.command || '');
3180
3181
  if (!command) { outputEmpty(); return; }
3181
3182
 
3183
+ const toolName = payload.tool_name || '';
3184
+ // beforeShellExecution supplies command directly; preToolUse uses tool_name + tool_input.
3185
+ if (!isShellTool(toolName) && typeof payload.command !== 'string') { outputEmpty(); return; }
3186
+
3182
3187
  let jwt = loadJwt();
3183
3188
  if (!jwt) { outputEmpty(); return; }
3184
3189
  jwt = await ensureFreshJwt(jwt);
@@ -3220,9 +3225,10 @@ async function main() {
3220
3225
  command, reasoning: scan.blockContext.slice(0, 200),
3221
3226
  violatedRules: scan.violatedIds,
3222
3227
  });
3228
+ const denyReason = '[synkro:installScan] BLOCKED: ' + scan.summary + '\\nDo not retry this install. Suggest a safe version to the user instead.';
3223
3229
  outputJson({
3224
- systemMessage: '[synkro:installScan] ' + scan.summary,
3225
- hookSpecificOutput: { hookEventName: 'PreToolUse', additionalContext: '[synkro:installScan] ' + scan.summary },
3230
+ systemMessage: denyReason,
3231
+ hookSpecificOutput: { hookEventName: 'PreToolUse', permissionDecision: 'deny', permissionDecisionReason: denyReason, additionalContext: denyReason },
3226
3232
  });
3227
3233
  } else if (scan.action === 'warn') {
3228
3234
  outputJson({
@@ -3230,11 +3236,7 @@ async function main() {
3230
3236
  hookSpecificOutput: { hookEventName: 'PreToolUse', additionalContext: '[synkro:installScan] ' + scan.summary },
3231
3237
  });
3232
3238
  } else {
3233
- const label = scan.scannedLabel || command.slice(0, 80);
3234
- outputJson({
3235
- systemMessage: '[synkro:installScan] ' + label + ' \\u2192 clean',
3236
- hookSpecificOutput: { hookEventName: 'PreToolUse', additionalContext: '[synkro:installScan] ' + label + ' \\u2192 clean' },
3237
- });
3239
+ outputEmpty();
3238
3240
  }
3239
3241
  } catch (err) {
3240
3242
  process.stderr.write('[synkro] installScan error: ' + String(err) + '\\n');
@@ -6649,7 +6651,7 @@ function writeConfigEnv(opts) {
6649
6651
  `SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
6650
6652
  `SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
6651
6653
  `SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
6652
- `SYNKRO_VERSION=${shellQuoteSingle("1.6.17")}`
6654
+ `SYNKRO_VERSION=${shellQuoteSingle("1.6.19")}`
6653
6655
  ];
6654
6656
  if (safeSynkroBin) lines.push(`SYNKRO_CLI_BIN=${shellQuoteSingle(safeSynkroBin)}`);
6655
6657
  if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
@@ -6687,7 +6689,7 @@ function collectLocalMetadata() {
6687
6689
  } catch {
6688
6690
  }
6689
6691
  try {
6690
- const remote = execSync5("git remote get-url origin", { encoding: "utf-8", timeout: 3e3 }).trim();
6692
+ const remote = execSync5("git remote get-url origin", { encoding: "utf-8", timeout: 3e3, stdio: ["pipe", "pipe", "pipe"] }).trim();
6691
6693
  const sshMatch = remote.match(/^git@[^:]+:(.+?)(?:\.git)?$/);
6692
6694
  const httpMatch = remote.match(/^https?:\/\/[^/]+\/(.+?)(?:\.git)?$/);
6693
6695
  const m = sshMatch || httpMatch;
@@ -6780,7 +6782,7 @@ function assertGatewayAllowed(gatewayUrl) {
6780
6782
  async function installCommand(opts = {}) {
6781
6783
  if (!detectGitRepo2()) {
6782
6784
  console.error("Synkro must be installed inside a git repository.");
6783
- console.error(" `cd` into your project \u2014 a git repo with an `origin` remote \u2014 and re-run `synkro install`.");
6785
+ console.error(" `cd` into your project and re-run `synkro install`.");
6784
6786
  process.exit(1);
6785
6787
  }
6786
6788
  const gatewayUrl = opts.gatewayUrl || sanitizeGatewayCandidate(process.env.SYNKRO_GATEWAY_URL) || "https://api.synkro.sh";
@@ -9316,7 +9318,7 @@ var args = process.argv.slice(2);
9316
9318
  var cmd = args[0] || "";
9317
9319
  var subArgs = args.slice(1);
9318
9320
  function printVersion() {
9319
- console.log("1.6.17");
9321
+ console.log("1.6.19");
9320
9322
  }
9321
9323
  function printHelp2() {
9322
9324
  console.log(`Synkro CLI \u2014 runtime safety for AI coding agents