Commit Graph
1210 Commits
Author SHA1 Message Date
ZacharyZhang-NY 1ea040c0f0 ci: move the release-installer build from Gitea back to GitHub Actions
GitHub-hosted windows-latest/macos-latest replace the self-hosted act_runner
pair; node 24 + corepack pnpm are set up explicitly (hosted images do not
preinstall pnpm), and assets attach via gh release upload --clobber instead
of the Gitea-API uploader script. macOS signing falls back to ad-hoc until a
Developer ID cert + APPLE_API_ISSUER secret are provisioned on GitHub.

Claude-Session: https://claude.ai/code/session_01A6RcwHhhsFYYrNdQB4ASuP
2026-09-01 01:10:07 -04:00
ZacharyZhang-NYandClaude Fable 5 e116e0efa3 CI: remove temporary runner smoke-test workflow
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 00:04:35 -04:00
ZacharyZhang-NYandClaude Fable 5 8a47bce6bd CI: build installers on release publish and attach them to the Gitea release
- .gitea/workflows/release-build.yml: on release published (plus a manual
  back-fill trigger), build the Windows NSIS installer and macOS dmg/zip
  (x64 + arm64) on the self-hosted runners and upload them to the release.
- scripts/ci/upload-release-assets.mjs: attaches release/ artifacts via the
  Gitea API; uploads first, then removes stale same-named assets.
- electron-builder.unsigned.yml: ad-hoc fallback config used while the mac
  runner has no Developer ID identity / notarization credentials.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 00:00:19 -04:00
ZacharyZhang-NYandClaude Fable 5 3536490d19 CI: add runner smoke-test workflow to probe Gitea runners
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-12 23:30:16 -04:00
ZacharyZhang-NY 7de378b41c A chat-wake reply is delivered by the system, not by prompt compliance
A wake run whose model answered in plain final text (the coding-tuned
Kimi family does this instead of calling send_message) completed
'successfully', closed its vehicle task, and left the founder staring
at a silent conversation — the reply lived only in provider_requests.
deliverChatReplyIfMissing now runs before a chat-wake run may complete:
when the run never posted into the source thread (run-start watermark,
so a send_message it did make suppresses the fallback), its final text
is delivered as the agent's reply. A delivery failure fails the run
loudly instead of closing it on silence.
2026-07-16 11:46:53 -04:00
ZacharyZhang-NY 75c73ce6f0 The founder probes through provider cooldowns; a served request lifts the park
A single transient failure from a background run used to silence the whole
company — founder included — for the full ten-minute cooldown. The
interactive lane now claims one probe per park window: the founder's
message tries the provider immediately, a success lifts the cooldown for
everyone (a served request is proof of health), and a failed probe re-arms
the park with the probe spent, so a real outage is never hammered.
Autonomous work still waits cooldowns out unconditionally.
2026-07-14 21:19:14 -04:00
ZacharyZhang-NY 9246e7e312 The founder gets a dedicated execution lane, not just queue priority
Claim priority alone still left the founder waiting behind whatever long
autonomous run held the single execution slot. The worker now runs two
slots: autonomous grinds the queue one run at a time as before, while
the interactive slot claims only human-triggered wakes and executes them
concurrently — a founder message answers in seconds regardless of what
the company is building in the background. Housekeeping (wake expiry,
goal reviews, heartbeat enqueue) now runs every tick instead of pausing
during long runs. Integration test pins the concurrency: the CEO's reply
lands while a gated autonomous run is still in flight.
2026-07-14 21:15:19 -04:00
ZacharyZhang-NY aa4cfc056d Human-triggered wakes claim before queued autonomous work
Wake runs stamp sourceSenderType into their secret scope, and the claim
query orders interactive-first: a wake born from an employee or board
message means a person is waiting at the keyboard, so it outranks any
autonomous backlog; within each lane FIFO holds. Non-chat runs carry no
stamp and stay in the autonomous lane. With wake expiry this closes the
live incident: the founder's CEO DM now claims on the next tick instead
of 13th in line. Red-green tested.
2026-07-14 20:46:51 -04:00
ZacharyZhang-NY 39aa292d09 Stale chat wakes expire instead of resuming days later
Live incident: the founder DMed the CEO and got silence — the reply run
sat 13th in a FIFO queue behind chat wakes from four days ago, which the
reopened app was faithfully executing (necro-replies that woke yet more
agents). A wake run is a conversation reply; past one hour the moment is
gone. expireStaleChatWakes (chat-agent-wake-service) fails queued
chat_mention runs older than the TTL and closes their vehicle tasks;
the worker tick runs it before claiming, with one log line. Real work
(heartbeat/kickoff triggers) never expires. Red-green tested.
2026-07-14 20:44:37 -04:00
ZacharyZhang-NY c7eafb2836 Founder-CEO chat round trip proven end to end; agents see the founder
loadChatContext labels human senders "[Name (founder)]" so a woken agent
knows it answers its boss, not a teammate. New integration test drives
the whole loop — founder DM wakes the CEO, the prompt names the founder,
the reply lands in the same pinned conversation and thread, the wake
task closes — and a Playwright spec pins the UI contract: badged CEO row
first, selected by default, message queues the wake run, channel recency
never displaces the pin. AGENTS.md documents the feature contracts.
2026-07-14 00:23:49 -04:00
ZacharyZhang-NY 3c44ff959d Messages pins the founder's CEO conversation at the top
buildConversations learns the org's CEO (c_suite, the runtime predicate)
and ranks the viewer's own direct conversation with them above recency —
counterpart resolution already works from the viewer's seat, so agent-to-
agent CEO chats never match. The row carries a CEO badge and, before the
first exchange, invites asking about progress, goals, or direction.
Being first, it is also the default conversation the page opens on.
2026-07-14 00:16:38 -04:00
ZacharyZhang-NY 4a7fac654e CEO can answer progress and rewrite goals from live data
Two c_suite tools in agent-goal-tools: company_status reports every goal
with real-work task counts (wake tasks and review checkpoints stay out),
work in flight, recent completions, and team headcount, so progress
answers come from the board instead of the model's memory; update_goal
rewrites an active goal's title/description when the founder redirects
the company, audited, CEO-or-owner gated. Both route through the sync
dispatcher; complete_goal now shares the same permission helper.
2026-07-14 00:13:08 -04:00
ZacharyZhang-NY 62ce1570cd Founder-CEO direct conversation is a structural invariant
Every org now keeps one direct chat between the primary employee and the
active c_suite agent: created at onboarding bootstrap (hard failure if
missing), repaired for existing orgs at startup. The existing
wakeDirectCounterparts path already wakes the CEO on every founder
message, so this space is the pinned "talk to your AI CEO" entry the
Messages page will surface next.
2026-07-14 00:07:30 -04:00
ZacharyZhang-NY 74195c6cdd Release 1.4.1 macOS: notarized DMGs uploaded, site links them, 1.4.0 DMGs retired from R2 2026-07-11 00:13:49 -04:00
ZacharyZhang-NY de0f28eb7c Release 1.4.1: Windows installer carries the streaming fix, site updated, 1.4.0 exe retired from R2
The 1.4.1 exe (signed, built-in skills verified incl. both humanizer
variants) is live at AC/AgentCompany-1.4.1-x64.exe; the download manifest
and site version track it, landing e2e green (12/12, PW_CHROME), Pages
deployed and probed end-to-end: /api/download 302s to 1.4.1, download-stats
healthy, superseded 1.4.0 exe deleted after verification. macOS DMGs stay
pinned at 1.4.0 until rebuilt on a mac.
2026-07-11 00:01:15 -04:00
ZacharyZhang-NY 0fa99d94a7 Chat-completions turns stream: reasoning models no longer die at the 60s header wall
Root cause of the stuck kimi-for-coding kickoff (task running forever, no
team spawning): runKimiCodeTurn posted stream:false, and a non-streaming
completion returns headers only after the whole generation — once the CEO's
context grew past ~150k chars, a reasoning turn needed >60s and provider-http's
header deadline aborted it ("Provider request timed out."), failing the run;
every heartbeat retry re-read the workspace, regrew the context, and died at
the same wall until the 3-run budget was gone.

