Commit Graph
222 Commits
Author SHA1 Message Date
ZacharyZhang-NY 8243f58ef7 refactor(automation): use Modal/ConfirmDialog for DeleteConfirmDialog 2026-04-16 22:02:29 -04:00
ZacharyZhang-NY d0c6d1f6d0 perf(db): resolve chain of command in a single recursive CTE to eliminate N+1 queries 2026-04-16 21:59:18 -04:00
ZacharyZhang-NY 2ec77677cb fix(renderer): classify DesktopEvent types to stop full-refresh fallthrough (D-05)
All 14+ non-specially-handled events were pushing into the batcher with
entityKeyFromEvent returning null, which set hasDomainChanged = true and
triggered a full snapshot refresh on every agent-message, run-status, and
heartbeat-status -- defeating the granular patch machinery.

Per-type classification:
- run-status         -> granular run-updated (patchRun by runId)
- heartbeat-status   -> granular agent-updated (patchAgent by agentId)
- agent-message      -> granular task-updated (patchTask refetches comments)
- new-message, thread-wait-state-updated, domain-changed
                     -> full refresh, coalesced via 500ms batcher window
- automation-fired, recovery-needed
                     -> snapshot-irrelevant, skipped at event source

Widen batcher window from 50ms to 500ms so bursts coalesce into one reload.
Granular batches still flush at the same window cadence.
2026-04-16 21:58:32 -04:00
ZacharyZhang-NY 8cf6be05bb fix(skills): enforce per-file and aggregate size caps for imported SKILL.md content 2026-04-16 21:58:32 -04:00
ZacharyZhang-NY c81d72fb9c fix(api-server): SSE stream pulls incremental events via seq cursor
Replace per-poll 5000-row scan + JS filter with indexed WHERE seq > ?
query (uses idx_run_events_run). Batch up to 500 per call, drain loop
on reconnect. Poll interval raised 500ms -> 1000ms.
2026-04-16 21:57:35 -04:00
ZacharyZhang-NY c5c3919c78 fix(skills): bound local skill walk with depth, file count, and symlink loop protection 2026-04-16 21:57:29 -04:00
ZacharyZhang-NY 0123103f58 fix(renderer): subscribe ConsoleView to logRevision to trigger re-render (D-04)
logRevision was bumped on every run-log event but no component subscribed,
so ref mutations to logBufferRef never triggered a re-render -- the console
pre stayed stale until something else forced a render.

Subscribe to logRevision via useAppStore and depend on it in the useMemo
that reads logBufferRef, keeping the ref-based buffer (cheap writes) while
restoring re-renders.
2026-04-16 21:57:08 -04:00
ZacharyZhang-NY 0119872db6 fix(renderer): use snapshot.currentCompanyId as single source of truth (D-03)
CompanySlice's standalone currentCompanyId field + setCurrentCompanyId action
were never written by any caller, so useDesktopEvents.ts read null and fell
through to full refresh for every entity event -- the granular patch
machinery was dead code.

