Files
cline/sdk/scripts/version.ts
T
Bee be3fc07263 feat: add @clinebot/enterprise SDK package (#85)
* feat: add @clinebot/enterprise SDK package

Introduces @clinebot/enterprise, a new optional composition layer that adds enterprise capabilities on top of @clinebot/core and @clinebot/agents without leaking enterprise-specific concerns into lower-level packages.

The package handles the full enterprise sync lifecycle:

1. Identity resolution — pluggable IdentityAdapter interface (WorkOS adapter included)
2. Control plane sync — fetches remote config bundles via EnterpriseControlPlane
3. Policy materialization — writes managed rules, workflows, and skills to disk so @clinebot/core discovers them through its standard local file path (no special in-memory injection)
4. Telemetry configuration — maps bundle data to normalized OpenTelemetryClientConfig from @clinebot/shared
5. Runtime integration — exposes createEnterprisePlugin() and prepareEnterpriseRuntime() to wire everything into @clinebot/core as an AgentExtension

Design decisions
- Provider-agnostic contracts — IdentityAdapter, EnterpriseControlPlane, and EnterpriseTelemetryAdapter are thin interfaces; WorkOS is an included provider, not a hard dependency
- File-based materialization — enterprise-managed instructions land on disk and are loaded through the same path as any local instruction file, keeping prompt assembly consistent
- Shared RemoteConfig — EnterpriseConfigBundle normalizes into RemoteConfig from @clinebot/shared; no separate enterprise-only config contract
- Clean boundary — if a feature works without org identity, remote policy, or enterprise telemetry, it doesn't belong in this package

* clean up

* refactor: rpc/src/client.ts

* revert package.json

* autoload

* rename agents directory to extensions

* fix renamed path

* fix: use renamed extensions path

* fix checkpoint hooks
2026-04-06 16:30:53 -07:00

116 lines
2.8 KiB
TypeScript

#!/usr/bin/env bun
import { readdir, readFile, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { parseArgs } from "node:util";
const { values, positionals } = parseArgs({
args: Bun.argv.slice(2),
options: {
dry: { type: "boolean", default: false },
},
allowPositionals: true,
strict: true,
});
let version = positionals[0];
function incrementPatchVersion(input: string): string {
const match = input.match(/^(\d+)\.(\d+)\.(\d+)(-[\w.]+)?$/);
if (!match) {
throw new Error(`Invalid semver version: ${input}`);
}
const [, major, minor, patch] = match;
return `${major}.${minor}.${Number(patch) + 1}`;
}
const root = join(import.meta.dir, "..");
const packagesDir = join(root, "packages");
const dirs = await readdir(packagesDir, { withFileTypes: true });
const workspaces = dirs.filter((d) => d.isDirectory()).map((d) => d.name);
if (!version) {
for (const workspace of workspaces) {
const pkgPath = join(packagesDir, workspace, "package.json");
try {
const raw = await readFile(pkgPath, "utf-8");
const pkg = JSON.parse(raw);
if (typeof pkg.version === "string") {
version = incrementPatchVersion(pkg.version);
break;
}
} catch {
// skip directories without a package.json
}
}
if (!version) {
console.error(
"Could not determine a current version from workspace package.json files.",
);
process.exit(1);
}
}
if (!/^\d+\.\d+\.\d+(-[\w.]+)?$/.test(version)) {
console.error(`Invalid semver version: ${version}`);
process.exit(1);
}
if (positionals[0] === undefined) {
console.log(`No version provided, defaulting to next patch: ${version}`);
}
async function runCommandOrThrow(cmd: string[], cwd: string): Promise<void> {
const proc = Bun.spawn(cmd, {
cwd,
stdout: "inherit",
stderr: "inherit",
});
const exitCode = await proc.exited;
if (exitCode !== 0) {
throw new Error(`${cmd[0]} exited with code ${exitCode}`);
}
}
let updated = 0;
for (const workspace of workspaces) {
const pkgPath = join(packagesDir, workspace, "package.json");
try {
const raw = await readFile(pkgPath, "utf-8");
const pkg = JSON.parse(raw);
if (pkg.internal === true) {
continue;
}
const oldVersion = pkg.version;
pkg.version = version;
const out = `${JSON.stringify(pkg, null, "\t")}\n`;
if (values.dry) {
console.log(`[dry] ${pkg.name}: ${oldVersion}${version}`);
} else {
await writeFile(pkgPath, out);
console.log(`${pkg.name}: ${oldVersion}${version}`);
}
updated++;
} catch {
// skip directories without a package.json
}
}
console.log(
`\n${values.dry ? "[dry] " : ""}Updated ${updated} package(s) to v${version}`,
);
if (!values.dry) {
await runCommandOrThrow(
["bun", "-F", "@clinebot/llms", "generate:models"],
root,
);
await runCommandOrThrow(["bun", "format", "--write"], root);
await runCommandOrThrow(["bun", "run", "build"], root);
}