Fix at the family level: accumulateChatStream (chat-format.ts) consumes the
standard OpenAI chunk deltas — content appends, indexed tool_call fragments,
reasoning_content keeping the 60s idle deadline fed — and a shared
runChatCompletionsStream drives makeChatCompletionsTurn (kimi, kimi-cn, xai,
groq, mistral, cerebras, openrouter) and runKimiCodeTurn.

Wire shape verified against MoonshotAI/kimi-cli (kosong streams by default)
and a live streamed probe of api.kimi.com/coding/v1 with the stored plan
credential: role opener, reasoning deltas, tool_call fragments (id+name then
argument text), finish_reason, [DONE] — all reassembled correctly.
verify:ci green including e2e.
2026-07-10 23:43:16 -04:00
ZacharyZhang-NY 3a7b267ead Update release-links.generated.ts 2026-07-10 23:39:12 -04:00
ZacharyZhang-NY 9f2c3fee29 Release 1.4.0: Windows installer rebuilt, site deployed, 1.3.0 exe and the 0.4.182 graveyard retired from R2
The 1.4.0 Windows build carries everything since 1.3.0: Kimi and Kimi CN as
OpenAI-compatible providers, Kimi Code plan sign-in via the official RFC 8628
device flow with token refresh, and official provider logos bundled into the
app for onboarding and Settings.

