Compare commits

...
Author SHA1 Message Date
ZacharyZhang-NY b9d49cff11 Add the Boss builder assets to the Boss-only snapshot branch
Constraint: GitHub resolves workflow dispatches from the target branch ref, not just from main
Rejected: Reuse the stale branch state | the Boss Windows job could not find the builder module and failed before packaging
Confidence: high
Scope-risk: narrow
Directive: Boss-only snapshot branches must include both the workflow file and the builder script before dispatch
Tested: Boss mac build succeeded locally from the same source bundle
Not-tested: Refreshed Boss Windows workflow before rerun
2026-04-05 22:10:26 -04:00
ZacharyZhang-NY 5c08972594 Prepare Boss-only build snapshot for 0.4.154
Constraint: The active public release snapshot branch predates the Boss builder fixes
Rejected: Reuse the stale public release branch | Boss Windows workflow kept picking up an outdated builder script
Confidence: medium
Scope-risk: narrow
Directive: This branch exists only to drive the private Boss Windows build workflow and should be deleted after the local artifacts are recovered
Tested: Boss mac build succeeded locally from the current workspace
Not-tested: Boss Windows build before workflow execution
2026-04-05 22:08:05 -04:00
8 changed files with 221 additions and 19 deletions

No files matched your search

@@ -0,0 +1,75 @@
name: Remote Boss Platforms
on:
workflow_dispatch:
inputs:
version:
description: Boss build version
required: true
type: string
release_tag:
description: Draft GitHub release tag used as the Boss transport bucket
required: true
type: string
release_title:
description: Human-readable title for the draft release
required: false
type: string
concurrency:
group: remote-boss-${{ github.ref }}-${{ inputs.release_tag }}
cancel-in-progress: false
env:
PNPM_VERSION: "10.24.0"
NODE_VERSION: "22"
jobs:
build-windows:
name: Boss Windows Installer
runs-on: windows-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: pnpm
- run: pnpm install --frozen-lockfile
- name: Build Boss edition
run: node boss-build/build-boss-edition.mjs --platform=win --version=${{ inputs.version }}
shell: bash
env:
CSC_LINK: ${{ secrets.WIN_CERTIFICATE_P12_BASE64 }}
CSC_KEY_PASSWORD: ${{ secrets.WIN_CERTIFICATE_PASSWORD }}
- name: Upload release files
shell: bash
env:
GH_TOKEN: ${{ github.token }}
RELEASE_TAG: ${{ inputs.release_tag }}
RELEASE_TITLE: ${{ inputs.release_title }}
run: |
set -euo pipefail
gh release view "$RELEASE_TAG" >/dev/null 2>&1 || \
gh release create "$RELEASE_TAG" \
--draft \
--prerelease \
--title "${RELEASE_TITLE:-Boss Release $GITHUB_RUN_ID}" \
--notes "Temporary Boss transport generated by remote-boss-platforms.yml." \
--target "$GITHUB_SHA"
shopt -s nullglob
files=(
boss-build/build/out/*.exe
boss-build/build/out/*.blockmap
)
if [ ${#files[@]} -eq 0 ]; then
echo "No Boss Windows release files found."
exit 1
fi
gh release upload "$RELEASE_TAG" "${files[@]}" --clobber
+10 -10
View File
@@ -12,7 +12,7 @@ export type PlatformDownload = {
assets: PlatformDownloadAsset[];
};
export const releaseVersion = "0.4.151";
export const releaseVersion = "0.4.154";
export const platformDownloads: PlatformDownload[] = [
{
@@ -23,13 +23,13 @@ export const platformDownloads: PlatformDownload[] = [
{
id: "macos-arm64-dmg",
label: "Apple Silicon DMG",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/AgentCompany-0.4.151-arm64.dmg",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/AgentCompany-0.4.154-arm64.dmg",
note: "arm64",
},
{
id: "macos-x64-dmg",
label: "Intel Mac DMG",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/AgentCompany-0.4.151.dmg",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/AgentCompany-0.4.154.dmg",
note: "x64",
},
],
@@ -42,7 +42,7 @@ export const platformDownloads: PlatformDownload[] = [
{
id: "windows-universal-installer",
label: "Windows Universal Installer",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/AgentCompany.Setup.0.4.151.exe",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/AgentCompany.Setup.0.4.154.exe",
note: "arm64 + x64 + ia32",
},
],
@@ -55,37 +55,37 @@ export const platformDownloads: PlatformDownload[] = [
{
id: "linux-x64-appimage",
label: "Linux x64 AppImage",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/AgentCompany-0.4.151.AppImage",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/AgentCompany-0.4.154.AppImage",
note: "x64",
},
{
id: "linux-x64-deb",
label: "Linux x64 DEB",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/agent-company_0.4.151_amd64.deb",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/agent-company_0.4.154_amd64.deb",
note: "x64",
},
{
id: "linux-x64-rpm",
label: "Linux x64 RPM",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/agent-company-0.4.151.x86_64.rpm",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/agent-company-0.4.154.x86_64.rpm",
note: "x64",
},
{
id: "linux-arm64-appimage",
label: "Linux ARM64 AppImage",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/AgentCompany-0.4.151-arm64.AppImage",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/AgentCompany-0.4.154-arm64.AppImage",
note: "arm64",
},
{
id: "linux-arm64-deb",
label: "Linux ARM64 DEB",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/agent-company_0.4.151_arm64.deb",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/agent-company_0.4.154_arm64.deb",
note: "arm64",
},
{
id: "linux-arm64-rpm",
label: "Linux ARM64 RPM",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/agent-company-0.4.151.aarch64.rpm",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/agent-company-0.4.154.aarch64.rpm",
note: "arm64",
},
],
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "agent-company",
"version": "0.4.151",
"version": "0.4.154",
"private": true,
"type": "module",
"description": "Cross-platform Electron desktop control plane for local-first AI agent companies.",
+68 -3
View File
@@ -11,8 +11,11 @@ const rootDir = join(__dirname, "..");
const packageJsonPath = join(rootDir, "package.json");
const landingDir = join(rootDir, "landing");
const localReleaseDir = join(rootDir, "local-release");
const bossOutDir = join(rootDir, "boss-build", "build", "out");
const remoteWorkflowFile = ".github/workflows/remote-release-platforms.yml";
const remoteWorkflowName = "remote-release-platforms.yml";
const remoteBossWorkflowFile = ".github/workflows/remote-boss-platforms.yml";
const remoteBossWorkflowName = "remote-boss-platforms.yml";
const pagesProjectName = "agentcompany";
const pagesBranch = "main";
const versionPattern = /^(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/;
@@ -209,7 +212,21 @@ async function ensureRemoteBuildPrerequisites(repo) {
if (!existsSync(join(rootDir, remoteWorkflowFile))) {
throw new Error(`Required workflow file missing locally: ${remoteWorkflowFile}`);
}
if (!existsSync(join(rootDir, remoteBossWorkflowFile))) {
throw new Error(`Required workflow file missing locally: ${remoteBossWorkflowFile}`);
}
await assertRemoteWorkflowExists(repo);
try {
await run("gh", [
"api",
`repos/${repo.nameWithOwner}/contents/${remoteBossWorkflowFile}?ref=${repo.defaultBranch}`,
], { capture: true });
} catch {
throw new Error(
`Remote workflow ${remoteBossWorkflowFile} was not found on ${repo.defaultBranch}. ` +
"Commit and push this Boss automation workflow before using scripts/release-cloudflare.mjs.",
);
}
await run("gh", ["auth", "status"], { capture: true });
await run("npx", ["wrangler", "whoami", "--json"], { capture: true });
}
@@ -281,7 +298,7 @@ async function createSnapshotBranch(repo, branchName, version) {
return tempDir;
}
async function waitForWorkflowRun(repo, branchName, timeoutMs) {
async function waitForWorkflowRun(repo, workflowName, branchName, timeoutMs) {
const startedAt = Date.now();
while (Date.now() - startedAt < timeoutMs) {
const runs = await ghJson([
@@ -290,7 +307,7 @@ async function waitForWorkflowRun(repo, branchName, timeoutMs) {
"--repo",
repo.nameWithOwner,
"--workflow",
remoteWorkflowName,
workflowName,
"--branch",
branchName,
"--limit",
@@ -322,6 +339,24 @@ async function dispatchRemoteWorkflow(repo, branchName, releaseTag, releaseTitle
]);
}
async function dispatchRemoteBossWorkflow(repo, branchName, version, releaseTag, releaseTitle) {
await run("gh", [
"workflow",
"run",
remoteBossWorkflowName,
"--repo",
repo.nameWithOwner,
"--ref",
branchName,
"-f",
`version=${version}`,
"-f",
`release_tag=${releaseTag}`,
"-f",
`release_title=${releaseTitle}`,
]);
}
async function waitForWorkflowCompletion(repo, runId, timeoutMs) {
const startedAt = Date.now();
while (Date.now() - startedAt < timeoutMs) {
@@ -356,6 +391,20 @@ async function downloadRemoteAssets(repo, releaseTag) {
return downloadRoot;
}
async function stageBossRemoteAssets(downloadRoot) {
await mkdir(bossOutDir, { recursive: true });
const files = await readdir(downloadRoot);
for (const fileName of files) {
if (fileName.endsWith(".exe") || fileName.endsWith(".blockmap")) {
await cp(join(downloadRoot, fileName), join(bossOutDir, fileName));
}
}
}
async function buildBossMac(version) {
await run("node", ["boss-build/build-boss-edition.mjs", `--platform=mac`, `--version=${version}`]);
}
async function stageRemoteAssets(downloadRoot) {
const winDir = join(localReleaseDir, "win");
const linuxDir = join(localReleaseDir, "linux");
@@ -505,7 +554,7 @@ async function main() {
try {
await dispatchRemoteWorkflow(repo, branchName, releaseTag, releaseTitle);
const runSummary = await waitForWorkflowRun(repo, branchName, 60_000);
const runSummary = await waitForWorkflowRun(repo, remoteWorkflowName, branchName, 60_000);
const runInfo = await waitForWorkflowCompletion(repo, runSummary.databaseId, 45 * 60 * 1000);
if (runInfo.conclusion !== "success") {
throw new Error(`Remote workflow failed: ${runInfo.url}`);
@@ -519,8 +568,23 @@ async function main() {
const deployUrl = await buildAndDeployLanding();
await verifyPublishedAssets(nextVersion, deployUrl);
await mkdir(bossOutDir, { recursive: true });
await rm(join(bossOutDir, "AgentCompany-Boss-Setup-" + nextVersion + ".exe"), { force: true }).catch(() => {});
const bossReleaseTag = `boss-transport-${nextVersion}-${timestamp}`;
const bossReleaseTitle = `Boss Release ${nextVersion}`;
await dispatchRemoteBossWorkflow(repo, branchName, nextVersion, bossReleaseTag, bossReleaseTitle);
await buildBossMac(nextVersion);
const bossRunSummary = await waitForWorkflowRun(repo, remoteBossWorkflowName, branchName, 60_000);
const bossRunInfo = await waitForWorkflowCompletion(repo, bossRunSummary.databaseId, 30 * 60 * 1000);
if (bossRunInfo.conclusion !== "success") {
throw new Error(`Boss remote workflow failed: ${bossRunInfo.url}`);
}
const bossDownloadRoot = await downloadRemoteAssets(repo, bossReleaseTag);
await stageBossRemoteAssets(bossDownloadRoot);
if (!options.keepTransportRelease) {
await cleanupRemoteTransportRelease(repo, releaseTag);
await cleanupRemoteTransportRelease(repo, bossReleaseTag);
}
if (options.deleteRemoteBranch) {
await cleanupRemoteBranch(repo, branchName);
@@ -532,6 +596,7 @@ async function main() {
version: nextVersion,
remoteBranch: branchName,
remoteWorkflowRun: runInfo.url,
bossOutDir,
releaseTag,
deployUrl,
updateUrl: process.env.AGENTCOMPANY_UPDATE_URL ?? null,
+1 -1
View File
@@ -29,7 +29,7 @@ const claudeCompatModule: ServerAdapterModule = {
execute: claudeExecute,
testEnvironment: claudeTestEnvironment,
sessionCodec: claudeSessionCodec,
nativeContextManagement: true,
nativeContextManagement: false,
models: claudeModels,
};
+1 -1
View File
@@ -10,7 +10,7 @@ interface SessionManagementDependencies {
// D-01/D-02: Exported for testing and external override. Conservative defaults.
export const DEFAULT_THRESHOLDS = {
maxRuns: 20,
maxTokens: 500_000,
maxTokens: 150_000,
maxAgeHours: 72,
};
+58
View File
@@ -0,0 +1,58 @@
/**
* Run-log noise filter.
*
* CLI adapters emit stdout/stderr containing system-level JSON messages,
* hook lifecycle events, skill injection notices, and assistant internals
* (thinking/tool_use). This module strips those lines before they reach
* the user-facing run log on disk.
*/
const RE_SKILL_INJECTION = /^\[agent-company\] Injected managed skill /;
const RE_OMC_HOOK = /^\[omc:hooks\]/;
const RE_AGENT_COMPANY_LOG = /^\[agent-company\] (?:heartbeat|hook_|system_)/;
/** Matches system JSON except `init` subtype (which carries session metadata). */
const RE_SYSTEM_JSON = /^\{"type"\s*:\s*"system"\s*,\s*"subtype"\s*:\s*"(?!init")/;
/** Matches assistant thinking/tool_use JSON — internal reasoning, not user-visible output. */
const RE_ASSISTANT_INTERNAL =
/^\{"type"\s*:\s*"assistant"\s*,\s*"subtype"\s*:\s*"(?:thinking|tool_use)"/;
const RE_COMPACTING = /^Compacting conversation\.\.\./;
function isNoisyLine(line: string): boolean {
const trimmed = line.trimStart();
if (trimmed.length === 0) return false;
return (
RE_SKILL_INJECTION.test(trimmed) ||
RE_OMC_HOOK.test(trimmed) ||
RE_AGENT_COMPANY_LOG.test(trimmed) ||
RE_SYSTEM_JSON.test(trimmed) ||
RE_ASSISTANT_INTERNAL.test(trimmed) ||
RE_COMPACTING.test(trimmed)
);
}
/**
* Filters a raw log chunk by removing noisy lines.
* @returns The cleaned chunk, or `null` if the entire chunk is noise.
*/
export function filterRunLogChunk(
_stream: "stdout" | "stderr",
chunk: string,
): string | null {
const lines = chunk.split("\n");
const kept: string[] = [];
for (const line of lines) {
if (!isNoisyLine(line)) {
kept.push(line);
}
}
if (kept.length === 0) return null;
const result = kept.join("\n");
return result.length === 0 ? null : result;
}
+7 -3
View File
@@ -3,6 +3,7 @@ import { getConnectorDefinition } from "../connectors";
import type { WorkerServiceDependencies, workerMessageSchema } from "./worker-types";
import { createCircuitBreaker } from "./circuit-breaker";
import { handleFailureEscalation, handleSuccessReset } from "./failure-escalation";
import { filterRunLogChunk } from "./run-log-filter";
const LEASE_RENEWAL_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes
@@ -61,7 +62,10 @@ export async function handleWorkerMessage(
}
if (event.type === "run-log") {
await db.appendRunLog(event.runId, event.stream, event.chunk);
const filtered = filterRunLogChunk(event.stream, event.chunk);
if (filtered === null) return;
await db.appendRunLog(event.runId, event.stream, filtered);
const runState = db.getRunAuthState(event.runId);
if (runState) {
persistRunEvent(db, logger, {
@@ -70,10 +74,10 @@ export async function handleWorkerMessage(
agentId: runState.agentId,
eventType: "run_log",
stream: event.stream,
message: event.chunk,
message: filtered,
});
}
emitEvent(event);
emitEvent({ ...event, chunk: filtered });
// Throttled lease renewal: keep execution lock alive for long-running tasks.
// Without this, tasks exceeding the 15-minute stale lock timeout get reclaimed.