update
This commit is contained in:
1 parent
9510e1c858
commit
6b47e95d36
19 files changed
+195
-1409
No files matched your search
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": "C:\\Users\\zhang\\Documents\\GitHub\\AgentCompany\\electron-builder.yml",
|
||||
"directories": {
|
||||
"output": "C:\\Users\\zhang\\Documents\\GitHub\\AgentCompany\\build\\release"
|
||||
},
|
||||
"extraMetadata": {
|
||||
"version": "0.4.52"
|
||||
}
|
||||
}
|
||||
@@ -17,4 +17,4 @@ x64:
|
||||
- out/**
|
||||
- package.json
|
||||
nsis:
|
||||
script: "!include \"C:\\Users\\yang\\Documents\\Github\\AgentCompany\\node_modules\\.pnpm\\app-builder-lib@26.8.1_dmg-_62d31da0b96a3ea7b7d51a6bbe3b3b6e\\node_modules\\app-builder-lib\\templates\\nsis\\include\\StdUtils.nsh\"\n!addincludedir \"C:\\Users\\yang\\Documents\\Github\\AgentCompany\\node_modules\\.pnpm\\app-builder-lib@26.8.1_dmg-_62d31da0b96a3ea7b7d51a6bbe3b3b6e\\node_modules\\app-builder-lib\\templates\\nsis\\include\"\n!macro _isUpdated _a _b _t _f\n ${StdUtils.TestParameter} $R9 \"updated\"\n StrCmp \"$R9\" \"true\" `${_t}` `${_f}`\n!macroend\n!define isUpdated `\"\" isUpdated \"\"`\n\n!macro _isForceRun _a _b _t _f\n ${StdUtils.TestParameter} $R9 \"force-run\"\n StrCmp \"$R9\" \"true\" `${_t}` `${_f}`\n!macroend\n!define isForceRun `\"\" isForceRun \"\"`\n\n!macro _isKeepShortcuts _a _b _t _f\n ${StdUtils.TestParameter} $R9 \"keep-shortcuts\"\n StrCmp \"$R9\" \"true\" `${_t}` `${_f}`\n!macroend\n!define isKeepShortcuts `\"\" isKeepShortcuts \"\"`\n\n!macro _isNoDesktopShortcut _a _b _t _f\n ${StdUtils.TestParameter} $R9 \"no-desktop-shortcut\"\n StrCmp \"$R9\" \"true\" `${_t}` `${_f}`\n!macroend\n!define isNoDesktopShortcut `\"\" isNoDesktopShortcut \"\"`\n\n!macro _isDeleteAppData _a _b _t _f\n ${StdUtils.TestParameter} $R9 \"delete-app-data\"\n StrCmp \"$R9\" \"true\" `${_t}` `${_f}`\n!macroend\n!define isDeleteAppData `\"\" isDeleteAppData \"\"`\n\n!macro _isForAllUsers _a _b _t _f\n ${StdUtils.TestParameter} $R9 \"allusers\"\n StrCmp \"$R9\" \"true\" `${_t}` `${_f}`\n!macroend\n!define isForAllUsers `\"\" isForAllUsers \"\"`\n\n!macro _isForCurrentUser _a _b _t _f\n ${StdUtils.TestParameter} $R9 \"currentuser\"\n StrCmp \"$R9\" \"true\" `${_t}` `${_f}`\n!macroend\n!define isForCurrentUser `\"\" isForCurrentUser \"\"`\n\n!macro addLangs\n !insertmacro MUI_LANGUAGE \"English\"\n !insertmacro MUI_LANGUAGE \"German\"\n !insertmacro MUI_LANGUAGE \"French\"\n !insertmacro MUI_LANGUAGE \"SpanishInternational\"\n !insertmacro MUI_LANGUAGE \"SimpChinese\"\n !insertmacro MUI_LANGUAGE \"TradChinese\"\n !insertmacro MUI_LANGUAGE \"Japanese\"\n !insertmacro MUI_LANGUAGE \"Korean\"\n !insertmacro MUI_LANGUAGE \"Italian\"\n !insertmacro MUI_LANGUAGE \"Dutch\"\n !insertmacro MUI_LANGUAGE \"Danish\"\n !insertmacro MUI_LANGUAGE \"Swedish\"\n !insertmacro MUI_LANGUAGE \"Norwegian\"\n !insertmacro MUI_LANGUAGE \"Finnish\"\n !insertmacro MUI_LANGUAGE \"Russian\"\n !insertmacro MUI_LANGUAGE \"Portuguese\"\n !insertmacro MUI_LANGUAGE \"PortugueseBR\"\n !insertmacro MUI_LANGUAGE \"Polish\"\n !insertmacro MUI_LANGUAGE \"Ukrainian\"\n !insertmacro MUI_LANGUAGE \"Czech\"\n !insertmacro MUI_LANGUAGE \"Slovak\"\n !insertmacro MUI_LANGUAGE \"Hungarian\"\n !insertmacro MUI_LANGUAGE \"Arabic\"\n !insertmacro MUI_LANGUAGE \"Turkish\"\n !insertmacro MUI_LANGUAGE \"Thai\"\n !insertmacro MUI_LANGUAGE \"Vietnamese\"\n!macroend\n\n!addplugindir /x86-unicode \"C:\\Users\\yang\\AppData\\Local\\electron-builder\\Cache\\nsis\\nsis-resources-3.4.1-nsis-resources-3.4.1\\plugins\\x86-unicode\"\n!include \"C:\\Users\\yang\\AppData\\Local\\Temp\\t-BM1w1t\\4-messages.nsh\"\n\n!include \"common.nsh\"\n!include \"extractAppPackage.nsh\"\n\n# https://github.com/electron-userland/electron-builder/issues/3972#issuecomment-505171582\nCRCCheck off\nWindowIcon Off\nAutoCloseWindow True\nRequestExecutionLevel ${REQUEST_EXECUTION_LEVEL}\n\nFunction .onInit\n !ifndef SPLASH_IMAGE\n SetSilent silent\n !endif\n\n !insertmacro check64BitAndSetRegView\nFunctionEnd\n\nFunction .onGUIInit\n InitPluginsDir\n\n !ifdef SPLASH_IMAGE\n File /oname=$PLUGINSDIR\\splash.bmp \"${SPLASH_IMAGE}\"\n BgImage::SetBg $PLUGINSDIR\\splash.bmp\n BgImage::Redraw\n !endif\nFunctionEnd\n\nSection\n !ifdef SPLASH_IMAGE\n HideWindow\n !endif\n\n StrCpy $INSTDIR \"$PLUGINSDIR\\app\"\n !ifdef UNPACK_DIR_NAME\n StrCpy $INSTDIR \"$TEMP\\${UNPACK_DIR_NAME}\"\n !endif\n\n RMDir /r $INSTDIR\n SetOutPath $INSTDIR\n\n !ifdef APP_DIR_64\n !ifdef APP_DIR_ARM64\n !ifdef APP_DIR_32\n ${if} ${IsNativeARM64}\n File /r \"${APP_DIR_ARM64}\\*.*\"\n ${elseif} ${RunningX64}\n File /r \"${APP_DIR_64}\\*.*\"\n ${else}\n File /r \"${APP_DIR_32}\\*.*\"\n ${endIf}\n !else\n ${if} ${IsNativeARM64}\n File /r \"${APP_DIR_ARM64}\\*.*\"\n ${else}\n File /r \"${APP_DIR_64}\\*.*\"\n {endIf}\n !endif\n !else\n !ifdef APP_DIR_32\n ${if} ${RunningX64}\n File /r \"${APP_DIR_64}\\*.*\"\n ${else}\n File /r \"${APP_DIR_32}\\*.*\"\n ${endIf}\n !else\n File /r \"${APP_DIR_64}\\*.*\"\n !endif\n !endif\n !else\n !ifdef APP_DIR_32\n File /r \"${APP_DIR_32}\\*.*\"\n !else\n !insertmacro extractEmbeddedAppPackage\n !endif\n !endif\n\n System::Call 'Kernel32::SetEnvironmentVariable(t, t)i (\"PORTABLE_EXECUTABLE_DIR\", \"$EXEDIR\").r0'\n System::Call Line truncated
|
||||
script: "!include \"C:\\Users\\zhang\\Documents\\GitHub\\AgentCompany\\node_modules\\.pnpm\\app-builder-lib@26.8.1_dmg-_62d31da0b96a3ea7b7d51a6bbe3b3b6e\\node_modules\\app-builder-lib\\templates\\nsis\\include\\StdUtils.nsh\"\n!addincludedir \"C:\\Users\\zhang\\Documents\\GitHub\\AgentCompany\\node_modules\\.pnpm\\app-builder-lib@26.8.1_dmg-_62d31da0b96a3ea7b7d51a6bbe3b3b6e\\node_modules\\app-builder-lib\\templates\\nsis\\include\"\n!macro _isUpdated _a _b _t _f\n ${StdUtils.TestParameter} $R9 \"updated\"\n StrCmp \"$R9\" \"true\" `${_t}` `${_f}`\n!macroend\n!define isUpdated `\"\" isUpdated \"\"`\n\n!macro _isForceRun _a _b _t _f\n ${StdUtils.TestParameter} $R9 \"force-run\"\n StrCmp \"$R9\" \"true\" `${_t}` `${_f}`\n!macroend\n!define isForceRun `\"\" isForceRun \"\"`\n\n!macro _isKeepShortcuts _a _b _t _f\n ${StdUtils.TestParameter} $R9 \"keep-shortcuts\"\n StrCmp \"$R9\" \"true\" `${_t}` `${_f}`\n!macroend\n!define isKeepShortcuts `\"\" isKeepShortcuts \"\"`\n\n!macro _isNoDesktopShortcut _a _b _t _f\n ${StdUtils.TestParameter} $R9 \"no-desktop-shortcut\"\n StrCmp \"$R9\" \"true\" `${_t}` `${_f}`\n!macroend\n!define isNoDesktopShortcut `\"\" isNoDesktopShortcut \"\"`\n\n!macro _isDeleteAppData _a _b _t _f\n ${StdUtils.TestParameter} $R9 \"delete-app-data\"\n StrCmp \"$R9\" \"true\" `${_t}` `${_f}`\n!macroend\n!define isDeleteAppData `\"\" isDeleteAppData \"\"`\n\n!macro _isForAllUsers _a _b _t _f\n ${StdUtils.TestParameter} $R9 \"allusers\"\n StrCmp \"$R9\" \"true\" `${_t}` `${_f}`\n!macroend\n!define isForAllUsers `\"\" isForAllUsers \"\"`\n\n!macro _isForCurrentUser _a _b _t _f\n ${StdUtils.TestParameter} $R9 \"currentuser\"\n StrCmp \"$R9\" \"true\" `${_t}` `${_f}`\n!macroend\n!define isForCurrentUser `\"\" isForCurrentUser \"\"`\n\n!macro addLangs\n !insertmacro MUI_LANGUAGE \"English\"\n !insertmacro MUI_LANGUAGE \"German\"\n !insertmacro MUI_LANGUAGE \"French\"\n !insertmacro MUI_LANGUAGE \"SpanishInternational\"\n !insertmacro MUI_LANGUAGE \"SimpChinese\"\n !insertmacro MUI_LANGUAGE \"TradChinese\"\n !insertmacro MUI_LANGUAGE \"Japanese\"\n !insertmacro MUI_LANGUAGE \"Korean\"\n !insertmacro MUI_LANGUAGE \"Italian\"\n !insertmacro MUI_LANGUAGE \"Dutch\"\n !insertmacro MUI_LANGUAGE \"Danish\"\n !insertmacro MUI_LANGUAGE \"Swedish\"\n !insertmacro MUI_LANGUAGE \"Norwegian\"\n !insertmacro MUI_LANGUAGE \"Finnish\"\n !insertmacro MUI_LANGUAGE \"Russian\"\n !insertmacro MUI_LANGUAGE \"Portuguese\"\n !insertmacro MUI_LANGUAGE \"PortugueseBR\"\n !insertmacro MUI_LANGUAGE \"Polish\"\n !insertmacro MUI_LANGUAGE \"Ukrainian\"\n !insertmacro MUI_LANGUAGE \"Czech\"\n !insertmacro MUI_LANGUAGE \"Slovak\"\n !insertmacro MUI_LANGUAGE \"Hungarian\"\n !insertmacro MUI_LANGUAGE \"Arabic\"\n !insertmacro MUI_LANGUAGE \"Turkish\"\n !insertmacro MUI_LANGUAGE \"Thai\"\n !insertmacro MUI_LANGUAGE \"Vietnamese\"\n!macroend\n\n!addplugindir /x86-unicode \"C:\\Users\\zhang\\AppData\\Local\\electron-builder\\Cache\\nsis\\nsis-resources-3.4.1-nsis-resources-3.4.1\\plugins\\x86-unicode\"\n!include \"C:\\Users\\zhang\\AppData\\Local\\Temp\\t-9Kaqeq\\4-messages.nsh\"\n\n!include \"common.nsh\"\n!include \"extractAppPackage.nsh\"\n\n# https://github.com/electron-userland/electron-builder/issues/3972#issuecomment-505171582\nCRCCheck off\nWindowIcon Off\nAutoCloseWindow True\nRequestExecutionLevel ${REQUEST_EXECUTION_LEVEL}\n\nFunction .onInit\n !ifndef SPLASH_IMAGE\n SetSilent silent\n !endif\n\n !insertmacro check64BitAndSetRegView\nFunctionEnd\n\nFunction .onGUIInit\n InitPluginsDir\n\n !ifdef SPLASH_IMAGE\n File /oname=$PLUGINSDIR\\splash.bmp \"${SPLASH_IMAGE}\"\n BgImage::SetBg $PLUGINSDIR\\splash.bmp\n BgImage::Redraw\n !endif\nFunctionEnd\n\nSection\n !ifdef SPLASH_IMAGE\n HideWindow\n !endif\n\n StrCpy $INSTDIR \"$PLUGINSDIR\\app\"\n !ifdef UNPACK_DIR_NAME\n StrCpy $INSTDIR \"$TEMP\\${UNPACK_DIR_NAME}\"\n !endif\n\n RMDir /r $INSTDIR\n SetOutPath $INSTDIR\n\n !ifdef APP_DIR_64\n !ifdef APP_DIR_ARM64\n !ifdef APP_DIR_32\n ${if} ${IsNativeARM64}\n File /r \"${APP_DIR_ARM64}\\*.*\"\n ${elseif} ${RunningX64}\n File /r \"${APP_DIR_64}\\*.*\"\n ${else}\n File /r \"${APP_DIR_32}\\*.*\"\n ${endIf}\n !else\n ${if} ${IsNativeARM64}\n File /r \"${APP_DIR_ARM64}\\*.*\"\n ${else}\n File /r \"${APP_DIR_64}\\*.*\"\n {endIf}\n !endif\n !else\n !ifdef APP_DIR_32\n ${if} ${RunningX64}\n File /r \"${APP_DIR_64}\\*.*\"\n ${else}\n File /r \"${APP_DIR_32}\\*.*\"\n ${endIf}\n !else\n File /r \"${APP_DIR_64}\\*.*\"\n !endif\n !endif\n !else\n !ifdef APP_DIR_32\n File /r \"${APP_DIR_32}\\*.*\"\n !else\n !insertmacro extractEmbeddedAppPackage\n !endif\n !endif\n\n System::Call 'Kernel32::SetEnvironmentVariable(t, t)i (\"PORTABLE_EXECUTABLE_DIR\", \"$EXEDIR\").r0'\n System::CLine truncated
|
||||
@@ -1,8 +1,8 @@
|
||||
version: 0.4.51
|
||||
version: 0.4.52
|
||||
files:
|
||||
- url: AgentCompany-Setup-0.4.51.exe
|
||||
sha512: B1hxeWw8AZhXNYxPJrT3AA3E7GMGuGrxM+tijoHEbxjJdtpEx47Cfw7iZA+LpzLABCVPE8JskvM8M7a2035ANg==
|
||||
size: 101558338
|
||||
path: AgentCompany-Setup-0.4.51.exe
|
||||
sha512: B1hxeWw8AZhXNYxPJrT3AA3E7GMGuGrxM+tijoHEbxjJdtpEx47Cfw7iZA+LpzLABCVPE8JskvM8M7a2035ANg==
|
||||
releaseDate: '2026-03-19T21:04:17.730Z'
|
||||
- url: AgentCompany-Setup-0.4.52.exe
|
||||
sha512: mwXuxahjwBeStj+5gPa8F6Ny6DZg1utectcrjLEt8Wx0IStZUVYA8aZrrx3OsYBsfGG9bJHq3/rZCFPRRoSkJw==
|
||||
size: 101559599
|
||||
path: AgentCompany-Setup-0.4.52.exe
|
||||
sha512: mwXuxahjwBeStj+5gPa8F6Ny6DZg1utectcrjLEt8Wx0IStZUVYA8aZrrx3OsYBsfGG9bJHq3/rZCFPRRoSkJw==
|
||||
releaseDate: '2026-03-20T01:27:11.948Z'
|
||||
@@ -1,264 +0,0 @@
|
||||
# 2026-03-17 Architecture Freeze
|
||||
|
||||
## Supported Platform Target
|
||||
|
||||
The product target remains cross-platform:
|
||||
|
||||
- macOS
|
||||
- Windows
|
||||
- Linux
|
||||
|
||||
The current codebase can build on the local host, but release readiness is not equivalent across targets yet.
|
||||
|
||||
### Platform-specific constraints to preserve
|
||||
|
||||
- macOS
|
||||
- hidden inset title bar
|
||||
- signing and notarization required for public release
|
||||
- `safeStorage` may block on keychain access
|
||||
- Windows
|
||||
- App User Model ID is required for correct notifications and taskbar integration
|
||||
- NSIS is the release target
|
||||
- code signing required for updater trust
|
||||
- Linux
|
||||
- safe storage backend can fall back to weaker semantics when no secret store exists
|
||||
- Wayland window behavior is more limited than X11
|
||||
- AppImage is the primary packaged target today
|
||||
|
||||
## External Research Decisions
|
||||
|
||||
### Electron security
|
||||
|
||||
Based on the current Electron security checklist:
|
||||
|
||||
- keep `nodeIntegration: false`
|
||||
- keep `contextIsolation: true`
|
||||
- keep `sandbox: true`
|
||||
- keep the custom `app://` protocol instead of `file://`
|
||||
- validate sender URLs on every IPC entry point
|
||||
- do not expose raw IPC objects in preload
|
||||
- define a restrictive CSP in local renderer content
|
||||
|
||||
### Utility process
|
||||
|
||||
The current choice of `utilityProcess.fork()` is still the right worker primitive.
|
||||
|
||||
Reasoning:
|
||||
|
||||
- it keeps heavy connector execution off the renderer
|
||||
- it is more aligned with Electron security guidance than broad use of `ELECTRON_RUN_AS_NODE`
|
||||
- it is compatible with future fuse hardening around `runAsNode`
|
||||
|
||||
### Secret storage
|
||||
|
||||
`safeStorage` remains the primary storage contract.
|
||||
|
||||
Fallback rules:
|
||||
|
||||
- use OS-backed `safeStorage` when real encryption is available
|
||||
- reject insecure runtime environments by default
|
||||
- allow AES vault fallback only in explicitly allowed test/insecure modes
|
||||
|
||||
### Updater
|
||||
|
||||
`electron-updater` remains acceptable, but only if release lanes are made real.
|
||||
|
||||
Required implications:
|
||||
|
||||
- real publish endpoint
|
||||
- signed macOS app
|
||||
- Windows signing
|
||||
- explicit metadata handling for the generic provider
|
||||
- download/apply UX in-app, not just “check available”
|
||||
|
||||
## Process Boundary Freeze
|
||||
|
||||
### Main process
|
||||
|
||||
Owns:
|
||||
|
||||
- app lifecycle
|
||||
- BrowserWindow creation
|
||||
- custom protocol registration
|
||||
- native menus / tray / dialogs / notifications
|
||||
- database initialization
|
||||
- worker process lifecycle
|
||||
- updater lifecycle
|
||||
- browser automation windows
|
||||
- privileged IPC handlers
|
||||
|
||||
Must not:
|
||||
|
||||
- become the place where all query, mutation, aggregation, and orchestration code accumulates
|
||||
|
||||
### Preload
|
||||
|
||||
Owns:
|
||||
|
||||
- typed, minimal bridge from renderer to approved use-cases
|
||||
|
||||
Must not:
|
||||
|
||||
- expose raw `ipcRenderer`
|
||||
- expose generic file-system or shell primitives
|
||||
- become a mirror of every DB method
|
||||
|
||||
### Renderer
|
||||
|
||||
Owns:
|
||||
|
||||
- operator workflows
|
||||
- presentation logic
|
||||
- optimistic local UI state
|
||||
- command palette / shell navigation
|
||||
- empty / loading / error / review states
|
||||
|
||||
Must not:
|
||||
|
||||
- talk in raw CRUD terms when the user is performing operator flows
|
||||
- own privileged state
|
||||
- load whole-world snapshots forever as the only data pattern
|
||||
|
||||
### Utility process
|
||||
|
||||
Owns:
|
||||
|
||||
- connector execution
|
||||
- per-run stream forwarding
|
||||
- cancellation
|
||||
- run queue scheduling local to worker
|
||||
|
||||
Must not:
|
||||
|
||||
- become the persistence layer
|
||||
- own security policy decisions that belong in main
|
||||
|
||||
## State Ownership Model
|
||||
|
||||
### Renderer-local state
|
||||
|
||||
- selected entities
|
||||
- open panels / modals
|
||||
- search queries
|
||||
- console UI state
|
||||
- transient filter/sort state
|
||||
|
||||
### Persisted domain state
|
||||
|
||||
- companies
|
||||
- connectors
|
||||
- workspaces
|
||||
- agents
|
||||
- goals / projects / tasks
|
||||
- approvals
|
||||
- runs
|
||||
- cost entries
|
||||
- activity
|
||||
- secrets
|
||||
- automation rules
|
||||
- workflows
|
||||
- browser actions
|
||||
|
||||
### Runtime execution state
|
||||
|
||||
- active worker jobs
|
||||
- agent concurrency map
|
||||
- workspace lock ownership
|
||||
- pending wakes
|
||||
- update progress
|
||||
- browser action queue
|
||||
|
||||
### Derived read models
|
||||
|
||||
These should be separated from write repositories:
|
||||
|
||||
- overview metrics
|
||||
- inbox
|
||||
- standup
|
||||
- run queue / attention views
|
||||
- workload and review summaries
|
||||
|
||||
## Storage Decision
|
||||
|
||||
### Current decision
|
||||
|
||||
Keep SQLite + WAL for this tranche.
|
||||
|
||||
### Constraints
|
||||
|
||||
- single-writer semantics remain acceptable if heavy aggregations are not kept in the same giant repository
|
||||
- crash recovery must preserve unfinished run semantics
|
||||
- backup / restore must remain profile-local and reversible
|
||||
|
||||
### Required follow-up
|
||||
|
||||
- split read models from write repositories
|
||||
- add offset-based log readers
|
||||
- keep artifacts and logs on disk, indexed in SQLite
|
||||
|
||||
## IPC Contract Strategy
|
||||
|
||||
### Contract rules
|
||||
|
||||
- every mutating IPC call must stay company-scoped when relevant
|
||||
- large payloads should use typed request objects, not positional args
|
||||
- contract names stay explicit and descriptive
|
||||
- result envelopes stay structured
|
||||
|
||||
### Next contract change
|
||||
|
||||
The next contract slice will add:
|
||||
|
||||
- dedicated run listing / filtering reads
|
||||
- chunked log reads
|
||||
- connector selection in onboarding
|
||||
|
||||
## Renderer Information Architecture Freeze
|
||||
|
||||
Primary desktop sections:
|
||||
|
||||
1. Overview
|
||||
2. Runs
|
||||
3. Tasks
|
||||
4. Approvals
|
||||
5. Messages
|
||||
6. Agents
|
||||
7. Workspaces
|
||||
8. Connectors
|
||||
9. Costs
|
||||
10. Activity
|
||||
11. Settings
|
||||
|
||||
Secondary knowledge/operations surfaces can remain, but they should not dominate the shell.
|
||||
|
||||
## Milestone Mapping
|
||||
|
||||
### Architecture Freeze
|
||||
|
||||
- this document accepted
|
||||
|
||||
### Interactive Prototype
|
||||
|
||||
- shell reordered around operator workflows
|
||||
- run console and runs list coherent
|
||||
|
||||
### Internal Alpha
|
||||
|
||||
- onboarding, connector health, task run, approval, message routing, and workspace inspection work together
|
||||
|
||||
### Cross-Platform Validation
|
||||
|
||||
- menu, tray, notification, and package behavior documented per OS
|
||||
|
||||
### Signed Beta
|
||||
|
||||
- updater feed real
|
||||
- signing path documented and testable
|
||||
|
||||
### Release Candidate
|
||||
|
||||
- all repo quality gates green
|
||||
|
||||
### Production Ready
|
||||
|
||||
- security audit, release hardening, and operator workflow polish complete
|
||||
@@ -1,307 +0,0 @@
|
||||
# 2026-03-17 Audit And Rebuild Plan
|
||||
|
||||
## Execution Order
|
||||
|
||||
This document is the Phase 1-4 artifact required by `AGENTS.md`.
|
||||
|
||||
1. ProjectManager: read the full PRD and define milestone gates.
|
||||
2. ResearchAnalyst: verify Electron runtime, security, packaging, updater, and OS constraints.
|
||||
3. TechnicalImplementationResearcher: freeze main/preload/renderer/storage/runtime boundaries.
|
||||
4. EnterpriseArchitect: validate dependency direction, module seams, IPC contracts, and naming rules.
|
||||
|
||||
Implementation work starts only after the decisions below are recorded.
|
||||
|
||||
## Scope
|
||||
|
||||
The audit covers:
|
||||
|
||||
- PRD alignment
|
||||
- Electron main / preload / renderer boundaries
|
||||
- IPC contracts, sender validation, and company scoping
|
||||
- connector runtime execution, orchestration, and background work
|
||||
- local persistence, backup / restore, workspace locking, and crash recovery
|
||||
- renderer information architecture, onboarding, and desktop UX
|
||||
- packaging, updater, release, and verification posture
|
||||
- adapter package quality and test coverage
|
||||
|
||||
## Baseline Evidence
|
||||
|
||||
### Repository state
|
||||
|
||||
- The working tree is already in a large, incomplete refactor state.
|
||||
- The repo is no longer a prototype shell; it already contains a local data model, automation engine, workflow engine, browser automation surface, and an Electron shell.
|
||||
- The implementation breadth is now large enough that coherence, not feature count, is the main problem.
|
||||
|
||||
### Verification results on 2026-03-17
|
||||
|
||||
- `pnpm typecheck`: pass
|
||||
- `pnpm test:unit`: pass
|
||||
- `pnpm test:integration`: pass
|
||||
- `pnpm test:packages`: pass
|
||||
- `pnpm test:e2e`: pass
|
||||
- `pnpm build:verify`: pass
|
||||
- `pnpm build:dir`: pass, producing `build/release/AgentCompany-0.4.26-arm64-mac.zip`
|
||||
- `pnpm lint`: fail
|
||||
|
||||
### Current build posture
|
||||
|
||||
- Main bundle: `out/main/index.js` about `592 kB`
|
||||
- Preload bundle: `out/preload/index.js` about `151 kB`
|
||||
- Renderer bundle: `out/renderer/assets/index-*.js` about `1.69 MB`
|
||||
- Packaging currently succeeds only on the host platform tested locally.
|
||||
|
||||
## Research Notes
|
||||
|
||||
The following external references were re-checked during this audit:
|
||||
|
||||
- Electron security checklist: https://www.electronjs.org/docs/latest/tutorial/security
|
||||
- BrowserWindow API and platform notices: https://www.electronjs.org/docs/latest/api/browser-window
|
||||
- Utility process API: https://www.electronjs.org/docs/latest/api/utility-process
|
||||
- safeStorage API: https://www.electronjs.org/docs/latest/api/safe-storage
|
||||
- Electron fuses: https://www.electronjs.org/docs/latest/tutorial/fuses
|
||||
- electron-builder auto-update guide: https://www.electron.build/auto-update
|
||||
- electron-builder publish guide: https://www.electron.build/publish
|
||||
|
||||
These references matter because the PRD explicitly requires secure preload exposure, custom protocol usage, sandboxing, OS-backed secret storage, release signing, and update integrity.
|
||||
|
||||
## Current State Summary
|
||||
|
||||
The application already has the following real subsystems:
|
||||
|
||||
- Electron shell with `contextIsolation`, `nodeIntegration: false`, `sandbox: true`, and a custom `app://` protocol
|
||||
- local `DatabaseSync` SQLite store with WAL mode
|
||||
- local API server for agent-driven actions
|
||||
- utility-process worker for connector execution
|
||||
- run orchestration, automation rules, workflow pipelines, messages, approvals, documents, meetings, sprints, and browser actions
|
||||
|
||||
The main issue is not “missing a single feature”.
|
||||
|
||||
The issue is that the system surface is broader than the stability and architecture boundaries that currently support it.
|
||||
|
||||
## Findings
|
||||
|
||||
### High severity
|
||||
|
||||
1. Main-process data access is concentrated in a single synchronous repository that is too large to remain reliable.
|
||||
- Evidence: `src/main/database.ts` is `3292` lines and owns schema setup, migrations, snapshots, orchestration state, cost accounting, approvals, messaging, workflow persistence, backup/restore, workspace locking, and dashboard aggregation.
|
||||
- Impact:
|
||||
- blocks maintainability
|
||||
- encourages cross-domain coupling
|
||||
- increases renderer-visible latency because many IPC calls read the same monolith
|
||||
|
||||
2. The renderer shell is still a god component and does not match the desktop-native operating model in the PRD.
|
||||
- Evidence: `src/renderer/App.tsx` is `1520` lines and owns navigation, data loading, company switching, command palette, modal orchestration, run log buffering, and page composition for every domain.
|
||||
- Impact:
|
||||
- feature interaction is hard to reason about
|
||||
- state ownership is blurred
|
||||
- operator workflows such as run monitoring are buried behind a console drawer instead of having first-class surfaces
|
||||
|
||||
3. The verification gate defined by the project itself is currently broken because lint does not run.
|
||||
- Evidence: `pnpm lint` fails with `ENOENT ... electron.vite.config.<timestamp>.mjs`.
|
||||
- Impact:
|
||||
- the release checklist in `AGENTS.md` is not met
|
||||
- CI or local quality enforcement is unreliable
|
||||
|
||||
4. Update and release readiness are not production-grade.
|
||||
- Evidence:
|
||||
- `electron-builder.yml` still defaults to a generic placeholder publish URL
|
||||
- `src/main/updater-service.ts` only checks availability; it does not implement a complete download/apply flow or pre-update backup
|
||||
- local mac packaging falls back to ad-hoc signing and skips notarization
|
||||
- Impact:
|
||||
- no shippable trust chain for public release
|
||||
- updater behavior is not aligned with PRD requirements
|
||||
|
||||
5. Automatic internal coordination is still mostly emergent behavior from prompts and heuristics, not a hardened orchestration contract.
|
||||
- Evidence:
|
||||
- `src/main/prompt-builder.ts` contains the majority of “real company behavior” instructions
|
||||
- `src/main/automation-service.ts` uses rule-triggered wakeups and message dispatch to simulate organization flow
|
||||
- no dedicated coordination state model exists for “conversation pending response”, “delegation awaiting acceptance”, or “review SLA breached”
|
||||
- Impact:
|
||||
- the system can appear intelligent in happy paths while remaining hard to debug in stalled paths
|
||||
- message flow, approvals, and delegation are not deterministic enough for a production control plane
|
||||
|
||||
### Medium severity
|
||||
|
||||
1. Snapshot loading is coarse-grained and expensive.
|
||||
- Evidence:
|
||||
- `db.listSnapshot()` reads nearly every table every time
|
||||
- `db.listRendererSnapshot()` still calls `listSnapshot()` first and only then filters by company
|
||||
- `App.refresh()` reloads the entire current company snapshot on most domain events
|
||||
- Impact:
|
||||
- unnecessary main-process work
|
||||
- unnecessary renderer re-renders
|
||||
- future scale problems once run/message/activity volume increases
|
||||
|
||||
2. Run log access is full-file based, not incremental.
|
||||
- Evidence:
|
||||
- `src/main/database.ts#readRunLog` returns the entire log file
|
||||
- renderer keeps in-memory log buffers in `App.tsx`
|
||||
- PRD mismatch:
|
||||
- PRD requires offset-based incremental log reading
|
||||
- Impact:
|
||||
- degraded performance on large logs
|
||||
- poor long-running run observability
|
||||
|
||||
3. The preload bridge is typed but too broad for the current architecture maturity.
|
||||
- Evidence: `src/preload/index.ts` exposes dozens of direct CRUD and orchestration methods.
|
||||
- Impact:
|
||||
- large privileged surface area
|
||||
- difficult contract governance
|
||||
- weak module boundaries between renderer and domain actions
|
||||
|
||||
4. Workflow and automation configuration crosses boundaries as opaque JSON strings.
|
||||
- Evidence:
|
||||
- `conditionsJson`, `actionConfigJson`, `stepsJson`, `triggerConfigJson`, `metadataJson`, `attachmentsJson` are passed across IPC and persistence as raw strings
|
||||
- Impact:
|
||||
- weak compile-time guarantees
|
||||
- more runtime parsing failures
|
||||
- harder migration and refactoring path
|
||||
|
||||
5. Onboarding still optimizes for spectacle more than operator clarity.
|
||||
- Evidence:
|
||||
- `src/renderer/components/CompanyOnboarding.tsx` strongly promises “autonomous company” behavior
|
||||
- connector choice and capability differences are not explicit enough
|
||||
- initial run review is not operator-first
|
||||
- Impact:
|
||||
- weak first-use trust
|
||||
- harder diagnosis when the selected connector is degraded or capability-limited
|
||||
|
||||
6. Browser/social automation is fragile and outside the core PRD center of gravity.
|
||||
- Evidence:
|
||||
- `src/main/browser-manager.ts` relies on direct DOM selectors, timed delays, and third-party site structure
|
||||
- Impact:
|
||||
- brittle surface
|
||||
- expands support burden
|
||||
- competes with higher-priority core orchestration work
|
||||
|
||||
7. The app supports many domains, but there is no dedicated Runs page.
|
||||
- Evidence:
|
||||
- run monitoring exists only through dashboard widgets and the bottom console drawer
|
||||
- PRD mismatch:
|
||||
- PRD requires live runs and log console as first-class operating surfaces
|
||||
|
||||
### Low severity
|
||||
|
||||
1. Renderer design language is coherent but still too web-dashboard-like for a desktop control plane.
|
||||
- Evidence:
|
||||
- system font stack in `src/renderer/styles.css`
|
||||
- single-column content area on many dense surfaces
|
||||
- heavy modal use for editing
|
||||
|
||||
2. Package-level runtime verification is narrow.
|
||||
- Evidence:
|
||||
- `test:packages` covers only `adapter-opencode-local` and `adapter-kimi-local`
|
||||
- `codex`, `claude`, and `gemini` packages do not have equivalent package test commands here
|
||||
|
||||
## Detailed Gap List By Domain
|
||||
|
||||
### Main / preload / IPC
|
||||
|
||||
- Sender validation exists and the custom protocol is correct, which is a good baseline.
|
||||
- Contracts are typed, but not versioned and not yet narrowed by capability groups.
|
||||
- `ipc-core-common.ts` and `ipc-domain-common.ts` still use `any`-heavy dependency wiring.
|
||||
- The privileged bridge still mirrors domain CRUD too directly instead of exposing operator use-cases.
|
||||
|
||||
### Data / orchestration
|
||||
|
||||
- Workspace lock handling exists, but it is still embedded inside the database class.
|
||||
- Queued-run recovery exists, but recovery semantics are still best-effort.
|
||||
- Workflow execution is inline, stateful, and sync-heavy in the main process service layer.
|
||||
- Aggregation views such as inbox, standup, and metrics are built inside the same DB class.
|
||||
|
||||
### Connectors
|
||||
|
||||
- Codex / Claude / Gemini / OpenCode have deeper execution paths than Kimi.
|
||||
- Kimi remains generic CLI mode with explicit capability downgrade.
|
||||
- Connector health checks use command probes and status translation, but operator feedback is still too shallow.
|
||||
- Connector discovery and operator selection are still secondary in first-launch UX.
|
||||
|
||||
### Renderer
|
||||
|
||||
- The UI covers a large domain surface, but the operating hierarchy is inverted:
|
||||
- overview first
|
||||
- CRUD pages second
|
||||
- runs/logs/workspaces hidden as secondary tools
|
||||
- The app does not yet “scream” workspace, run, and coordination as the primary desktop tasks.
|
||||
|
||||
### Testing / release
|
||||
|
||||
- Current automated coverage is better than zero, but still not close to the PRD completion criteria.
|
||||
- E2E currently proves only first-launch onboarding and console toggle.
|
||||
- No E2E covers:
|
||||
- task run lifecycle
|
||||
- approval resolution
|
||||
- message routing
|
||||
- workflow execution
|
||||
- connector health state changes
|
||||
- backup/restore
|
||||
- workspace locking / recovery
|
||||
- Release docs do not yet define signed beta, RC, and production lanes.
|
||||
|
||||
## Rebuild Direction
|
||||
|
||||
### Tranche A: operator shell and observability
|
||||
|
||||
- add first-class Runs navigation and run triage workflow
|
||||
- move run logs to chunked readers instead of whole-file loads
|
||||
- make onboarding explicitly choose connector and workspace intent
|
||||
- fix lint so the repo’s minimum quality gate works again
|
||||
|
||||
### Tranche B: boundary extraction
|
||||
|
||||
- split `AppDatabase` into read models, command repositories, and orchestration state store
|
||||
- reduce preload surface to bounded capability groups
|
||||
- split renderer shell from feature pages and detail inspectors
|
||||
|
||||
### Tranche C: release hardening
|
||||
|
||||
- define real update lanes and signing rules
|
||||
- add updater backup/install flow
|
||||
- document mac notarization, Windows signing, Linux packaging behavior
|
||||
- flip relevant Electron fuses during packaging
|
||||
|
||||
## Milestone Gates
|
||||
|
||||
### Architecture Freeze
|
||||
|
||||
- audit findings accepted
|
||||
- platform target confirmed
|
||||
- process boundaries frozen
|
||||
- core run / workspace / connector model frozen
|
||||
|
||||
### Interactive Prototype
|
||||
|
||||
- onboarding, connectors, agents, tasks, runs, console, workspaces all coherent
|
||||
|
||||
### Internal Alpha
|
||||
|
||||
- connector lifecycle, approvals, message routing, and crash recovery usable end-to-end
|
||||
|
||||
### Cross-Platform Validation
|
||||
|
||||
- macOS, Windows, Linux behavior documented and smoke-validated
|
||||
|
||||
### Signed Beta Build
|
||||
|
||||
- signing path defined
|
||||
- updater feed real
|
||||
- rollback / backup strategy documented
|
||||
|
||||
### Release Candidate
|
||||
|
||||
- lint, typecheck, unit, integration, E2E, build, and packaging gates all green
|
||||
|
||||
### Production Readiness
|
||||
|
||||
- security audit complete
|
||||
- no placeholder release config remains
|
||||
- operator workflows are deterministic and observable
|
||||
|
||||
## Next Implementation Slice
|
||||
|
||||
The next code tranche will target:
|
||||
|
||||
1. repair the lint gate
|
||||
2. add first-class Runs navigation and incremental log loading
|
||||
3. make onboarding force an explicit connector choice
|
||||
4. keep build packaging green while making these changes
|
||||
@@ -1,31 +0,0 @@
|
||||
# 2026-03-17 Runtime/Security Tranche
|
||||
|
||||
This tranche locks the first production-boundary fixes before larger module extraction.
|
||||
|
||||
## Scope
|
||||
|
||||
- tighten agent run-token authority in the local API server
|
||||
- stop default connector execution from bypassing runtime permission/sandbox flags
|
||||
- harden renderer IPC sender validation
|
||||
- prevent secret bindings from overriding process-critical environment keys
|
||||
- make browser-action cancellation affect real execution, not only database state
|
||||
|
||||
## Why this tranche comes first
|
||||
|
||||
These issues sit underneath every feature:
|
||||
|
||||
1. A compromised or overpowered run token could mutate company structure, approvals, and browser automation.
|
||||
2. A globally bypassed connector runtime defeats approval and sandbox posture for all task runs.
|
||||
3. Loose origin matching weakens the only boundary between renderer and privileged main-process handlers.
|
||||
4. Fake cancellation creates visible state drift between the UI and external side effects.
|
||||
5. Unrestricted env injection allows privilege escalation through runtime process configuration.
|
||||
|
||||
## Intended outcome
|
||||
|
||||
After this tranche:
|
||||
|
||||
- agent runs can no longer approve approvals or request arbitrary organization changes without role-based checks
|
||||
- connector child processes run without implicit dangerous bypass flags
|
||||
- only exact trusted renderer origins can invoke privileged IPC handlers
|
||||
- reserved env keys are blocked from connector secret bindings
|
||||
- cancelling a browser action cancels queued or active execution, not just the row in SQLite
|
||||
@@ -1,49 +0,0 @@
|
||||
## Intent
|
||||
Unify and harden cross-process message flow in AgentCompany so API/IPC/automation/renderer behavior is consistent, secure, and production-safe.
|
||||
|
||||
## Verdict: CONTESTED (pre-fix) -> PASS (post-fix)
|
||||
Pre-fix review surfaced multiple high-severity issues; after remediation in this cycle, no remaining high-severity blocker is accepted.
|
||||
|
||||
## Findings
|
||||
1. **[high] Unsafe connector bypass inconsistency** (`src/main/orchestrator/worker.ts:114-119`)
|
||||
- Lens: Skeptic, Architect
|
||||
- Principle: `fix-root-causes`, `boundary-discipline`
|
||||
- Recommendation: gate `dangerouslySkipPermissions` by explicit env flag.
|
||||
|
||||
2. **[high] API message path missing real-time message event parity** (`src/main/api-server.ts:1456-1465`)
|
||||
- Lens: Architect, Minimalist
|
||||
- Principle: `prove-it-works`, `foundational-thinking`
|
||||
- Recommendation: wire `emitEvent` through API callbacks and dispatch dependencies.
|
||||
|
||||
3. **[high] Mark-read visibility check false negatives under message volume** (`src/main/ipc-agent-coordination-handlers.ts:82-87`)
|
||||
- Lens: Skeptic
|
||||
- Principle: `prove-it-works`
|
||||
- Recommendation: replace bounded list scan with targeted lookup by `messageId`.
|
||||
|
||||
4. **[medium] Message validation drift risk (schema vs dispatch normalization)** (`src/shared/contracts.ts:413-436`, `src/main/message-dispatch.ts:99-110`)
|
||||
- Lens: Skeptic, Architect, Minimalist
|
||||
- Principle: `foundational-thinking`
|
||||
- Recommendation: enforce same recipient/channel invariants in dispatch layer (implemented).
|
||||
|
||||
5. **[medium] Wake target resolution snapshot scaling risk** (`src/main/message-dispatch.ts:177-223`)
|
||||
- Lens: Skeptic, Architect
|
||||
- Principle: `cost-aware-delegation`
|
||||
- Recommendation: follow-up optimization to avoid full snapshot traversal per message.
|
||||
|
||||
6. **[low] Direct-channel avatar identity ambiguity** (`src/renderer/components/communication.tsx:134-140`, `:288-304`)
|
||||
- Lens: Skeptic, Minimalist
|
||||
- Principle: `outcome-oriented-execution`
|
||||
- Recommendation: bind avatar identity to active viewer context (deferred).
|
||||
|
||||
## What Went Well
|
||||
- Message flow now has one dispatch path shared by API, IPC, and automation.
|
||||
- Quality gates (typecheck/lint/unit/integration/e2e/build) all pass after remediation.
|
||||
- Build pipeline now emits cleaned release artifacts to `/build/release` with explicit version.
|
||||
|
||||
## Lead Judgment
|
||||
1. Accept. Fixed in this cycle.
|
||||
2. Accept. Fixed in this cycle.
|
||||
3. Accept. Fixed in this cycle.
|
||||
4. Accept. Partially fixed by dispatch-layer invariant enforcement; future refactor can further reduce duplication.
|
||||
5. Accept as valid risk. Deferred to next optimization wave because correctness/security was prioritized first.
|
||||
6. Accept as low-priority UX consistency issue. Deferred.
|
||||
@@ -1,203 +0,0 @@
|
||||
# AgentCompany Cross-Feature Integrity Audit (2026-03-18)
|
||||
|
||||
## Scope
|
||||
|
||||
- `PRD.md`
|
||||
- Electron runtime code under `src/main`, `src/preload`, `src/renderer`, `src/shared`
|
||||
- Connector adapters under `packages/*`
|
||||
- Build and packaging config: `package.json`, `electron-builder.yml`, `electron.vite.config.ts`, `scripts/build-desktop.mjs`
|
||||
- Existing validation assets under `tests/unit`, `tests/integration`, `tests/e2e`
|
||||
- Current Electron guidance and packaging guidance from official Electron and electron-builder documentation
|
||||
|
||||
## Pipeline Mapping
|
||||
|
||||
### Phase 1: ProjectManager
|
||||
|
||||
- Confirmed product target remains a local-first Electron desktop control plane, not a browser-shaped admin shell.
|
||||
- Current milestone for this remediation wave: cross-feature integrity, autonomous execution gating, and release validation.
|
||||
|
||||
### Phase 2: ResearchAnalyst
|
||||
|
||||
- Checked current Electron guidance for:
|
||||
- context isolation and preload boundaries
|
||||
- sandbox and navigation restrictions
|
||||
- utility-process usage
|
||||
- packaging and update prerequisites
|
||||
|
||||
### Phase 3: TechnicalImplementationResearcher
|
||||
|
||||
- Traced how connector health, onboarding, hiring, orchestration, snapshot loading, and renderer forms interact.
|
||||
- Focused on defects where one subsystem looked valid locally but corrupted another subsystem at runtime.
|
||||
|
||||
### Phase 4: EnterpriseArchitect
|
||||
|
||||
- Validated that the highest-severity current issues were policy drift and hidden truncation, not absence of feature surfaces.
|
||||
- Chose to fix shared policy and shared data integrity before any cosmetic refactor.
|
||||
|
||||
## What Is Already Real
|
||||
|
||||
- Main / preload / renderer separation exists.
|
||||
- Renderer does not depend on direct Node access.
|
||||
- SQLite-backed local-first persistence exists.
|
||||
- The app already contains real systems for onboarding, companies, agents, goals, projects, tasks, approvals, runs, costs, meetings, knowledge, documents, social accounts, automation, messaging, and packaging.
|
||||
- Worker execution already runs outside the renderer.
|
||||
|
||||
## Highest-Severity Findings From This Audit
|
||||
|
||||
### 1. Global snapshot truncation polluted company-scoped behavior
|
||||
|
||||
Source:
|
||||
|
||||
- `src/main/database.ts`
|
||||
|
||||
Problem:
|
||||
|
||||
- `listSnapshot()` hard-capped `runs`, `cost_entries`, `agent_messages`, and `activity`.
|
||||
- `listRendererSnapshot()` then filtered that already-truncated global result down to the current company.
|
||||
- This allowed newer rows from other companies to displace current-company runs, messages, costs, and activity from the renderer snapshot.
|
||||
|
||||
Why this matters:
|
||||
|
||||
- Inbox severity, board unread counts, standup summaries, cost totals, run history, and communication history could silently diverge from real persisted state.
|
||||
- The defect was cross-feature by construction because multiple views derived from the same truncated snapshot.
|
||||
|
||||
### 2. Connector policy drift allowed non-production runtimes onto the main execution path
|
||||
|
||||
Sources:
|
||||
|
||||
- `src/main/onboarding-service.ts`
|
||||
- `src/main/orchestration-service.ts`
|
||||
- `src/main/ipc-core-work-graph-handlers.ts`
|
||||
- `src/main/api-server.ts`
|
||||
- `src/renderer/components/CompanyOnboarding.tsx`
|
||||
- `src/renderer/components/organization.tsx`
|
||||
- `src/main/connectors.ts`
|
||||
- `packages/adapter-kimi-local/src/server/test.ts`
|
||||
|
||||
Problem:
|
||||
|
||||
- Health checks marked generic or partial runtimes as `degraded`.
|
||||
- Onboarding and orchestration still treated `degraded` as runnable.
|
||||
- Hiring and agent editing could still bind agents to connectors that were not suitable for autonomous execution.
|
||||
- `kimi_local` was explicitly documented as generic downgraded mode but was still able to enter product-critical flows.
|
||||
|
||||
Why this matters:
|
||||
|
||||
- The app could create or keep agents on runtimes that do not guarantee session resume or structured transcripts.
|
||||
- That breaks the internal coordination model because messaging, run tracking, recovery, and auditability depend on a stable execution contract.
|
||||
|
||||
### 3. Policy enforcement was inconsistent across desktop UI, IPC, and local agent API
|
||||
|
||||
Problem:
|
||||
|
||||
- Even if the renderer restricted a path, API or IPC handlers could still write invalid connector assignments unless the same rule existed server-side.
|
||||
|
||||
Why this matters:
|
||||
|
||||
- The system would appear correct in one surface and remain invalid in another.
|
||||
- That is an integrity failure, not a pure UI bug.
|
||||
|
||||
### 4. Architecture remains operationally real but still too concentrated
|
||||
|
||||
Largest modules remain heavy:
|
||||
|
||||
- `src/main/database.ts`
|
||||
- `src/main/api-server.ts`
|
||||
- `src/main/automation-service.ts`
|
||||
- `src/main/prompt-builder.ts`
|
||||
- `src/renderer/App.tsx`
|
||||
- `src/renderer/components/communication.tsx`
|
||||
- `src/renderer/components/execution.tsx`
|
||||
|
||||
Interpretation:
|
||||
|
||||
- The app is no longer a blank prototype, but some boundaries are still broader than a stable long-term production shape.
|
||||
- This is a structural follow-up item, not a reason to leave integrity bugs unfixed.
|
||||
|
||||
## Remediation Implemented In This Wave
|
||||
|
||||
### Shared connector execution policy
|
||||
|
||||
- Added `src/shared/connector-policy.ts`.
|
||||
- Defined a single execution-readiness rule used by main and renderer.
|
||||
- Autonomous execution now requires:
|
||||
- connector status `ready`
|
||||
- session resume support
|
||||
- structured transcript support
|
||||
|
||||
### Snapshot integrity correction
|
||||
|
||||
- Kept protective limits on the global snapshot path used by broad system scans.
|
||||
- Moved renderer and company analytics onto company-scoped SQL reads instead of filtering a global snapshot in memory.
|
||||
- Added company + `created_at` indexes so the scoped history reads can stay predictable as data grows.
|
||||
|
||||
### Main-side enforcement
|
||||
|
||||
- Onboarding now rejects non-execution-ready connectors instead of silently falling back.
|
||||
- Orchestration now blocks autonomous runs when the connector is not execution-ready.
|
||||
- IPC agent save / hire request paths now reject non-execution-ready connectors.
|
||||
- Local agent API hire requests now reject non-execution-ready connectors.
|
||||
|
||||
### Renderer alignment
|
||||
|
||||
- Onboarding only offers execution-ready connectors and explains why others are blocked.
|
||||
- Agent creation only offers execution-ready connectors.
|
||||
- Agent editing keeps blocked current connectors visible for repair, but prevents saving or waking until the agent is moved onto a ready connector.
|
||||
- Dashboard connector health now uses the same execution-readiness rule as onboarding and orchestration.
|
||||
|
||||
## Verification Executed
|
||||
|
||||
- `pnpm typecheck`
|
||||
- `pnpm lint`
|
||||
- `pnpm test:unit`
|
||||
- `pnpm test:integration`
|
||||
- `pnpm test:e2e`
|
||||
- `AGENTCOMPANY_BUILD_VERSION=0.4.39 pnpm build`
|
||||
|
||||
Build artifact produced in this session:
|
||||
|
||||
- `build/release/AgentCompany-0.4.39-arm64-mac.zip`
|
||||
|
||||
## Adversarial Review Outcome
|
||||
|
||||
- Reviewer CLI used: `claude -p`
|
||||
- Lenses run: skeptic, architect, minimalist
|
||||
- Accepted findings from that pass:
|
||||
- global LIMIT removal was the wrong fix; replaced with company-scoped SQL snapshot reads while keeping global caps
|
||||
- connector lookup failure needed structured `CONNECTOR_NOT_FOUND` handling instead of uncaught throws
|
||||
- dashboard readiness needed to use the same connector policy as onboarding and orchestration
|
||||
- Rejected findings from that pass:
|
||||
- version bump concerns were procedural, not product risk
|
||||
- pure shared readiness helpers used by renderer were acceptable because they remain data-only and build-safe in the current architecture
|
||||
|
||||
## Residual Risks Still Present After This Wave
|
||||
|
||||
### 1. Preload surface is still broad
|
||||
|
||||
- It is typed, but still larger than ideal for a final hardened desktop app.
|
||||
|
||||
### 2. Several modules are still too large
|
||||
|
||||
- The codebase still needs deeper boundary extraction in `database`, `api-server`, `automation-service`, renderer shell composition, and some feature panels.
|
||||
|
||||
### 3. Cross-platform packaging has not yet been runtime-verified on all target OSes in this session
|
||||
|
||||
- Packaging config exists for macOS, Windows, and Linux.
|
||||
- This session validated macOS packaging only.
|
||||
|
||||
### 4. Signing / updater production readiness still depends on release credentials and environment
|
||||
|
||||
- The code and config exist, but release trust still depends on actual signing/notarization/update infrastructure material.
|
||||
|
||||
## External References Used
|
||||
|
||||
- Electron security checklist:
|
||||
- https://www.electronjs.org/docs/latest/tutorial/security
|
||||
- Electron context bridge:
|
||||
- https://www.electronjs.org/docs/latest/api/context-bridge
|
||||
- Electron utility process:
|
||||
- https://www.electronjs.org/docs/latest/api/utility-process
|
||||
- electron-builder auto-update:
|
||||
- https://www.electron.build/auto-update
|
||||
- electron-builder macOS code signing:
|
||||
- https://www.electron.build/code-signing-mac
|
||||
@@ -1,167 +0,0 @@
|
||||
# AgentCompany Full System Audit + Cross-Feature Remediation (2026-03-18)
|
||||
|
||||
## Scope and Method
|
||||
|
||||
- Repository scan scope: `src/main`, `src/preload`, `src/renderer`, `src/shared`, `tests`, `scripts`, build config.
|
||||
- File inventory baseline: `173` tracked files (`rg --files | wc -l`).
|
||||
- Validation gates executed after remediation:
|
||||
- `pnpm typecheck`
|
||||
- `pnpm lint`
|
||||
- `pnpm typecheck:all`
|
||||
- `pnpm test:unit`
|
||||
- `pnpm test:integration`
|
||||
- `pnpm test:packages`
|
||||
- `pnpm test:e2e`
|
||||
- `AGENTCOMPANY_BUILD_VERSION=0.4.28 pnpm build`
|
||||
|
||||
## Mandatory Pipeline Mapping
|
||||
|
||||
### Phase 1 (ProjectManager): Scope + Milestones
|
||||
|
||||
- Current working milestone interpreted as: stabilize autonomous coordination + message workflow + desktop shell release readiness.
|
||||
- Release artifact target confirmed: macOS arm64 zip output in `/build/release`.
|
||||
|
||||
### Phase 2 (ResearchAnalyst): Electron + Desktop Constraints
|
||||
|
||||
- Security baseline validated against Electron guidance:
|
||||
- renderer with `contextIsolation: true`, `nodeIntegration: false`, `sandbox: true` in desktop shell and browser windows.
|
||||
- webview attach blocked; external navigation constrained in shell manager.
|
||||
- Packaging/update baseline validated against `electron-builder.yml` and runtime build script.
|
||||
|
||||
### Phase 3 (TechnicalImplementationResearcher): Integration Model
|
||||
|
||||
- High-friction subsystem identified: message pipeline drift across API/IPC/automation/renderer.
|
||||
- Root cause: duplicated validation + duplicated wake/emit logic + per-entrypoint special behavior.
|
||||
- Strategy used: unify dispatch semantics in one `main` module and route all entrypoints through it.
|
||||
|
||||
### Phase 4 (EnterpriseArchitect): Boundary Enforcement
|
||||
|
||||
- Main/preload/renderer boundary retained.
|
||||
- IPC contract hardened for message semantics (`direct`/`department`/`project` requirements).
|
||||
- Connector execution defaults tightened to avoid implicit unsafe permission bypass.
|
||||
|
||||
### Phase 5-8 (Implementation + Verification)
|
||||
|
||||
Implemented and validated in this cycle (details below).
|
||||
|
||||
## Cross-Feature Coupling Audit (Before Fix)
|
||||
|
||||
### Critical coupling defects
|
||||
|
||||
1. Message contract drift between API / IPC / automation
|
||||
- Different validation, wake-up targeting, and event emission behavior.
|
||||
2. Direct-message send path in renderer could lose recipient context outside reply mode.
|
||||
3. Mark-read visibility check used bounded list (`limit=500`), causing false negatives at scale.
|
||||
4. API message write path did not emit `new-message` event, unlike IPC/automation.
|
||||
5. Connector execution safety policy inconsistent (`claude_local` bypass always on).
|
||||
6. Console visibility control removed from header, breaking e2e contract and operator UX.
|
||||
|
||||
## Remediation Implemented
|
||||
|
||||
### 1) Unified message dispatch (single source of truth)
|
||||
|
||||
- Added: `src/main/message-dispatch.ts`
|
||||
- Centralized:
|
||||
- input normalization
|
||||
- company/agent/project/parent validation
|
||||
- send + event emission
|
||||
- domain refresh publication
|
||||
- wake target resolution by channel
|
||||
|
||||
### 2) API, IPC, automation now use same dispatch behavior
|
||||
|
||||
- API send route now uses `dispatchAgentMessage` and shared schema parse.
|
||||
- IPC send handler now uses `dispatchAgentMessage`.
|
||||
- Automation actions (`send_message`, escalation, cross-department notify) now use `dispatchAgentMessage`.
|
||||
|
||||
### 3) IPC + API mark-read visibility correction
|
||||
|
||||
- Added `messageId` filter support to `db.listAgentMessages(...)`.
|
||||
- Replaced broad visibility scans with targeted message visibility lookup (`limit: 1` + `messageId`).
|
||||
- Removed over-restrictive direct-recipient-only mark-read branch to avoid false denial when sender marks visible thread entries.
|
||||
|
||||
### 4) API event parity restored
|
||||
|
||||
- `AgentApiServer` now receives and uses `emitEvent` callback.
|
||||
- API-originated message writes now emit `new-message` event consistently with IPC/automation.
|
||||
|
||||
### 5) Connector security tightening
|
||||
|
||||
- `claude_local` execution config now ties `dangerouslySkipPermissions` to `AGENTCOMPANY_ALLOW_UNSAFE_CONNECTOR_BYPASS` (default false).
|
||||
- `.env.example` documents this guard variable.
|
||||
|
||||
### 6) Renderer communication channel correctness
|
||||
|
||||
- DM channels now store participant sets and resolve recipient deterministically for composer send path.
|
||||
- Compose modal enforces target requirements per channel (department/project require target; non-target channels clear target state).
|
||||
|
||||
### 7) Contract hardening
|
||||
|
||||
- `agentMessageInputSchema.superRefine(...)` enforces:
|
||||
- direct must provide `toAgentId`
|
||||
- department/project must provide `channelTargetId`
|
||||
- non-direct must not provide `toAgentId`
|
||||
- Dispatch layer now enforces the same non-direct recipient prohibition, eliminating API/automation semantic mismatch.
|
||||
|
||||
### 8) Desktop UX/e2e compatibility restore
|
||||
|
||||
- Restored header `Show console / Hide console` control in `App.tsx` with stable ARIA/title semantics used by e2e.
|
||||
|
||||
## Adversarial Review (Opposite Model CLI)
|
||||
|
||||
- Ran `claude -p` in three lenses: `skeptic`, `architect`, `minimalist`.
|
||||
- Output artifacts stored under `/tmp/adversarial-review-agentcompany-20260318-120225/`.
|
||||
- Key accepted findings addressed in this cycle:
|
||||
- unsafe connector bypass inconsistency
|
||||
- API event parity gap
|
||||
- bounded mark-read visibility check correctness gap
|
||||
- Remaining contested/medium findings (deferred) tracked in “Open Risks”.
|
||||
|
||||
## Open Risks / Remaining Work
|
||||
|
||||
1. `resolveMessageWakeTargets` is snapshot-based and can be heavy at larger org scale.
|
||||
2. Incident/company channel wake fan-out can cause high wake volume without throttling.
|
||||
3. Message attachment JSON is stored as raw string; no structural JSON validation yet.
|
||||
4. Some renderer DM channel avatar semantics still depend on ambiguous channel-level `agentId` for two-party threads.
|
||||
5. Update/notarization production credential flow still depends on release environment material availability.
|
||||
|
||||
## Verification Evidence
|
||||
|
||||
- Type safety: pass (`pnpm typecheck`, `pnpm typecheck:all`).
|
||||
- Lint: pass (`pnpm lint`).
|
||||
- Unit/integration/package tests: pass.
|
||||
- E2E smoke: pass.
|
||||
- Build packaging:
|
||||
- build folder cleaned by script
|
||||
- version used: `0.4.28`
|
||||
- artifact produced: `build/release/AgentCompany-0.4.28-arm64-mac.zip`
|
||||
|
||||
## External Research References
|
||||
|
||||
- Electron security checklist and architecture guidance:
|
||||
- https://www.electronjs.org/docs/latest/tutorial/security
|
||||
- Preload and contextBridge guidance:
|
||||
- https://www.electronjs.org/docs/latest/tutorial/tutorial-preload
|
||||
- https://www.electronjs.org/docs/latest/api/context-bridge
|
||||
- BrowserWindow/webPreferences hardening:
|
||||
- https://www.electronjs.org/docs/latest/api/browser-window
|
||||
- Utility/background process model:
|
||||
- https://www.electronjs.org/docs/latest/api/utility-process
|
||||
- Packaging and auto-update config:
|
||||
- https://www.electron.build/
|
||||
- https://www.electron.build/auto-update
|
||||
|
||||
## Changed Files (this remediation wave)
|
||||
|
||||
- `src/main/message-dispatch.ts` (new)
|
||||
- `src/main/api-server.ts`
|
||||
- `src/main/ipc-agent-coordination-handlers.ts`
|
||||
- `src/main/database.ts`
|
||||
- `src/main/automation-service.ts`
|
||||
- `src/main/bootstrap-application.ts`
|
||||
- `src/main/orchestrator/worker.ts`
|
||||
- `src/shared/contracts.ts`
|
||||
- `src/renderer/components/communication.tsx`
|
||||
- `src/renderer/App.tsx`
|
||||
- `.env.example`
|
||||
- `package.json`
|
||||
@@ -1,333 +0,0 @@
|
||||
# AgentCompany Integrated Audit Matrix (2026-03-18)
|
||||
|
||||
## Scope
|
||||
|
||||
This audit covered:
|
||||
|
||||
- `PRD.md`
|
||||
- Electron main / preload / renderer source under `src/main`, `src/preload`, `src/renderer`, `src/shared`
|
||||
- Packaging and runtime config: `electron-builder.yml`, `electron.vite.config.ts`, `scripts/build-desktop.mjs`
|
||||
- Existing validation assets under `tests/unit`, `tests/integration`, `tests/e2e`
|
||||
- Runtime validation through a live Electron launch with real IPC, onboarding, org creation, approvals, and run orchestration
|
||||
|
||||
## Evidence Collected
|
||||
|
||||
Validation commands executed in this session:
|
||||
|
||||
- `pnpm typecheck`
|
||||
- `pnpm lint`
|
||||
- `pnpm test:unit`
|
||||
- `pnpm test:integration`
|
||||
- `pnpm test:e2e`
|
||||
- `pnpm electron-vite build`
|
||||
|
||||
Additional runtime scenarios executed against the built Electron app:
|
||||
|
||||
- full first-launch onboarding to desktop shell
|
||||
- navigation sweep across desktop sections
|
||||
- live hire request flow with `autoApproveHires = true`
|
||||
- live hire request flow with `autoApproveHires = false`
|
||||
- negative-path validation that legacy `saveAgent` creation and `pending_approval -> idle` status bypasses are rejected
|
||||
|
||||
## Current Architecture Reality
|
||||
|
||||
What already exists and is materially real:
|
||||
|
||||
- main / preload / renderer separation is implemented
|
||||
- renderer uses typed preload APIs instead of raw Node access
|
||||
- `contextIsolation: true`, `nodeIntegration: false`, `sandbox: true` are used for the main desktop shell
|
||||
- orchestration worker runs in an Electron utility process
|
||||
- SQLite-backed local-first state model exists
|
||||
- connectors for `codex_local`, `claude_local`, `gemini_local`, `opencode_local`, `kimi_local` exist
|
||||
- approvals, runs, costs, activity, automation, meetings, knowledge, documents, sprints, social, messages, workspaces, and onboarding all exist in code and UI
|
||||
|
||||
What is still structurally weak:
|
||||
|
||||
- several modules are still too large to be considered stable long-term coordination boundaries
|
||||
- cross-feature side effects still live in a few orchestration-heavy modules instead of a smaller explicit event-policy layer
|
||||
- some release/security/product rules exist in PRD and code, but not all are enforced uniformly in every write path
|
||||
|
||||
Largest modules by line count at audit time:
|
||||
|
||||
- `src/main/database.ts`: 3348
|
||||
- `src/renderer/components/execution.tsx`: 1726
|
||||
- `src/renderer/components/communication.tsx`: 1726
|
||||
- `src/main/api-server.ts`: 1697
|
||||
- `src/renderer/components/automation.tsx`: 1693
|
||||
- `src/renderer/App.tsx`: 1606
|
||||
- `src/main/prompt-builder.ts`: 1541
|
||||
|
||||
## PRD Matrix
|
||||
|
||||
### 1. Local Profile / Company
|
||||
|
||||
Status: implemented, with one policy caveat
|
||||
|
||||
Evidence:
|
||||
|
||||
- local profile bootstrap, backup/restore, company switching, settings persistence all exist
|
||||
- onboarding successfully creates company, workspace, goal, initial run, and opens desktop shell
|
||||
|
||||
Remaining risk:
|
||||
|
||||
- company policy toggles are present, but some governance behavior is still distributed across UI, IPC, API, and automation rather than centralized in a single policy service
|
||||
|
||||
### 2. Connector Management
|
||||
|
||||
Status: implemented
|
||||
|
||||
Evidence:
|
||||
|
||||
- connector registry UI exists
|
||||
- connector health service exists
|
||||
- model listing and auth terminal support exist
|
||||
- command/env binding handling exists
|
||||
|
||||
Remaining risk:
|
||||
|
||||
- connector execution policy is still sensitive to environment-based behavior and deserves a dedicated policy surface, not scattered guard clauses
|
||||
|
||||
### 3. Agent Registry / Org Structure
|
||||
|
||||
Status: implemented, previously inconsistent, partially hardened in this wave
|
||||
|
||||
Evidence:
|
||||
|
||||
- org chart, agent roster, hiring pipeline, manager/report relationships, and budget fields exist
|
||||
- pending-approval lifecycle exists in data model and approval resolution logic
|
||||
|
||||
Critical finding fixed in this wave:
|
||||
|
||||
- renderer previously allowed direct agent creation from the Agents page, bypassing `hire_agent` approval and breaking synchronization between Hiring, Approvals, onboarding, and org history
|
||||
- renderer also allowed direct status edits that could move a pending hire into an active state without an approval decision
|
||||
|
||||
Remediation added:
|
||||
|
||||
- dedicated `requestHire` IPC contract
|
||||
- transactional `createHireRequest(...)` persistence path
|
||||
- renderer Agent creation now submits hire requests instead of active agents
|
||||
- IPC `saveAgent` now rejects new-agent creation and rejects direct pending-hire activation
|
||||
|
||||
Runtime proof:
|
||||
|
||||
- with `autoApproveHires = false`, a new hire lands in `pending_approval`
|
||||
- direct `saveAgent` creation returns `AGENT_CREATION_REQUIRES_HIRE_REQUEST`
|
||||
- direct status bypass returns `AGENT_APPROVAL_REQUIRED`
|
||||
- formal approval transitions the same agent record to `idle`
|
||||
|
||||
### 4. Goals / Projects / Tasks
|
||||
|
||||
Status: implemented
|
||||
|
||||
Evidence:
|
||||
|
||||
- onboarding creates goal and project structure
|
||||
- task creation, comments, assignment, review states, kanban/list views, and run linkage exist
|
||||
- task status changes feed automation/orchestration paths
|
||||
|
||||
Remaining risk:
|
||||
|
||||
- feature is functionally present, but task + review + message + automation interactions are still distributed across large renderer and main modules
|
||||
|
||||
### 5. Run Orchestration / Session Continuity
|
||||
|
||||
Status: implemented, with scaling caveats
|
||||
|
||||
Evidence:
|
||||
|
||||
- run creation, queueing, worker dispatch, recovery, logs, cancellation, and run status events exist
|
||||
- utility-process worker is used instead of running orchestration in the renderer
|
||||
- integration tests cover autonomous chain and recovery cases
|
||||
|
||||
Remaining risk:
|
||||
|
||||
- orchestration and wake logic remain heavily centralized
|
||||
- cross-feature triggers are correct at current scope, but scaling behavior and event fan-out still need a slimmer event-policy boundary
|
||||
|
||||
### 6. Approvals / Governance
|
||||
|
||||
Status: implemented, materially improved in this wave
|
||||
|
||||
Evidence:
|
||||
|
||||
- approvals UI, decision handling, related task linkage, and automation callbacks exist
|
||||
- board-side approval decisions update state and trigger follow-up automations
|
||||
|
||||
Critical finding fixed in this wave:
|
||||
|
||||
- agent creation governance could be bypassed from the desktop UI and IPC write path
|
||||
|
||||
Remaining risk:
|
||||
|
||||
- other approval-governed domains, especially termination and production-deploy style flows, still deserve the same hard policy treatment across all entrypoints
|
||||
|
||||
### 7. Cost / Budget
|
||||
|
||||
Status: implemented
|
||||
|
||||
Evidence:
|
||||
|
||||
- budget fields, cost entries, cost dashboard, thresholds, and budget-related automation logic exist
|
||||
|
||||
Remaining risk:
|
||||
|
||||
- budgets are enforced operationally, but not all escalation policy is centralized; some cost behavior is still advisory rather than hard-stopping privileged actions
|
||||
|
||||
### 8. Activity / Audit / Logs
|
||||
|
||||
Status: implemented
|
||||
|
||||
Evidence:
|
||||
|
||||
- activity timeline exists
|
||||
- many core mutations add activity entries
|
||||
- run logs exist and are streamable into renderer console panels
|
||||
|
||||
Remaining risk:
|
||||
|
||||
- structured logging exists, but the audit trail is still assembled from multiple write sites instead of passing through a smaller domain-event backbone
|
||||
|
||||
### 9. Secrets / Config / Environment
|
||||
|
||||
Status: implemented, hardened in this wave
|
||||
|
||||
Evidence:
|
||||
|
||||
- Electron `safeStorage` is used where available
|
||||
- encrypted fallback vault exists behind explicit env opt-in
|
||||
- env binding resolution exists for connector runs
|
||||
|
||||
Security hardening added in this wave:
|
||||
|
||||
- `NODE_OPTIONS` was removed from the runtime environment allowlist so spawned agent runtimes do not inherit host-side Node injection flags by default
|
||||
|
||||
Remaining risk:
|
||||
|
||||
- preload API surface is still large, even if typed
|
||||
- env policy should eventually be expressed as explicit runtime capability profiles per connector, not only a static allowlist
|
||||
|
||||
### 10. Workspace / Repo / Artifact Management
|
||||
|
||||
Status: implemented
|
||||
|
||||
Evidence:
|
||||
|
||||
- workspace registry, path selection, repo URL/ref fields, primary workspace logic, and lock metadata exist
|
||||
- orchestration resolves workspace context into runtime env
|
||||
|
||||
Remaining risk:
|
||||
|
||||
- workspace locking and stale-lock cleanup exist, but deserve more explicit operator-facing conflict states in UI for complex multi-run contention
|
||||
|
||||
### 11. Notifications / State Awareness
|
||||
|
||||
Status: implemented
|
||||
|
||||
Evidence:
|
||||
|
||||
- desktop notifications exist
|
||||
- tray/menu/window controls exist
|
||||
- sidebar badges, inbox, and console surfacing exist
|
||||
|
||||
Remaining risk:
|
||||
|
||||
- notification strategy is present but not yet tuned as a full release-quality desktop attention model across macOS, Windows, and Linux
|
||||
|
||||
## Electron / Security / Release Audit
|
||||
|
||||
### Security Baseline
|
||||
|
||||
Status: mostly aligned
|
||||
|
||||
Confirmed:
|
||||
|
||||
- secure BrowserWindow defaults are in place
|
||||
- renderer does not receive raw Node primitives
|
||||
- preload uses typed IPC contract calls
|
||||
- utility process is used for background orchestration work
|
||||
- vault prefers OS-backed secret storage
|
||||
|
||||
New hardening applied:
|
||||
|
||||
- runtime env no longer forwards host `NODE_OPTIONS`
|
||||
- pending-hire governance cannot be bypassed from renderer IPC
|
||||
|
||||
Still open:
|
||||
|
||||
- preload surface is broader than ideal for a production app of this size
|
||||
- some domain rules are enforced in handlers rather than at a smaller dedicated policy layer
|
||||
|
||||
### Packaging / Release
|
||||
|
||||
Status: partially complete
|
||||
|
||||
Confirmed:
|
||||
|
||||
- `electron-builder.yml` targets macOS, Windows, Linux
|
||||
- build script cleans `/build`, stages a non-mutating build version, and outputs into `/build/release`
|
||||
- e2e and build use the current Electron/Vite packaging path correctly
|
||||
|
||||
Still open:
|
||||
|
||||
- this audit validated runtime on the current local platform only
|
||||
- cross-platform runtime differences and signing/notarization behavior still need explicit validation evidence per target platform
|
||||
- updater flow currently checks availability but does not yet provide a fully operator-visible download/install lifecycle
|
||||
|
||||
### Performance
|
||||
|
||||
Status: acceptable for current prototype depth, not yet release-optimized
|
||||
|
||||
Evidence:
|
||||
|
||||
- app launches and is usable in live runtime checks
|
||||
- worker isolation prevents heavy agent runs from living in renderer
|
||||
|
||||
Remaining risk:
|
||||
|
||||
- renderer build currently produces an approximately `1.7 MB` main JS chunk, which is too large for a polished long-term desktop shell
|
||||
- mega-components still make fine-grained performance work harder than it should be
|
||||
|
||||
## External Research Used
|
||||
|
||||
Primary references used for this audit:
|
||||
|
||||
- Electron security checklist: https://www.electronjs.org/docs/latest/tutorial/security
|
||||
- Electron process model / utility process guidance: https://www.electronjs.org/docs/latest/tutorial/process-model
|
||||
- Electron safe storage API: https://www.electronjs.org/docs/latest/api/safe-storage
|
||||
- electron-builder auto-update guidance: https://www.electron.build/auto-update
|
||||
|
||||
These references were used to validate:
|
||||
|
||||
- secure BrowserWindow / preload expectations
|
||||
- utility-process suitability for background work
|
||||
- safe secret storage expectations
|
||||
- updater/build configuration direction
|
||||
|
||||
## Remediation Implemented In This Wave
|
||||
|
||||
Files changed in this wave:
|
||||
|
||||
- `src/shared/contracts.ts`
|
||||
- `src/preload/index.ts`
|
||||
- `src/main/runtime-env.ts`
|
||||
- `src/main/database.ts`
|
||||
- `src/main/ipc-core-work-graph-handlers.ts`
|
||||
- `src/renderer/components/organization.tsx`
|
||||
- `src/renderer/App.tsx`
|
||||
|
||||
Concrete changes:
|
||||
|
||||
- added typed `requestHire` contract and preload API
|
||||
- added transactional `createHireRequest(...)` database path
|
||||
- rerouted renderer new-agent flow into hiring / approvals pipeline
|
||||
- blocked direct renderer IPC creation of active agents
|
||||
- blocked direct renderer status promotion of pending hires
|
||||
- tightened runtime env inheritance by removing `NODE_OPTIONS`
|
||||
|
||||
## Remaining High-Value Follow-Ups
|
||||
|
||||
1. Split `App.tsx`, `database.ts`, `api-server.ts`, `automation-service.ts`, `communication.tsx`, and `execution.tsx` into smaller domain slices.
|
||||
2. Pull wake / publish / automation side effects into an explicit domain-event policy layer instead of leaving them distributed in orchestration-heavy modules.
|
||||
3. Shrink the renderer entry chunk with section-level lazy loading for heavyweight desktop panels.
|
||||
4. Make updater lifecycle operator-visible beyond availability checks.
|
||||
5. Validate runtime behavior on Windows and Linux rather than relying only on configured targets.
|
||||
@@ -1,13 +0,0 @@
|
||||
# Docs Index
|
||||
|
||||
Active documents only.
|
||||
|
||||
- [2026-03-17-audit-and-rebuild-plan.md](./2026-03-17-audit-and-rebuild-plan.md)
|
||||
- [2026-03-17-architecture-freeze.md](./2026-03-17-architecture-freeze.md)
|
||||
- [2026-03-17-runtime-security-tranche.md](./2026-03-17-runtime-security-tranche.md)
|
||||
|
||||
Removed:
|
||||
|
||||
- duplicate audit snapshots
|
||||
- duplicate rebuild plans
|
||||
- stale one-off implementation deltas that no longer matched the working tree
|
||||
+9
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "agent-company",
|
||||
"version": "0.4.47",
|
||||
"version": "0.4.52",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"description": "Cross-platform Electron desktop control plane for local-first AI agent companies.",
|
||||
@@ -66,5 +66,12 @@
|
||||
"node": ">=22.0.0",
|
||||
"pnpm": ">=10.0.0"
|
||||
},
|
||||
"packageManager": "pnpm@10.24.0"
|
||||
"packageManager": "pnpm@10.24.0",
|
||||
"pnpm": {
|
||||
"onlyBuiltDependencies": [
|
||||
"electron",
|
||||
"electron-winstaller",
|
||||
"esbuild"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,19 @@ import { constants as fsConstants, promises as fs } from "node:fs";
|
||||
import path from "node:path";
|
||||
import { StringDecoder } from "node:string_decoder";
|
||||
|
||||
/**
|
||||
* Decode a Buffer as GBK (CP936). Used as a fallback when UTF-8 decoding
|
||||
* produces replacement characters on Chinese Windows systems where the
|
||||
* system ANSI code page is GBK and chcp 65001 is ineffective for piped I/O.
|
||||
*/
|
||||
function decodeGbkBuffer(buf: Buffer): string {
|
||||
try {
|
||||
return new TextDecoder("gbk").decode(buf);
|
||||
} catch {
|
||||
return buf.toString("utf8");
|
||||
}
|
||||
}
|
||||
|
||||
export interface RunProcessResult {
|
||||
exitCode: number | null;
|
||||
signal: string | null;
|
||||
@@ -331,10 +344,14 @@ export async function runChildProcess(
|
||||
let stderr = "";
|
||||
let logChain: Promise<void> = Promise.resolve();
|
||||
|
||||
// Use StringDecoder to correctly handle multi-byte UTF-8 characters
|
||||
// that may be split across chunk boundaries (e.g. Chinese characters).
|
||||
// Use StringDecoder to handle multi-byte characters split across chunks.
|
||||
// On Windows, child process stdout may arrive in GBK (CP936) instead
|
||||
// of UTF-8 when chcp 65001 is ineffective (piped stdout has no console).
|
||||
// We detect this per-stream and fall back to GBK decoding if needed.
|
||||
const stdoutDecoder = new StringDecoder("utf8");
|
||||
const stderrDecoder = new StringDecoder("utf8");
|
||||
let stdoutIsGbk = false;
|
||||
let stderrIsGbk = false;
|
||||
|
||||
const timeout =
|
||||
opts.timeoutSec > 0
|
||||
@@ -350,7 +367,20 @@ export async function runChildProcess(
|
||||
: null;
|
||||
|
||||
child.stdout?.on("data", (chunk: unknown) => {
|
||||
const text = chunk instanceof Buffer ? stdoutDecoder.write(chunk) : String(chunk);
|
||||
let text: string;
|
||||
if (chunk instanceof Buffer) {
|
||||
if (stdoutIsGbk) {
|
||||
text = decodeGbkBuffer(chunk);
|
||||
} else {
|
||||
text = stdoutDecoder.write(chunk);
|
||||
if (text.includes("\ufffd") && chunk.length > 0) {
|
||||
stdoutIsGbk = true;
|
||||
text = decodeGbkBuffer(chunk);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
text = String(chunk);
|
||||
}
|
||||
stdout = appendWithCap(stdout, text);
|
||||
logChain = logChain
|
||||
.then(() => opts.onLog("stdout", text))
|
||||
@@ -358,7 +388,20 @@ export async function runChildProcess(
|
||||
});
|
||||
|
||||
child.stderr?.on("data", (chunk: unknown) => {
|
||||
const text = chunk instanceof Buffer ? stderrDecoder.write(chunk) : String(chunk);
|
||||
let text: string;
|
||||
if (chunk instanceof Buffer) {
|
||||
if (stderrIsGbk) {
|
||||
text = decodeGbkBuffer(chunk);
|
||||
} else {
|
||||
text = stderrDecoder.write(chunk);
|
||||
if (text.includes("\ufffd") && chunk.length > 0) {
|
||||
stderrIsGbk = true;
|
||||
text = decodeGbkBuffer(chunk);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
text = String(chunk);
|
||||
}
|
||||
stderr = appendWithCap(stderr, text);
|
||||
logChain = logChain
|
||||
.then(() => opts.onLog("stderr", text))
|
||||
|
||||
+26
-2
@@ -10,6 +10,29 @@ import type { AppDatabase } from "./database";
|
||||
import { dispatchAgentMessage } from "./message-dispatch";
|
||||
import type { DesktopEvent } from "@shared/types";
|
||||
|
||||
/**
|
||||
* Decode an HTTP request body to a UTF-8 string, handling the common Windows
|
||||
* encoding issue where Chinese/CJK characters arrive in GBK (CP936) instead
|
||||
* of UTF-8. On Chinese Windows the system ANSI code page is GBK; tools like
|
||||
* curl encode command-line arguments using that code page when stdout is piped
|
||||
* (chcp 65001 does not help because there is no real console). We try strict
|
||||
* UTF-8 first and, only if the bytes are invalid UTF-8, fall back to GBK.
|
||||
*/
|
||||
function decodeBodyToUtf8(raw: Buffer): string {
|
||||
if (raw.length === 0) return "";
|
||||
try {
|
||||
return new TextDecoder("utf-8", { fatal: true }).decode(raw);
|
||||
} catch {
|
||||
// Bytes are not valid UTF-8 — most likely GBK from Chinese Windows.
|
||||
try {
|
||||
return new TextDecoder("gbk").decode(raw);
|
||||
} catch {
|
||||
// Last resort: lossy UTF-8 (replaces invalid bytes with U+FFFD).
|
||||
return raw.toString("utf8");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type RequestHandler = (
|
||||
req: IncomingMessage,
|
||||
res: ServerResponse,
|
||||
@@ -234,7 +257,8 @@ export class AgentApiServer {
|
||||
});
|
||||
req.on("end", () => {
|
||||
try {
|
||||
const data = Buffer.concat(chunks).toString("utf8");
|
||||
const raw = Buffer.concat(chunks);
|
||||
const data = decodeBodyToUtf8(raw);
|
||||
resolve(data ? JSON.parse(data) : null);
|
||||
}
|
||||
catch { reject(new Error("Invalid JSON")); }
|
||||
@@ -244,7 +268,7 @@ export class AgentApiServer {
|
||||
}
|
||||
|
||||
private json(res: ServerResponse, status: number, data: unknown) {
|
||||
res.writeHead(status, { "Content-Type": "application/json" });
|
||||
res.writeHead(status, { "Content-Type": "application/json; charset=utf-8" });
|
||||
res.end(JSON.stringify(data));
|
||||
}
|
||||
|
||||
|
||||
+33
-4
@@ -76,6 +76,32 @@ function safeRealpath(targetPath: string) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the last complete UTF-8 character boundary in a buffer.
|
||||
* Returns the number of bytes up to (and including) the last complete character.
|
||||
* This prevents corrupting multi-byte CJK characters when slicing at chunk edges.
|
||||
*/
|
||||
function findUtf8Boundary(buffer: Buffer, bytesRead: number): number {
|
||||
if (bytesRead === 0) return 0;
|
||||
// Walk backwards past continuation bytes (10xxxxxx)
|
||||
let pos = bytesRead - 1;
|
||||
while (pos >= 0 && (buffer[pos] & 0xc0) === 0x80) {
|
||||
pos--;
|
||||
}
|
||||
if (pos < 0) return bytesRead;
|
||||
const lead = buffer[pos];
|
||||
let charLen: number;
|
||||
if ((lead & 0x80) === 0) charLen = 1;
|
||||
else if ((lead & 0xe0) === 0xc0) charLen = 2;
|
||||
else if ((lead & 0xf0) === 0xe0) charLen = 3;
|
||||
else if ((lead & 0xf8) === 0xf0) charLen = 4;
|
||||
else return bytesRead;
|
||||
// If the character is complete within the buffer, keep all bytes
|
||||
if (pos + charLen <= bytesRead) return bytesRead;
|
||||
// Otherwise truncate before the incomplete character
|
||||
return pos;
|
||||
}
|
||||
|
||||
function taskPriorityOrderSql(columnName: string) {
|
||||
return `case ${columnName}
|
||||
when 'critical' then 4
|
||||
@@ -1156,14 +1182,14 @@ export class AppDatabase {
|
||||
.run(id, input.companyId, input.taskId, input.agentId, input.workspaceId, input.connectorId, logPath, ts, ts);
|
||||
this.db.prepare("update tasks set active_run_id = ?, updated_at = ? where id = ?").run(id, ts, input.taskId);
|
||||
});
|
||||
writeFileSync(logPath, "");
|
||||
writeFileSync(logPath, "", "utf8");
|
||||
return { id, logPath };
|
||||
}
|
||||
|
||||
appendRunLog(runId: string, stream: "stdout" | "stderr", chunk: string) {
|
||||
const run = this.db.prepare("select log_path as logPath from runs where id = ?").get(runId) as { logPath: string | null } | undefined;
|
||||
if (!run?.logPath) return;
|
||||
return appendFile(run.logPath, `[${new Date().toISOString()}][${stream}] ${chunk}`);
|
||||
return appendFile(run.logPath, `[${new Date().toISOString()}][${stream}] ${chunk}`, "utf8");
|
||||
}
|
||||
|
||||
readRunLog(runId: string) {
|
||||
@@ -1207,9 +1233,12 @@ export class AppDatabase {
|
||||
try {
|
||||
const buffer = Buffer.allocUnsafe(bytesToRead);
|
||||
const bytesRead = readSync(fileDescriptor, buffer, 0, bytesToRead, safeOffset);
|
||||
const nextOffset = safeOffset + bytesRead;
|
||||
// Find the last complete UTF-8 character boundary to avoid corrupting
|
||||
// multi-byte characters (e.g. Chinese/CJK 3-byte sequences) at the edge.
|
||||
const safeBytesRead = findUtf8Boundary(buffer, bytesRead);
|
||||
const nextOffset = safeOffset + safeBytesRead;
|
||||
return {
|
||||
content: buffer.subarray(0, bytesRead).toString("utf8"),
|
||||
content: buffer.subarray(0, safeBytesRead).toString("utf8"),
|
||||
offset: safeOffset,
|
||||
nextOffset,
|
||||
totalBytes,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { existsSync } from "node:fs";
|
||||
import { extname } from "node:path";
|
||||
import { pathToFileURL } from "node:url";
|
||||
import { resolve, sep } from "node:path";
|
||||
import {
|
||||
@@ -81,14 +82,33 @@ export function createDesktopShellService({
|
||||
}
|
||||
|
||||
function registerProtocol() {
|
||||
protocol.handle("app", (request) => {
|
||||
const textMimeTypes: Record<string, string> = {
|
||||
".html": "text/html; charset=utf-8",
|
||||
".js": "text/javascript; charset=utf-8",
|
||||
".mjs": "text/javascript; charset=utf-8",
|
||||
".css": "text/css; charset=utf-8",
|
||||
".json": "application/json; charset=utf-8",
|
||||
".svg": "image/svg+xml; charset=utf-8",
|
||||
};
|
||||
protocol.handle("app", async (request) => {
|
||||
const url = new URL(request.url);
|
||||
const relativePath = decodeURIComponent(url.pathname === "/" ? "index.html" : url.pathname.replace(/^\/+/, ""));
|
||||
const targetPath = resolve(rendererDist, relativePath);
|
||||
if (!isWithinDirectory(rendererDist, targetPath) || !existsSync(targetPath)) {
|
||||
return new Response("Not found", { status: 404 });
|
||||
}
|
||||
return net.fetch(pathToFileURL(targetPath).toString());
|
||||
const response = await net.fetch(pathToFileURL(targetPath).toString());
|
||||
const mime = textMimeTypes[extname(targetPath).toLowerCase()];
|
||||
if (mime) {
|
||||
const headers = new Headers(response.headers);
|
||||
headers.set("Content-Type", mime);
|
||||
return new Response(response.body, {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
headers,
|
||||
});
|
||||
}
|
||||
return response;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+27
-18
@@ -451,38 +451,47 @@ Do not print or echo AGENT_COMPANY_API_KEY into comments, summaries, or external
|
||||
## Authentication & Request Format
|
||||
Every API call MUST include these headers:
|
||||
Authorization: Bearer $AGENT_COMPANY_API_KEY
|
||||
Content-Type: application/json
|
||||
Content-Type: application/json; charset=utf-8
|
||||
X-Agent-Company-Run-Id: ${ctx.runId}
|
||||
|
||||
Example using curl:
|
||||
curl -s -X GET "$AGENT_COMPANY_API_URL/api/agents/me" \\
|
||||
-H "Authorization: Bearer $AGENT_COMPANY_API_KEY" \\
|
||||
-H "Content-Type: application/json" \\
|
||||
-H "X-Agent-Company-Run-Id: ${ctx.runId}"
|
||||
IMPORTANT: On Windows, prefer using Node.js fetch() for API calls instead of curl,
|
||||
because curl on Windows may corrupt non-ASCII characters (Chinese, Japanese, etc.).
|
||||
If you must use curl, write the JSON body to a temp file first and use curl -d @file.
|
||||
|
||||
Example using fetch (Node.js):
|
||||
Example using fetch (Node.js) — PREFERRED:
|
||||
const res = await fetch(\`\${process.env.AGENT_COMPANY_API_URL}/api/agents/me\`, {
|
||||
headers: {
|
||||
"Authorization": \`Bearer \${process.env.AGENT_COMPANY_API_KEY}\`,
|
||||
"Content-Type": "application/json",
|
||||
"Content-Type": "application/json; charset=utf-8",
|
||||
"X-Agent-Company-Run-Id": "${ctx.runId}"
|
||||
}
|
||||
});
|
||||
const data = await res.json();
|
||||
|
||||
Example POST using curl:
|
||||
Example POST using fetch (Node.js) — PREFERRED for non-ASCII content:
|
||||
const res = await fetch(\`\${process.env.AGENT_COMPANY_API_URL}/api/companies/${ctx.agent.companyId}/issues\`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Authorization": \`Bearer \${process.env.AGENT_COMPANY_API_KEY}\`,
|
||||
"Content-Type": "application/json; charset=utf-8",
|
||||
"X-Agent-Company-Run-Id": "${ctx.runId}"
|
||||
},
|
||||
body: JSON.stringify({title:"Task title",description:"Details",assigneeAgentId:"agent-id",priority:"medium",status:"todo"})
|
||||
});
|
||||
|
||||
Example GET using curl:
|
||||
curl -s -X GET "$AGENT_COMPANY_API_URL/api/agents/me" \\
|
||||
-H "Authorization: Bearer $AGENT_COMPANY_API_KEY" \\
|
||||
-H "Content-Type: application/json; charset=utf-8" \\
|
||||
-H "X-Agent-Company-Run-Id: ${ctx.runId}"
|
||||
|
||||
Example POST using curl (write body to temp file to avoid encoding issues):
|
||||
echo '{"title":"Task title","description":"Details","priority":"medium","status":"todo"}' > /tmp/body.json
|
||||
curl -s -X POST "$AGENT_COMPANY_API_URL/api/companies/${ctx.agent.companyId}/issues" \\
|
||||
-H "Authorization: Bearer $AGENT_COMPANY_API_KEY" \\
|
||||
-H "Content-Type: application/json" \\
|
||||
-H "Content-Type: application/json; charset=utf-8" \\
|
||||
-H "X-Agent-Company-Run-Id: ${ctx.runId}" \\
|
||||
-d '{"title":"Task title","description":"Details","assigneeAgentId":"agent-id","priority":"medium","status":"todo"}'
|
||||
|
||||
Example PATCH using curl:
|
||||
curl -s -X PATCH "$AGENT_COMPANY_API_URL/api/issues/ISSUE_ID" \\
|
||||
-H "Authorization: Bearer $AGENT_COMPANY_API_KEY" \\
|
||||
-H "Content-Type: application/json" \\
|
||||
-H "X-Agent-Company-Run-Id: ${ctx.runId}" \\
|
||||
-d '{"status":"in_review","comment":"Work completed. Summary of changes: ..."}'
|
||||
-d @/tmp/body.json
|
||||
|
||||
IMPORTANT: Always check the HTTP response status. 200/201 = success, 4xx = client error (read the error message), 5xx = server error (retry once then report).
|
||||
|
||||
|
||||
@@ -323,6 +323,10 @@ export function App() {
|
||||
}
|
||||
}, [snapshot, locale]);
|
||||
|
||||
useEffect(() => {
|
||||
document.documentElement.lang = locale === "zh" ? "zh-CN" : "en";
|
||||
}, [locale]);
|
||||
|
||||
const handleLocaleChange = useCallback(async (newLocale: AppLocale) => {
|
||||
setLocale(newLocale);
|
||||
try {
|
||||
|
||||
+10
-2
@@ -1,5 +1,13 @@
|
||||
@import "tailwindcss";
|
||||
|
||||
@theme {
|
||||
--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
||||
"Microsoft YaHei", "PingFang SC", "Hiragino Sans GB",
|
||||
"Noto Sans CJK SC", Helvetica, Arial, sans-serif;
|
||||
--font-mono: "JetBrains Mono Variable", "Microsoft YaHei", ui-monospace,
|
||||
SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
||||
}
|
||||
|
||||
:root {
|
||||
color-scheme: light;
|
||||
--bg: #fbfbfb;
|
||||
@@ -82,7 +90,7 @@ body {
|
||||
margin: 0;
|
||||
background: var(--bg);
|
||||
color: var(--text);
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Microsoft YaHei", "PingFang SC", "Hiragino Sans GB", "Noto Sans CJK SC", Helvetica, Arial, sans-serif;
|
||||
font-family: var(--font-sans);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
@@ -120,7 +128,7 @@ select {
|
||||
}
|
||||
|
||||
.mono {
|
||||
font-family: "JetBrains Mono Variable", "Microsoft YaHei", monospace;
|
||||
font-family: var(--font-mono);
|
||||
}
|
||||
|
||||
.surface {
|
||||
|
||||
Reference in new issue
Block a user