Shipping steps, each verified: unit suite green on the release tree -> signed
NSIS build (both humanizer skill variants bundled) -> uploaded to R2 and
probed 200 at full size (102,605,596 bytes) -> manifest bumped (Windows
v1.4.0; macOS stays on its live v1.3.0 DMGs) -> landing e2e 12/12 (PW_CHROME
fallback) -> Pages deployed -> production /api/download 302s to the 1.4.0 exe
and download-stats serves -> superseded 1.3.0 exe deleted (404 confirmed) ->
nine orphaned 0.4.182-era objects (installer, mac zips, blockmaps, stale
electron-updater latest*.yml) purged; publish: null means nothing consumes
them. Bucket now holds exactly the three assets the site links.
2026-07-10 23:12:21 -04:00
ZacharyZhang-NY a4021b2029 Every provider wears its official mark: logo.dev art downloaded once, bundled forever
- 16 brand PNGs land in src/renderer/src/assets/provider-logos (img.logo.dev, size 128, same publishable token as connectors) with a README recording each domain and the refresh command - no runtime fetch, nothing to download again
- shared/ProviderLogo.tsx maps catalog keys to the bundled art on a white tile (transparent marks stay legible in dark theme); custom endpoints keep the letter tile since no official brand exists
- Settings provider rows/cards and the onboarding provider step now share the same component; old letter-tile ProviderLogo removed
- Verified via Playwright screenshot captures: onboarding and Settings both render the real marks; full e2e green
2026-07-10 20:18:41 -04:00
ZacharyZhang-NY 177e25aab5 The Kimi family is visible end-to-end: e2e asserts onboarding and Settings, AGENTS.md learns the provider recipe
- desktop.spec.ts verifies Kimi / Kimi CN / Kimi Code cards in the onboarding provider step, the device-flow sign-in button on Kimi Code, and all three under Settings -> Providers
- AGENTS.md documents the catalog-driven provider architecture and the Kimi endpoints so the doc stays truthful
- Full gate green: typecheck, lint, unit (269), contract, integration, replay-eval, Playwright e2e (3)
2026-07-10 17:21:37 -04:00
ZacharyZhang-NY 327de38e78 Kimi Code joins as an OAuth plan provider: RFC 8628 device flow, verified against the live endpoints
- New oauth/kimi-code-flow.ts mirrors the official kimi-cli: form-encoded device_authorization + token polling at auth.kimi.com with the required X-Msh-* device headers, pure poll interpreter, 15-minute tokens refreshed via refresh_token grant
- Agent loop runs chat completions at https://api.kimi.com/coding/v1 with the Bearer access token; default model kimi-for-coding (kimi-for-coding-highspeed for Allegretto+ plans)
- Live model listing via /coding/v1/models; credential refresh wired into the turn credential resolver
- Migration 057 seeds the provider (disabled) into existing organizations
- Wire protocol probed live: device code issued, authorization_pending poll observed, 401 envelope on the coding API confirmed
2026-07-10 17:18:31 -04:00
ZacharyZhang-NY 813276de71 Kimi and Kimi CN join the provider catalog: OpenAI-compatible endpoints, verified live
- kimi -> https://api.moonshot.ai/v1 (platform.kimi.ai keys), kimi-cn -> https://api.moonshot.cn/v1 (platform.kimi.com keys)
- Adapters via openAiCompatibleAdapter; agent loop via makeChatCompletionsTurn; live model listing
- Curated fallback models per current docs: kimi-k2.7-code, kimi-k2.7-code-highspeed, kimi-k2.6
- Migration 056 seeds both providers (disabled) into existing organizations
- Both endpoints probed live: OpenAI-style 401 error envelope confirmed
2026-07-10 17:12:16 -04:00
ZacharyZhang-NY c30cbce459 update 2026-07-10 16:35:35 -04:00
ZacharyZhang-NY 9328eb22d9 Release 1.3.0 macOS: notarized DMGs uploaded, 1.2.0 retired from R2 2026-07-09 22:24:58 -04:00
ZacharyZhang-NY 09c69f0738 Release 1.3.0: Windows installer rebuilt, site updated, 1.2.0 exe retired
The 1.3.0 Windows build carries everything since 1.2.0: the self-healing
queue (transient provider failures park instead of killing tasks), the
chat-wake and task-done lifecycle contracts, the goal-review loop with
audited complete_goal, workspace execution tools (list/read/run) behind the
requires_filesystem grant, default web access (web_search/fetch_url with
SSRF guard) for every agent, and the board/shell UI fixes.

Shipping steps, each verified: verify:ci green -> signed NSIS build (both
humanizer skill variants bundled) -> uploaded to R2 and probed 200 at full
size -> manifest bumped (Windows v1.3.0; macOS stays on its live v1.2.0
DMGs, now labeled honestly) -> landing e2e 12/12 -> Pages deployed ->
production /api/download 302s to the 1.3.0 exe and download-stats serves ->
superseded 1.2.0 exe deleted from R2 (404 confirmed). Bucket holds exactly
one Windows build again.
2026-07-09 21:59:06 -04:00
ZacharyZhang-NY 64d4476f5a Five shell fixes: pinned Work header, honest close targets, a draggable sidebar top
- Work page is now a flush route: the title, project overview, and column
  headers stay put and each board column scrolls its own cards (List and
  Timeline scroll inside their own region). The page no longer scrolls its
  header away under 300 tasks.