- Remove currentCompanyId field + setCurrentCompanyId from CompanySlice
- refreshBadges reads from snapshot.currentCompanyId
- useDesktopEvents reads companyId from snapshot.currentCompanyId
- Update store unit test to seed snapshot instead of calling removed action
2026-04-16 21:56:40 -04:00
ZacharyZhang-NY a130dc29f5 fix(tasks): route updateTaskSession/getTaskSession through task_sessions table
Stop writing new session data back to the legacy tasks.session_json
column; updateTaskSession now upserts the active task_sessions row
(updating the session pointed to by tasks.active_session_id, creating
one when absent), and getTaskSession reads from the same row so
session data has a single source of truth. Adds migration 27 to
backfill pre-existing tasks.session_json values into task_sessions
idempotently via INSERT OR IGNORE guarded on task_id. The legacy
column is kept for read-only history and is not dropped.
2026-04-16 21:53:12 -04:00
ZacharyZhang-NY ccf0c2a500 fix(schema): remove duplicate-column fallback; make migrations idempotent
Stop silently swallowing duplicate-column errors in the migration
runner; any real migration failure now throws. Replace try/catch-based
column additions in ensureOptionalColumns and migrations 19-22 with
pragma table_info checks so repeated startup is idempotent without
tolerating error signals. Reorder initializeDatabase so runMigrations
runs before ensureOptionalColumns to avoid migration 13 adding columns
that ensureOptionalColumns already created on fresh databases.
2026-04-16 21:52:43 -04:00
ZacharyZhang-NY 5201b6623b fix(database): enable WAL mode and busy_timeout on every DB connection
Applies WAL journal, 5s busy_timeout, synchronous=NORMAL, and
foreign_keys=ON pragmas immediately after opening each connection so
concurrent main+worker writers share the same locking configuration
and avoid SQLITE_BUSY under contention.
2026-04-16 21:52:25 -04:00
ZacharyZhang-NY a6d0a567a8 fix(ipc-credentials): use shared registerHandle and precise redactSecrets (I-02)
Two tightly-coupled hardening changes to the credential IPC module.

(1) Drop the self-built `DesktopOk/DesktopErr/ok/err/handle` helpers
that called `ipcMain.handle` directly, bypassing the trusted-renderer
check in `ipc-support.registerHandle` and the `ZodError ->
IPC_INVALID_PAYLOAD` sanitizer. The module now takes `registerHandle`
and `fail` as deps (wired from `createIpcSupport`) and imports `ok`
from `ipc-core-common`, mirroring the OAuth handler layout.

(2) Tighten `redactSecrets` to issuer-prefixed patterns only (Bearer,
`sk-`, `sk-ant-`, `sk-proj-`, AKIA access key IDs, three-segment JWTs).
The previous blanket `[A-Fa-f0-9]{40,}` and `[A-Za-z0-9+/]{48,}={0,2}`
rules were shredding legitimate diagnostic text — git SHAs, UUIDs,
Fireworks model identifiers like `accounts/fireworks/models/...`, and
any long opaque ID — into `[REDACTED-HEX]` / `[REDACTED-B64]`, which
made provider errors unreadable in the renderer.
2026-04-16 21:49:53 -04:00
ZacharyZhang-NY ff0c01fe87 fix(worker): claim workspace lock in main before enqueue (D-02)
The lock was previously claimed when the worker reported `running`, which
is after `agent.prompt` had already started streaming. Two concurrent
runs targeting the same workspace could both pass the main-side checks,
both get enqueued, and both read half-written state before one of them
lost the lock race and was cancelled mid-flight.

Move the `claimWorkspaceLock` call into `dispatchRunToWorker` so main
coordinates exclusivity authoritatively. If the lock is unavailable,
the run is finished as failed and never enqueued. The worker-side
lease-renewal path is preserved since it is a lease, not a lock.
2026-04-16 21:49:30 -04:00
ZacharyZhang-NY f86b3ddbac fix(ipc-oauth): use shared registerHandle for trust and error sanitization (I-01)
The self-built `ok/err/handle` helpers called `ipcMain.handle` directly,
which meant every OAuth IPC channel skipped the trusted-renderer check
in `ipc-support.registerHandle` and its `ZodError -> IPC_INVALID_PAYLOAD`
sanitizer. Any renderer origin could invoke these channels, and thrown
zod errors would leak the raw validator message.

Take `registerHandle` and `fail` as dependencies so callers wire in the
hardened variants from `createIpcSupport`, drop the local helpers, and
import `ok` from `ipc-core-common`. Zod inputs stay on `safeParse` to
preserve the explicit `INVALID_INPUT` code + message path.
2026-04-16 21:48:47 -04:00
ZacharyZhang-NY a1f021ff4a fix(worker): invert connector bypass default and gate on packaged build (S-01)
Previously `AGENTCOMPANY_ALLOW_UNSAFE_CONNECTOR_BYPASS !== "false"` meant
packaged builds defaulted to passing `dangerouslyBypassApprovalsAndSandbox`,
`dangerouslySkipPermissions`, `yolo`, and `--sandbox danger-full-access`
to CLI connectors, bypassing ApprovalService entirely.

