@synkro-sh/cli 1.10.10 → 1.10.11

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
@@ -147,7 +147,7 @@ function getIdentity() {
147
147
  if (cached2) return cached2;
148
148
  let cliVersion2 = "0.0.0";
149
149
  try {
150
- cliVersion2 = "1.10.10";
150
+ cliVersion2 = "1.10.11";
151
151
  } catch {
152
152
  }
153
153
  const creds = loadCredentialsIdentity();
@@ -7933,7 +7933,7 @@ var init_dockerInstall = __esm({
7933
7933
  HOST_PGLITE_PORT = parseInt(process.env.SYNKRO_HOST_PGLITE_PORT || "15433", 10);
7934
7934
  CONTAINER_NAME = resolveContainerName();
7935
7935
  defaultImageVersion = () => {
7936
- if (true) return "1.10.10";
7936
+ if (true) return "1.10.11";
7937
7937
  try {
7938
7938
  const pkg = JSON.parse(readFileSync17(new URL("../../package.json", import.meta.url), "utf8"));
7939
7939
  if (pkg.version) return pkg.version;
@@ -8993,7 +8993,7 @@ function writeConfigEnv(opts) {
8993
8993
  `SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle2(credsPath)}`,
8994
8994
  `SYNKRO_TIER=${shellQuoteSingle2(safeTier)}`,
8995
8995
  `SYNKRO_INFERENCE=${shellQuoteSingle2(safeInference)}`,
8996
- `SYNKRO_VERSION=${shellQuoteSingle2("1.10.10")}`
8996
+ `SYNKRO_VERSION=${shellQuoteSingle2("1.10.11")}`
8997
8997
  ];
8998
8998
  if (safeSynkroBin) lines2.push(`SYNKRO_CLI_BIN=${shellQuoteSingle2(safeSynkroBin)}`);
8999
8999
  if (safeUserId) lines2.push(`SYNKRO_USER_ID=${shellQuoteSingle2(safeUserId)}`);
@@ -9740,7 +9740,7 @@ async function installCommand(opts = {}) {
9740
9740
  await setTelemetryState({ enabled: true, remoteFlushEnabled: telemetryConsent });
9741
9741
  emit("install", {
9742
9742
  phase: "started",
9743
- cli_version_to: "1.10.10",
9743
+ cli_version_to: "1.10.11",
9744
9744
  agents_detected: agents.map((a) => a.kind),
9745
9745
  with_github: false,
9746
9746
  with_local_cc: false,
@@ -18317,6 +18317,7 @@ var init_screen = __esm({
18317
18317
  cwd;
18318
18318
  write;
18319
18319
  transcript = [];
18320
+ inlinePanel = [];
18320
18321
  draft = "";
18321
18322
  input = "";
18322
18323
  selectionAnchor = null;
@@ -18358,6 +18359,17 @@ var init_screen = __esm({
18358
18359
  this.selectionFocus = null;
18359
18360
  this.draw();
18360
18361
  }
18362
+ setInlinePanel(lines2) {
18363
+ this.inlinePanel = [...lines2];
18364
+ this.scrollOffset = 0;
18365
+ this.draw();
18366
+ }
18367
+ commitInlinePanel(lines2) {
18368
+ this.inlinePanel = [];
18369
+ this.transcript.push(...lines2);
18370
+ this.scrollOffset = 0;
18371
+ this.draw();
18372
+ }
18361
18373
  selectionRange() {
18362
18374
  if (this.selectionAnchor === null || this.selectionFocus === null || this.selectionAnchor === this.selectionFocus) return null;
18363
18375
  return [Math.min(this.selectionAnchor, this.selectionFocus), Math.max(this.selectionAnchor, this.selectionFocus)];
@@ -18466,7 +18478,7 @@ var init_screen = __esm({
18466
18478
  const status = this.status === "Ready" ? S2.secondary + " \xB7 Ready" + S2.reset : statusLine({ tick: this.tick, text: this.status, elapsedMs: Date.now() - this.statusSince, width });
18467
18479
  const rule = S2.border + " " + "\u2500".repeat(inner) + S2.reset;
18468
18480
  const inputRows = this.inputRows(width);
18469
- const composer = [rule, ...inputRows.map((row2, i) => S2.composer + (i ? " " : S2.user + " \u276F ") + this.selectedText(row2) + (i === inputRows.length - 1 ? S2.user + " \u258C" : "") + S2.reset), rule];
18481
+ const composer = this.inlinePanel.length ? [rule] : [rule, ...inputRows.map((row2, i) => S2.composer + (i ? " " : S2.user + " \u276F ") + this.selectedText(row2) + (i === inputRows.length - 1 ? S2.user + " \u258C" : "") + S2.reset), rule];
18470
18482
  const usedPercent = this.context ? Math.min(100, Math.round(this.used / this.context * 100)) : null;
18471
18483
  const contextUsage = usedPercent === null ? "\u2014 context" : usedPercent + "% context";
18472
18484
  const resetDate = this.weeklyResetsAt == null ? "" : " \xB7 " + resetDateFormat.format(new Date(this.weeklyResetsAt * 1e3));
@@ -18477,7 +18489,7 @@ var init_screen = __esm({
18477
18489
  const right = badge + S2.secondary + " \xB7 " + provider + (this.model ? " " + cleanOutput(this.model) : "") + " \xB7 \u29C9 powered by synkro " + S2.reset + S2.canvas;
18478
18490
  const footer = left + " ".repeat(Math.max(1, width - visible(left) - visible(right))) + right;
18479
18491
  const viewport = Math.max(3, height - composer.length - 2);
18480
- const fullContent = [...this.transcript, ...draft, status];
18492
+ const fullContent = [...this.transcript, ...draft, ...this.inlinePanel, status];
18481
18493
  const maxScroll = Math.max(0, fullContent.length - viewport);
18482
18494
  const effectiveOffset = Math.min(this.scrollOffset, maxScroll);
18483
18495
  const end = fullContent.length - effectiveOffset;
@@ -18566,17 +18578,22 @@ async function loadFixPoll(itemId, fetchImpl = fetch) {
18566
18578
  recommendedIdx
18567
18579
  };
18568
18580
  }
18569
- async function recordFixPoll(itemId, chosenIdx, fetchImpl = fetch) {
18581
+ async function recordFixPoll(itemId, selection, fetchImpl = fetch) {
18570
18582
  const response = await fetchImpl(pollBaseUrl() + "/record", {
18571
18583
  method: "POST",
18572
18584
  headers: { "content-type": "application/json" },
18573
- body: JSON.stringify({ item_id: itemId, chosen_idx: chosenIdx })
18585
+ body: JSON.stringify({
18586
+ item_id: itemId,
18587
+ chosen_idx: selection.chosenIdx,
18588
+ custom_response: selection.customResponse || void 0
18589
+ })
18574
18590
  });
18575
18591
  return response.ok;
18576
18592
  }
18577
- function fixPollLines(poll, selected, width = 100) {
18593
+ function fixPollLines(poll, selected, width = 100, customResponse = "", editingCustom = false) {
18578
18594
  const max = Math.max(32, width - 10);
18579
- const choices = [...poll.candidates, "None of the above"];
18595
+ const choices = [...poll.candidates, CUSTOM_CHOICE, NONE_CHOICE];
18596
+ const customIndex = poll.candidates.length;
18580
18597
  const scope = [poll.ruleId, poll.filePath].filter(Boolean).join(" \xB7 ");
18581
18598
  const lines2 = [
18582
18599
  "",
@@ -18590,40 +18607,101 @@ function fixPollLines(poll, selected, width = 100) {
18590
18607
  const text = wrap(index + 1 + ". " + recommendation + neutralizeTerminalControls(choice), max);
18591
18608
  lines2.push(prefix + (text[0] || "") + S2.reset);
18592
18609
  for (const continuation of text.slice(1)) lines2.push(" " + continuation);
18610
+ if (index === customIndex && editingCustom) {
18611
+ const answer = neutralizeTerminalControls(customResponse);
18612
+ const answerLines = wrap("Your answer: " + answer + "\u258C", max - 2);
18613
+ for (const answerLine of answerLines) lines2.push(S2.user + " " + answerLine + S2.reset);
18614
+ }
18593
18615
  });
18594
- lines2.push("", S2.dim + " \u2191/\u2193 select \xB7 Enter confirm \xB7 1-" + choices.length + " choose" + S2.reset);
18616
+ const footer = editingCustom ? " Type your answer \xB7 Enter submit \xB7 Esc back" : " \u2191/\u2193 select \xB7 Enter confirm \xB7 " + (choices.length === 10 ? "1-9/0" : "1-" + choices.length) + " choose";
18617
+ lines2.push("", S2.dim + footer + S2.reset);
18618
+ return lines2;
18619
+ }
18620
+ function fixPollResultLines(poll, selection, recorded, width = 100) {
18621
+ const max = Math.max(32, width - 14);
18622
+ const scope = [poll.ruleId, poll.filePath].filter(Boolean).join(" \xB7 ");
18623
+ const selected = selection.customResponse ? "Custom answer: " + selection.customResponse : selection.chosenIdx >= 0 && selection.chosenIdx < poll.candidates.length ? "Selected: " + poll.candidates[selection.chosenIdx] : "Selected: " + NONE_CHOICE;
18624
+ const lines2 = [
18625
+ "",
18626
+ (recorded ? S2.ok : S2.blocked) + S2.bold + " " + (recorded ? "Synkro decision recorded" : "Synkro decision was not recorded") + S2.reset,
18627
+ ...scope ? [S2.dim + " " + neutralizeTerminalControls(scope) + S2.reset] : []
18628
+ ];
18629
+ const answer = wrap(neutralizeTerminalControls(selected), max);
18630
+ answer.forEach((line, index) => lines2.push((index ? " " : S2.user + " \u23BF ") + line + S2.reset));
18595
18631
  return lines2;
18596
18632
  }
18597
18633
  async function pickFixPoll(poll, io = {}) {
18598
18634
  const input = io.input || process.stdin;
18599
18635
  const output = io.output || process.stdout;
18600
- if (!input.isTTY || !output.isTTY) return -1;
18636
+ if (!input.isTTY || !output.isTTY) return { chosenIdx: -1, customResponse: "" };
18637
+ const customIndex = poll.candidates.length;
18638
+ const noneIndex = customIndex + 1;
18639
+ const choices = poll.candidates.length + 2;
18601
18640
  let selected = poll.recommendedIdx >= 0 && poll.recommendedIdx < poll.candidates.length ? poll.recommendedIdx : 0;
18641
+ let customResponse = "";
18642
+ let editingCustom = false;
18602
18643
  let rendered = 0;
18603
18644
  const draw = () => {
18604
- if (rendered) output.write("\x1B[" + rendered + "A\x1B[J");
18605
- const lines2 = fixPollLines(poll, selected, Number(output.columns || 100));
18606
- output.write(lines2.join("\n") + "\n");
18607
- rendered = lines2.length;
18645
+ const lines2 = fixPollLines(
18646
+ poll,
18647
+ selected,
18648
+ Number(output.columns || 100),
18649
+ customResponse,
18650
+ editingCustom
18651
+ );
18652
+ if (io.render) io.render(lines2);
18653
+ else {
18654
+ if (rendered) output.write("\x1B[" + rendered + "A\x1B[J");
18655
+ output.write(lines2.join("\n") + "\n");
18656
+ rendered = lines2.length;
18657
+ }
18608
18658
  };
18609
- const choice = await new Promise((resolve9) => {
18610
- const choices = poll.candidates.length + 1;
18659
+ return new Promise((resolve9) => {
18611
18660
  const wasRaw = Boolean(input.isRaw);
18612
- const done = (index) => {
18661
+ const done = (selection) => {
18613
18662
  input.off("data", onData);
18614
18663
  if (input.setRawMode) input.setRawMode(wasRaw);
18615
- resolve9(index === poll.candidates.length ? -1 : index);
18664
+ resolve9(selection);
18665
+ };
18666
+ const confirmSelection = () => {
18667
+ if (selected < customIndex) return done({ chosenIdx: selected, customResponse: "" });
18668
+ if (selected === noneIndex) return done({ chosenIdx: -1, customResponse: "" });
18669
+ editingCustom = true;
18670
+ draw();
18616
18671
  };
18617
18672
  const onData = (chunk) => {
18618
18673
  const key2 = chunk.toString("utf8");
18619
- if (key2 === "") return done(poll.candidates.length);
18620
- if (key2 === "\x1B" || key2.toLowerCase() === "n") return done(poll.candidates.length);
18621
- if (key2 === "\r" || key2 === "\n") return done(selected);
18674
+ if (editingCustom) {
18675
+ if (key2 === "") return done({ chosenIdx: -1, customResponse: "" });
18676
+ if (key2 === "\x1B") {
18677
+ editingCustom = false;
18678
+ draw();
18679
+ return;
18680
+ }
18681
+ const typed = key2.replace(/\u001b\[[0-9;?]*[ -/]*[@-~]/g, "");
18682
+ for (const char of typed) {
18683
+ if (char === "\r" || char === "\n") {
18684
+ const answer = customResponse.trim();
18685
+ if (answer) return done({ chosenIdx: -2, customResponse: answer });
18686
+ } else if (char === "\x7F" || char === "\b") customResponse = customResponse.slice(0, -1);
18687
+ else if (char === "") customResponse = "";
18688
+ else if (char === "") customResponse = customResponse.replace(/\s*\S+\s*$/, "");
18689
+ else if (char >= " " && customResponse.length < MAX_CUSTOM_RESPONSE) customResponse += char;
18690
+ }
18691
+ draw();
18692
+ return;
18693
+ }
18694
+ if (key2 === "") return done({ chosenIdx: -1, customResponse: "" });
18695
+ if (key2 === "\x1B" || key2.toLowerCase() === "n") return done({ chosenIdx: -1, customResponse: "" });
18696
+ if (key2 === "\r" || key2 === "\n") return confirmSelection();
18622
18697
  if (key2 === "\x1B[A" || key2 === "k") selected = (selected - 1 + choices) % choices;
18623
18698
  else if (key2 === "\x1B[B" || key2 === "j") selected = (selected + 1) % choices;
18624
- else if (/^[1-9]$/.test(key2)) {
18625
- const index = Number(key2) - 1;
18626
- if (index < choices) return done(index);
18699
+ else if (/^[0-9]$/.test(key2)) {
18700
+ const index = key2 === "0" ? 9 : Number(key2) - 1;
18701
+ if (index < choices) {
18702
+ selected = index;
18703
+ return confirmSelection();
18704
+ }
18627
18705
  } else return;
18628
18706
  draw();
18629
18707
  };
@@ -18632,7 +18710,6 @@ async function pickFixPoll(poll, io = {}) {
18632
18710
  input.on("data", onData);
18633
18711
  draw();
18634
18712
  });
18635
- return choice;
18636
18713
  }
18637
18714
  async function resolveFixPolls(events, io = {}) {
18638
18715
  const ids = Array.from(new Set(events.filter((event) => event.type === "tool-end").flatMap((event) => event.pollIds?.length ? event.pollIds : [event.pollId || ""]).filter(Boolean)));
@@ -18640,17 +18717,23 @@ async function resolveFixPolls(events, io = {}) {
18640
18717
  for (const itemId of ids) {
18641
18718
  const poll = await loadFixPoll(itemId, io.fetchImpl).catch(() => null);
18642
18719
  if (!poll) continue;
18643
- const chosen = await pickFixPoll(poll, io);
18644
- const ok = await recordFixPoll(itemId, chosen, io.fetchImpl).catch(() => false);
18645
- if (ok) recorded.push(chosen);
18646
- else (io.output || process.stdout).write(S2.blocked + " Could not record that Synkro decision.\n" + S2.reset);
18720
+ const selection = await pickFixPoll(poll, io);
18721
+ const ok = await recordFixPoll(itemId, selection, io.fetchImpl).catch(() => false);
18722
+ const result = fixPollResultLines(poll, selection, ok, Number((io.output || process.stdout).columns || 100));
18723
+ if (io.commit) io.commit(result);
18724
+ else (io.output || process.stdout).write(result.join("\n") + "\n");
18725
+ if (ok) recorded.push(selection.chosenIdx);
18647
18726
  }
18648
18727
  return recorded;
18649
18728
  }
18729
+ var CUSTOM_CHOICE, NONE_CHOICE, MAX_CUSTOM_RESPONSE;
18650
18730
  var init_fixPoll = __esm({
18651
18731
  "cli/harness/fixPoll.ts"() {
18652
18732
  "use strict";
18653
18733
  init_render2();
18734
+ CUSTOM_CHOICE = "Write my own answer";
18735
+ NONE_CHOICE = "None of the above";
18736
+ MAX_CUSTOM_RESPONSE = 4e3;
18654
18737
  }
18655
18738
  });
18656
18739
 
@@ -18659,6 +18742,12 @@ function deleteSelectedText(value, range) {
18659
18742
  if (!range) return value.slice(0, -1);
18660
18743
  return value.slice(0, range[0]) + value.slice(range[1]);
18661
18744
  }
18745
+ function idlePromptControl(data, hasSelection) {
18746
+ if (data === "\x1B") return hasSelection ? "delete-selection" : "ignore";
18747
+ if (data.includes("")) return "clear";
18748
+ if (data.includes("")) return "exit";
18749
+ return null;
18750
+ }
18662
18751
  function handleScrollInput(screen, data) {
18663
18752
  let handled = false;
18664
18753
  const mousePattern = /\x1b\[<(\d+);\d+;\d+[Mm]/g;
@@ -18739,19 +18828,24 @@ function readPrompt(screen) {
18739
18828
  screen.setInput(value);
18740
18829
  return;
18741
18830
  }
18742
- if (data === "\x1B") {
18743
- if (selection) {
18744
- value = deleteSelectedText(value, selection);
18745
- screen.setInput(value);
18746
- } else finish(null);
18831
+ const control = idlePromptControl(data, Boolean(selection));
18832
+ if (control === "delete-selection") {
18833
+ value = deleteSelectedText(value, selection);
18834
+ screen.setInput(value);
18835
+ return;
18836
+ }
18837
+ if (control === "clear") {
18838
+ value = "";
18839
+ screen.setInput(value);
18840
+ return;
18841
+ }
18842
+ if (control === "exit") {
18843
+ finish(null);
18747
18844
  return;
18748
18845
  }
18846
+ if (control === "ignore") return;
18749
18847
  if (data.startsWith("\x1B")) return;
18750
18848
  for (const char of data) {
18751
- if (char === "" || char === "") {
18752
- finish(null);
18753
- return;
18754
- }
18755
18849
  if (char === "\r" || char === "\n") {
18756
18850
  finish(value);
18757
18851
  return;
@@ -18789,12 +18883,11 @@ async function cancellable(screen, run2) {
18789
18883
  }
18790
18884
  async function resolveScreenFixPolls(screen, events) {
18791
18885
  if (!events.some((event) => event.type === "tool-end" && Boolean(event.pollId))) return;
18792
- screen.leave();
18793
- try {
18794
- await resolveFixPolls(events);
18795
- } finally {
18796
- screen.enter();
18797
- }
18886
+ screen.setStatus("Decision required");
18887
+ await resolveFixPolls(events, {
18888
+ render: (lines2) => screen.setInlinePanel(lines2),
18889
+ commit: (lines2) => screen.commitInlinePanel(lines2)
18890
+ });
18798
18891
  }
18799
18892
  async function runSynkroSession(harness, cwd, prompt) {
18800
18893
  if (prompt) return runOnce(harness, cwd, prompt);
@@ -20169,7 +20262,7 @@ function pseudonymousHostnameHash(installationId, host) {
20169
20262
  }
20170
20263
  function cliVersion() {
20171
20264
  try {
20172
- return "1.10.10";
20265
+ return "1.10.11";
20173
20266
  } catch {
20174
20267
  return "0.0.0";
20175
20268
  }
@@ -20939,7 +21032,7 @@ var subArgs = args.slice(1);
20939
21032
  var isDetachedChild = process.env.SYNKRO_TELEMETRY_DETACHED === "1";
20940
21033
  var FLUSH_SKIP = /* @__PURE__ */ new Set(["grade", "inventory-sync", "version", "--version", "-v", "help", "--help", "-h", ""]);
20941
21034
  function printVersion() {
20942
- console.log("1.10.10");
21035
+ console.log("1.10.11");
20943
21036
  }
20944
21037
  function printHelp2() {
20945
21038
  console.log(`Synkro CLI \u2014 runtime safety for AI coding agents