- Team page drops the hiring-pipeline block (and its orphaned component and
  i18n key) — four columns of mostly-zero counters said nothing the roster
  doesn't.
- Clicking outside the search overlay closes it; the Close button stops
  being the only exit.
- The sidebar's top strip is a window drag region now (the topbar only
  covers the main pane). Interactive children opt out of dragging, and the
  org button shrinks to its content so the strip actually has drag area.
- The operator's name hugs their avatar in the sidebar foot: buttons
  center text by UA default and the flexed name span inherited it;
  text-align: left ends that.
2026-07-09 21:07:56 -04:00
ZacharyZhang-NY fb81505cb1 The board card says one thing: pills learn to stay in their box
Cards on the Work board overflowed their frame and shouted six facts at
once. Two root causes, both fixed at the source:

- Pills truncated by counting characters in JS (truncate(title, 18)) while
  the CSS said white-space: nowrap with no max-width — CJK glyphs are twice
  as wide, so 18 Chinese characters punched straight through the card edge.
  The Pill component now owns truncation: max-width + an inner .pill-text
  with a real ellipsis. Every pill in the app inherits the fix; the JS
  truncation helper is gone.
- The card repeated what every other card already said: identical goal,
  workspace, and (in the Done column) status pills on all 280 cards carried
  zero information. A card now states what is particular to it: a title
  clamped to three lines, the project, the run state while the task is
  live, the assignee, and the actions. Goal and workspace stay in the task
  detail dialog where they belong.
- Done cards are no longer struck through — a six-line Chinese title with a
  line through it reads as vandalism, not completion. Done cards just go
  quiet.

Verified visually against the rebuilt app's board screenshot; full suite
plus e2e green.
2026-07-09 20:59:41 -04:00
ZacharyZhang-NY 34ea33cb8d Goal completion is a claim, not a decision: the independent audit
Adopted from studying Claude Code's /goal (completion judged by a fresh
model, never the one doing the work) and pi-goal-x's auditor (isolated
session, read-only tools, explicit approval marker, rejects scaffold-only
and proxy-metric completions).

complete_goal no longer closes a goal on the caller's word:
- It now takes a required `evidence` claim, and permission/argument gates
  run before any audit spend.
- The audit is an isolated tool-turn loop: fresh conversation (the auditor
  never sees the executor's transcript), read-only workspace tools (no
  run_command), strict auditor instructions, at most 6 iterations.
- Only an explicit <approved/> closes the goal (recorded with the audit
  verdict). <disapproved/>, no marker, or an exhausted budget all leave the
  goal active and hand the decisive gap back to the caller as the tool
  result.
- The handler moved from the sync dispatcher into the run loop's async
  routing because it needs provider access; the goal-review prompt warns
  that substanceless claims will bounce.

AGENTS.md documents both this and the web-access contract.
2026-07-09 20:46:53 -04:00
ZacharyZhang-NY 80e70649c3 Every agent gets the live web: web_search and fetch_url by default
"Be ashamed to guess APIs blindly; be proud to look things up carefully" —
until now the agents had no way to look anything up: no search, no fetch,
so market research, API usage, and competitive claims were all invented
from model memory.

agent-web-tools.ts, carried by every agent in every run (same pattern as
the workspace tools, no grant needed):
- web_search: keyless DuckDuckGo HTML backend; parses titles, unwraps the
  /l/?uddg= redirect hrefs, pairs snippets; reports honestly when nothing
  parses instead of fabricating results. Verified against the live endpoint.
- fetch_url: readable-text extraction (dependency-free HTML-to-text with
  entity decoding), 20k-char page cap, 2MB body cap read in chunks, 30s
  timeout.
- SSRF guard on both: hostnames resolve before connecting and loopback,
  private, link-local, CGNAT, and reserved ranges are refused — re-checked
  on every redirect hop, so a public page cannot bounce the agent into
  127.0.0.1 or the cloud metadata address. IPv6 and v4-mapped forms covered.
- The fetcher is injectable, so the test suite covers the guard, redirect
  policy, truncation, extraction, and the DuckDuckGo parser without
  touching the network.
2026-07-09 20:42:12 -04:00
ZacharyZhang-NY 26de3129b1 Goals end at achieved, not at an empty board: the goal-review loop
The board draining to 280/280 done left the company idle under a
still-active goal, with 24 markdown files and zero code as its life's work.
Two structural gaps caused it: goals had no lifecycle (status was written
once as 'active' and never read again — nothing re-engages anyone when the
last task closes), and nothing anywhere distinguished plans from product,
so every "engineering" objective closed on documents.

