Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
58 changes: 51 additions & 7 deletions scripts/publish-alias-package.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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, "..");
Expand All @@ -28,35 +36,69 @@ 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);
process.stderr.write(result.stderr);
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);
}

const rootPackage = JSON.parse(await readFile(join(repoRoot, "package.json"), "utf8"));
const packageVersion = rootPackage.version;

if (!dryRun && isPublished(ALIAS_PACKAGE_NAME, packageVersion)) {
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);
}
}

if (!dryRun && isVersionPublished(ALIAS_PACKAGE_NAME, packageVersion)) {
console.log(`${ALIAS_PACKAGE_NAME}@${packageVersion} is already published; skipping alias publish.`);
process.exit(0);
}
Expand Down Expand Up @@ -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 });
Expand Down
Loading