@synkro-sh/cli 1.6.9 → 1.6.10
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 +72 -39
- package/dist/bootstrap.js.map +1 -1
- package/package.json +1 -1
package/dist/bootstrap.js
CHANGED
|
@@ -3984,23 +3984,13 @@ async function main() {
|
|
|
3984
3984
|
}).catch(() => {});
|
|
3985
3985
|
}
|
|
3986
3986
|
|
|
3987
|
-
|
|
3988
|
-
|
|
3987
|
+
// Transcript consent gates only CLOUD transmission. Local persistence \u2014
|
|
3988
|
+
// this machine's own PGLite \u2014 is the same category as the local telemetry
|
|
3989
|
+
// already captured for every command, so it always runs.
|
|
3990
|
+
const cloudConsent = process.env.SYNKRO_TRANSCRIPT_CONSENT !== 'no';
|
|
3989
3991
|
const gitRepo = detectRepo(cwd);
|
|
3990
|
-
if (!gitRepo) { outputEmpty(); return; }
|
|
3991
|
-
|
|
3992
|
-
let captureDepth = 'local_only';
|
|
3993
|
-
try {
|
|
3994
|
-
const r = await fetch(GATEWAY_URL + '/api/v1/hook/config', {
|
|
3995
|
-
headers: { Authorization: 'Bearer ' + jwt },
|
|
3996
|
-
signal: AbortSignal.timeout(3000),
|
|
3997
|
-
});
|
|
3998
|
-
const data = await r.json() as any;
|
|
3999
|
-
captureDepth = data.capture_depth || 'local_only';
|
|
4000
|
-
} catch {}
|
|
4001
|
-
|
|
4002
|
-
if (captureDepth === 'local_only') { outputEmpty(); return; }
|
|
4003
3992
|
|
|
3993
|
+
// Offset-tracked extraction of new user/assistant turns from the transcript.
|
|
4004
3994
|
const offsetDir = join(homedir(), '.synkro', '.transcript-offsets');
|
|
4005
3995
|
mkdirSync(offsetDir, { recursive: true });
|
|
4006
3996
|
const offsetFile = join(offsetDir, sessionId);
|
|
@@ -4035,7 +4025,7 @@ async function main() {
|
|
|
4035
4025
|
}).join(' ').slice(0, 8000);
|
|
4036
4026
|
}
|
|
4037
4027
|
|
|
4038
|
-
const msg: any = { message_index: i, type: entry.type, content: text };
|
|
4028
|
+
const msg: any = { message_index: i, type: entry.type, content: text, ts: entry.timestamp || null };
|
|
4039
4029
|
if (entry.type === 'assistant') {
|
|
4040
4030
|
const toolCalls = (Array.isArray(content) ? content : [])
|
|
4041
4031
|
.filter((c: any) => c?.type === 'tool_use')
|
|
@@ -4053,16 +4043,39 @@ async function main() {
|
|
|
4053
4043
|
|
|
4054
4044
|
if (messages.length === 0) { outputEmpty(); return; }
|
|
4055
4045
|
|
|
4056
|
-
|
|
4057
|
-
|
|
4058
|
-
|
|
4059
|
-
}
|
|
4060
|
-
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
|
|
4064
|
-
|
|
4065
|
-
|
|
4046
|
+
// Local persist \u2014 always. The conversation timeline lives in PGLite.
|
|
4047
|
+
const mcpPort = process.env.SYNKRO_MCP_PORT || '18931';
|
|
4048
|
+
let mcpToken = '';
|
|
4049
|
+
try { mcpToken = readFileSync(join(homedir(), '.synkro', '.mcp-jwt'), 'utf-8').trim(); } catch {}
|
|
4050
|
+
if (mcpToken) {
|
|
4051
|
+
fetch('http://127.0.0.1:' + mcpPort + '/api/conversation-sync', {
|
|
4052
|
+
method: 'POST',
|
|
4053
|
+
headers: { 'Content-Type': 'application/json', Authorization: 'Bearer ' + mcpToken },
|
|
4054
|
+
body: JSON.stringify({ session_id: sessionId, repo: gitRepo || '', messages }),
|
|
4055
|
+
signal: AbortSignal.timeout(5000),
|
|
4056
|
+
}).catch(() => {});
|
|
4057
|
+
}
|
|
4058
|
+
|
|
4059
|
+
// Cloud sync \u2014 only when consented and the org isn't local-only.
|
|
4060
|
+
if (cloudConsent && gitRepo) {
|
|
4061
|
+
let captureDepth = 'local_only';
|
|
4062
|
+
try {
|
|
4063
|
+
const r = await fetch(GATEWAY_URL + '/api/v1/hook/config', {
|
|
4064
|
+
headers: { Authorization: 'Bearer ' + jwt },
|
|
4065
|
+
signal: AbortSignal.timeout(3000),
|
|
4066
|
+
});
|
|
4067
|
+
const data = await r.json() as any;
|
|
4068
|
+
captureDepth = data.capture_depth || 'local_only';
|
|
4069
|
+
} catch {}
|
|
4070
|
+
if (captureDepth !== 'local_only') {
|
|
4071
|
+
fetch(GATEWAY_URL + '/api/v1/cli/sync-transcripts', {
|
|
4072
|
+
method: 'POST',
|
|
4073
|
+
headers: { 'Content-Type': 'application/json', Authorization: 'Bearer ' + jwt },
|
|
4074
|
+
body: JSON.stringify({ repo: gitRepo, sessions: [{ cc_session_id: sessionId, messages }] }),
|
|
4075
|
+
signal: AbortSignal.timeout(10000),
|
|
4076
|
+
}).catch(() => {});
|
|
4077
|
+
}
|
|
4078
|
+
}
|
|
4066
4079
|
|
|
4067
4080
|
outputEmpty();
|
|
4068
4081
|
} catch {
|
|
@@ -6049,6 +6062,12 @@ async function dockerInstall(opts = {}) {
|
|
|
6049
6062
|
...process.env.SYNKRO_CURSOR_MODEL ? ["-e", `SYNKRO_CURSOR_MODEL=${process.env.SYNKRO_CURSOR_MODEL}`] : [],
|
|
6050
6063
|
// Connected repo — the server seeds the local app + ruleset named after it.
|
|
6051
6064
|
...opts.connectedRepo ? ["-e", `SYNKRO_CONNECTED_REPO=${opts.connectedRepo}`] : [],
|
|
6065
|
+
// Real account identity (from config.env via process.env) — telemetry is
|
|
6066
|
+
// stamped with these instead of a `local-user` placeholder, so the data is
|
|
6067
|
+
// correctly attributed from the first graded command.
|
|
6068
|
+
...process.env.SYNKRO_ORG_ID ? ["-e", `SYNKRO_ORG_ID=${process.env.SYNKRO_ORG_ID}`] : [],
|
|
6069
|
+
...process.env.SYNKRO_USER_ID ? ["-e", `SYNKRO_USER_ID=${process.env.SYNKRO_USER_ID}`] : [],
|
|
6070
|
+
...process.env.SYNKRO_EMAIL ? ["-e", `SYNKRO_EMAIL=${process.env.SYNKRO_EMAIL}`] : [],
|
|
6052
6071
|
image
|
|
6053
6072
|
];
|
|
6054
6073
|
const run = spawnSync2("docker", args2, { encoding: "utf-8", stdio: "inherit", timeout: 6e4 });
|
|
@@ -6271,6 +6290,7 @@ var init_dockerInstall = __esm({
|
|
|
6271
6290
|
// cli/commands/install.ts
|
|
6272
6291
|
var install_exports = {};
|
|
6273
6292
|
__export(install_exports, {
|
|
6293
|
+
detectGitRepo: () => detectGitRepo2,
|
|
6274
6294
|
installCommand: () => installCommand,
|
|
6275
6295
|
parseArgs: () => parseArgs
|
|
6276
6296
|
});
|
|
@@ -6459,7 +6479,7 @@ function writeConfigEnv(opts) {
|
|
|
6459
6479
|
`SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
|
|
6460
6480
|
`SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
|
|
6461
6481
|
`SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
|
|
6462
|
-
`SYNKRO_VERSION=${shellQuoteSingle("1.6.
|
|
6482
|
+
`SYNKRO_VERSION=${shellQuoteSingle("1.6.10")}`
|
|
6463
6483
|
];
|
|
6464
6484
|
if (safeSynkroBin) lines.push(`SYNKRO_CLI_BIN=${shellQuoteSingle(safeSynkroBin)}`);
|
|
6465
6485
|
if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
|
|
@@ -6586,6 +6606,11 @@ function assertGatewayAllowed(gatewayUrl) {
|
|
|
6586
6606
|
}
|
|
6587
6607
|
}
|
|
6588
6608
|
async function installCommand(opts = {}) {
|
|
6609
|
+
if (!detectGitRepo2()) {
|
|
6610
|
+
console.error("Synkro must be installed inside a git repository.");
|
|
6611
|
+
console.error(" `cd` into your project \u2014 a git repo with an `origin` remote \u2014 and re-run `synkro install`.");
|
|
6612
|
+
process.exit(1);
|
|
6613
|
+
}
|
|
6589
6614
|
const gatewayUrl = opts.gatewayUrl || sanitizeGatewayCandidate(process.env.SYNKRO_GATEWAY_URL) || "https://api.synkro.sh";
|
|
6590
6615
|
try {
|
|
6591
6616
|
assertGatewayAllowed(gatewayUrl);
|
|
@@ -6925,15 +6950,19 @@ async function installCommand(opts = {}) {
|
|
|
6925
6950
|
console.log("\u2713 Synkro installed.");
|
|
6926
6951
|
}
|
|
6927
6952
|
function detectGitRepo2() {
|
|
6928
|
-
|
|
6929
|
-
|
|
6930
|
-
|
|
6931
|
-
|
|
6932
|
-
|
|
6933
|
-
|
|
6934
|
-
}
|
|
6935
|
-
|
|
6953
|
+
const run = (cmd2) => {
|
|
6954
|
+
try {
|
|
6955
|
+
return execSync5(cmd2, { encoding: "utf-8", timeout: 5e3, stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
6956
|
+
} catch {
|
|
6957
|
+
return "";
|
|
6958
|
+
}
|
|
6959
|
+
};
|
|
6960
|
+
const remoteUrl = run("git remote get-url origin");
|
|
6961
|
+
if (remoteUrl) {
|
|
6962
|
+
return remoteUrl.replace(/^git@[^:]+:/, "").replace(/^https?:\/\/[^/]+\//, "").replace(/\.git$/, "");
|
|
6936
6963
|
}
|
|
6964
|
+
const root = run("git rev-parse --show-toplevel");
|
|
6965
|
+
return root ? root.split("/").pop() || null : null;
|
|
6937
6966
|
}
|
|
6938
6967
|
function getClaudeProjectsFolder() {
|
|
6939
6968
|
const cwd = process.cwd();
|
|
@@ -8861,6 +8890,9 @@ __export(lifecycle_exports, {
|
|
|
8861
8890
|
stopCommand: () => stopCommand,
|
|
8862
8891
|
updateCommand: () => updateCommand
|
|
8863
8892
|
});
|
|
8893
|
+
function resolveConnectedRepo() {
|
|
8894
|
+
return detectGitRepo2() ?? readContainerConfig()?.connectedRepo ?? void 0;
|
|
8895
|
+
}
|
|
8864
8896
|
async function stopCommand() {
|
|
8865
8897
|
assertDockerAvailable();
|
|
8866
8898
|
console.log("Synkro: stopping server\n");
|
|
@@ -8877,7 +8909,7 @@ async function startCommand(rest = []) {
|
|
|
8877
8909
|
if (cfg.explicit) {
|
|
8878
8910
|
console.log(`Synkro: starting server (${cfg.claudeWorkers} claude + ${cfg.cursorWorkers} cursor)
|
|
8879
8911
|
`);
|
|
8880
|
-
await dockerUpdate({ claudeWorkers: cfg.claudeWorkers, cursorWorkers: cfg.cursorWorkers });
|
|
8912
|
+
await dockerUpdate({ claudeWorkers: cfg.claudeWorkers, cursorWorkers: cfg.cursorWorkers, connectedRepo: resolveConnectedRepo() });
|
|
8881
8913
|
const ready = await waitForContainerReady(6e4);
|
|
8882
8914
|
if (!ready) {
|
|
8883
8915
|
console.error("\n\u26A0 container did not pass /healthz within 60s");
|
|
@@ -8907,7 +8939,7 @@ async function updateCommand() {
|
|
|
8907
8939
|
console.log("Synkro: updating to the latest container image");
|
|
8908
8940
|
console.log(` preserving pool: ${claudeWorkers} claude + ${cursorWorkers} cursor worker(s)
|
|
8909
8941
|
`);
|
|
8910
|
-
await dockerUpdate({ claudeWorkers, cursorWorkers, connectedRepo:
|
|
8942
|
+
await dockerUpdate({ claudeWorkers, cursorWorkers, connectedRepo: resolveConnectedRepo() });
|
|
8911
8943
|
const ready = await waitForContainerReady(9e4);
|
|
8912
8944
|
if (!ready) {
|
|
8913
8945
|
console.error("\n\u26A0 container did not pass its health check within 90s \u2014 check: docker logs synkro-server");
|
|
@@ -8921,7 +8953,7 @@ async function restartCommand(rest = []) {
|
|
|
8921
8953
|
if (cfg.explicit) {
|
|
8922
8954
|
console.log(`Synkro: restarting server (${cfg.claudeWorkers} claude + ${cfg.cursorWorkers} cursor)
|
|
8923
8955
|
`);
|
|
8924
|
-
await dockerUpdate({ claudeWorkers: cfg.claudeWorkers, cursorWorkers: cfg.cursorWorkers });
|
|
8956
|
+
await dockerUpdate({ claudeWorkers: cfg.claudeWorkers, cursorWorkers: cfg.cursorWorkers, connectedRepo: resolveConnectedRepo() });
|
|
8925
8957
|
const ready = await waitForContainerReady(6e4);
|
|
8926
8958
|
if (!ready) {
|
|
8927
8959
|
console.error("\n\u26A0 container did not pass /healthz within 60s");
|
|
@@ -8944,6 +8976,7 @@ var init_lifecycle = __esm({
|
|
|
8944
8976
|
"cli/commands/lifecycle.ts"() {
|
|
8945
8977
|
"use strict";
|
|
8946
8978
|
init_dockerInstall();
|
|
8979
|
+
init_install();
|
|
8947
8980
|
}
|
|
8948
8981
|
});
|
|
8949
8982
|
|
|
@@ -8971,7 +9004,7 @@ var args = process.argv.slice(2);
|
|
|
8971
9004
|
var cmd = args[0] || "";
|
|
8972
9005
|
var subArgs = args.slice(1);
|
|
8973
9006
|
function printVersion() {
|
|
8974
|
-
console.log("1.6.
|
|
9007
|
+
console.log("1.6.10");
|
|
8975
9008
|
}
|
|
8976
9009
|
function printHelp2() {
|
|
8977
9010
|
console.log(`Synkro CLI \u2014 runtime safety for AI coding agents
|