Require both explicit opt-in (`AGENTCOMPANY_ALLOW_UNSAFE_CONNECTOR_BYPASS=true`)
and a non-packaged build. Packaged builds hard-refuse regardless of the env
var. Main process forks the worker with `AGENTCOMPANY_PACKAGED=<app.isPackaged>`
so the worker has an authoritative packaged signal.
2026-04-16 21:48:10 -04:00
ZacharyZhang-NY f8052c3741 refactor(scheduler): split 15s tick into 4 independent intervals
Split the single 15s setInterval in scheduler.ts (6 serial jobs) into 4
independent schedulers so a slow job no longer stalls the others:

- scheduler-heartbeat.ts (15s): wake eligible agents, CEO bootstrap,
  schedule automation trigger
- scheduler-lock-recovery.ts (60s): stale task-lock recovery and stale
  workspace-lock release
- scheduler-idle-automation.ts (60s): idle-agent automation dispatch
- scheduler-housekeeping.ts (300s): monthly budget reset, expired budget
  incident auto-close, stale review sweep, expired wakeup purge

scheduler.ts is now a thin composer exposing startAllSchedulers /
stopAllSchedulers. Bootstrap and service-graph updated accordingly.
Business logic, error isolation, and atomic actions preserved.
2026-04-16 21:47:09 -04:00
ZacharyZhang-NY 2676400e0c fix(ipc-credentials): serialize testCredential env mutations (S-03)
Pi-ai's `streamSimple`/`SimpleStreamOptions` has no per-request env
escape hatch; its Azure/AWS/GCP ADC providers read `process.env`
directly. The previous implementation wrote `extraEnv` into
`process.env` globally and relied on a `finally` after
`stream.result()` to clean up, so two concurrent `testCredential`
calls would clobber each other's env, expose the wrong credential
to in-flight streams, and on error paths fail to restore
previously-set values.

Wrap the env-mutating branch in a module-level promise chain so at
most one `extraEnv` test runs at a time, snapshot the prior value
of every key we overwrite, and restore (or delete when unset) in
`finally`. Tests that resolve to `extraEnv: undefined` bypass the
mutex entirely.
2026-04-16 21:43:44 -04:00
ZacharyZhang-NY ff08ab3e35 fix(desktop-shell-window): stop blocking main process on untrusted-link dialog
showMessageBoxSync froze the main-process event loop while the user
decided whether to open an external link, stalling agent-event workers,
IPC, and the scheduler for the duration of the dialog. setWindowOpenHandler
still returns synchronously with action: "deny"; the confirmation dialog
runs in an async continuation that only reaches shell.openExternal when
the user approves.
2026-04-16 21:42:29 -04:00
ZacharyZhang-NY f803b0b826 fix(api-server): require Origin header when no bearer token
Origin-less requests previously skipped the allowlist entirely, meaning
any process that omitted the Origin header (trivial for a non-browser
attacker) could reach the auth layer. Browsers always send Origin, so
rejecting Origin-less browser-style requests closes the bypass without
breaking agent CLIs, which authenticate with a bearer token instead.

New policy:
 - Requests with a Bearer Authorization header: Origin optional; if
   present it must be in the allowlist.
 - All other requests (including CORS preflight): Origin required and
   must be in the allowlist.
