fix(keys): snippets survive being pasted into real zsh

The copyable text opened with a "# hint" line — but default interactive
zsh has interactivecomments off, so the line was parsed as a command, and
the "!" inside «(перезапишет!)» fired history expansion: pasting the
OpenCode snippet died with "zsh: event not found: )" before doing
anything. Hints now live in the UI above the snippet; the clipboard gets
commands only. Verified by piping the actual rendered snippet through an
interactive zsh: the config file lands intact.
This commit is contained in:
infosave2007
2026-08-08 14:16:22 +03:00
parent f385c2254b
commit b689180717
+22 -16
View File
@@ -62,14 +62,12 @@ export async function renderKeys() {
// Harness auto-setup scripts first (the gateway speaks OpenAI at /v1/* and
// Anthropic at /v1/messages, so Claude Code connects natively), SDKs after.
const buildSnips = (osKind) => osKind === "ps" ? {
"Claude Code": `# ${t("keys.h.claude")}
$env:ANTHROPIC_BASE_URL = "${origin}"
"Claude Code": `$env:ANTHROPIC_BASE_URL = "${origin}"
$env:ANTHROPIC_AUTH_TOKEN = "${key}"
$env:ANTHROPIC_MODEL = "cortiq-auto"
claude`,
Codex: `# ${t("keys.h.codex")}
New-Item -ItemType Directory -Force "$HOME\\.codex" | Out-Null
Codex: `New-Item -ItemType Directory -Force "$HOME\\.codex" | Out-Null
Add-Content "$HOME\\.codex\\config.toml" @'
model = "cortiq-auto"
model_provider = "cortiq"
@@ -83,8 +81,7 @@ wire_api = "chat"
$env:CORTIQ_API_KEY = "${key}"
codex`,
OpenCode: `# ${t("keys.h.opencode")}
New-Item -ItemType Directory -Force "$HOME\\.config\\opencode" | Out-Null
OpenCode: `New-Item -ItemType Directory -Force "$HOME\\.config\\opencode" | Out-Null
Set-Content "$HOME\\.config\\opencode\\opencode.json" @'
{
"$schema": "https://opencode.ai/config.json",
@@ -100,8 +97,7 @@ Set-Content "$HOME\\.config\\opencode\\opencode.json" @'
'@
opencode`,
Continue: `# ${t("keys.h.continue")}
New-Item -ItemType Directory -Force "$HOME\\.continue" | Out-Null
Continue: `New-Item -ItemType Directory -Force "$HOME\\.continue" | Out-Null
Add-Content "$HOME\\.continue\\config.yaml" @'
models:
- name: Cortiq Auto
@@ -122,14 +118,12 @@ ${t("keys.h.cline2")}`,
-H "Content-Type: application/json" \`
-d '{"model":"cortiq-auto","messages":[{"role":"user","content":"Привет!"}]}'`,
} : {
"Claude Code": `# ${t("keys.h.claude")}
export ANTHROPIC_BASE_URL="${origin}"
"Claude Code": `export ANTHROPIC_BASE_URL="${origin}"
export ANTHROPIC_AUTH_TOKEN="${key}"
export ANTHROPIC_MODEL="cortiq-auto"
claude`,
Codex: `# ${t("keys.h.codex")}
mkdir -p ~/.codex && cat >> ~/.codex/config.toml <<'EOF'
Codex: `mkdir -p ~/.codex && cat >> ~/.codex/config.toml <<'EOF'
model = "cortiq-auto"
model_provider = "cortiq"
@@ -142,8 +136,7 @@ EOF
export CORTIQ_API_KEY="${key}"
codex`,
OpenCode: `# ${t("keys.h.opencode")}
mkdir -p ~/.config/opencode && cat > ~/.config/opencode/opencode.json <<'EOF'
OpenCode: `mkdir -p ~/.config/opencode && cat > ~/.config/opencode/opencode.json <<'EOF'
{
"$schema": "https://opencode.ai/config.json",
"provider": {
@@ -158,8 +151,7 @@ mkdir -p ~/.config/opencode && cat > ~/.config/opencode/opencode.json <<'EOF'
EOF
opencode`,
Continue: `# ${t("keys.h.continue")}
mkdir -p ~/.continue && cat >> ~/.continue/config.yaml <<'EOF'
Continue: `mkdir -p ~/.continue && cat >> ~/.continue/config.yaml <<'EOF'
models:
- name: Cortiq Auto
provider: openai
@@ -205,7 +197,19 @@ console.log(resp.choices[0].message.content);`,
}
rebuildSnips();
let cur = "Claude Code";
// per-harness hint lives OUTSIDE the copyable text: a leading "# comment"
// in a pasted snippet is not a comment in default interactive zsh, and a
// "!" inside it triggers history expansion ("event not found")
const HINTS = {
"Claude Code": () => t("keys.h.claude"),
Codex: () => t("keys.h.codex"),
OpenCode: () => t("keys.h.opencode"),
Continue: () => t("keys.h.continue"),
};
const hintHost = h("div", { class: "muted small", style: "margin-bottom:6px" });
const paintHint = () => { hintHost.textContent = HINTS[cur] ? HINTS[cur]() : ""; };
const pre = h("pre", { class: "conv-log snippet" }, snips[cur]);
paintHint();
const seg = h(
"div",
{ class: "seg" },
@@ -213,6 +217,7 @@ console.log(resp.choices[0].message.content);`,
h("button", { class: (i === 0 ? "active" : "") + (["curl", "python", "javascript"].includes(k) ? " sdk" : ""), "data-snip": k, onClick: (e) => {
cur = k;
pre.textContent = snips[k];
paintHint();
protoWarn.style.display = k === "Claude Code" && protoWarn.childNodes.length ? "" : "none";
paintStatus();
seg.querySelectorAll("button").forEach((b) => b.classList.remove("active"));
@@ -321,6 +326,7 @@ console.log(resp.choices[0].message.content);`,
h("div", { class: "muted small", style: "margin-bottom:8px" },
lastCreatedKey ? t("keys.snip.withKey") : openMode ? t("keys.snip.openMode") : t("keys.snip.hint")),
h("div", { class: "flex", style: "gap:8px; margin-bottom:8px; flex-wrap:wrap" }, seg, h("div", { class: "grow" }), keyIn, applyBtn, osSeg, copy),
hintHost,
pre,
statusHost,
protoWarn,