The loop, closed:
- tasks.origin (migration 055) records provenance: chat_wake for mention
  vehicles (backfilled from their runs), goal_review for checkpoints, null
  for real work. Chatter and checkpoints can therefore never count as
  progress.
- spawnGoalReviews (each worker tick): an active goal with zero open tasks
  and real progress since the last review gets ONE review task for the goal
  owner. The review demands evidence — list the workspace, read the code,
  run the tests; documents are how work starts, not proof it happened — and
  must end in exactly one of: complete_goal, or the next wave of tasks with
  requires_filesystem engineering. A review closed with neither spawns
  nothing: termination is structural, not a counter.
- complete_goal (CEO or goal owner) finally lets someone say a goal is
  achieved, audited.
- CEO and department-head voices now state the doctrine: a goal that
  promises software closes on code that builds and passes tests in the
  workspace, and implementation is delegated with requires_filesystem: true.

On the live profile this arms one review: the active platform goal has 0
open tasks and 21 real completed ones, so the CEO gets the checkpoint on
next launch and the company starts building instead of stopping.
2026-07-09 20:29:42 -04:00
ZacharyZhang-NY 291816aa06 Give agents hands: workspace read/list/exec tools so engineers build instead of describing
Every "engineering" deliverable the company ever produced was a markdown
skeleton, because documentation was the ceiling of the toolset:
write_deliverable and create_document were the only artifact tools. An
engineer could not see the files that exist, read a line of code, or run a
single command — and create_task hardcoded requires_filesystem to false, so
the entire approval-gated read_write mount plumbing was dead code.

New workspace capability (agent-workspace-tools.ts):
- list_files / read_file: explore the bound workspace, traversal-guarded by
  the same resolveWorkspacePath used for writes, size- and count-capped.
