@synkro-sh/cli 1.6.13 → 1.6.14

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
@@ -1556,7 +1556,7 @@ export function parseVerdict(resp: string): Verdict {
1556
1556
  // Gated cloud telemetry POST \u2014 fires only when storage mode is 'cloud'. The
1557
1557
  // local PGLite spool (appendLocalTelemetry) always gets the data regardless,
1558
1558
  // so 'local' storage keeps everything on the machine.
1559
- function shipCloud(jwt: string, path: string, body: Record<string, any>, timeoutMs = 3000): void {
1559
+ export function shipCloud(jwt: string, path: string, body: Record<string, any>, timeoutMs = 3000): void {
1560
1560
  if ((process.env.SYNKRO_STORAGE_MODE || 'local') !== 'cloud') return;
1561
1561
  fetch(GATEWAY_URL + path, {
1562
1562
  method: 'POST',
@@ -1644,6 +1644,10 @@ const SPOOL_DRAIN_PREFIX = 'telemetry-spool.jsonl.draining.';
1644
1644
  // appendLocalTelemetry \u2014 durably records one telemetry event. The synchronous
1645
1645
  // append IS the durability guarantee; nothing here can drop the event.
1646
1646
  export function appendLocalTelemetry(body: Record<string, any>): void {
1647
+ // Cloud storage mode: the dashboard reads Timescale and a cloud-only setup
1648
+ // has no container to drain a local spool \u2014 so skip it. Cloud telemetry goes
1649
+ // via shipCloud; the local spool is only meaningful in local storage mode.
1650
+ if ((process.env.SYNKRO_STORAGE_MODE || 'local') !== 'local') return;
1647
1651
  const event = { ...body, _ts: new Date().toISOString() };
1648
1652
  try {
1649
1653
  appendFileSync(TELEMETRY_SPOOL, JSON.stringify(event) + '\\n');
@@ -3728,7 +3732,7 @@ main();
3728
3732
  STOP_SUMMARY_TS = `#!/usr/bin/env bun
3729
3733
  import {
3730
3734
  loadJwt, detectRepo, loadConfig, tag, readStdin, aggregateUsage, cleanupSessionLog,
3731
- outputJson, outputEmpty, appendLocalTelemetry, setupCursorHookSignals, hookSessionId, GATEWAY_URL,
3735
+ outputJson, outputEmpty, appendLocalTelemetry, shipCloud, setupCursorHookSignals, hookSessionId, GATEWAY_URL,
3732
3736
  } from './_synkro-common.ts';
3733
3737
 
3734
3738
  async function main() {
@@ -3880,7 +3884,7 @@ main();
3880
3884
  import {
3881
3885
  loadJwt, loadConfig, readStdin, hashCommand, consentGrant, consentHasActive, consentConsume,
3882
3886
  appendSessionAction,
3883
- outputEmpty, appendLocalTelemetry, setupCursorHookSignals, isShellTool, hookSessionId, GATEWAY_URL,
3887
+ outputEmpty, appendLocalTelemetry, shipCloud, setupCursorHookSignals, isShellTool, hookSessionId, GATEWAY_URL,
3884
3888
  } from './_synkro-common.ts';
3885
3889
 
3886
3890
  async function main() {
@@ -3943,7 +3947,7 @@ main();
3943
3947
  TRANSCRIPT_SYNC_TS = `#!/usr/bin/env bun
3944
3948
  import {
3945
3949
  loadJwt, detectRepo, readStdin, aggregateUsage, appendLocalTelemetry,
3946
- outputEmpty, setupCursorHookSignals, hookSessionId, GATEWAY_URL, readSessionLog,
3950
+ outputEmpty, setupCursorHookSignals, hookSessionId, GATEWAY_URL, readSessionLog, shipCloud,
3947
3951
  } from './_synkro-common.ts';
3948
3952
  import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
3949
3953
  import { join, dirname } from 'node:path';
@@ -4436,7 +4440,7 @@ main().catch((e) => {
4436
4440
  CURSOR_EDIT_CAPTURE_TS = `#!/usr/bin/env bun
4437
4441
  import {
4438
4442
  loadJwt, ensureFreshJwt, detectRepo, readStdin,
4439
- appendSessionAction, appendLocalTelemetry, log, GATEWAY_URL,
4443
+ appendSessionAction, appendLocalTelemetry, shipCloud, log, GATEWAY_URL,
4440
4444
  } from './_synkro-common.ts';
4441
4445
  import { existsSync, readFileSync } from 'node:fs';
4442
4446
  import { basename, dirname, join } from 'node:path';
@@ -6500,7 +6504,7 @@ function writeConfigEnv(opts) {
6500
6504
  `SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
6501
6505
  `SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
6502
6506
  `SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
6503
- `SYNKRO_VERSION=${shellQuoteSingle("1.6.13")}`
6507
+ `SYNKRO_VERSION=${shellQuoteSingle("1.6.14")}`
6504
6508
  ];
6505
6509
  if (safeSynkroBin) lines.push(`SYNKRO_CLI_BIN=${shellQuoteSingle(safeSynkroBin)}`);
6506
6510
  if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
@@ -9028,6 +9032,29 @@ function updateConfigValue(key, value) {
9028
9032
  if (!found) updated.splice(updated.length - 1, 0, `${key}='${value}'`);
9029
9033
  writeFileSync10(CONFIG_PATH5, updated.join("\n"), "utf-8");
9030
9034
  }
9035
+ async function reconcileContainer() {
9036
+ const cfg = readConfigEnv();
9037
+ const cloudOnly = (cfg.SYNKRO_GRADING_MODE || "local") === "byok" && (cfg.SYNKRO_STORAGE_MODE || "local") === "cloud";
9038
+ try {
9039
+ const { dockerInstall: dockerInstall2, dockerSafeStop: dockerSafeStop2, readContainerConfig: readContainerConfig2, assertDockerAvailable: assertDockerAvailable2, waitForContainerReady: waitForContainerReady2 } = await Promise.resolve().then(() => (init_dockerInstall(), dockerInstall_exports));
9040
+ const existing = readContainerConfig2();
9041
+ if (cloudOnly && existing) {
9042
+ console.log("Cloud-only mode \u2014 the local container is no longer needed; stopping it...");
9043
+ await dockerSafeStop2();
9044
+ console.log(" \u2713 container stopped (grading \u2192 BYOK, telemetry \u2192 cloud).");
9045
+ } else if (!cloudOnly && !existing) {
9046
+ assertDockerAvailable2();
9047
+ console.log("This mode needs the Synkro container \u2014 provisioning...");
9048
+ const { detectGitRepo: detectGitRepo3 } = await Promise.resolve().then(() => (init_install(), install_exports));
9049
+ await dockerInstall2({ claudeWorkers: 8, cursorWorkers: 0, connectedRepo: detectGitRepo3() ?? void 0 });
9050
+ const ready = await waitForContainerReady2(6e4);
9051
+ console.log(ready ? " \u2713 container running." : " \u26A0 container did not pass its health check \u2014 see `docker logs synkro-server`.");
9052
+ }
9053
+ } catch (err) {
9054
+ console.warn(` \u26A0 Container reconcile skipped: ${err.message}`);
9055
+ console.warn(" Run `synkro install` to (re)provision the container if needed.");
9056
+ }
9057
+ }
9031
9058
  async function configCommand(args2) {
9032
9059
  if (args2.length === 0) {
9033
9060
  const config2 = readConfigEnv();
@@ -9057,6 +9084,7 @@ To change:`);
9057
9084
  console.log(" BYOK grading uses your own provider key \u2014 register one in the");
9058
9085
  console.log(" dashboard under Settings \u2192 Provider Keys if you have not already.");
9059
9086
  }
9087
+ await reconcileContainer();
9060
9088
  return;
9061
9089
  }
9062
9090
  if (args2[0] === "storage") {
@@ -9067,6 +9095,7 @@ To change:`);
9067
9095
  }
9068
9096
  updateConfigValue("SYNKRO_STORAGE_MODE", value);
9069
9097
  console.log(`\u2713 Storage mode set to '${value}'.`);
9098
+ await reconcileContainer();
9070
9099
  return;
9071
9100
  }
9072
9101
  let inferenceValue;
@@ -9140,7 +9169,7 @@ var args = process.argv.slice(2);
9140
9169
  var cmd = args[0] || "";
9141
9170
  var subArgs = args.slice(1);
9142
9171
  function printVersion() {
9143
- console.log("1.6.13");
9172
+ console.log("1.6.14");
9144
9173
  }
9145
9174
  function printHelp2() {
9146
9175
  console.log(`Synkro CLI \u2014 runtime safety for AI coding agents