Package release 0.4.170 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:
1 parent
aba2dac3c5
commit
d543c19aae
4 files changed
+118
-7
No files matched your search
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "agent-company",
|
"name": "agent-company",
|
||||||
"version": "0.4.167",
|
"version": "0.4.170",
|
||||||
"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.",
|
||||||
|
|||||||
@@ -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();
|
||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user