Initialize project and ignore local references

This commit is contained in:
ZacharyZhang-NY committed 2026-03-15 22:17:07 -04:00
1 parent a11ac3eaba
commit 2af82b6bb3
132 files changed
+29426

No files matched your search

+53
View File
@@ -0,0 +1,53 @@
import { spawn } from "node:child_process";
const extraArgs = process.argv.slice(2);
const env = { ...process.env };
if (env.CSC_IDENTITY_AUTO_DISCOVERY === undefined) {
env.CSC_IDENTITY_AUTO_DISCOVERY = "false";
}
const allowedPublishModes = new Set(["always", "never", "onTag", "onTagOrDraft"]);
const explicitPublishArg = extraArgs.some((arg) => arg === "--publish" || arg.startsWith("--publish="));
const requestedPublishMode = env.AGENTCOMPANY_ELECTRON_PUBLISH?.trim();
let publishMode = "never";
if (requestedPublishMode) {
if (!allowedPublishModes.has(requestedPublishMode)) {
console.warn(
`[build-desktop] Ignoring invalid AGENTCOMPANY_ELECTRON_PUBLISH="${requestedPublishMode}". ` +
"Falling back to --publish never.",
);
} else {
publishMode = requestedPublishMode;
}
}
const builderArgs = ["exec", "electron-builder", "--config", "electron-builder.yml"];
if (!explicitPublishArg) {
builderArgs.push("--publish", publishMode);
}
builderArgs.push(...extraArgs);
const child = spawn(
"pnpm",
builderArgs,
{
stdio: "inherit",
env,
shell: process.platform === "win32",
},
);
child.on("exit", (code, signal) => {
if (signal) {
process.kill(process.pid, signal);
return;
}
process.exit(code ?? 1);
});
child.on("error", (error) => {
console.error(error);
process.exit(1);
});
+215
View File
@@ -0,0 +1,215 @@
#!/usr/bin/env python3
"""Generate AgentCompany app icons (PNG, ICO, ICNS, SVG).
Design v3b: Bold "A" monogram that doubles as an org-chart hierarchy.
Two terracotta legs meet at an apex, with three warm crossbars of
decreasing brightness (CEO → Managers → ICs). All tones stay warm.
"""
from __future__ import annotations
import math
import shutil
import subprocess
from pathlib import Path
from PIL import Image, ImageDraw, ImageFilter
ROOT = Path(__file__).resolve().parents[1]
ASSETS = ROOT / "assets"
ICONSET = ASSETS / "icon.iconset"
PNG_PATH = ASSETS / "icon.png"
ICO_PATH = ASSETS / "icon.ico"
ICNS_PATH = ASSETS / "icon.icns"
SVG_PATH = ASSETS / "icon.svg"
SIZE = 1024
# ── Brand palette ──────────────────────────────────────────────────────
TERRACOTTA = (217, 119, 69) # #d97745
SLATE_TOP = (17, 19, 21) # #111315
SLATE_BOT = (27, 31, 35) # #1b1f23
# Bar colours — all warm, decreasing brightness
BAR_CEO = (255, 235, 215) # warm cream — brightest
BAR_MGR = (235, 180, 140) # warm peach
BAR_IC = (190, 140, 105) # muted terracotta
def rgba(r: int, g: int, b: int, a: int = 255) -> tuple[int, int, int, int]:
return (r, g, b, a)
def blend(
a: tuple[int, ...], b: tuple[int, ...], t: float,
) -> tuple[int, ...]:
return tuple(int(a[i] + (b[i] - a[i]) * t) for i in range(len(a)))
def build_icon() -> Image.Image:
# ── 1. Gradient background with warm glow ──────────────────────────
bg = Image.new("RGBA", (SIZE, SIZE), (0, 0, 0, 0))
px = bg.load()
top_c = rgba(*SLATE_TOP)
bot_c = rgba(*SLATE_BOT)
glow_cx, glow_cy = SIZE * 0.44, SIZE * 0.34
glow_r = SIZE * 0.78
for y in range(SIZE):
t = y / (SIZE - 1)
base = blend(top_c, bot_c, t)
for x in range(SIZE):
d = math.hypot(x - glow_cx, y - glow_cy) / glow_r
warmth = max(0.0, 1.0 - d) ** 1.8 * 0.13
px[x, y] = blend(base, rgba(*TERRACOTTA), warmth)
# ── 2. Rounded-rect mask + shadow ──────────────────────────────────
icon = Image.new("RGBA", (SIZE, SIZE), (0, 0, 0, 0))
mask = Image.new("L", (SIZE, SIZE), 0)
inset = 64
ImageDraw.Draw(mask).rounded_rectangle(
(inset, inset, SIZE - inset, SIZE - inset), radius=224, fill=255,
)
shadow_alpha = mask.filter(ImageFilter.GaussianBlur(28))
shadow_layer = Image.new("RGBA", (SIZE, SIZE), (0, 0, 0, 48))
shadow_layer.putalpha(shadow_alpha)
icon.alpha_composite(shadow_layer, (0, 12))
icon.alpha_composite(bg)
icon.putalpha(mask)
# ── 3. Draw the "A" mark ───────────────────────────────────────────
overlay = Image.new("RGBA", (SIZE, SIZE), (0, 0, 0, 0))
draw = ImageDraw.Draw(overlay)
cx = SIZE // 2
apex_y = 200
base_y = 800
leg_w = 64
base_half = 250
def leg_x(y: int) -> tuple[float, float]:
t = (y - apex_y) / (base_y - apex_y)
spread = base_half * t
return (cx - spread, cx + spread)
ll_top, _ = leg_x(apex_y)
ll_bot, _ = leg_x(base_y)
_, lr_top = leg_x(apex_y)
_, lr_bot = leg_x(base_y)
left_leg = [
(ll_top - leg_w * 0.35, apex_y),
(ll_top + leg_w * 0.35, apex_y),
(ll_bot + leg_w, base_y),
(ll_bot - leg_w, base_y),
]
right_leg = [
(lr_top - leg_w * 0.35, apex_y),
(lr_top + leg_w * 0.35, apex_y),
(lr_bot + leg_w, base_y),
(lr_bot - leg_w, base_y),
]
draw.polygon(left_leg, fill=rgba(*TERRACOTTA, 240))
draw.polygon(right_leg, fill=rgba(*TERRACOTTA, 240))
# ── 4. Three crossbars — warm tones, hierarchy brightness ──────────
bar_h = 42
bar_r = 12
bar_pad = 14
tiers = [
(440, rgba(*BAR_CEO)),
(545, rgba(*BAR_MGR)),
(650, rgba(*BAR_IC)),
]
for bar_cy, fill in tiers:
left_cx, right_cx = leg_x(bar_cy)
bx0 = int(left_cx + bar_pad)
bx1 = int(right_cx - bar_pad)
draw.rounded_rectangle(
(bx0, bar_cy - bar_h // 2, bx1, bar_cy + bar_h // 2),
radius=bar_r,
fill=fill,
)
# ── 5. Apex beacon ─────────────────────────────────────────────────
dot_r = 20
dot_cy = apex_y - 2
draw.ellipse(
(cx - dot_r, dot_cy - dot_r, cx + dot_r, dot_cy + dot_r),
fill=rgba(*BAR_CEO),
)
icon.alpha_composite(overlay)
return icon
def save_svg() -> None:
svg = """\
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" fill="none">
<defs>
<linearGradient id="bg" x1="200" x2="824" y1="96" y2="928" gradientUnits="userSpaceOnUse">
<stop stop-color="#111315"/>
<stop offset="1" stop-color="#1b1f23"/>
</linearGradient>
<radialGradient id="glow" cx="0" cy="0" r="1"
gradientTransform="translate(450 348) rotate(36) scale(800)" gradientUnits="userSpaceOnUse">
<stop stop-color="#d97745" stop-opacity=".13"/>
<stop offset="1" stop-color="#d97745" stop-opacity="0"/>
</radialGradient>
</defs>
<rect width="896" height="896" x="64" y="64" rx="224" fill="url(#bg)"/>
<rect width="896" height="896" x="64" y="64" rx="224" fill="url(#glow)"/>
<polygon points="490,200 534,200 578,800 298,800" fill="#d97745" fill-opacity=".94"/>
<polygon points="490,200 534,200 726,800 446,800" fill="#d97745" fill-opacity=".94"/>
<rect x="400" y="419" width="224" height="42" rx="12" fill="#ffebd7"/>
<rect x="374" y="524" width="276" height="42" rx="12" fill="#ebb48c"/>
<rect x="348" y="629" width="328" height="42" rx="12" fill="#be8c69"/>
<circle cx="512" cy="198" r="20" fill="#ffebd7"/>
</svg>
"""
SVG_PATH.write_text(svg, encoding="utf-8")
def save_png_and_ico(image: Image.Image) -> None:
ASSETS.mkdir(parents=True, exist_ok=True)
image.save(PNG_PATH, format="PNG")
image.save(
ICO_PATH,
format="ICO",
sizes=[(16, 16), (24, 24), (32, 32), (48, 48), (64, 64), (128, 128), (256, 256)],
)
def save_icns(image: Image.Image) -> None:
if ICONSET.exists():
shutil.rmtree(ICONSET)
ICONSET.mkdir(parents=True, exist_ok=True)
for size in (16, 32, 64, 128, 256, 512):
image.resize((size, size), Image.Resampling.LANCZOS).save(
ICONSET / f"icon_{size}x{size}.png", format="PNG",
)
image.resize((size * 2, size * 2), Image.Resampling.LANCZOS).save(
ICONSET / f"icon_{size}x{size}@2x.png", format="PNG",
)
subprocess.run(
["iconutil", "-c", "icns", str(ICONSET), "-o", str(ICNS_PATH)],
check=True,
)
shutil.rmtree(ICONSET)
def main() -> None:
ASSETS.mkdir(parents=True, exist_ok=True)
save_svg()
image = build_icon()
save_png_and_ico(image)
save_icns(image)
print(f"Generated: {PNG_PATH}, {ICO_PATH}, {ICNS_PATH}, {SVG_PATH}")
if __name__ == "__main__":
main()
+34
View File
@@ -0,0 +1,34 @@
#!/bin/bash
# Patch the Electron.app bundle name so macOS shows "AgentCompany"
# in the dock and menu bar during development.
# This runs as a postinstall hook and is safe to re-run.
set -euo pipefail
APP_NAME="AgentCompany"
# Find the Electron.app Info.plist (works with pnpm hoisted or nested)
PLIST=$(find node_modules -path "*/electron/dist/Electron.app/Contents/Info.plist" -maxdepth 8 2>/dev/null | head -1)
if [ -z "$PLIST" ]; then
echo "[patch-electron-name] Electron.app not found, skipping."
exit 0
fi
# Also find helper plists
HELPERS_DIR=$(dirname "$PLIST")/../Frameworks
MAIN_PLIST="$PLIST"
echo "[patch-electron-name] Patching $MAIN_PLIST"
/usr/libexec/PlistBuddy -c "Set :CFBundleName $APP_NAME" "$MAIN_PLIST" 2>/dev/null || true
/usr/libexec/PlistBuddy -c "Set :CFBundleDisplayName $APP_NAME" "$MAIN_PLIST" 2>/dev/null || true
# Patch helper apps too (they show in Activity Monitor)
for HELPER in "$HELPERS_DIR"/Electron\ Helper*.app/Contents/Info.plist; do
if [ -f "$HELPER" ]; then
HELPER_NAME=$(basename "$(dirname "$(dirname "$HELPER")")" .app | sed "s/Electron Helper/$APP_NAME Helper/")
/usr/libexec/PlistBuddy -c "Set :CFBundleName $HELPER_NAME" "$HELPER" 2>/dev/null || true
fi
done
echo "[patch-electron-name] Done — dock and menu bar will show \"$APP_NAME\"."
+244
View File
@@ -0,0 +1,244 @@
/**
* Seed script: Create a multi-agent Research Company with 8 specialized roles.
*
* Usage: Run via the AgentCompany API after creating a company and workspace.
*
* Team Structure:
* ProjectManager (CEO — reports to Board)
* ├── WebResearcher (IC — primary data gathering)
* ├── DataAnalyst (IC — market data synthesis)
* ├── ReportArchitect (IC — report writing)
* ├── VisualDesigner (IC — presentation design)
* ├── FactChecker (IC — source verification)
* ├── EnterpriseArchitect (Manager — standards guardian)
* │ └── SecurityAuditor (IC — ethics & privacy)
* └── (all other ICs report to ProjectManager)
*/
interface AgentDefinition {
name: string;
role: string;
title: string;
capabilities: string;
reportsTo: string | null; // name of manager, null = CEO
connectorId: string;
budgetMonthlyUsd: number;
}
const RESEARCH_TEAM: AgentDefinition[] = [
{
name: "ProjectManager",
role: "Research Project Coordinator",
title: "CEO — Research Operations",
capabilities: [
"Review research brief/PRD first.",
"Define research objectives, target markets (geographic/demographic), and key questions to answer.",
"Create research timeline with milestones (data collection → analysis → report writing).",
"Ensure compliance with data privacy regulations (GDPR, CCPA) when collecting public data.",
"Define deliverable formats (PDF report, presentation deck, raw data spreadsheet).",
"Set authority thresholds (peer-reviewed only, or include industry reports).",
"Tools: File system, Documentation viewer, Project management board.",
].join(" "),
reportsTo: null, // Top-level executive
connectorId: "claude_local",
budgetMonthlyUsd: 500,
},
{
name: "WebResearcher",
role: "Agent Browser Research Specialist",
title: "Senior Research Analyst",
capabilities: [
"PRIMARY DATA GATHERING ROLE.",
"Use Agent Browser extensively to gather market data.",
"Research competitor websites (feature comparison, pricing pages, positioning statements).",
"Search industry reports (Gartner, McKinsey, Statista, IBISWorld).",
"Scrape public financial data (earnings reports, SEC 10-K filings, Crunchbase funding data).",
"Research social media sentiment (Reddit discussions, LinkedIn professional opinions, Twitter/X trends).",
"Find authoritative sources only (.edu, .gov, established publications like WSJ, Reuters).",
"Archive all sources with URLs, access dates, and credibility ratings.",
"Use advanced search operators (site:, filetype:, intitle:) for precision.",
"Never paywall-bypass illegally.",
"Tools: Agent Browser, Web scraper (legal/ethical only), Documentation library, Archive.org.",
].join(" "),
reportsTo: "ProjectManager",
connectorId: "claude_local",
budgetMonthlyUsd: 300,
},
{
name: "DataAnalyst",
role: "Market Data Synthesizer",
title: "Senior Data Analyst",
capabilities: [
"Structure collected data into analytical frameworks (SWOT analysis, Porter's Five Forces, TAM/SAM/SOM market sizing).",
"Create comparison matrices for competitor analysis (features, pricing, market share).",
"Normalize pricing data across different currencies and regions (PPP adjustment).",
"Identify market trends and patterns using statistical methods.",
"Verify statistical significance of findings (sample sizes, confidence intervals).",
"Create data visualizations (Matplotlib/Seaborn charts, Tableau dashboards) from research findings.",
"Flag data gaps and limitations.",
"Tools: Spreadsheet (Excel/Google Sheets), Data visualization tools, Python (Pandas, Jupyter), Statistical calculator.",
].join(" "),
reportsTo: "ProjectManager",
connectorId: "codex_local",
budgetMonthlyUsd: 250,
},
{
name: "ReportArchitect",
role: "Research Report Engineer",
title: "Lead Technical Writer",
capabilities: [
"Write comprehensive research reports with clear structure: Executive Summary, Methodology, Key Findings, Competitive Landscape, Market Trends, Risk Analysis, and Strategic Recommendations.",
"Ensure actionable insights (not just data dumping).",
"Write for specific target audience (C-suite executives need high-level strategy, Product Managers need feature comparisons).",
"Maintain consistent citation style throughout (APA 7th edition recommended).",
"Include appendices for raw data and detailed methodology.",
"Tools: Document editor (Word/Google Docs), Markdown, Citation manager (Zotero/Mendeley).",
].join(" "),
reportsTo: "ProjectManager",
connectorId: "claude_local",
budgetMonthlyUsd: 200,
},
{
name: "VisualDesigner",
role: "Research Presentation Designer",
title: "Visual Design Specialist",
capabilities: [
"Design professional layouts for research deliverables.",
"Create color-coded competitive landscapes (perceptual maps, magic quadrants).",
"Design infographics for key statistics and trends.",
"Ensure brand consistency in all materials (client fonts, colors, logos).",
"Create presentation templates (PowerPoint/Google Slides) with master slides.",
"Optimize layouts for readability and visual hierarchy (information density management).",
"Ensure accessibility in charts (colorblind-friendly palettes, alt text).",
"Tools: Design software (Figma/Adobe Illustrator), Presentation tools (PowerPoint/Keynote), Image preview.",
].join(" "),
reportsTo: "ProjectManager",
connectorId: "gemini_local",
budgetMonthlyUsd: 200,
},
{
name: "FactChecker",
role: "Source Verification Specialist",
title: "Research Integrity Analyst",
capabilities: [
"Verify all statistics and claims against original primary sources (not secondary citations).",
"Check for outdated information (ensure market data is < 2 years old unless historical trend analysis).",
"Identify potential biases in sources (vendor-funded research, self-reported data).",
"Cross-reference competitor claims with independent third-party validation.",
"Ensure all images/charts have proper attribution and licensing.",
"Verify calculation accuracy in market sizing (TAM calculations, CAGR formulas).",
"Flag uncertain or questionable data with confidence ratings.",
"Tools: Agent Browser (re-verification), Documentation library, Archive.org (historical verification).",
].join(" "),
reportsTo: "ProjectManager",
connectorId: "claude_local",
budgetMonthlyUsd: 150,
},
{
name: "EnterpriseArchitect",
role: "Research Standards Guardian",
title: "Head of Research Integrity",
capabilities: [
"ENFORCE RESEARCH INTEGRITY STANDARDS:",
"NO plagiarism — all content must be original synthesis or properly cited with quotation marks for direct quotes.",
"NO unsupported claims — every statistic needs inline citation (Author, Year) or footnote.",
"File naming convention: YYYY-MM-DD_Topic_Source_Description.pdf.",
"Variable naming in datasets: descriptive snake_case (market_share_percent_2024 not ms24).",
"NO circular reporting — Wikipedia cannot cite itself, avoid tertiary sources citing each other.",
"Primary sources preferred over secondary (SEC filings > News articles about filings).",
"Methodology section must be explicit about data collection methods and limitations.",
"NO speculation presented as fact — clearly distinguish between 'Data shows X' and 'Analyst suggests Y might happen'.",
"Conflict of interest disclosure mandatory (funded by industry player vs independent).",
"Tools: Plagiarism checker (Turnitin/Copyscape), Document editor, Reference manager.",
].join(" "),
reportsTo: "ProjectManager",
connectorId: "claude_local",
budgetMonthlyUsd: 200,
},
{
name: "SecurityAuditor",
role: "Research Ethics & Privacy Auditor",
title: "Privacy & Compliance Officer",
capabilities: [
"Final audit before delivery:",
"Verify no private/personal data (PII) was collected without consent (check datasets for names, emails, phone numbers scraped from social media).",
"Ensure no proprietary/trade secret information was accessed inappropriately (no hacked data, no insider leaks).",
"Check for defamatory content about competitors (stick to verified facts, no opinion-as-fact).",
"Verify licensing of third-party images/data (Creative Commons attribution, Fair Use justification documented).",
"Ensure confidential client information is redacted if sample reports contain examples.",
"Check that web scraping complied with robots.txt and Terms of Service (rate limiting respected).",
"Tools: Privacy scanner (PII detection), Document review, Legal compliance checklist.",
].join(" "),
reportsTo: "EnterpriseArchitect",
connectorId: "claude_local",
budgetMonthlyUsd: 150,
},
];
/**
* Generate curl commands to seed the research team via the AgentCompany API.
* Replace $API_URL, $API_KEY, $COMPANY_ID, and $WORKSPACE_ID with real values.
*/
function generateSetupCommands(): string {
const lines: string[] = [
"#!/bin/bash",
"# Research Company Multi-Agent Team Setup",
"# Prerequisites:",
"# 1. AgentCompany desktop running with a company and workspace created",
"# 2. At least one connector (claude_local) in 'ready' status",
"# 3. Set these variables:",
"",
'API_URL="${AGENT_COMPANY_API_URL:-http://127.0.0.1:3456}"',
'API_KEY="${AGENT_COMPANY_API_KEY}"',
'COMPANY_ID="${AGENT_COMPANY_COMPANY_ID}"',
'WORKSPACE_ID="${AGENT_COMPANY_WORKSPACE_ID}"',
"",
];
// Create agents in order (CEO first, then reports)
const agentVarMap = new Map<string, string>();
for (const agent of RESEARCH_TEAM) {
const varName = agent.name.toUpperCase() + "_ID";
const reportsToVar = agent.reportsTo
? agentVarMap.get(agent.reportsTo) ?? "null"
: "null";
agentVarMap.set(agent.name, `$${varName}`);
lines.push(`# Create ${agent.name} — ${agent.role}`);
lines.push(`${varName}=$(curl -s -X POST "$API_URL/api/companies/$COMPANY_ID/agents" \\`);
lines.push(` -H "Authorization: Bearer $API_KEY" \\`);
lines.push(` -H "Content-Type: application/json" \\`);
lines.push(` -d '{`);
lines.push(` "name": "${agent.name}",`);
lines.push(` "role": "${agent.role}",`);
lines.push(` "title": "${agent.title}",`);
lines.push(` "connectorId": "${agent.connectorId}",`);
lines.push(` "workspaceId": "'$WORKSPACE_ID'",`);
lines.push(` "capabilities": ${JSON.stringify(agent.capabilities)},`);
lines.push(` "budgetMonthlyUsd": ${agent.budgetMonthlyUsd}${agent.reportsTo ? `,\n "reportsTo": "'${reportsToVar}'"` : ""}`);
lines.push(` }' | jq -r '.agentId // .id')`);
lines.push(`echo "Created ${agent.name}: $${varName}"`);
lines.push("");
}
return lines.join("\n");
}
// Export for use in tests or scripts
export { RESEARCH_TEAM, type AgentDefinition };
// Print setup commands when run directly
if (typeof process !== "undefined" && process.argv[1]?.includes("seed-research-team")) {
console.log(generateSetupCommands());
console.log("\n# Team Structure:");
console.log("# ProjectManager (CEO)");
console.log("# ├── WebResearcher (IC)");
console.log("# ├── DataAnalyst (IC)");
console.log("# ├── ReportArchitect (IC)");
console.log("# ├── VisualDesigner (IC)");
console.log("# ├── FactChecker (IC)");
console.log("# └── EnterpriseArchitect (Manager)");
console.log("# └── SecurityAuditor (IC)");
}