- run_command: real shell execution with the workspace as cwd, 120s timeout,
  16k output cap. Gated on the task's approved filesystem grant — the same
  requires_filesystem flag that flips the mount to read_write and routes the
  task through operator approval (auto-approved only in AI-CEO mode, which
  is that mode's explicit contract).
- create_task now takes requires_filesystem, so the CEO and officers can
  delegate engineering work that is allowed to change code and run tests.
- Prompts brief every agent on the tools, and filesystem tasks state the
  bar directly: real output is code that builds and tests that pass — a
  document describing the work does not close an engineering task.

Tests: tool registry, dependency-folder-skipping listing, traversal refusal,
the run_command access gate plus exit-code reporting, and the create_task
approval path for filesystem work.
2026-07-09 19:23:28 -04:00
ZacharyZhang-NY 9c85b5ee3c A task is finished when it reaches done, not when a run ends
The two real goal tasks from July 9 each got exactly one session: the run
completed, the agent never moved the task off backlog, and the heartbeat's
"has a completed run" exclusion locked them out forever. The agents could
not have closed them anyway — update_task_status requires a task_id the
prompt never carried.

The progress contract, made explicit end to end:
- The task prompt now carries "Task id: ..." and tells the agent exactly how
  to end a session: done via update_task_status when the work is complete,
  in_progress with a note on what remains when it is not.
- The heartbeat re-enqueues any open task with no run in flight — a
  completed run that left its task open earns a follow-up session, with the
  prompt stating how many prior sessions were spent so the agent continues
  instead of redoing work. The retry budget (3 non-transient runs) still
  bounds every task; a task that spends it parks with one log line naming it.
- Scripted agents in the integration suites now close their tasks the way
  the contract expects real ones to.
2026-07-09 19:17:44 -04:00
ZacharyZhang-NY 2526633bfb Chat-wake tasks live and die with their reply run
Of the 202 tasks stranded in the backlog on July 9, 200 were "Reply to ..."
wake vehicles: every agent @mention creates a task plus a queued run, the
reply goes out, and nothing ever closed the task — a task with a completed
run is never enqueued again, so each one became a permanent zombie row. On
top of that, every message in an active thread minted a fresh wake even when
the target already had one queued, multiplying runs that would each read the
same conversation.

The lifecycle contract, made explicit:
- The reply run IS the wake task's deliverable. Completing a chat_mention
  run now closes its task (backlog/in_progress -> done, via the audited
  status path). Tasks an agent moved to review are left alone.
- One pending wake per (agent, thread): wakeFromMention returns the queued
  run instead of minting a duplicate — that run reads the thread's newest
  messages when it executes anyway.
- Migration 054 heals existing rows: wake tasks whose runs are all spent
  close as done; in-flight wakes keep working. This also stops Fix 1's
  retry-budget healing from resurrecting 31 stale replies on next launch.

The chat-governance loop test now completes each pending wake run between
posts, matching how the exchange actually interleaves in production.
2026-07-09 19:11:02 -04:00
ZacharyZhang-NY 927bdc91f2 Self-healing queue: transient provider failures park the provider, never burn retries
The July 9 run died at 07:22 when the GPT account hit its plan-side usage
limit: every later request failed with "The usage limit has been reached",
each failure counted against the 3-attempt retry budget, and 31 tasks were
abandoned for good while the worker kept hammering 12 doomed requests a
minute until the queue drained.

Root fix, three parts sharing one classifier:
- isTransientProviderFailure() in provider-runtime-domain recognises
  provider-side verdicts (usage limit, rate limit, 429, overloaded) plus the
  internal monthly-quota message; matching is against recorded
  task_runs.error_message rows, so historical damage heals retroactively.
- enqueueHeartbeatRuns computes the retry budget with that predicate instead
  of an exact match on the internal quota string alone.
- A transient failure parks the provider for a 10-minute cooldown: the
  heartbeat stops enqueuing its tasks and the worker leaves its queued runs
  unclaimed, then a single probe run re-arms or clears the park. Transitions
  are logged once each way.

Tests: predicate unit tests, budget-exemption regression on the raw provider
message, cooldown park/resume with an injected clock, claim exclusion.
2026-07-09 19:04:44 -04:00
ZacharyZhang-NY 4e11ca13ec update 2026-07-09 01:30:45 -04:00
ZacharyZhang-NY 0227d1f424 Release 1.2.0: rebuilt installer on R2, old build retired, site live
- Bump to 1.2.0 (language-aware humanizer house style with the bundled
  humanizer-zh skill, resizable chat split and composer, topbar pause
  toggle consistency)
- Packaged the NSIS installer with both humanizer variants verified in
  resources/built-in-skills; uploaded to AC/AgentCompany-1.2.0-x64.exe
  (public 200, byte-exact) and deleted the 1.1.0 build per the release
  cleanup rule (verified 404)
- Landing manifest points at 1.2.0; landing e2e green; deployed to
  Cloudflare Pages and verified live: page shows 1.2.0, tracked
  download 302s to the new installer, stats API healthy
2026-07-09 01:22:12 -04:00
ZacharyZhang-NY eaaf36f859 Language-aware house style and a resizable chat split
House style now follows the app language: Chinese UI forces the new
bundled humanizer-zh skill into every run, English forces humanizer -
one variant per run, picked by preference with cross-language fallback
so an older catalogue never silently loses house style. Both variants
are protected from grant/revoke, list_skills labels each with its
language, the bundle guard requires both, and startup sync imports the
new skill into existing orgs on next launch. Covered by a unit test
that flips app_state.language and asserts which humanizer compiles.

The chat split is now adjustable: drag the conversation list's right
edge (200-480px, persisted in localStorage) and the composer textarea
grew a native vertical resize grip capped at 40vh.
2026-07-09 01:14:05 -04:00
ZacharyZhang-NY c027508b97 Retire the 1.0.0 installer and take dead macOS links off the site
Deleting the old Windows build from R2 surfaced something worse: the
two macOS DMG links had no objects behind them at all - the mac builds
were never uploaded, so every mac download click has been a 404.

- R2 now holds exactly one desktop artifact: AC/AgentCompany-1.1.0-x64
  .exe (old exe deleted on operator instruction, verified 404)
- The release manifest drops the macOS entry with a comment explaining
  how it comes back (upload real DMGs first); footer mac links removed;
  hero reads "Available on Windows - macOS build coming soon"
- Root fix in platform-support: FAQ/JSON-LD copy now derives from
  whatever platforms the manifest actually ships instead of
  hard-requiring macos+windows, so the site structurally cannot
  advertise a platform without a real artifact behind it
- Landing e2e updated (>=1 tracked asset) and green; redeployed and
  verified live: no r2.dev leaks, no mac links, coming-soon copy shown,
  tracked download 302s to the 1.1.0 installer
2026-07-09 00:54:19 -04:00
ZacharyZhang-NY a489accc38 update 2026-07-09 00:39:48 -04:00
ZacharyZhang-NY 5aff9dd606 Make the pause toggle a standard topbar button
The pause control was a hand-rolled pill (999px radius, its own
padding and font size) sitting next to the standard "New task" button,
so the two never matched. It now renders as the shared .button class -
one source of truth for height, padding, and corner radius - with a
single amber modifier for the paused state. Verified side by side in
the captured Work-page screenshot.
2026-07-09 00:14:34 -04:00
ZacharyZhang-NY cb71afa6b7 Avatar photo uploads and a global handbrake for the agent engine
Two operator asks, one review gate:

Avatar portraits (migration 052): the avatar editor gains "Upload
photo" - the renderer downscales the chosen picture to a ~96px cover
crop and stores it as a small data URL (PNG keeps transparency, the
rest compresses to JPEG), so the snapshot stays light and the CSP needs
nothing new. The portrait wins over emoji and initials everywhere the
shared Avatar renders (chat, org chart, office card, sidebar), and
"Remove photo" falls back cleanly. The main process validates scheme
and size (base64 image data URL, <=300k chars) so a rogue caller cannot
re-bloat the snapshot. e2e uploads a real PNG through the profile
dialog and sees the portrait land in the sidebar.

Global pause (migration 053): when agents start talking in circles,
one topbar toggle - visible on every page - pulls the handbrake.
app_state.autorun_paused survives restarts; the queue worker checks it
each tick and neither enqueues nor claims while set (the run already in
flight finishes). Queued work simply waits and the paused state renders
as an amber "resume" pill. A unit test drives the real worker: paused
leaves a queued run untouched through many ticks, resuming claims it
within moments; e2e flips the toggle in the live shell.
2026-07-09 00:09:02 -04:00
ZacharyZhang-NY 78e88807da Give chat a real scroll contract: open at latest, stick, jump back
The conversation pane had no scroll management at all - it opened at
the top of history, ignored arriving messages, and offered no way back
down other than dragging through long replies.

- Opening a conversation lands on the newest message (the component is
  keyed by space, so mount = open)
- A reader at the bottom stays pinned as new messages arrive; a reader
  up in history is left undisturbed
- The moment the reader leaves the bottom, a floating "Jump to latest"
  pill appears above the composer; clicking it smooth-scrolls back and
  the pill hides itself again
- The scroll region is a proper role="log" landmark; e2e seeds a dozen
  multi-line messages over real IPC, scrolls to the top, and drives the
  pill's appear -> click -> return-to-bottom -> disappear cycle
2026-07-08 23:55:52 -04:00
ZacharyZhang-NY 9834714fa6 Renderer sweep round two: survive orphans, hiccups, and busy inboxes
The renderer half of the project review surfaced five real defects:

- One unresolvable message sender or mention target blanked the whole
  Messages page mid-render; both now degrade to a visible "Former
  member" placeholder instead of throwing
- A failed initial snapshot load left a permanently blank window with a
  swallowed rejection; loads now log loudly and retry every 1.5s until
  the main process answers
- With no conversation selected, the view followed the recency sort:
  any incoming message yanked the visible conversation to the newest
  space and marked it read unseen. The implicit default now pins itself
  once (render-time state adjustment)
- The avatar directory keyed names across ALL organizations, so a
  same-named principal in another org hijacked the custom avatar; it
  now scopes to the active org
- The conversation search query survived switching spaces, silently
  filtering the new space by the old term; ChatConversation is keyed by
  space id so per-space UI state resets

Also verified clean by the same sweep: no lingering references to the
removed snapshot fields, no stale closures in the office rAF loop,
org-chart zoom math, and the chat message ordering invariant is
guaranteed at the data layer (created_at desc limit + reverse).
2026-07-08 23:50:17 -04:00
ZacharyZhang-NY 04093c4869 Harden the seams a project sweep surfaced
A systematic review of the whole codebase (main process, renderer,
IPC/migration/packaging seams) surfaced four real defects; each is
fixed at its root:

- Legacy catalogue drift: the operator's profile still carried 89
  active skills from the removed ~/.agents import era next to the 228
  built-ins. Catalogue sync now mirrors the bundle - actives whose slug
  the bundle does not ship retire (bindings keep resolving via their
  pinned revisions; retired skills leave list_skills and cannot be
  granted anew)
- Broken-bundle guard: staging now refuses a bundle without the
  humanizer skill, so an empty or quarantined resources folder can
  never trigger the mirror pass into retiring a healthy catalogue
- Duplicate agent names: @mentions, DM routing, and task assignment all
  resolve by name, so createAgent and updateAgent renames now reject a
  name already held by an active agent (case-insensitive); the mention
  resolver still refuses to guess between legacy duplicates
- Stale DM titles: agent-to-agent conversation rows titled themselves
  from the frozen creation-time space name, so renames never reached
  the sidebar; direct titles now derive from members' current names

Verified clean in the same sweep: IPC surface (82 channels, handler +
preload + api aligned), per-migration transactions with rollback,
quota-parking month rollover, retry-budget counting, meeting spot
reuse across floor-plan rebuilds.
2026-07-08 23:41:51 -04:00
ZacharyZhang-NY c50f17190c Animate the whip: a crack at the strike point and a flinch on the target
Every whip click now lands visibly, wherever the target is standing:

- simulation.whip() always registers a WhipCrackEffect at the struck
  agent and starts their hit reaction; step() ages both away. The
  discipline rule is unchanged - only snack-bar/restroom slackers are
  sent hustling home; desk, CEO office, and meeting stay safe
- office-renderer draws the strike: a lash sweeping in from the upper
  right that collapses into an impact starburst with an expanding ring
  (~450ms), while the struck agent shakes with anime-style pain sparks
  over their head (~600ms), fading as the flinch drains
- The office e2e now collects pageerror during the run and lets the
  effect play out after a whip-mode click, so a throwing frame in the
  rAF loop fails the suite instead of dying silently
2026-07-08 23:41:33 -04:00
ZacharyZhang-NY 1f89ea7089 Stop shipping megabytes of skill prompts in every snapshot refresh
The whole app turned to molasses because snapshot.load() shipped the
entire skill_runtime_snapshots table - unbounded, compiled_prompt
included - over IPC on every refresh. A real profile carried 142 rows
totaling 144MB (1.1MB each from the pre-cap CEO compile-all era), so
every coalesced refresh serialized ~144MB of JSON. The forced-humanizer
rework made it worse by adding a row per run for every agent.

- Drop skillRuntimeSnapshots, skillRevisions, skillTests, and
  skillBindings from the renderer snapshot: no renderer surface reads
  them; skill internals are main-process state. Only the lightweight
  skillDefinitions catalogue still ships.
- Project provider_requests without raw_response_json (4.1MB across the
  newest 100 rows; RunsPage only reads responseText)
- Migration 051 purges the bug-era compiled prompts from existing DBs
- resolveRuntimeSnapshot is now idempotent per run: a run re-queued by
  startup recovery reuses its frozen snapshot instead of dying on the
  uniqueness guard and burning real retry budget
- Regression test pins the contract: a 2MB database row must not add
  bytes to the snapshot (payload asserted under 400KB)
2026-07-08 23:20:56 -04:00
ZacharyZhang-NY 4ab20e679c Add the whip to the office toolbar: slackers hustle back to their desks
- New bottom toolbar on the pixel office floor with a Whip tool;
  toggling it turns the cursor to a crosshair, clicks whip instead of
  opening the detail card, Escape puts the whip away
- Simulation.whip(): an agent inside the snack bar or restroom drops
  whatever they are carrying and hustles back to their desk at 1.8x
  speed for a few seconds; agents at their desks, in the CEO office,
  or in the meeting room are working and stay untouched
- Room membership decides the outcome (rectContains against the same
  floor-plan rooms the renderer draws), so the rule matches what the
  player sees
- Unit tests cover the whip matrix; e2e drives the toolbar toggle in
  the live shell
2026-07-08 21:51:47 -04:00
ZacharyZhang-NY 2bb2acd635 Grow a real OKR company: officers, departments, ranks - and a stable chart
Researched how OKR-run companies cascade (company objective -> C-suite
officers per function -> department objectives -> individual key
results) and encoded that shape into how the CEO builds the org.

- hire_agent gains seniority (director/lead/staff; c_suite stays
  reserved for the CEO's privileges) and a business-card title, so the
  CEO hires a CTO/CFO/CMO as directors instead of a flat pool of ICs
- CEO persona + goal kickoff now direct the OKR cascade: hire 2-4
  officers, hand each a department objective, let them build teams;
  department heads get their own doctrine (hire leads/staff, cascade
  key results as tasks, report up)
- Migration 050 adds Finance and Sales to every org's canonical
  departments (backfilled for existing DBs) so a real C-suite has
  somewhere to hire
- Org chart viewport is a fixed-height scroll region: zooming rescales
  the diagram inside it instead of resizing the card
- Unit test drives a live three-level chain: CEO -> CTO (director) ->
  Engineering Manager (lead) -> staff, with rank/title persisted
2026-07-08 21:47:07 -04:00
ZacharyZhang-NY c3924af9ac Office life: everyone roams, meetings convene in pairs, card follows agent
- The detail card now rides beside the clicked agent (flipping and
  clamping at viewport edges via a pure cardPositionFor helper) instead
  of pinning to the top-right corner; it follows a walking agent
- Every agent - the CEO and busy agents included - periodically visits
  the coffee machine, snack bar, and restroom; work status no longer
  recalls a walker mid-break
- The office convenes meetings around the meeting table every few
  minutes: at least two settled attendees walk over, dwell together on
  distinct table spots, and head back; a solo office never meets
- Meeting spots ship as lane-wired amenities so pathing stays correct
  by construction; floor-plan invariants (collider-free, reachable)
  cover them automatically
- e2e asserts the card opens beside the sprite, not in a corner
2026-07-08 21:40:53 -04:00
ZacharyZhang-NY e55b8b85b0 Make every identity editable: agent and operator names plus avatars
- Migration 049: avatar_emoji/avatar_color on agents and employees
- updateAgent accepts a new name (mention-name validated) and avatar;
  new updateEmployeeProfile renames the operator and sets their avatar
- Avatars are emoji-on-color tiles (renderer CSP blocks remote images);
  an AvatarDirectoryContext built from the snapshot lets the shared
  Avatar component honor custom looks at every call site - chat rows,
  conversation list, org chart, office card, sidebar - without
  threading props through pages
- Team edit dialog gains Name + avatar editor (CEO included); the
  sidebar foot opens an Edit-profile dialog for the operator
- e2e: rename an agent to a new mention handle with an emoji avatar,
  edit the operator profile, both verified in the live shell
2026-07-08 21:33:23 -04:00