@synkro-sh/cli 1.7.37 → 1.7.38
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 +17 -55
- package/dist/bootstrap.js.map +1 -1
- package/package.json +1 -1
package/dist/bootstrap.js
CHANGED
|
@@ -839,34 +839,6 @@ function filePathFromToolInput(ti: any): string {
|
|
|
839
839
|
return ti.file_path || ti.notebook_path || ti.path || ti.target_file || '';
|
|
840
840
|
}
|
|
841
841
|
|
|
842
|
-
// Latest real human message from a CC transcript (JSONL). Scans from the end for a
|
|
843
|
-
// user turn, skipping sidechain (sub-agent) turns, meta entries, tool-result-only
|
|
844
|
-
// turns, and the synthetic local-command/caveat wrappers. Returns '' if none found.
|
|
845
|
-
function latestUserText(transcript: string): string {
|
|
846
|
-
const lines = transcript.split('\n');
|
|
847
|
-
for (let i = lines.length - 1; i >= 0; i--) {
|
|
848
|
-
const ln = lines[i].trim();
|
|
849
|
-
if (!ln) continue;
|
|
850
|
-
let o: any;
|
|
851
|
-
try { o = JSON.parse(ln); } catch { continue; }
|
|
852
|
-
if (o && (o.isSidechain || o.isMeta)) continue;
|
|
853
|
-
const m = o && o.message;
|
|
854
|
-
const role = (m && m.role) || (o && o.type);
|
|
855
|
-
if (role !== 'user') continue;
|
|
856
|
-
const c = m && m.content;
|
|
857
|
-
let text = '';
|
|
858
|
-
if (typeof c === 'string') text = c;
|
|
859
|
-
else if (Array.isArray(c)) {
|
|
860
|
-
text = c.filter((b: any) => b && b.type === 'text' && typeof b.text === 'string').map((b: any) => b.text).join(' ');
|
|
861
|
-
}
|
|
862
|
-
text = text.trim();
|
|
863
|
-
if (!text) continue;
|
|
864
|
-
if (text.startsWith('<local-command') || text.startsWith('<command-') || text.startsWith('Caveat:') || text.startsWith('<system-reminder')) continue;
|
|
865
|
-
return text;
|
|
866
|
-
}
|
|
867
|
-
return '';
|
|
868
|
-
}
|
|
869
|
-
|
|
870
842
|
interface StubOpts {
|
|
871
843
|
needsFile?: boolean;
|
|
872
844
|
needsTranscript?: boolean;
|
|
@@ -914,29 +886,6 @@ export async function runStub(surface: string, opts: StubOpts = {}): Promise<voi
|
|
|
914
886
|
// Gather host-only inputs the container can't read.
|
|
915
887
|
const envelope: any = { payload, harness, cwd: root || cwd, sessionId, synkroFileText };
|
|
916
888
|
|
|
917
|
-
// Sub-agent attribution (host-side — the container has no access to ~/.claude).
|
|
918
|
-
// A spawned sub-agent's tool-call hooks carry the ROOT session_id but a sidechain
|
|
919
|
-
// transcript at agent-<id>.jsonl (vs the main <session_id>.jsonl). Detect it from
|
|
920
|
-
// transcript_path, and read the ROOT transcript for the human turn that dispatched
|
|
921
|
-
// this (the sub-agent's own transcript starts with the task prompt, not the human).
|
|
922
|
-
try {
|
|
923
|
-
const tpath = typeof payload.transcript_path === 'string' ? payload.transcript_path : '';
|
|
924
|
-
const tbase = tpath.split('/').pop() || '';
|
|
925
|
-
const am = tbase.match(/^agent-(.+)\.jsonl$/);
|
|
926
|
-
if (am) {
|
|
927
|
-
envelope.isSubagent = true;
|
|
928
|
-
envelope.agentId = am[1];
|
|
929
|
-
try {
|
|
930
|
-
const dir = tpath.slice(0, tpath.length - tbase.length);
|
|
931
|
-
const rootPath = dir + sessionId + '.jsonl';
|
|
932
|
-
if (rootPath !== tpath && existsSync(rootPath)) {
|
|
933
|
-
const msg = latestUserText(readFileSync(rootPath, 'utf-8'));
|
|
934
|
-
if (msg) envelope.triggeringMessage = msg.slice(0, 2000);
|
|
935
|
-
}
|
|
936
|
-
} catch {}
|
|
937
|
-
}
|
|
938
|
-
} catch {}
|
|
939
|
-
|
|
940
889
|
if (opts.needsFile) {
|
|
941
890
|
const fp = filePathFromToolInput(payload.tool_input || {});
|
|
942
891
|
if (fp && existsSync(fp)) {
|
|
@@ -961,7 +910,12 @@ export async function runStub(surface: string, opts: StubOpts = {}): Promise<voi
|
|
|
961
910
|
// result (the server waits up to 30s for the completion grade), so it needs a
|
|
962
911
|
// wait above that budget — not the 6s telemetry default — or the stub abandons
|
|
963
912
|
// the request before the result lands and the completion shows up a hook late.
|
|
964
|
-
|
|
913
|
+
// prompt-submit is the opposite: it's INTERACTIVE (blocks the user's prompt from
|
|
914
|
+
// being sent) under a short 5s hook timeout, so it gets ONE short attempt (below)
|
|
915
|
+
// and a tight per-attempt budget that fits inside 5s — never the 6s×3 telemetry path.
|
|
916
|
+
const timeoutMs = surface === 'bash-followup' ? 32000
|
|
917
|
+
: surface === 'prompt-submit' ? 3500
|
|
918
|
+
: (opts.telemetry ? 6000 : 28000);
|
|
965
919
|
// Cloud has no local container to reach. Post the SAME envelope to the org's grader
|
|
966
920
|
// via the gateway's /grade/submit as role 'scan:<surface>'; the container runs
|
|
967
921
|
// scanRouter (runScan) server-side and returns the SAME shaped decision — so cloud
|
|
@@ -987,7 +941,11 @@ export async function runStub(surface: string, opts: StubOpts = {}): Promise<voi
|
|
|
987
941
|
// — the server side is idempotent-ish (completion in-flight guard, dup evidence
|
|
988
942
|
// is harmless). Blocking hooks make ONE attempt: their response IS the verdict
|
|
989
943
|
// and a retry would double-grade. Normal case: first attempt wins, no delay.
|
|
990
|
-
|
|
944
|
+
// prompt-submit is EXCLUDED from the retry: it runs on the interactive prompt
|
|
945
|
+
// path under a 5s hook timeout, and 3×6s+backoff (19.5s) blew that budget and
|
|
946
|
+
// fired "hook timed out after 5s" on every prompt whenever the server was slow.
|
|
947
|
+
// Dropping an occasional prompt tick is harmless; stalling the user is not.
|
|
948
|
+
const attempts = (opts.telemetry && surface !== 'prompt-submit') ? 3 : 1;
|
|
991
949
|
let text = '';
|
|
992
950
|
for (let i = 0; i < attempts; i++) {
|
|
993
951
|
try {
|
|
@@ -3815,6 +3773,10 @@ async function dockerInstall(opts = {}) {
|
|
|
3815
3773
|
// interactive AskUserQuestion poll and fall through to generate-the-fix. Only
|
|
3816
3774
|
// passed when the operator set it; otherwise the image default (1) applies.
|
|
3817
3775
|
...process.env.SYNKRO_FIX_POLL ? ["-e", `SYNKRO_FIX_POLL=${process.env.SYNKRO_FIX_POLL}`] : [],
|
|
3776
|
+
// Route CWE grades to the cloud /api/v1/cwe-scan endpoint (arm-C: full-catalog
|
|
3777
|
+
// retrieval + ensemble) instead of the local single-prompt path. Grading stays
|
|
3778
|
+
// local for every other surface. Benchmark lever; default off.
|
|
3779
|
+
...process.env.SYNKRO_CWE_VIA_ENDPOINT ? ["-e", `SYNKRO_CWE_VIA_ENDPOINT=${process.env.SYNKRO_CWE_VIA_ENDPOINT}`] : [],
|
|
3818
3780
|
// Connected repo — the server seeds the local app + ruleset named after it.
|
|
3819
3781
|
...opts.connectedRepo ? ["-e", `SYNKRO_CONNECTED_REPO=${opts.connectedRepo}`] : [],
|
|
3820
3782
|
// Real account identity (from config.env via process.env) — telemetry is
|
|
@@ -4829,7 +4791,7 @@ function writeConfigEnv(opts) {
|
|
|
4829
4791
|
`SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
|
|
4830
4792
|
`SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
|
|
4831
4793
|
`SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
|
|
4832
|
-
`SYNKRO_VERSION=${shellQuoteSingle("1.7.
|
|
4794
|
+
`SYNKRO_VERSION=${shellQuoteSingle("1.7.38")}`
|
|
4833
4795
|
];
|
|
4834
4796
|
if (safeSynkroBin) lines.push(`SYNKRO_CLI_BIN=${shellQuoteSingle(safeSynkroBin)}`);
|
|
4835
4797
|
if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
|
|
@@ -9027,7 +8989,7 @@ var args = process.argv.slice(2);
|
|
|
9027
8989
|
var cmd = args[0] || "";
|
|
9028
8990
|
var subArgs = args.slice(1);
|
|
9029
8991
|
function printVersion() {
|
|
9030
|
-
console.log("1.7.
|
|
8992
|
+
console.log("1.7.38");
|
|
9031
8993
|
}
|
|
9032
8994
|
function printHelp2() {
|
|
9033
8995
|
console.log(`Synkro CLI \u2014 runtime safety for AI coding agents
|