2026-04-16 21:42:04 -04:00
ZacharyZhang-NY deb980448c fix(ipc-thread-handlers): drop redundant try/catch wrappers and duplicate emit
Every handler was wrapping its body in try/catch and returning fail(code,
error.message), leaking raw DB messages to the renderer and bypassing the
sanitizer in registerHandle. Removed the 14 inner try/catch shells so
errors surface through ipc-support's IPC_HANDLER_FAILED / IPC_INVALID_PAYLOAD
path. Also removed the duplicate emitEvent({ type: 'domain-changed' }) in
addThreadEvent — publishDomainChanged already emits the same event.
2026-04-16 21:37:58 -04:00
ZacharyZhang-NY 6c6cc96060 fix(agent-permissions): propagate DB errors instead of silently denying
safeGetAgent was catching all errors and returning null, causing every
permission check (canControlAgent / canManageOrganization / canRequestHire)
to silently deny when the database threw. Only swallow the 'Agent not found'
case and let real DB errors propagate up to registerHandle's sanitizer.
2026-04-16 21:37:16 -04:00
ZacharyZhang-NY 893a0ddec1 chore(preload): drop stale @planned notes on delete{Task,Goal,Project,Workspace}
Handlers for deleteTask/deleteGoal/deleteProject live in
ipc-core-task-graph-handlers.ts:166-168 (backed by
database/tasks-crud.ts and database/entity-crud.ts), and
deleteWorkspace lives at line 169 (backed by database/workspaces.ts).
The four @planned comments were misleading.
2026-04-16 21:36:55 -04:00
ZacharyZhang-NY 734c789f50 fix(orchestration): remove one-time heartbeat cleanup from scheduler startup 2026-04-16 21:36:43 -04:00
ZacharyZhang-NY 1a57622849 fix(automation): remove silent JSON.parse fallback in executeAutomationAction 2026-04-16 21:36:41 -04:00
ZacharyZhang-NY a612ea7bea fix(communication): set searchLoading=true in setSearchQuery
setSearchQuery only incremented searchRequestId without flipping
searchLoading, so the UI could not distinguish "searching" from "no
results". Now loading flips true on non-empty query and clears
(results + loading) on empty query. setSearchResults keeps the
existing id-match logic to flip loading false on arrival.
2026-04-16 21:36:37 -04:00
ZacharyZhang-NY aa1afd0db2 fix(vault): remove NODE_ENV=test and VITEST auto-enable of insecure fallback so only explicit opt-in unlocks it 2026-04-16 21:36:29 -04:00
ZacharyZhang-NY cfe5f9ff73 fix(oauth): scope failPending to matching connectorId so cancelling one OAuth does not reject others 2026-04-16 21:36:22 -04:00
ZacharyZhang-NY 1b578c111a update 2026-04-16 14:48:51 -04:00
ZacharyZhang-NY 9779c4d1ca update 2026-04-07 20:18:47 -04:00
ZacharyZhang-NY f5d4f8b705 update 2026-04-06 00:35:27 -04:00
ZacharyZhang-NY 72157f0703 update 2026-04-05 23:47:56 -04:00
ZacharyZhang-NY 9145572422 update 2026-04-05 20:14:48 -04:00
ZacharyZhang-NY b8dda3c8d0 update 2026-04-04 17:01:26 -04:00
ZacharyZhang-NY 67c757f481 update 2026-04-04 12:03:50 -04:00
ZacharyZhang-NYandClaude Sonnet 4.6 66158e222e update
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 22:02:28 -04:00
ZacharyZhang-NY aed312124b update 2026-03-30 16:24:29 -04:00
ZacharyZhang-NY 6f1de8047e update 2026-03-30 00:15:21 -04:00
ZacharyZhang-NY 65e85135c1 large update 2026-03-29 14:08:15 -04:00
ZacharyZhang-NY 2ed952f19c Merge branch 'worktree-agent-afbb9437' 2026-03-28 03:26:56 -04:00
ZacharyZhang-NY 29e4f9f430 Merge branch 'worktree-agent-a8526086'
# Conflicts:
#	.planning/STATE.md
2026-03-28 03:19:28 -04:00
ZacharyZhang-NYandClaude Opus 4.6 758bc077ff fix(quick-260328-48g): fix heartbeat task duplication with Paperclip-style coalescing
- Remove self-defeating heartbeat task filter that excluded heartbeat tasks from candidates
- Add Paperclip-style task reuse: recycle existing done/in_review heartbeat tasks instead of creating new ones
- Fix status bug: new heartbeat tasks created as "todo" instead of "in_progress" so CAS checkout succeeds
- Wire one-time duplicate cleanup sweep into heartbeat scheduler startup

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 03:17:17 -04:00
ZacharyZhang-NYandClaude Opus 4.6 4b5492ea34 feat(quick-260328-48g): add database methods for heartbeat task reuse and cleanup
- Add findReusableHeartbeatTask() to find most recent done/in_review heartbeat task per agent
- Add cleanupDuplicateHeartbeatTasks() to cancel old duplicates using ROW_NUMBER window function
- Add 12 unit tests covering coalescing behavior, cross-agent isolation, status filtering

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 03:14:40 -04:00
ZacharyZhang-NY 80fa4221dc feat(260327-w3o): add CEO skill instructions to prompt-builder
- Step 1: review available skills before designing org structure
- Step 3: assign skills to agents after each hire is approved
- Priority 3: check/assign agent skills before delegating tasks
2026-03-27 23:11:16 -04:00
ZacharyZhang-NY 74d31f8365 feat(260327-w3o): add 5 skill REST API endpoints for agent access
- GET /api/companies/:companyId/skills (list company skills)
- GET /api/skills/:skillId (skill detail with markdown)
- POST /api/agents/:agentId/skills (assign skill to agent)
- DELETE /api/agents/:agentId/skills/:skillId (remove skill)
- GET /api/agents/:agentId/skills (list agent's skills)
2026-03-27 23:10:31 -04:00
ZacharyZhang-NYandClaude Opus 4.6 702f560b87 feat(260327-vvv): expand CEO Team Building Phase Step 1 with workspace exploration
- Step 1 now instructs codebase exploration (ls, read key files, understand structure)
- Added company identity consideration guidance for org design decisions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 23:00:06 -04:00
ZacharyZhang-NYandClaude Opus 4.6 4bb9c5ce9f feat(260327-vvv): add codebase scan and company context to CEO kickoff task
- Kickoff task now instructs CEO to explore workspace codebase before planning
- Company name and description interpolated into both activeGoal and fallback branches

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 22:59:45 -04:00
ZacharyZhang-NY 72848fcb00 feat(11): scan ~/.agents/skills/ and ~/.claude/skills/ for auto-import
Skills from user home directories are now auto-imported when listing
company skills. Deduplication handled by canonical key uniqueness.
Scans: ~/.agents/skills/, ~/.claude/skills/, and workspace .agents/skills/.
Cross-platform: uses HOME or USERPROFILE env var.
2026-03-27 22:49:44 -04:00
ZacharyZhang-NY 6480b7f49f fix(11): repair broken color patterns from CSS variable migration
- ChannelSidebar: replace inline color-mix style with Tailwind classes for task discussion icons
- MessageItem: replace broken priority config (color-mix inline) with Tailwind utility classes
- MessageItem: replace broken department badge hex-alpha pattern with Tailwind classes
- automation-config: restore ACCENT/LINE as hex values (used in template literal alpha suffixes)
- desktop-shell-service: set nativeTheme.themeSource to sync Windows title bar with app theme
2026-03-27 22:44:14 -04:00
ZacharyZhang-NY 3b756fd30d feat: scan workspace .agents/skills/ directories for skill imports
Add scanWorkspaceSkills method to skill service that iterates all
workspace local paths for a company and imports SKILL.md files from
.agents/skills/ subdirectories. Uses path.join for cross-platform
compatibility (Windows/macOS/Linux). The scan runs automatically
when skills are listed via IPC, with graceful error handling per
workspace so one bad path does not block the entire listing.

Also adds listWorkspaceLocalPaths to database for retrieving workspace
paths by company.
2026-03-27 22:38:02 -04:00
ZacharyZhang-NY 831acc3b06 fix: use tinted backgrounds for message priority badges
Priority badges had identical bg and text colors (both solid destructive
red for urgent), creating oversized solid-color blocks. Use 15% tinted
backgrounds so text remains readable and badges appear as subtle pills.
2026-03-27 22:36:35 -04:00