From bb6cdfeccf944ddce713f8f1f653c38477b74724 Mon Sep 17 00:00:00 2001 From: Daniil Koryto Date: Mon, 13 Apr 2026 12:17:14 +0300 Subject: [PATCH 1/3] chore: harden alias publish bootstrap --- AGENTS.md | 2 ++ CHANGELOG.md | 2 ++ scripts/publish-alias-package.mjs | 58 +++++++++++++++++++++++++++---- 3 files changed, 55 insertions(+), 7 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index dd68863..c7fe7a1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -247,6 +247,8 @@ Fallback entrypoints: Alias publishing: - `publish-alias-package.mjs` builds the `@gonkagate/claude-code-setup` alias package from the current root build output +- if that alias package is not visible on npm yet, the script skips alias publishing so the primary `@gonkagate/claude-code` release can complete; bootstrap the alias package with `--allow-create-package` or `ALLOW_ALIAS_PACKAGE_CREATE=1`, then configure Trusted Publishing before requiring alias publish success +- alias package publishing uses provenance only in GitHub Actions OIDC; local bootstrap publishes without provenance because npm cannot generate it outside a supported CI provider They must not replace `npx` as the primary public UX. diff --git a/CHANGELOG.md b/CHANGELOG.md index ccf69d3..83ad5f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +- Made local alias package bootstrap publish without npm provenance because provenance requires a supported CI/OIDC provider. +- Made alias package publishing skip cleanly until `@gonkagate/claude-code-setup` is bootstrapped on npm, with an explicit override for the first package publish. - Added `@gonkagate/claude-code-setup` as a setup-style alias for the existing Claude Code installer. - Improved npm package metadata and README copy for better package-page clarity, discovery, and onboarding. - Added a curated model registry and model picker to the public installer flow. diff --git a/scripts/publish-alias-package.mjs b/scripts/publish-alias-package.mjs index 8ed73b6..c38085e 100644 --- a/scripts/publish-alias-package.mjs +++ b/scripts/publish-alias-package.mjs @@ -8,6 +8,14 @@ import { fileURLToPath } from "node:url"; const ALIAS_PACKAGE_NAME = "@gonkagate/claude-code-setup"; const ALIAS_BIN_NAME = "claude-code-setup"; const dryRun = process.argv.includes("--dry-run"); +const allowCreatePackage = process.argv.includes("--allow-create-package") + || process.env.ALLOW_ALIAS_PACKAGE_CREATE === "1"; +const requireExistingPackage = process.argv.includes("--require-package") + || process.env.REQUIRE_ALIAS_PACKAGE === "1"; +const disableProvenance = process.argv.includes("--no-provenance") + || process.env.DISABLE_ALIAS_PACKAGE_PROVENANCE === "1"; +const canUseGitHubActionsProvenance = process.env.GITHUB_ACTIONS === "true" + && process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN !== undefined; const scriptDir = dirname(fileURLToPath(import.meta.url)); const repoRoot = resolve(scriptDir, ".."); @@ -28,20 +36,30 @@ function run(command, args, options = {}) { } } -function isPublished(packageName, version) { - const result = spawnSync("npm", ["view", `${packageName}@${version}`, "version"], { +function isNpmNotFound(output) { + return output.includes("E404") || output.includes("404 Not Found"); +} + +function npmView(args) { + const result = spawnSync("npm", ["view", ...args], { cwd: repoRoot, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }); if (result.status === 0) { - return true; + return { + exists: true, + output: result.stdout + }; } const output = `${result.stdout}\n${result.stderr}`; - if (output.includes("E404") || output.includes("404 Not Found")) { - return false; + if (isNpmNotFound(output)) { + return { + exists: false, + output + }; } process.stdout.write(result.stdout); @@ -49,6 +67,14 @@ function isPublished(packageName, version) { process.exit(result.status ?? 1); } +function canViewPackage(packageName) { + return npmView([packageName, "name"]).exists; +} + +function isVersionPublished(packageName, version) { + return npmView([`${packageName}@${version}`, "version"]).exists; +} + async function assertExists(path) { await access(path, fsConstants.R_OK); } @@ -56,11 +82,27 @@ async function assertExists(path) { const rootPackage = JSON.parse(await readFile(join(repoRoot, "package.json"), "utf8")); const packageVersion = rootPackage.version; -if (!dryRun && isPublished(ALIAS_PACKAGE_NAME, packageVersion)) { +if (isVersionPublished(ALIAS_PACKAGE_NAME, packageVersion)) { console.log(`${ALIAS_PACKAGE_NAME}@${packageVersion} is already published; skipping alias publish.`); process.exit(0); } +if (!dryRun && !canViewPackage(ALIAS_PACKAGE_NAME)) { + console.warn(`${ALIAS_PACKAGE_NAME} is not visible on npm yet, or this publisher cannot access it.`); + + if (allowCreatePackage) { + console.warn("Attempting first publish because alias package creation was explicitly allowed."); + } else if (requireExistingPackage) { + console.warn(`Bootstrap ${ALIAS_PACKAGE_NAME} on npm and configure Trusted Publishing for this workflow, then rerun npm run publish:alias.`); + console.warn("Alias package publishing is required for this run, so failing now."); + process.exit(1); + } else { + console.warn(`Bootstrap ${ALIAS_PACKAGE_NAME} on npm and configure Trusted Publishing for this workflow, then rerun npm run publish:alias.`); + console.warn("Skipping alias publish so the primary @gonkagate/claude-code release can complete."); + process.exit(0); + } +} + for (const path of ["bin", "dist", "docs", "README.md", "CHANGELOG.md", "LICENSE"]) { await assertExists(join(repoRoot, path)); } @@ -98,8 +140,10 @@ try { const publishArgs = ["publish", "--access", "public"]; if (dryRun) { publishArgs.push("--dry-run"); - } else { + } else if (canUseGitHubActionsProvenance && !disableProvenance) { publishArgs.push("--provenance"); + } else { + console.warn("Publishing without provenance because this is not a GitHub Actions OIDC environment."); } run("npm", publishArgs, { cwd: packageRoot }); From f19cfc78cc5246699e065b045a7ec40309694e02 Mon Sep 17 00:00:00 2001 From: Daniil Koryto Date: Wed, 29 Apr 2026 11:11:22 +0300 Subject: [PATCH 2/3] feat: add kimi-k2.6 to curated model registry --- CHANGELOG.md | 1 + README.md | 43 +++++++++++++++++++++++++++-------------- docs/how-it-works.md | 5 +++-- docs/troubleshooting.md | 5 +++-- src/constants/models.ts | 7 +++++++ src/install/prompts.ts | 2 +- test/install.test.ts | 8 +++++++- 7 files changed, 50 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 83ad5f2..ea82135 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Unreleased +- Added curated model support for `kimi-k2.6` -> `moonshotai/Kimi-K2.6` in the installer model picker and docs. - Made local alias package bootstrap publish without npm provenance because provenance requires a supported CI/OIDC provider. - Made alias package publishing skip cleanly until `@gonkagate/claude-code-setup` is bootstrapped on npm, with an explicit override for the first package publish. - Added `@gonkagate/claude-code-setup` as a setup-style alias for the existing Claude Code installer. diff --git a/README.md b/README.md index 9459e00..490dca7 100644 --- a/README.md +++ b/README.md @@ -2,23 +2,20 @@ Set up Claude Code to use GonkaGate in one `npx` command. -This CLI installer is for developers who already have local `Claude Code` and want to use it with GonkaGate, the gateway to Gonka Network, without editing shell profiles, exporting long env var blocks, or writing `.env` files by hand. - -Under the hood it configures Claude Code to use GonkaGate's Anthropic-compatible endpoint at `https://api.gonkagate.com`. - -It does not install `Claude Code` itself. It configures an existing local Claude Code install. - -## Quick Start - ```bash npx @gonkagate/claude-code ``` -Setup-style alias for consistency with the other GonkaGate agent installers: +![Package](https://img.shields.io/badge/package-%40gonkagate%2Fclaude--code-6E63FF?style=flat-square) +![Node](https://img.shields.io/badge/node-%3E%3D18-4DA2FF?style=flat-square) +![License](https://img.shields.io/badge/license-Apache--2.0-2A2A2A?style=flat-square) -```bash -npx @gonkagate/claude-code-setup -``` +[![Website](https://img.shields.io/badge/Website-gonkagate.com-111827?style=flat-square)](https://gonkagate.com/en) +[![Docs](https://img.shields.io/badge/Docs-API%20Guides-2563EB?style=flat-square)](https://gonkagate.com/en/docs) +[![API%20Key](https://img.shields.io/badge/API%20Key-Dashboard-F97316?style=flat-square)](https://gonkagate.com/en/register) +[![Telegram](https://img.shields.io/badge/Telegram-%40gonkagate-229ED9?style=flat-square&logo=telegram&logoColor=white)](https://t.me/gonkagate) +[![X](https://img.shields.io/badge/X-%40gonkagate-000000?style=flat-square&logo=x&logoColor=white)](https://x.com/gonkagate) +[![LinkedIn](https://img.shields.io/badge/LinkedIn-GonkaGate-0A66C2?style=flat-square&logo=linkedin&logoColor=white)](https://www.linkedin.com/company/gonkagate) ## See It In Action @@ -28,6 +25,21 @@ From API key to a working Claude Code setup in one short walkthrough: Need an API key first? [Create one on GonkaGate](https://gonkagate.com/en). +## Overview + +`@gonkagate/claude-code` is for developers who already have local `Claude Code` +and want to use it with GonkaGate without editing shell profiles, exporting +long env var blocks, or writing `.env` files by hand. + +Under the hood it configures Claude Code to use GonkaGate's Anthropic- +compatible endpoint at `https://api.gonkagate.com`. + +It does not install `Claude Code` itself. It configures an existing local +Claude Code install. + +For setup-style naming consistency, the alias +`npx @gonkagate/claude-code-setup` runs the same installer. + You will be asked for: - your GonkaGate API key (`gp-...`) in a hidden interactive prompt @@ -42,11 +54,12 @@ You need: - Node.js 18+ - a GonkaGate API key -## Supported Model +## Supported Models -Current public Claude Code model in the curated registry: +Current public Claude Code models in the curated registry: -- `qwen3-235b` -> `qwen/qwen3-235b-a22b-instruct-2507-fp8` +- `qwen3-235b` -> `qwen/qwen3-235b-a22b-instruct-2507-fp8` (default) +- `kimi-k2.6` -> `moonshotai/Kimi-K2.6` ## What It Does diff --git a/docs/how-it-works.md b/docs/how-it-works.md index 0860f27..9a870b2 100644 --- a/docs/how-it-works.md +++ b/docs/how-it-works.md @@ -12,9 +12,10 @@ These values are intentionally fixed by the installer: - Auth variable: `ANTHROPIC_AUTH_TOKEN` - Model selection comes only from a curated in-repo allowlist -Today the curated public Claude Code model registry contains one supported entry: +Today the curated public Claude Code model registry contains: -- `qwen3-235b` -> `qwen/qwen3-235b-a22b-instruct-2507-fp8` (default, current only option) +- `qwen3-235b` -> `qwen/qwen3-235b-a22b-instruct-2507-fp8` (default) +- `kimi-k2.6` -> `moonshotai/Kimi-K2.6` Users provide only: diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 9f5683c..80bb8f1 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -14,9 +14,10 @@ The installer writes Claude Code settings, but an existing direct login can stil This installer writes the selected model from its curated GonkaGate-supported registry. -Today that curated list contains one option: +Today that curated list contains: -- `qwen3-235b` -> `qwen/qwen3-235b-a22b-instruct-2507-fp8` +- `qwen3-235b` -> `qwen/qwen3-235b-a22b-instruct-2507-fp8` (default) +- `kimi-k2.6` -> `moonshotai/Kimi-K2.6` If that model is unavailable, the likely cause is a backend deployment or model availability mismatch. This installer does not expose custom base URL or arbitrary custom model overrides, so the right next step is GonkaGate support or the backend troubleshooting docs in `gonka-proxy`. diff --git a/src/constants/models.ts b/src/constants/models.ts index c0cec64..fc13644 100644 --- a/src/constants/models.ts +++ b/src/constants/models.ts @@ -13,6 +13,13 @@ const curatedModelRegistry = [ modelId: "qwen/qwen3-235b-a22b-instruct-2507-fp8", description: "Current GonkaGate public Claude Code model.", isDefault: true + }, + { + key: "kimi-k2.6", + displayName: "MoonshotAI Kimi K2.6", + modelId: "moonshotai/Kimi-K2.6", + description: "GonkaGate public Claude Code model.", + isDefault: false } ] as const satisfies readonly SupportedModelDefinition[]; diff --git a/src/install/prompts.ts b/src/install/prompts.ts index fa384f4..15c98d5 100644 --- a/src/install/prompts.ts +++ b/src/install/prompts.ts @@ -126,7 +126,7 @@ export function buildModelPromptConfig( value: model.key, name: model.displayName, short: model.key, - description: model.description ? `${model.description} Model ID: ${model.modelId}` : `Model ID: ${model.modelId}` + description: `${model.description ? `${model.description} ` : ""}Model ID: ${model.modelId}` })), pageSize: Math.min(models.length, 8), loop: false, diff --git a/test/install.test.ts b/test/install.test.ts index 02cdf5b..e3ca6a3 100644 --- a/test/install.test.ts +++ b/test/install.test.ts @@ -14,7 +14,7 @@ import { buildModelPromptConfig, buildTrackedLocalSettingsPromptConfig, promptFo import { validateApiKey } from "../src/install/validate-api-key.js"; import { writeSettings } from "../src/install/write-settings.js"; import { CLAUDE_SETTINGS_SCHEMA_URL, GONKAGATE_BASE_URL } from "../src/constants/gateway.js"; -import { DEFAULT_MODEL, DEFAULT_MODEL_KEY } from "../src/constants/models.js"; +import { DEFAULT_MODEL, DEFAULT_MODEL_KEY, requireSupportedModel } from "../src/constants/models.js"; test("mergeSettingsWithGonkaEnv preserves unrelated settings and updates gateway env", () => { const merged = mergeSettingsWithGonkaEnv( @@ -81,6 +81,12 @@ test("parseArgs accepts supported --model values and rejects unsupported ones", assert.throws(() => parseCliOptions(["--model", "not-supported"], silentOutput), /Allowed choices are/); }); +test("supported model registry includes kimi-k2.6", () => { + const model = requireSupportedModel("kimi-k2.6"); + + assert.equal(model.modelId, "moonshotai/Kimi-K2.6"); +}); + test("loadSettings rejects invalid JSON instead of overwriting it", async () => { const directory = await mkdtemp(path.join(tmpdir(), "gonkagate-invalid-json-")); const filePath = path.join(directory, "settings.json"); From 9a444e035c8f5be5ab5bc13770b58457f316276a Mon Sep 17 00:00:00 2001 From: Daniil Koryto Date: Wed, 29 Apr 2026 11:20:15 +0300 Subject: [PATCH 3/3] fix: make kimi-k2.6 the default curated model --- README.md | 4 ++-- docs/how-it-works.md | 4 ++-- docs/troubleshooting.md | 4 ++-- src/constants/models.ts | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 490dca7..e525d0d 100644 --- a/README.md +++ b/README.md @@ -58,8 +58,8 @@ You need: Current public Claude Code models in the curated registry: -- `qwen3-235b` -> `qwen/qwen3-235b-a22b-instruct-2507-fp8` (default) -- `kimi-k2.6` -> `moonshotai/Kimi-K2.6` +- `qwen3-235b` -> `qwen/qwen3-235b-a22b-instruct-2507-fp8` +- `kimi-k2.6` -> `moonshotai/Kimi-K2.6` (default) ## What It Does diff --git a/docs/how-it-works.md b/docs/how-it-works.md index 9a870b2..81e63f4 100644 --- a/docs/how-it-works.md +++ b/docs/how-it-works.md @@ -14,8 +14,8 @@ These values are intentionally fixed by the installer: Today the curated public Claude Code model registry contains: -- `qwen3-235b` -> `qwen/qwen3-235b-a22b-instruct-2507-fp8` (default) -- `kimi-k2.6` -> `moonshotai/Kimi-K2.6` +- `qwen3-235b` -> `qwen/qwen3-235b-a22b-instruct-2507-fp8` +- `kimi-k2.6` -> `moonshotai/Kimi-K2.6` (default) Users provide only: diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 80bb8f1..22ec710 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -16,8 +16,8 @@ This installer writes the selected model from its curated GonkaGate-supported re Today that curated list contains: -- `qwen3-235b` -> `qwen/qwen3-235b-a22b-instruct-2507-fp8` (default) -- `kimi-k2.6` -> `moonshotai/Kimi-K2.6` +- `qwen3-235b` -> `qwen/qwen3-235b-a22b-instruct-2507-fp8` +- `kimi-k2.6` -> `moonshotai/Kimi-K2.6` (default) If that model is unavailable, the likely cause is a backend deployment or model availability mismatch. This installer does not expose custom base URL or arbitrary custom model overrides, so the right next step is GonkaGate support or the backend troubleshooting docs in `gonka-proxy`. diff --git a/src/constants/models.ts b/src/constants/models.ts index fc13644..d306a4c 100644 --- a/src/constants/models.ts +++ b/src/constants/models.ts @@ -12,14 +12,14 @@ const curatedModelRegistry = [ displayName: "Qwen 3 235B Instruct", modelId: "qwen/qwen3-235b-a22b-instruct-2507-fp8", description: "Current GonkaGate public Claude Code model.", - isDefault: true + isDefault: false }, { key: "kimi-k2.6", displayName: "MoonshotAI Kimi K2.6", modelId: "moonshotai/Kimi-K2.6", description: "GonkaGate public Claude Code model.", - isDefault: false + isDefault: true } ] as const satisfies readonly SupportedModelDefinition[];