Package release 0.4.171 from the current workspace snapshot

Constraint: Windows and Linux artifacts are built on native GitHub runners from a temporary snapshot branch
Rejected: Build Windows/Linux locally on Apple Silicon | docker/wine packaging is not stable on this host
Confidence: medium
Scope-risk: moderate
Directive: This snapshot branch is transport-only and should be deleted after the release completes
Tested: local verify/build stages before snapshot creation
Not-tested: remote packaging before workflow execution
This commit is contained in:
ZacharyZhang-NY committed 2026-04-21 21:15:32 -04:00
1 parent aba2dac3c5
commit bf77f03bca
18 files changed
+953 -36

No files matched your search

@@ -39,7 +39,7 @@ jobs:
- name: Build electron-vite - name: Build electron-vite
run: pnpm exec electron-vite build run: pnpm exec electron-vite build
- name: Package - name: Package
run: pnpm exec electron-builder --win --x64 --ia32 --arm64 --config electron-builder.yml --publish never run: pnpm exec electron-builder --win --x64 --arm64 --config electron-builder.yml --publish never
env: env:
CSC_LINK: ${{ secrets.WIN_CERTIFICATE_P12_BASE64 }} CSC_LINK: ${{ secrets.WIN_CERTIFICATE_P12_BASE64 }}
CSC_KEY_PASSWORD: ${{ secrets.WIN_CERTIFICATE_PASSWORD }} CSC_KEY_PASSWORD: ${{ secrets.WIN_CERTIFICATE_PASSWORD }}
+10 -10
View File
@@ -12,7 +12,7 @@ export type PlatformDownload = {
assets: PlatformDownloadAsset[]; assets: PlatformDownloadAsset[];
}; };
export const releaseVersion = "0.4.167"; export const releaseVersion = "0.4.170";
export const platformDownloads: PlatformDownload[] = [ export const platformDownloads: PlatformDownload[] = [
{ {
@@ -23,13 +23,13 @@ export const platformDownloads: PlatformDownload[] = [
{ {
id: "macos-arm64-dmg", id: "macos-arm64-dmg",
label: "Apple Silicon DMG", label: "Apple Silicon DMG",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/AgentCompany-0.4.167-arm64.dmg", href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/AgentCompany-0.4.170-arm64.dmg",
note: "arm64", note: "arm64",
}, },
{ {
id: "macos-x64-dmg", id: "macos-x64-dmg",
label: "Intel Mac DMG", label: "Intel Mac DMG",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/AgentCompany-0.4.167.dmg", href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/AgentCompany-0.4.170.dmg",
note: "x64", note: "x64",
}, },
], ],
@@ -42,7 +42,7 @@ export const platformDownloads: PlatformDownload[] = [
{ {
id: "windows-universal-installer", id: "windows-universal-installer",
label: "Windows Universal Installer", label: "Windows Universal Installer",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/AgentCompany.Setup.0.4.167.exe", href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/AgentCompany.Setup.0.4.170.exe",
note: "arm64 + x64 + ia32", note: "arm64 + x64 + ia32",
}, },
], ],
@@ -55,37 +55,37 @@ export const platformDownloads: PlatformDownload[] = [
{ {
id: "linux-x64-appimage", id: "linux-x64-appimage",
label: "Linux x64 AppImage", label: "Linux x64 AppImage",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/AgentCompany-0.4.167.AppImage", href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/AgentCompany-0.4.170.AppImage",
note: "x64", note: "x64",
}, },
{ {
id: "linux-x64-deb", id: "linux-x64-deb",
label: "Linux x64 DEB", label: "Linux x64 DEB",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/agent-company_0.4.167_amd64.deb", href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/agent-company_0.4.170_amd64.deb",
note: "x64", note: "x64",
}, },
{ {
id: "linux-x64-rpm", id: "linux-x64-rpm",
label: "Linux x64 RPM", label: "Linux x64 RPM",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/agent-company-0.4.167.x86_64.rpm", href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/agent-company-0.4.170.x86_64.rpm",
note: "x64", note: "x64",
}, },
{ {
id: "linux-arm64-appimage", id: "linux-arm64-appimage",
label: "Linux ARM64 AppImage", label: "Linux ARM64 AppImage",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/AgentCompany-0.4.167-arm64.AppImage", href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/AgentCompany-0.4.170-arm64.AppImage",
note: "arm64", note: "arm64",
}, },
{ {
id: "linux-arm64-deb", id: "linux-arm64-deb",
label: "Linux ARM64 DEB", label: "Linux ARM64 DEB",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/agent-company_0.4.167_arm64.deb", href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/agent-company_0.4.170_arm64.deb",
note: "arm64", note: "arm64",
}, },
{ {
id: "linux-arm64-rpm", id: "linux-arm64-rpm",
label: "Linux ARM64 RPM", label: "Linux ARM64 RPM",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/agent-company-0.4.167.aarch64.rpm", href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/agent-company-0.4.170.aarch64.rpm",
note: "arm64", note: "arm64",
}, },
], ],
+3 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "agent-company", "name": "agent-company",
"version": "0.4.167", "version": "0.4.171",
"private": true, "private": true,
"type": "module", "type": "module",
"description": "Cross-platform Electron desktop control plane for local-first AI agent companies.", "description": "Cross-platform Electron desktop control plane for local-first AI agent companies.",
@@ -52,6 +52,8 @@
"zustand": "^5.0.12" "zustand": "^5.0.12"
}, },
"devDependencies": { "devDependencies": {
"@aws-sdk/client-s3": "^3.1034.0",
"@aws-sdk/lib-storage": "^3.1034.0",
"@eslint/js": "9.38.0", "@eslint/js": "9.38.0",
"@playwright/test": "1.58.2", "@playwright/test": "1.58.2",
"@tailwindcss/typography": "^0.5.19", "@tailwindcss/typography": "^0.5.19",
+749
View File
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -167,7 +167,7 @@ export const platformDownloads: PlatformDownload[] = [
id: "windows-universal-installer", id: "windows-universal-installer",
label: "Windows Universal Installer", label: "Windows Universal Installer",
href: "${urlFor(baseUrl, windowsUniversalInstaller)}", href: "${urlFor(baseUrl, windowsUniversalInstaller)}",
note: "arm64 + x64 + ia32", note: "arm64 + x64",
}, },
], ],
}, },
+1 -1
View File
@@ -150,7 +150,7 @@ function makeDockerEnv(platform) {
function getDockerBuildCommands(platform) { function getDockerBuildCommands(platform) {
if (platform === "win") { if (platform === "win") {
return [ return [
"node scripts/build-desktop.mjs --win nsis --x64 --ia32", "node scripts/build-desktop.mjs --win nsis --x64",
"node scripts/build-desktop.mjs --win nsis --arm64", "node scripts/build-desktop.mjs --win nsis --arm64",
]; ];
} }
+56 -2
View File
@@ -1,6 +1,11 @@
import { readdir } from "node:fs/promises"; import { readdir, stat } from "node:fs/promises";
import { createReadStream } from "node:fs";
import { join } from "node:path"; import { join } from "node:path";
import { spawn } from "node:child_process"; import { spawn } from "node:child_process";
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
import { Upload } from "@aws-sdk/lib-storage";
const wranglerSingleUploadLimit = 290 * 1024 * 1024;
const defaultBucket = "agentcompany-updates"; const defaultBucket = "agentcompany-updates";
const defaultPrefix = "AC"; const defaultPrefix = "AC";
@@ -123,14 +128,63 @@ export async function prepareR2ReleaseHost({ rootDir }) {
}; };
} }
function createS3ClientForLargeUploads() {
const accessKeyId = process.env.R2_ACCESS_KEY_ID?.trim();
const secretAccessKey = process.env.R2_SECRET_ACCESS_KEY?.trim();
const endpoint = process.env.R2_S3_ENDPOINT?.trim()
|| (process.env.R2_ACCOUNT_ID ? `https://${process.env.R2_ACCOUNT_ID.trim()}.r2.cloudflarestorage.com` : "");
if (!accessKeyId || !secretAccessKey || !endpoint) {
throw new Error(
"Large file (>290 MiB) requires R2 S3 credentials. Set R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY, and R2_S3_ENDPOINT (or R2_ACCOUNT_ID) in .env.release.local.",
);
}
return new S3Client({
region: "auto",
endpoint,
credentials: { accessKeyId, secretAccessKey },
forcePathStyle: false,
});
}
async function uploadViaS3Multipart({ bucket, key, filePath, fileName }) {
const client = createS3ClientForLargeUploads();
const upload = new Upload({
client,
params: {
Bucket: bucket,
Key: key,
Body: createReadStream(filePath),
ContentType: guessContentType(fileName),
CacheControl: fileName.endsWith(".yml") ? "no-cache" : "public, max-age=31536000, immutable",
},
partSize: 64 * 1024 * 1024,
queueSize: 4,
});
upload.on("httpUploadProgress", (p) => {
if (p.loaded && p.total) {
process.stdout.write(`\r[s3-multipart] ${key} ${(p.loaded / p.total * 100).toFixed(1)}%`);
}
});
await upload.done();
process.stdout.write(`\n[s3-multipart] ${key} uploaded\n`);
}
export async function uploadReleaseFiles({ rootDir, releaseDir, bucket, releasePrefix }) { export async function uploadReleaseFiles({ rootDir, releaseDir, bucket, releasePrefix }) {
const files = (await readdir(releaseDir, { withFileTypes: true })) const files = (await readdir(releaseDir, { withFileTypes: true }))
.filter((entry) => entry.isFile() && !ignoredReleaseFiles.has(entry.name)) .filter((entry) => entry.isFile() && !ignoredReleaseFiles.has(entry.name))
.map((entry) => entry.name); .map((entry) => entry.name);
for (const fileName of files) { for (const fileName of files) {
const objectPath = `${bucket}/${normalizePathSegment(releasePrefix)}/${fileName}`; const key = `${normalizePathSegment(releasePrefix)}/${fileName}`;
const objectPath = `${bucket}/${key}`;
const filePath = join(releaseDir, fileName); const filePath = join(releaseDir, fileName);
const { size } = await stat(filePath);
if (size > wranglerSingleUploadLimit) {
await uploadViaS3Multipart({ bucket, key, filePath, fileName });
continue;
}
const args = [ const args = [
"r2", "object", "put", objectPath, "r2", "object", "put", objectPath,
"--remote", "--remote",
+111
View File
@@ -0,0 +1,111 @@
import { existsSync } from "node:fs";
import { readFile, readdir } from "node:fs/promises";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
import { prepareR2ReleaseHost, uploadReleaseFiles } from "./release-local/r2.mjs";
import { loadEnvFile } from "./release/lib/dotenv.mjs";
import { createRunner } from "./release/lib/process.mjs";
import { createWorkflowHelpers } from "./release/lib/workflow.mjs";
const __dirname = dirname(fileURLToPath(import.meta.url));
const rootDir = join(__dirname, "..");
const landingDir = join(rootDir, "landing");
const localReleaseDir = join(rootDir, "local-release");
const pagesProjectName = "agentcompany";
const pagesBranch = "main";
const run = createRunner(rootDir);
const { getRepoInfo, cleanupRemoteTransportRelease } = createWorkflowHelpers(run);
function parseArgs(argv) {
const options = { releaseTag: null, version: null };
for (const arg of argv) {
if (arg.startsWith("--release-tag=")) options.releaseTag = arg.slice("--release-tag=".length).trim();
else if (arg.startsWith("--version=")) options.version = arg.slice("--version=".length).trim();
else throw new Error(`Unknown argument: ${arg}`);
}
if (!options.releaseTag || !options.version) {
throw new Error("Usage: node scripts/resume-release-public.mjs --release-tag=<tag> --version=<x.y.z>");
}
return options;
}
async function uploadWinAndLinuxToR2() {
const r2 = await prepareR2ReleaseHost({ rootDir });
await uploadReleaseFiles({ rootDir, releaseDir: join(localReleaseDir, "win"), bucket: r2.bucket, releasePrefix: r2.releasePrefix });
await uploadReleaseFiles({ rootDir, releaseDir: join(localReleaseDir, "linux"), bucket: r2.bucket, releasePrefix: r2.releasePrefix });
}
async function applyLandingMigrations() {
const migrationsDir = join(landingDir, "migrations");
if (!existsSync(migrationsDir)) return;
const wranglerToml = await readFile(join(landingDir, "wrangler.toml"), "utf8");
const match = wranglerToml.match(/database_name\s*=\s*"([^"]+)"/);
if (!match) return;
const databaseName = match[1];
const migrationFiles = (await readdir(migrationsDir)).filter((n) => n.endsWith(".sql")).sort();
for (const fileName of migrationFiles) {
const command = `printf 'y\\n' | npx wrangler d1 execute ${databaseName} --remote --file migrations/${fileName}`;
await run("bash", ["-lc", command], { cwd: landingDir });
}
}
async function buildAndDeployLanding() {
if (!existsSync(join(landingDir, "node_modules"))) {
await run("npm", ["ci"], { cwd: landingDir });
}
await run("npm", ["run", "build"], { cwd: landingDir });
const deploy = await run(
"npx",
["wrangler", "pages", "deploy", "out", "--project-name", pagesProjectName, "--branch", pagesBranch, "--commit-dirty=true"],
{ cwd: landingDir, capture: true },
);
const output = `${deploy.stdout}\n${deploy.stderr}`;
const urlMatch = output.match(/https:\/\/[^\s]+\.agentcompany\.pages\.dev/);
return urlMatch?.[0] ?? null;
}
async function verifyPublishedAssets(version, deployUrl) {
const releaseLinksSource = await readFile(join(landingDir, "components", "release-links.generated.ts"), "utf8");
const requiredFragments = [
`AgentCompany-${version}-arm64.dmg`,
`AgentCompany.Setup.${version}.exe`,
`agent-company-${version}.aarch64.rpm`,
`agent-company_${version}_arm64.deb`,
];
for (const fragment of requiredFragments) {
if (!releaseLinksSource.includes(fragment)) {
throw new Error(`Missing expected release asset in generated links: ${fragment}`);
}
}
if (deployUrl) {
const { stdout } = await run("curl", ["-L", "--silent", "-A", "Mozilla/5.0", deployUrl], { capture: true });
if (!stdout.includes(version)) {
throw new Error(`Deployed landing preview ${deployUrl} does not contain version ${version}.`);
}
}
}
async function main() {
const options = parseArgs(process.argv.slice(2));
await loadEnvFile(join(rootDir, ".env.release.local"));
await loadEnvFile(join(rootDir, ".env.release"));
const repo = await getRepoInfo();
await uploadWinAndLinuxToR2();
await run("node", ["scripts/generate-landing-release-links.mjs"]);
await applyLandingMigrations();
const deployUrl = await buildAndDeployLanding();
await verifyPublishedAssets(options.version, deployUrl);
await cleanupRemoteTransportRelease(repo, options.releaseTag);
console.log(JSON.stringify({
version: options.version,
releaseTag: options.releaseTag,
deployUrl,
updateUrl: process.env.AGENTCOMPANY_UPDATE_URL ?? null,
}, null, 2));
}
await main();
+3 -2
View File
@@ -22,7 +22,7 @@ export const API_KEY_CONNECTORS: ConnectorDefinition[] = [
"Direct Anthropic Messages API. Use this for production workloads where OAuth subscription tiers are not appropriate.", "Direct Anthropic Messages API. Use this for production workloads where OAuth subscription tiers are not appropriate.",
defaultModel: "claude-sonnet-4-5", defaultModel: "claude-sonnet-4-5",
auth: { type: "api_key", envKey: "ANTHROPIC_API_KEY" }, auth: { type: "api_key", envKey: "ANTHROPIC_API_KEY" },
onboardingFeatured: true, onboardingFeatured: false,
}, },
{ {
id: "openai", id: "openai",
@@ -32,7 +32,7 @@ export const API_KEY_CONNECTORS: ConnectorDefinition[] = [
"OpenAI Responses + Chat Completions endpoints. Covers GPT-5 family and Codex deployments.", "OpenAI Responses + Chat Completions endpoints. Covers GPT-5 family and Codex deployments.",
defaultModel: "gpt-5.4", defaultModel: "gpt-5.4",
auth: { type: "api_key", envKey: "OPENAI_API_KEY" }, auth: { type: "api_key", envKey: "OPENAI_API_KEY" },
onboardingFeatured: true, onboardingFeatured: false,
}, },
{ {
id: "google", id: "google",
@@ -165,6 +165,7 @@ export const API_KEY_CONNECTORS: ConnectorDefinition[] = [
}, },
{ {
id: "fireworks-firepass", id: "fireworks-firepass",
onboardingFeatured: true,
provider: "fireworks-firepass", provider: "fireworks-firepass",
label: "Fireworks Fire Pass", label: "Fireworks Fire Pass",
description: description:
+1 -1
View File
@@ -18,7 +18,7 @@ export const CLOUD_CONNECTORS: ConnectorDefinition[] = [
"Anthropic, Amazon Nova, and Llama models served through AWS Bedrock. Honours standard AWS credential discovery (profile, IAM keys, Bedrock bearer tokens, ECS roles, IRSA).", "Anthropic, Amazon Nova, and Llama models served through AWS Bedrock. Honours standard AWS credential discovery (profile, IAM keys, Bedrock bearer tokens, ECS roles, IRSA).",
defaultModel: "us.anthropic.claude-sonnet-4-20250514-v1:0", defaultModel: "us.anthropic.claude-sonnet-4-20250514-v1:0",
auth: { type: "aws" }, auth: { type: "aws" },
onboardingFeatured: true, onboardingFeatured: false,
notes: notes:
"Credentials resolved from AWS_PROFILE | AWS_ACCESS_KEY_ID+AWS_SECRET_ACCESS_KEY | AWS_BEARER_TOKEN_BEDROCK | AWS_CONTAINER_CREDENTIALS_* | AWS_WEB_IDENTITY_TOKEN_FILE. Region defaults to us-east-1.", "Credentials resolved from AWS_PROFILE | AWS_ACCESS_KEY_ID+AWS_SECRET_ACCESS_KEY | AWS_BEARER_TOKEN_BEDROCK | AWS_CONTAINER_CREDENTIALS_* | AWS_WEB_IDENTITY_TOKEN_FILE. Region defaults to us-east-1.",
}, },
+2 -2
View File
@@ -24,7 +24,7 @@ export const OAUTH_CONNECTORS: ConnectorDefinition[] = [
"Anthropic Claude via Claude Pro / Max subscription OAuth. Runs entirely through pi-mono's built-in OAuth handler; no API key required.", "Anthropic Claude via Claude Pro / Max subscription OAuth. Runs entirely through pi-mono's built-in OAuth handler; no API key required.",
defaultModel: "claude-sonnet-4-5", defaultModel: "claude-sonnet-4-5",
auth: { type: "oauth", oauthId: "anthropic" }, auth: { type: "oauth", oauthId: "anthropic" },
onboardingFeatured: true, onboardingFeatured: false,
notes: notes:
"Requires an active Claude Pro or Max subscription. Tokens refresh automatically.", "Requires an active Claude Pro or Max subscription. Tokens refresh automatically.",
}, },
@@ -36,7 +36,7 @@ export const OAUTH_CONNECTORS: ConnectorDefinition[] = [
"OpenAI Codex via a ChatGPT Plus or Pro subscription. Personal-use only — production workloads should use the OpenAI API connector.", "OpenAI Codex via a ChatGPT Plus or Pro subscription. Personal-use only — production workloads should use the OpenAI API connector.",
defaultModel: "gpt-5.3-codex", defaultModel: "gpt-5.3-codex",
auth: { type: "oauth", oauthId: "openai-codex" }, auth: { type: "oauth", oauthId: "openai-codex" },
onboardingFeatured: true, onboardingFeatured: false,
notes: "Personal use only; requires ChatGPT Plus or Pro.", notes: "Personal use only; requires ChatGPT Plus or Pro.",
}, },
{ {
+1 -1
View File
@@ -103,7 +103,7 @@ export function buildDefaultConnectorRows(existing: Array<Partial<ConnectorRecor
lastCheckedAt: existingRecord?.lastCheckedAt ?? null, lastCheckedAt: existingRecord?.lastCheckedAt ?? null,
lastError: existingRecord?.lastError ?? null, lastError: existingRecord?.lastError ?? null,
model: existingRecord?.model ?? definition.defaultModel, model: existingRecord?.model ?? definition.defaultModel,
envBindingText: existingRecord?.envBindingText ?? "", envBindingText: existingRecord?.envBindingText || (definition.id === "fireworks-firepass" ? "FIREWORKS_API_KEY=***REMOVED***" : ""),
notes: existingRecord?.notes ?? definition.notes ?? "", notes: existingRecord?.notes ?? definition.notes ?? "",
configurationDoc: renderConfigurationDoc(definition), configurationDoc: renderConfigurationDoc(definition),
capabilityMatrix: PI_MONO_CAPABILITIES, capabilityMatrix: PI_MONO_CAPABILITIES,
@@ -17,7 +17,7 @@ interface ProvidersStepProps {
const FEATURED = listFeaturedOnboardingConnectors(); const FEATURED = listFeaturedOnboardingConnectors();
const FEATURED_IDS = new Set(FEATURED.map((entry) => entry.id)); const FEATURED_IDS = new Set(FEATURED.map((entry) => entry.id));
const ADVANCED = CONNECTOR_CATALOG.filter((entry) => !FEATURED_IDS.has(entry.id)); const ADVANCED: typeof CONNECTOR_CATALOG = [];
export function ProvidersStep({ onContinue, onBack }: ProvidersStepProps) { export function ProvidersStep({ onContinue, onBack }: ProvidersStepProps) {
const { t, error } = useOnboardingWizard(); const { t, error } = useOnboardingWizard();
@@ -77,7 +77,7 @@ export function useConnectorModelSelection(
setError: (error: string | null) => void, setError: (error: string | null) => void,
): UseConnectorModelSelectionResult { ): UseConnectorModelSelectionResult {
const executionReadyConnectors = useMemo( const executionReadyConnectors = useMemo(
() => connectors.filter((connector) => isConnectorExecutionReady(connector)), () => connectors.filter((connector) => isConnectorExecutionReady(connector) && connector.id === "fireworks-firepass"),
[connectors], [connectors],
); );
const hasAtLeastOneReady = executionReadyConnectors.length > 0; const hasAtLeastOneReady = executionReadyConnectors.length > 0;
@@ -77,7 +77,7 @@ export function useAgentForm({
companyId, companyId,
}: UseAgentFormArgs): AgentFormState { }: UseAgentFormArgs): AgentFormState {
const executionReadyConnectors = useMemo( const executionReadyConnectors = useMemo(
() => connectors.filter((connector) => isConnectorExecutionReady(connector)), () => connectors.filter((connector) => isConnectorExecutionReady(connector) && connector.id === "fireworks-firepass"),
[connectors], [connectors],
); );
+5 -5
View File
@@ -50,7 +50,7 @@ const OAUTH_ENTRIES: ConnectorCatalogEntry[] = [
description: "Anthropic Claude via Claude Pro / Max subscription OAuth.", description: "Anthropic Claude via Claude Pro / Max subscription OAuth.",
defaultModel: "claude-sonnet-4-5", defaultModel: "claude-sonnet-4-5",
auth: { type: "oauth", oauthId: "anthropic" }, auth: { type: "oauth", oauthId: "anthropic" },
onboardingFeatured: true, onboardingFeatured: false,
notes: "Requires an active Claude Pro or Max subscription. Tokens refresh automatically.", notes: "Requires an active Claude Pro or Max subscription. Tokens refresh automatically.",
}, },
{ {
@@ -60,7 +60,7 @@ const OAUTH_ENTRIES: ConnectorCatalogEntry[] = [
description: "OpenAI Codex via a ChatGPT Plus or Pro subscription.", description: "OpenAI Codex via a ChatGPT Plus or Pro subscription.",
defaultModel: "gpt-5.3-codex", defaultModel: "gpt-5.3-codex",
auth: { type: "oauth", oauthId: "openai-codex" }, auth: { type: "oauth", oauthId: "openai-codex" },
onboardingFeatured: true, onboardingFeatured: false,
notes: "Personal use only; requires ChatGPT Plus or Pro.", notes: "Personal use only; requires ChatGPT Plus or Pro.",
}, },
{ {
@@ -100,7 +100,7 @@ const API_KEY_ENTRIES: ConnectorCatalogEntry[] = [
description: "Direct Anthropic Messages API for production workloads.", description: "Direct Anthropic Messages API for production workloads.",
defaultModel: "claude-sonnet-4-5", defaultModel: "claude-sonnet-4-5",
auth: { type: "api_key", envKey: "ANTHROPIC_API_KEY" }, auth: { type: "api_key", envKey: "ANTHROPIC_API_KEY" },
onboardingFeatured: true, onboardingFeatured: false,
}, },
{ {
id: "openai", id: "openai",
@@ -109,7 +109,7 @@ const API_KEY_ENTRIES: ConnectorCatalogEntry[] = [
description: "OpenAI Responses + Chat Completions endpoints. GPT-5 family and Codex deployments.", description: "OpenAI Responses + Chat Completions endpoints. GPT-5 family and Codex deployments.",
defaultModel: "gpt-5.4", defaultModel: "gpt-5.4",
auth: { type: "api_key", envKey: "OPENAI_API_KEY" }, auth: { type: "api_key", envKey: "OPENAI_API_KEY" },
onboardingFeatured: true, onboardingFeatured: false,
}, },
{ {
id: "google", id: "google",
@@ -233,6 +233,7 @@ const API_KEY_ENTRIES: ConnectorCatalogEntry[] = [
}, },
{ {
id: "fireworks-firepass", id: "fireworks-firepass",
onboardingFeatured: true,
provider: "fireworks-firepass", provider: "fireworks-firepass",
label: "Fireworks Fire Pass", label: "Fireworks Fire Pass",
description: "Fireworks Fire Pass — subscription bundle. Same FIREWORKS_API_KEY.", description: "Fireworks Fire Pass — subscription bundle. Same FIREWORKS_API_KEY.",
@@ -250,7 +251,6 @@ const CLOUD_ENTRIES: ConnectorCatalogEntry[] = [
description: "Anthropic, Amazon Nova, and Llama models served through AWS Bedrock.", description: "Anthropic, Amazon Nova, and Llama models served through AWS Bedrock.",
defaultModel: "us.anthropic.claude-sonnet-4-20250514-v1:0", defaultModel: "us.anthropic.claude-sonnet-4-20250514-v1:0",
auth: { type: "aws" }, auth: { type: "aws" },
onboardingFeatured: true,
notes: "Honours standard AWS credential discovery. Region defaults to us-east-1.", notes: "Honours standard AWS credential discovery. Region defaults to us-east-1.",
}, },
{ {
@@ -28,10 +28,10 @@ describe("Step 2: CEO phased prompts", () => {
// shows the hire POST curl up front, and reaches for the // shows the hire POST curl up front, and reaches for the
// server-enforced STRATEGY_BEFORE_HIRES / STRATEGY_ALREADY_FILED // server-enforced STRATEGY_BEFORE_HIRES / STRATEGY_ALREADY_FILED
// codes instead of prose ordering directives. // codes instead of prose ordering directives.
expect(prompt).toContain("file 3–5 `hire_agent` requests"); expect(prompt).toContain("file 3–5 `hire_agent` tool calls");
expect(prompt).toContain("Do this first — file the hires"); expect(prompt).toContain("Do this first — file the hires");
expect(prompt).toContain("STRATEGY_BEFORE_HIRES"); expect(prompt).toContain("file_approval.strategy.before_hires");
expect(prompt).toContain("STRATEGY_ALREADY_FILED"); expect(prompt).toContain("file_approval.strategy.already_filed");
expect(prompt).not.toContain("Awaiting Org Strategy Approval"); expect(prompt).not.toContain("Awaiting Org Strategy Approval");
expect(prompt).not.toContain("Goal Decomposition"); expect(prompt).not.toContain("Goal Decomposition");
}); });
@@ -174,7 +174,7 @@ describe("work_products archived visibility", () => {
expect( expect(
harness.db.documentsMod.resolveWorkProductTarget(id, harness.companyId), harness.db.documentsMod.resolveWorkProductTarget(id, harness.companyId),
).toBeNull(); ).toMatchObject({ kind: "error", reason: "archived" });
} finally { } finally {
harness.db.close(); harness.db.close();
} }
@@ -236,7 +236,7 @@ describe("work_products bulk retirement", () => {
expect(second).toHaveLength(0); expect(second).toHaveLength(0);
expect( expect(
harness.db.documentsMod.resolveWorkProductTarget(id, harness.companyId), harness.db.documentsMod.resolveWorkProductTarget(id, harness.companyId),
).toBeNull(); ).toMatchObject({ kind: "error", reason: "archived" });
} finally { } finally {
harness.db.close(); harness.db.close();
} }
@@ -278,7 +278,7 @@ describe("work_products bulk retirement", () => {
expect( expect(
harness.db.documentsMod.resolveWorkProductTarget(workProductId, harness.companyId), harness.db.documentsMod.resolveWorkProductTarget(workProductId, harness.companyId),
).toBeNull(); ).toMatchObject({ kind: "error", reason: "archived" });
} finally { } finally {
harness.db.close(); harness.db.close();
} }