@synkro-sh/cli 1.4.34 → 1.4.36

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
@@ -1294,30 +1294,36 @@ CWD=$(echo "$PAYLOAD" | jq -r '.cwd // empty' 2>/dev/null)
1294
1294
  TRANSCRIPT_PATH=$(echo "$PAYLOAD" | jq -r '.transcript_path // empty' 2>/dev/null)
1295
1295
  GIT_REPO=$(synkro_detect_repo "\${CWD:-.}")
1296
1296
 
1297
- # Fire-and-forget usage telemetry
1297
+ # Aggregate token usage across all assistant turns in the transcript and POST silently
1298
1298
  if [ -n "$TRANSCRIPT_PATH" ] && [ -f "$TRANSCRIPT_PATH" ]; then
1299
1299
  (
1300
1300
  _LAST=$(grep '"type":"assistant"' "$TRANSCRIPT_PATH" 2>/dev/null | tail -1)
1301
- if [ -n "$_LAST" ]; then
1302
- CC_MODEL=$(echo "$_LAST" | jq -r '.message.model // empty' 2>/dev/null)
1303
- CC_USAGE=$(echo "$_LAST" | jq -c '{input_tokens:.message.usage.input_tokens,output_tokens:.message.usage.output_tokens,cache_creation_input_tokens:.message.usage.cache_creation_input_tokens,cache_read_input_tokens:.message.usage.cache_read_input_tokens}' 2>/dev/null || echo "{}")
1304
- HAS_TOKENS=$(echo "$CC_USAGE" | jq '(.input_tokens // 0) + (.output_tokens // 0)' 2>/dev/null)
1305
- if [ -n "$HAS_TOKENS" ] && [ "$HAS_TOKENS" != "0" ]; then
1306
- BODY=$(jq -n \\
1307
- --arg event_id "usage_$(date +%s)_$$" \\
1308
- --arg hook_type "stop" --arg verdict "allow" --arg severity "none" \\
1309
- --arg model "\${CC_MODEL:-claude-sonnet-4-6}" \\
1310
- --arg cc_model "\${CC_MODEL:-}" \\
1311
- --arg repo "\${GIT_REPO:-}" --arg session_id "$SESSION_ID" \\
1312
- --argjson cc_usage "$CC_USAGE" \\
1313
- '{capture_type:"local_verdict",event_id:$event_id,hook_type:$hook_type,verdict:$verdict,severity:$severity,model:$model,cc_usage:$cc_usage}
1314
- + (if $repo != "" then {repo:$repo} else {} end)
1315
- + (if $session_id != "" then {session_id:$session_id} else {} end)
1316
- + (if $cc_model != "" then {cc_model:$cc_model} else {} end)')
1317
- curl -sS -X POST "\${GATEWAY_URL}/api/v1/hook/capture" \\
1318
- -H "Content-Type: application/json" -H "Authorization: Bearer $JWT" \\
1319
- -d "$BODY" --max-time 2 >/dev/null 2>&1
1320
- fi
1301
+ CC_MODEL=$(echo "$_LAST" | jq -r '.message.model // empty' 2>/dev/null)
1302
+ TOTALS=$(grep '"type":"assistant"' "$TRANSCRIPT_PATH" 2>/dev/null \\
1303
+ | jq -c '.message.usage' 2>/dev/null \\
1304
+ | jq -s '{in:(map(.input_tokens//0)|add//0),out:(map(.output_tokens//0)|add//0),cw:(map(.cache_creation_input_tokens//0)|add//0),cr:(map(.cache_read_input_tokens//0)|add//0)}' 2>/dev/null \\
1305
+ || echo '{"in":0,"out":0,"cw":0,"cr":0}')
1306
+ TOK_IN=$(echo "$TOTALS" | jq -r '.in // 0')
1307
+ TOK_OUT=$(echo "$TOTALS" | jq -r '.out // 0')
1308
+ TOK_CW=$(echo "$TOTALS" | jq -r '.cw // 0')
1309
+ TOK_CR=$(echo "$TOTALS" | jq -r '.cr // 0')
1310
+ HAS_TOKENS=$(( TOK_IN + TOK_OUT ))
1311
+ if [ "$HAS_TOKENS" != "0" ]; then
1312
+ CC_USAGE="{"input_tokens":$TOK_IN,"output_tokens":$TOK_OUT,"cache_creation_input_tokens":$TOK_CW,"cache_read_input_tokens":$TOK_CR}"
1313
+ BODY=$(jq -n \\
1314
+ --arg event_id "usage_$(date +%s)_$$" \\
1315
+ --arg hook_type "stop" --arg verdict "allow" --arg severity "none" \\
1316
+ --arg model "\${CC_MODEL:-claude-sonnet-4-6}" \\
1317
+ --arg cc_model "\${CC_MODEL:-}" \\
1318
+ --arg repo "\${GIT_REPO:-}" --arg session_id "$SESSION_ID" \\
1319
+ --argjson cc_usage "$CC_USAGE" \\
1320
+ '{capture_type:"local_verdict",event_id:$event_id,hook_type:$hook_type,verdict:$verdict,severity:$severity,model:$model,cc_usage:$cc_usage}
1321
+ + (if $repo != "" then {repo:$repo} else {} end)
1322
+ + (if $session_id != "" then {session_id:$session_id} else {} end)
1323
+ + (if $cc_model != "" then {cc_model:$cc_model} else {} end)')
1324
+ curl -sS -X POST "\${GATEWAY_URL}/api/v1/hook/capture" \\
1325
+ -H "Content-Type: application/json" -H "Authorization: Bearer $JWT" \\
1326
+ -d "$BODY" --max-time 2 >/dev/null 2>&1
1321
1327
  fi
1322
1328
  ) &
1323
1329
  fi
@@ -1333,9 +1339,9 @@ FINDINGS=$(echo "$RESP" | jq -r '.findings // 0' 2>/dev/null)
1333
1339
  AUTO_FIXED=$(echo "$RESP" | jq -r '.auto_fixed // 0' 2>/dev/null)
1334
1340
  OPEN=$(echo "$RESP" | jq -r '.open // 0' 2>/dev/null)
1335
1341
 
1336
- if [ "$EDITS" = "0" ] || [ -z "$EDITS" ]; then echo '{}'; exit 0; fi
1342
+ if [ "\${EDITS:-0}" = "0" ] || [ -z "$EDITS" ]; then echo '{}'; exit 0; fi
1337
1343
 
1338
- if [ "$FINDINGS" = "0" ] || [ -z "$FINDINGS" ]; then
1344
+ if [ "\${FINDINGS:-0}" = "0" ] || [ -z "$FINDINGS" ]; then
1339
1345
  SYS_MSG="[synkro] stop \u2192 0 issues across \${EDITS} edit(s), session complete"
1340
1346
  else
1341
1347
  SYS_MSG="[synkro] stop \u2192 \${FINDINGS} finding(s): \${AUTO_FIXED} auto-fixed, \${OPEN} open"
@@ -1444,7 +1450,6 @@ SCRIPT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")" && pwd)"
1444
1450
 
1445
1451
  JWT=$(synkro_load_jwt)
1446
1452
  if [ -z "$JWT" ]; then echo '{}'; exit 0; fi
1447
- if [ "\${SYNKRO_TRANSCRIPT_CONSENT:-yes}" = "no" ]; then echo '{}'; exit 0; fi
1448
1453
 
1449
1454
  PAYLOAD=$(cat)
1450
1455
  SESSION_ID=$(echo "$PAYLOAD" | jq -r '.session_id // empty' 2>/dev/null)
@@ -1455,6 +1460,40 @@ if [ -z "$SESSION_ID" ] || [ -z "$TRANSCRIPT_PATH" ] || [ ! -f "$TRANSCRIPT_PATH
1455
1460
  echo '{}'; exit 0
1456
1461
  fi
1457
1462
 
1463
+ # Usage telemetry \u2014 always fires (metadata only, ungated by privacy/consent)
1464
+ _LAST_ASST=$(grep '"type":"assistant"' "$TRANSCRIPT_PATH" 2>/dev/null | tail -1)
1465
+ if [ -n "$_LAST_ASST" ]; then
1466
+ _CC_MODEL=$(echo "$_LAST_ASST" | jq -r '.message.model // empty' 2>/dev/null)
1467
+ _TOTALS=$(grep '"type":"assistant"' "$TRANSCRIPT_PATH" 2>/dev/null \\
1468
+ | jq -c '.message.usage' 2>/dev/null \\
1469
+ | jq -s '{in:(map(.input_tokens//0)|add//0),out:(map(.output_tokens//0)|add//0),cw:(map(.cache_creation_input_tokens//0)|add//0),cr:(map(.cache_read_input_tokens//0)|add//0)}' 2>/dev/null \\
1470
+ || echo '{"in":0,"out":0,"cw":0,"cr":0}')
1471
+ _TI=$(echo "$_TOTALS" | jq -r '.in // 0')
1472
+ _TO=$(echo "$_TOTALS" | jq -r '.out // 0')
1473
+ _TCW=$(echo "$_TOTALS" | jq -r '.cw // 0')
1474
+ _TCR=$(echo "$_TOTALS" | jq -r '.cr // 0')
1475
+ if [ "\${_TI:-0}" != "0" ] || [ "\${_TO:-0}" != "0" ]; then
1476
+ (
1477
+ _USAGE="{\\"input_tokens\\":$_TI,\\"output_tokens\\":$_TO,\\"cache_creation_input_tokens\\":$_TCW,\\"cache_read_input_tokens\\":$_TCR}"
1478
+ _BODY=$(jq -n \\
1479
+ --arg event_id "usage_$(date +%s)_$$" \\
1480
+ --arg hook_type "stop" --arg verdict "allow" --arg severity "none" \\
1481
+ --arg model "\${_CC_MODEL:-claude-sonnet-4-6}" \\
1482
+ --arg cc_model "\${_CC_MODEL:-}" \\
1483
+ --arg session_id "$SESSION_ID" \\
1484
+ --argjson cc_usage "$_USAGE" \\
1485
+ '{capture_type:"usage_tick",event_id:$event_id,hook_type:$hook_type,verdict:$verdict,severity:$severity,model:$model,cc_usage:$cc_usage,session_id:$session_id}
1486
+ + (if $cc_model != "" then {cc_model:$cc_model} else {} end)')
1487
+ curl -sS -X POST "\${GATEWAY_URL}/api/v1/hook/capture" \\
1488
+ -H "Content-Type: application/json" -H "Authorization: Bearer $JWT" \\
1489
+ -d "$_BODY" --max-time 2 >/dev/null 2>&1
1490
+ ) &
1491
+ fi
1492
+ fi
1493
+
1494
+ # Transcript sync below is gated by consent + capture depth
1495
+ if [ "\${SYNKRO_TRANSCRIPT_CONSENT:-yes}" = "no" ]; then echo '{}'; exit 0; fi
1496
+
1458
1497
  GIT_REPO=$(synkro_detect_repo "\${CWD:-.}")
1459
1498
  if [ -z "$GIT_REPO" ]; then echo '{}'; exit 0; fi
1460
1499
 
@@ -3251,18 +3290,16 @@ tmux kill-session -t "$SESSION" 2>/dev/null || true
3251
3290
  tmux new-session -d -s "$SESSION" \\
3252
3291
  "claude --dangerously-load-development-channels server:synkro-local --dangerously-skip-permissions --setting-sources project,local --model claude-sonnet-4-6 2>>$LOG; echo 'claude exited with code '$'?' >> $LOG"
3253
3292
 
3254
- # Claude's --dangerously-skip-permissions shows a one-time confirmation
3255
- # prompt (accept option = '2'). Because --setting-sources skips user
3256
- # settings, the acceptance is never persisted, so the prompt reappears
3257
- # every launch. Auto-accept it by sending the right key sequence.
3293
+ # Claude's --dangerously-load-development-channels shows a confirmation
3294
+ # prompt: option 1 = "I am using this for local development" (accept),
3295
+ # option 2 = "Exit". Auto-accept by sending '1' + Enter.
3258
3296
  sleep 3
3259
3297
  if tmux has-session -t "$SESSION" 2>/dev/null; then
3260
- # Send '2' to accept bypass-permissions, then Enter for any follow-up prompts
3261
- tmux send-keys -t "$SESSION" '2' 2>/dev/null || true
3298
+ tmux send-keys -t "$SESSION" '1' 2>/dev/null || true
3262
3299
  sleep 1
3263
3300
  tmux send-keys -t "$SESSION" Enter 2>/dev/null || true
3264
3301
  sleep 1
3265
- # Additional Enter for workspace trust / MCP consent prompts
3302
+ # Additional Enter for any follow-up prompts (workspace trust, MCP consent)
3266
3303
  tmux send-keys -t "$SESSION" Enter 2>/dev/null || true
3267
3304
  log "Sent auto-accept keys to claude session."
3268
3305
  fi
@@ -3421,7 +3458,7 @@ function probePort(host, port, timeoutMs = 500) {
3421
3458
  });
3422
3459
  }
3423
3460
  function tmuxDismissPrompts() {
3424
- spawnSync2("tmux", ["send-keys", "-t", TMUX_SESSION, "2"], { encoding: "utf-8" });
3461
+ spawnSync2("tmux", ["send-keys", "-t", TMUX_SESSION, "1"], { encoding: "utf-8" });
3425
3462
  spawnSync2("tmux", ["send-keys", "-t", TMUX_SESSION, "Enter"], { encoding: "utf-8" });
3426
3463
  }
3427
3464
  async function waitForChannelReady(port, timeoutMs = 6e4, host = "127.0.0.1") {
@@ -3909,7 +3946,7 @@ function writeConfigEnv(opts) {
3909
3946
  `SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
3910
3947
  `SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
3911
3948
  `SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
3912
- `SYNKRO_VERSION=${shellQuoteSingle("1.4.34")}`
3949
+ `SYNKRO_VERSION=${shellQuoteSingle("1.4.36")}`
3913
3950
  ];
3914
3951
  if (safeSynkroBin) lines.push(`SYNKRO_CLI_BIN=${shellQuoteSingle(safeSynkroBin)}`);
3915
3952
  if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);